summaryrefslogtreecommitdiff
path: root/plugins/adplug/adplug/mid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/adplug/adplug/mid.cpp')
-rw-r--r--plugins/adplug/adplug/mid.cpp148
1 files changed, 84 insertions, 64 deletions
diff --git a/plugins/adplug/adplug/mid.cpp b/plugins/adplug/adplug/mid.cpp
index e3dd88c5..03a2d84a 100644
--- a/plugins/adplug/adplug/mid.cpp
+++ b/plugins/adplug/adplug/mid.cpp
@@ -1,6 +1,6 @@
/*
* Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2008 Simon Peter, <dn.tlp@gmx.net>, et al.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -62,6 +62,11 @@
* 10/15/2005: Changes by Simon Peter
* Added rhythm mode support for CMF format.
*
+ * 09/13/2008: Changes by Adam Nielsen (malvineous@shikadi.net)
+ * Fixed a couple of CMF rhythm mode bugs
+ * Disabled note velocity for CMF files
+ * Added support for nonstandard CMF AM+VIB controller (for VGFM CMFs)
+ *
* Other acknowledgements:
* Allegro - for the midi instruments and the midi volume table
* SCUMM Revisited - for getting the .LAA / .MIDs out of those
@@ -106,9 +111,6 @@ void CmidPlayer::midiprintf(const char *format, ...)
// AdLib standard operator table
const unsigned char CmidPlayer::adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12};
-// dunno
-const int CmidPlayer::ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0};
-
// map CMF drum channels 12 - 15 to corresponding AdLib drum operators
// bass drum (channel 11) not mapped, cause it's handled like a normal instrument
const int CmidPlayer::map_chan[] = { 0x14, 0x12, 0x15, 0x11 };
@@ -300,12 +302,13 @@ bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp)
if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF;
break;
case 0x84:
- if (s[1]==0x00 && load_sierra_ins(filename, fp))
- if (s[2]==0xf0)
- good=FILE_ADVSIERRA;
- else
- good=FILE_SIERRA;
- break;
+ if (s[1]==0x00 && load_sierra_ins(filename, fp)) {
+ if (s[2]==0xf0)
+ good=FILE_ADVSIERRA;
+ else
+ good=FILE_SIERRA;
+ }
+ break;
default:
if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS;
break;
@@ -346,30 +349,24 @@ void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst)
midi_write_adlib(0x20+adlib_opadd[voice],inst[0]);
midi_write_adlib(0x23+adlib_opadd[voice],inst[1]);
- if ((adlib_style&LUCAS_STYLE)!=0)
- {
+ if (adlib_style & LUCAS_STYLE) {
midi_write_adlib(0x43+adlib_opadd[voice],0x3f);
if ((inst[10] & 1)==0)
midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
- else
- midi_write_adlib(0x40+adlib_opadd[voice],0x3f);
- }
else
- {
- if ((adlib_style&SIERRA_STYLE)!=0)
- {
- midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+ midi_write_adlib(0x40+adlib_opadd[voice],0x3f);
+
+ } else if ((adlib_style & SIERRA_STYLE) || (adlib_style & CMF_STYLE)) {
+ midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+ midi_write_adlib(0x43+adlib_opadd[voice],inst[3]);
+
+ } else {
+ midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+ if ((inst[10] & 1)==0)
midi_write_adlib(0x43+adlib_opadd[voice],inst[3]);
- }
- else
- {
- midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
- if ((inst[10] & 1)==0)
- midi_write_adlib(0x43+adlib_opadd[voice],inst[3]);
- else
- midi_write_adlib(0x43+adlib_opadd[voice],0);
- }
- }
+ else
+ midi_write_adlib(0x43+adlib_opadd[voice],0);
+ }
midi_write_adlib(0x60+adlib_opadd[voice],inst[4]);
midi_write_adlib(0x63+adlib_opadd[voice],inst[5]);
@@ -390,7 +387,8 @@ void CmidPlayer::midi_fm_percussion(int ch, unsigned char *inst)
midi_write_adlib(0x60 + opadd, inst[4]);
midi_write_adlib(0x80 + opadd, inst[6]);
midi_write_adlib(0xe0 + opadd, inst[8]);
- midi_write_adlib(0xc0 + opadd, inst[10]);
+ if (opadd < 0x13) // only output this for the modulator, not the carrier, as it affects the entire channel
+ midi_write_adlib(0xc0 + percussion_map[ch - 11], inst[10]);
}
void CmidPlayer::midi_fm_volume(int voice, int volume)
@@ -429,7 +427,7 @@ void CmidPlayer::midi_fm_playnote(int voice, int note, int volume)
midi_fm_volume(voice,volume);
midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff));
- c=((freq&0x300) >> 8)+(oct<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0);
+ c=((freq&0x300) >> 8)+((oct&7)<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0);
midi_write_adlib(0xb0+voice,(unsigned char)c);
}
@@ -541,58 +539,62 @@ bool CmidPlayer::update()
} else
on = percussion_map[c - 11];
- if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128)
- {
- if (adlib_mode == ADLIB_MELODIC || c < 12)
+ if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) {
+ if (adlib_mode == ADLIB_MELODIC || c < 12) // 11 == bass drum, handled like a normal instrument, on == channel 6 thanks to percussion_map[] above
midi_fm_instrument(on,ch[c].ins);
else
midi_fm_percussion(c, ch[c].ins);
- if ((adlib_style&MIDI_STYLE)!=0)
- {
+ if (adlib_style & MIDI_STYLE) {
nv=((ch[c].vol*vel)/128);
- if ((adlib_style&LUCAS_STYLE)!=0)
- nv*=2;
+ if ((adlib_style&LUCAS_STYLE)!=0) nv*=2;
if (nv>127) nv=127;
nv=my_midi_fm_vol_table[nv];
if ((adlib_style&LUCAS_STYLE)!=0)
nv=(int)((float)sqrt((float)nv)*11);
- }
- else
- {
+ } else if (adlib_style & CMF_STYLE) {
+ // CMF doesn't support note velocity (even though some files have them!)
+ nv = 127;
+ } else {
nv=vel;
- }
+ }
- midi_fm_playnote(on,note+ch[c].nshift,nv*2);
+ midi_fm_playnote(on,note+ch[c].nshift,nv*2); // sets freq in rhythm mode
chp[on][0]=c;
chp[on][1]=note;
chp[on][2]=0;
if(adlib_mode == ADLIB_RYTHM && c >= 11) {
+ // Still need to turn off the perc instrument before playing it again,
+ // as not all songs send a noteoff.
midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11)));
+ // Play the perc instrument
midi_write_adlib(0xbd, adlib_data[0xbd] | (0x10 >> (c - 11)));
}
- }
- else
- {
- if (vel==0) //same code as end note
- {
- for (i=0; i<9; i++)
- if (chp[i][0]==c && chp[i][1]==note)
- {
- // midi_fm_volume(i,0); // really end the note
- midi_fm_endnote(i);
- chp[i][0]=-1;
+ } else {
+ if (vel==0) { //same code as end note
+ if (adlib_mode == ADLIB_RYTHM && c >= 11) {
+ // Turn off the percussion instrument
+ midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11)));
+ //midi_fm_endnote(percussion_map[c]);
+ chp[percussion_map[c - 11]][0]=-1;
+ } else {
+ for (i=0; i<9; i++) {
+ if (chp[i][0]==c && chp[i][1]==note) {
+ // midi_fm_volume(i,0); // really end the note
+ midi_fm_endnote(i);
+ chp[i][0]=-1;
}
+ }
}
- else
- { // i forget what this is for.
+ } else {
+ // i forget what this is for.
chp[on][0]=-1;
chp[on][2]=0;
- }
}
- midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel);
+ }
+ midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel);
}
else
midiprintf ("off");
@@ -616,8 +618,25 @@ midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2);
ch[c].vol=vel;
midiprintf("vol");
break;
+ case 0x63:
+ if (adlib_style & CMF_STYLE) {
+ // Custom extension to allow CMF files to switch the
+ // AM+VIB depth on and off (officially this is on,
+ // and there's no way to switch it off.) Controller
+ // values:
+ // 0 == AM+VIB off
+ // 1 == VIB on
+ // 2 == AM on
+ // 3 == AM+VIB on
+ midi_write_adlib(0xbd, (adlib_data[0xbd] & ~0xC0) | (vel << 6));
+ midiprintf(" AM+VIB depth change - AM %s, VIB %s\n",
+ (adlib_data[0xbd] & 0x80) ? "on" : "off",
+ (adlib_data[0xbd] & 0x40) ? "on" : "off"
+ );
+ }
+ break;
case 0x67:
- midiprintf ("\n\nhere:%d\n\n",vel);
+ midiprintf("Rhythm mode: %d\n", vel);
if ((adlib_style&CMF_STYLE)!=0) {
adlib_mode=vel;
if(adlib_mode == ADLIB_RYTHM)
@@ -811,11 +830,12 @@ fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000));
midiprintf ("\n");
for (i=0; i<16; i++)
- if (track[i].on)
- if (track[i].pos < track[i].tend)
- midiprintf ("<%d>",track[i].iwait);
- else
- midiprintf("stop");
+ if (track[i].on) {
+ if (track[i].pos < track[i].tend)
+ midiprintf ("<%d>",track[i].iwait);
+ else
+ midiprintf("stop");
+ }
/*
if (ret==0 && type==FILE_ADVSIERRA)