diff options
author | Jamieson Christian | 2003-05-15 00:05:32 +0000 |
---|---|---|
committer | Jamieson Christian | 2003-05-15 00:05:32 +0000 |
commit | 979b4654152e0b8ac2a6282844700d1d098a3dbf (patch) | |
tree | 178824c226df2faaa15ac281cdc5c61ae5934897 /backends | |
parent | f3a5fc79c1d22338a8ed60a63b9571162a5dd581 (diff) | |
download | scummvm-rg350-979b4654152e0b8ac2a6282844700d1d098a3dbf.tar.gz scummvm-rg350-979b4654152e0b8ac2a6282844700d1d098a3dbf.tar.bz2 scummvm-rg350-979b4654152e0b8ac2a6282844700d1d098a3dbf.zip |
Added rudimentary Adlib percussion support.
Semantic fixes -- Adlib "MIDI Channels" are now "Voices"
Miscellaneous cleanup/streamlining.
svn-id: r7520
Diffstat (limited to 'backends')
-rw-r--r-- | backends/midi/adlib.cpp | 430 |
1 files changed, 274 insertions, 156 deletions
diff --git a/backends/midi/adlib.cpp b/backends/midi/adlib.cpp index 4738501b3f..999586ee28 100644 --- a/backends/midi/adlib.cpp +++ b/backends/midi/adlib.cpp @@ -26,7 +26,7 @@ #include "common/util.h" class MidiDriver_ADLIB; -struct MidiChannelAdl; +struct AdlibVoice; struct InstrumentExtra { byte a, b, c, d, e, f, g, h; @@ -54,9 +54,9 @@ struct AdlibInstrument { class AdlibPart : public MidiChannel { friend class MidiDriver_ADLIB; -private: +protected: // AdlibPart *_prev, *_next; - MidiChannelAdl *_mc; + AdlibVoice *_voice; int16 _pitchbend; byte _pitchbend_factor; int8 _transpose_eff; @@ -68,7 +68,7 @@ private: byte _pri_eff; AdlibInstrument _part_instr; -private: +protected: MidiDriver_ADLIB *_owner; bool _allocated; byte _channel; @@ -104,6 +104,35 @@ public: void sysEx_customInstrument (uint32 type, byte *instr); }; +// FYI (Jamieson630) +// It is assumed that any invocation to AdlibPercussionChannel +// will be done through the MidiChannel base class as opposed to the +// AdlibPart base class. If this were NOT the case, all the functions +// listed below would need to be virtual in AdlibPart as well as MidiChannel. +class AdlibPercussionChannel : public AdlibPart { + friend class MidiDriver_ADLIB; + +protected: + void init (MidiDriver_ADLIB *owner, byte channel); + +public: + void noteOff (byte note); + void noteOn (byte note, byte velocity); + void programChange (byte program) { } + void pitchBend (int16 bend) { } + + // Control Change messages + void controlChange (byte control, byte value) { } + void modulationWheel (byte value) { } + void pitchBendFactor (byte value) { } + void detune (byte value) { } + void priority (byte value) { } + void sustain (bool value) { } + + // SysEx messages + void sysEx_customInstrument (uint32 type, byte *instr) { } +}; + struct Struct10 { byte active; int16 cur_val; @@ -130,9 +159,9 @@ struct Struct11 { Struct10 *s10; }; -struct MidiChannelAdl { +struct AdlibVoice { AdlibPart *_part; - MidiChannelAdl *_next, *_prev; + AdlibVoice *_next, *_prev; byte _waitforpedal; byte _note; byte _channel; @@ -145,7 +174,7 @@ struct MidiChannelAdl { Struct10 _s10b; Struct11 _s11b; - MidiChannelAdl() : _part (0), _next(0), _prev(0) {} + AdlibVoice() : _part (0), _next(0), _prev(0) {} }; struct AdlibSetParams { @@ -411,6 +440,63 @@ static byte map_gm_to_fm [128][30] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // Unknown }; +struct PercussionMapEntry { + byte _key; // 0 means no map data + char *_name; + byte _instrument [30]; +}; + +static PercussionMapEntry gm_percussion_to_fm [47] = { + // The first entry is actual for key 34 (0-based) + { 0, "Acoustic Bass Drum", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Bass Drum 1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 72, "Side Stick", { 0x0F, 0x21, 0x07, 0xE3, 0x01, 0x09, 0x30, 0x0B, 0xF6, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 59, "Acoustic Snare", { 0x00, 0x3F, 0x09, 0x00, 0x02, 0x06, 0x00, 0x57, 0x00, 0x7C, 0x0E, 0x80, 0x02, 0x08, 0x03, 0x1B, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 65, "Hand Clap", { 0x00, 0x3F, 0x09, 0x00, 0x02, 0x06, 0x00, 0x57, 0x00, 0x7C, 0x0E, 0x80, 0x02, 0x08, 0x03, 0x1B, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 71, "Electric Snare", { 0x00, 0x3F, 0x09, 0x00, 0x02, 0x06, 0x00, 0x57, 0x00, 0x7C, 0x0E, 0x80, 0x02, 0x08, 0x03, 0x1B, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 50, "Low Floor Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 80, "Closed Hi-Hat", { 0x00, 0x3F, 0x09, 0x00, 0x02, 0x06, 0x00, 0x57, 0x00, 0x7C, 0x0E, 0x80, 0x02, 0x08, 0x03, 0x1B, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 55, "High Floor Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 74, "Pedal Hi-Hat", { 0x00, 0x3F, 0x09, 0x00, 0x02, 0x06, 0x00, 0x57, 0x00, 0x7C, 0x0E, 0x80, 0x02, 0x08, 0x03, 0x1B, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 62, "Low Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 72, "Open Hi-Hat", { 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } }, + { 70, "Low-Mid Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 78, "High-Mid Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 60, "Crash Cymbal 1", { 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } }, + { 86, "High Tom", { 0x0F, 0x10, 0x10, 0x09, 0x49, 0x02, 0x12, 0x07, 0x9A, 0x7C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Ride Cymbal 1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Chinese Cymbal", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Ride Bell", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 61, "Tambourine", { 0xE0, 0x3F, 0xAF, 0xF5, 0x7F, 0xEC, 0x2E, 0x0E, 0xC4, 0x7A, 0x08, 0x01, 0x00, 0x03, 0x1E, 0x01, 0x1E, 0x00, 0x00, 0x1E, 0xA8, 0x00, 0x01, 0x20, 0x06, 0x23, 0x04, 0x03, 0x20, 0x00 } }, + { 75, "Splash Cymbal", { 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } }, + { 60, "Cowbell", { 0xEC, 0x34, 0x07, 0x00, 0x01, 0xE7, 0x3F, 0x05, 0x00, 0x4F, 0x09, 0xA1, 0x00, 0x01, 0x1E, 0x02, 0x1D, 0x01, 0x01, 0x22, 0xA8, 0x00, 0x01, 0x24, 0x06, 0x20, 0x04, 0x03, 0x24, 0x00 } }, + { 69, "Crash Cymbal 2", { 0xCF, 0x3B, 0x2A, 0xFE, 0x7E, 0xC0, 0xC0, 0x0C, 0xEB, 0x63, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 } }, + { 0, "Vibraslap", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Ride Cymbal 2", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "High Bongo", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Low Bongo", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Mute High Conga", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 66, "Open High Conga", { 0x21, 0x3F, 0x05, 0x95, 0x00, 0x21, 0x30, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 60, "Low Conga", { 0x21, 0x3F, 0x05, 0x95, 0x00, 0x21, 0x30, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "High Timbale", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Low Timbale", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "High Agogo", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Low Agogo", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Cabasa", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Maracas", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Short Whistle", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Long Whistle", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Short Guiro", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Long Guiro", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Claves", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 72, "High Wood Block", { 0x0F, 0x21, 0x07, 0xE3, 0x01, 0x09, 0x30, 0x0B, 0xF6, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 66, "Low Wood Block", { 0x0F, 0x21, 0x07, 0xE3, 0x01, 0x09, 0x30, 0x0B, 0xF6, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Mute Cuica", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 62, "Open Cuica", { 0x00, 0x23, 0x96, 0x00, 0x00, 0x00, 0x3F, 0x69, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x21, 0x08, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x00, 0x0B, 0x3E, 0x12, 0x1F, 0x00, 0x00, 0x1F, 0x00 } }, + { 0, "Mute Triangle", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0, "Open Triangle", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } +}; + static byte lookup_table[64][32]; const byte volume_table[] = { 0, 4, 7, 11, @@ -482,6 +568,7 @@ typedef void TimerCallback (void *); class MidiDriver_ADLIB : public MidiDriver { friend class AdlibPart; + friend class AdlibPercussionChannel; public: MidiDriver_ADLIB(); @@ -504,7 +591,7 @@ public: } MidiChannel *allocateChannel(); - MidiChannel *getPercussionChannel() { return NULL; } // Percussion currently not supported + MidiChannel *getPercussionChannel() { return &_percussion; } // Percussion partially supported private: bool _isOpen; @@ -519,18 +606,16 @@ private: int _adlib_timer_counter; uint16 channel_table_2[9]; - int _midichan_index; + int _voice_index; int _next_tick; uint16 curnote_table[9]; - MidiChannelAdl _midi_channels[9]; + AdlibVoice _voices[9]; AdlibPart _parts[32]; - - void sysEx_customInstrument (AdlibPart *part, uint32 type, byte *instr); + AdlibPercussionChannel _percussion; void generate_samples(int16 *buf, int len); void on_timer(); - void part_set_instrument (AdlibPart *part, AdlibInstrument * instr); - void part_key_on (AdlibPart *part, byte note, byte velocity); + void part_key_on (AdlibPart *part, AdlibInstrument *instr, byte note, byte velocity); void part_key_off (AdlibPart *part, byte note); void adlib_key_off(int chan); @@ -546,21 +631,21 @@ private: void adlib_write(byte port, byte value); void adlib_playnote(int channel, int note); - MidiChannelAdl *allocate_midichan(byte pri); + AdlibVoice *allocate_voice(byte pri); void reset_tick(); - void mc_off(MidiChannelAdl * mc); + void mc_off(AdlibVoice * voice); - static void link_mc (AdlibPart *part, MidiChannelAdl *mc); - void mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11); - void mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11, byte flags, + static void link_mc (AdlibPart *part, AdlibVoice *voice); + void mc_inc_stuff(AdlibVoice *voice, Struct10 * s10, Struct11 * s11); + void mc_init_stuff(AdlibVoice *voice, Struct10 * s10, Struct11 * s11, byte flags, InstrumentExtra * ie); static void struct10_init(Struct10 * s10, InstrumentExtra * ie); static byte struct10_ontimer(Struct10 * s10, Struct11 * s11); static void struct10_setup(Struct10 * s10); static int random_nr(int a); - void mc_key_on (MidiChannelAdl * mc, byte note, byte velocity); + void mc_key_on (AdlibVoice *voice, AdlibInstrument *instr, byte note, byte velocity); static void premix_proc(void *param, int16 *buf, uint len); }; @@ -581,7 +666,7 @@ void AdlibPart::noteOff (byte note) { } void AdlibPart::noteOn (byte note, byte velocity) { - _owner->part_key_on (this, note, velocity); + _owner->part_key_on (this, &_part_instr, note, velocity); } void AdlibPart::programChange (byte program) { @@ -595,15 +680,15 @@ void AdlibPart::programChange (byte program) { if (!count) warning ("No Adlib instrument defined for GM program %d", (int) program); _program = program; - _owner->part_set_instrument (this, (AdlibInstrument *) &map_gm_to_fm [program]); + memcpy(&_part_instr, &map_gm_to_fm [program], sizeof(AdlibInstrument)); } void AdlibPart::pitchBend (int16 bend) { - MidiChannelAdl *mc; + AdlibVoice *voice; _pitchbend = bend; - for (mc = _mc; mc; mc = mc->_next) { - _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff, + for (voice = _voice; voice; voice = voice->_next) { + _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff, (_pitchbend * _pitchbend_factor >> 6) + _detune_eff); } } @@ -628,45 +713,45 @@ void AdlibPart::controlChange (byte control, byte value) { } void AdlibPart::modulationWheel (byte value) { - MidiChannelAdl *mc; + AdlibVoice *voice; _modwheel = value; - for (mc = _mc; mc; mc = mc->_next) { - if (mc->_s10a.active && mc->_s11a.flag0x40) - mc->_s10a.modwheel = _modwheel >> 2; - if (mc->_s10b.active && mc->_s11b.flag0x40) - mc->_s10b.modwheel = _modwheel >> 2; + for (voice = _voice; voice; voice = voice->_next) { + if (voice->_s10a.active && voice->_s11a.flag0x40) + voice->_s10a.modwheel = _modwheel >> 2; + if (voice->_s10b.active && voice->_s11b.flag0x40) + voice->_s10b.modwheel = _modwheel >> 2; } } void AdlibPart::volume (byte value) { - MidiChannelAdl *mc; + AdlibVoice *voice; _vol_eff = value; - for (mc = _mc; mc; mc = mc->_next) { - _owner->adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2][_vol_eff >> 2]]); - if (mc->_twochan) { - _owner->adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1][_vol_eff >> 2]]); + for (voice = _voice; voice; voice = voice->_next) { + _owner->adlib_set_param(voice->_channel, 0, volume_table[lookup_table[voice->_vol_2][_vol_eff >> 2]]); + if (voice->_twochan) { + _owner->adlib_set_param(voice->_channel, 13, volume_table[lookup_table[voice->_vol_1][_vol_eff >> 2]]); } } } void AdlibPart::pitchBendFactor (byte value) { - MidiChannelAdl *mc; + AdlibVoice *voice; _pitchbend_factor = value; - for (mc = _mc; mc; mc = mc->_next) { - _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff, + for (voice = _voice; voice; voice = voice->_next) { + _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff, (_pitchbend * _pitchbend_factor >> 6) + _detune_eff); } } void AdlibPart::detune (byte value) { - MidiChannelAdl *mc; + AdlibVoice *voice; _detune_eff = value; - for (mc = _mc; mc; mc = mc->_next) { - _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff, + for (voice = _voice; voice; voice = voice->_next) { + _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff, (_pitchbend * _pitchbend_factor >> 6) + _detune_eff); } } @@ -676,24 +761,66 @@ void AdlibPart::priority (byte value) { } void AdlibPart::sustain (bool value) { - MidiChannelAdl *mc; + AdlibVoice *voice; _pedal = value; if (!value) { - for (mc = _mc; mc; mc = mc->_next) { - if (mc->_waitforpedal) - _owner->mc_off(mc); + for (voice = _voice; voice; voice = voice->_next) { + if (voice->_waitforpedal) + _owner->mc_off(voice); } } } void AdlibPart::allNotesOff() { - while (_mc) - _owner->mc_off (_mc); + while (_voice) + _owner->mc_off (_voice); } void AdlibPart::sysEx_customInstrument (uint32 type, byte *instr) { - _owner->sysEx_customInstrument (this, type, instr); + if (type == 'ADL ') { + AdlibInstrument *i = &_part_instr; + memcpy(i, instr, sizeof(AdlibInstrument)); + } +} + +// MidiChannel method implementations for percussion + +void AdlibPercussionChannel::init (MidiDriver_ADLIB *owner, byte channel) { + AdlibPart::init (owner, channel); + _pri_eff = 0; + _vol_eff = 127; +} + +void AdlibPercussionChannel::noteOff (byte note) { + // Jamieson630: Unless I run into a specific instrument that + // may require a key off, I'm going to ignore this message. + // The rationale is that a percussion instrument should + // fade out of its own accord, and the Adlib instrument + // definitions used should follow this rule. Since + // percussion voices are allocated at the lowest priority + // anyway, we know that "hanging" percussion sounds will + // not prevent later musical instruments (or even other + // percussion sounds) from playing. +/* + if (note < 34 || note > 81) + return; // Out of GM range + byte key = gm_percussion_to_fm [note-34]._key; + if (key == 0) + return; + _owner->part_key_off (this, key); +*/ +} + +void AdlibPercussionChannel::noteOn (byte note, byte velocity) { + if (note < 34 || note > 81) + return; // Out of GM range + byte key = gm_percussion_to_fm [note-34]._key; + if (key == 0) { + debug (2, "No FM map for GM percussion key %d (%s)", (int) note, gm_percussion_to_fm [note-34]._name); + return; + } + _owner->part_key_on (this, (AdlibInstrument *) &gm_percussion_to_fm [note-34]._instrument, key, velocity); } // MidiDriver method implementations @@ -703,6 +830,7 @@ MidiDriver_ADLIB::MidiDriver_ADLIB() { for (i = 0; i < ARRAYSIZE(_parts); ++i) { _parts[i].init (this, i); } + _percussion.init (this, 0); _game_SmallHeader = false; _isOpen = false; } @@ -713,12 +841,12 @@ int MidiDriver_ADLIB::open() { _isOpen = true; int i; - MidiChannelAdl *mc; + AdlibVoice *voice; - for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) { - mc->_channel = i; - mc->_s11a.s10 = &mc->_s10b; - mc->_s11b.s10 = &mc->_s10a; + for (i = 0, voice = _voices; i != ARRAYSIZE(_voices); i++, voice++) { + voice->_channel = i; + voice->_s11a.s10 = &voice->_s10b; + voice->_s11b.s10 = &voice->_s10a; } _adlib_reg_cache = (byte *)calloc(256, 1); @@ -740,9 +868,9 @@ int MidiDriver_ADLIB::open() { void MidiDriver_ADLIB::close() { uint i; - for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) { - if (_midi_channels [i]._part) - mc_off (&_midi_channels [i]); + for (i = 0; i < ARRAYSIZE(_voices); ++i) { + if (_voices [i]._part) + mc_off (&_voices [i]); } // Detach the premix callback handler @@ -760,14 +888,19 @@ void MidiDriver_ADLIB::send (uint32 b) { byte param1 = (byte) ((b >> 8) & 0xFF); byte cmd = (byte) (b & 0xF0); byte chan = (byte) (b & 0x0F); - AdlibPart *part = &_parts [chan]; + + AdlibPart *part; + if (chan == 9) + part = &_percussion; + else + part = &_parts [chan]; switch (cmd) { case 0x80:// Note Off - part_key_off (part, param1); + part->noteOff (param1); break; case 0x90: // Note On - part_key_on (part, param1, param2); + part->noteOn (param1, param2); break; case 0xA0: // Aftertouch break; // Not supported. @@ -775,8 +908,7 @@ void MidiDriver_ADLIB::send (uint32 b) { part->controlChange (param1, param2); break; case 0xC0: // Program Change - if (chan != 9) - part->programChange (param1); + part->programChange (param1); break; case 0xD0: // Channel Pressure break; // Not supported. @@ -805,25 +937,18 @@ uint32 MidiDriver_ADLIB::property (int prop, uint32 param) { } void MidiDriver_ADLIB::setPitchBendRange (byte channel, uint range) { - MidiChannelAdl *mc; + AdlibVoice *voice; AdlibPart *part = &_parts [channel]; part->_pitchbend_factor = range; - for (mc = part->_mc; mc; mc = mc->_next) { - adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, + for (voice = part->_voice; voice; voice = voice->_next) { + adlib_note_on(voice->_channel, voice->_note + part->_transpose_eff, (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff); } } void MidiDriver_ADLIB::sysEx_customInstrument (byte channel, uint32 type, byte *instr) { - sysEx_customInstrument (&_parts [channel], type, instr); -} - -void MidiDriver_ADLIB::sysEx_customInstrument (AdlibPart *part, uint32 type, byte *instr) { - if (type == 'ADL ') { - AdlibInstrument *i = &part->_part_instr; - memcpy(i, instr, sizeof(AdlibInstrument)); - } + _parts[channel].sysEx_customInstrument (type, instr); } void MidiDriver_ADLIB::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) { @@ -888,68 +1013,68 @@ void MidiDriver_ADLIB::reset_tick() { } void MidiDriver_ADLIB::on_timer() { - MidiChannelAdl *mc; + AdlibVoice *voice; int i; _adlib_timer_counter += 0xD69; while (_adlib_timer_counter >= 0x411B) { _adlib_timer_counter -= 0x411B; - mc = _midi_channels; - for (i = 0; i != ARRAYSIZE(_midi_channels); i++, mc++) { - if (!mc->_part) + voice = _voices; + for (i = 0; i != ARRAYSIZE(_voices); i++, voice++) { + if (!voice->_part) continue; - if (mc->_duration && (mc->_duration -= 0x11) <= 0) { - mc_off(mc); + if (voice->_duration && (voice->_duration -= 0x11) <= 0) { + mc_off(voice); return; } - if (mc->_s10a.active) { - mc_inc_stuff(mc, &mc->_s10a, &mc->_s11a); + if (voice->_s10a.active) { + mc_inc_stuff(voice, &voice->_s10a, &voice->_s11a); } - if (mc->_s10b.active) { - mc_inc_stuff(mc, &mc->_s10b, &mc->_s11b); + if (voice->_s10b.active) { + mc_inc_stuff(voice, &voice->_s10b, &voice->_s11b); } } } } -void MidiDriver_ADLIB::mc_off(MidiChannelAdl * mc2) { - MidiChannelAdl *mc = (MidiChannelAdl *)mc2, *tmp; +void MidiDriver_ADLIB::mc_off(AdlibVoice *voice) { + AdlibVoice *tmp; - adlib_key_off(mc->_channel); + adlib_key_off(voice->_channel); - tmp = mc->_prev; + tmp = voice->_prev; - if (mc->_next) - mc->_next->_prev = tmp; + if (voice->_next) + voice->_next->_prev = tmp; if (tmp) - tmp->_next = mc->_next; + tmp->_next = voice->_next; else - mc->_part->_mc = mc->_next; - mc->_part = NULL; + voice->_part->_voice = voice->_next; + voice->_part = NULL; } -void MidiDriver_ADLIB::mc_inc_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11) { +void MidiDriver_ADLIB::mc_inc_stuff(AdlibVoice *voice, Struct10 *s10, Struct11 *s11) { byte code; - AdlibPart *part = mc->_part; + AdlibPart *part = voice->_part; code = struct10_ontimer(s10, s11); if (code & 1) { switch (s11->param) { case 0: - mc->_vol_2 = s10->start_value + s11->modify_val; - adlib_set_param(mc->_channel, 0, - volume_table[lookup_table[mc->_vol_2] + voice->_vol_2 = s10->start_value + s11->modify_val; + adlib_set_param(voice->_channel, 0, + volume_table[lookup_table[voice->_vol_2] [part->_vol_eff >> 2]]); break; case 13: - mc->_vol_1 = s10->start_value + s11->modify_val; - if (mc->_twochan) { - adlib_set_param(mc->_channel, 13, - volume_table[lookup_table[mc->_vol_1] + voice->_vol_1 = s10->start_value + s11->modify_val; + if (voice->_twochan) { + adlib_set_param(voice->_channel, 13, + volume_table[lookup_table[voice->_vol_1] [part->_vol_eff >> 2]]); } else { - adlib_set_param(mc->_channel, 13, mc->_vol_1); + adlib_set_param(voice->_channel, 13, voice->_vol_1); } break; case 30: @@ -959,14 +1084,14 @@ void MidiDriver_ADLIB::mc_inc_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 s11->s10->unk3 = (char)s11->modify_val; break; default: - adlib_set_param(mc->_channel, s11->param, + adlib_set_param(voice->_channel, s11->param, s10->start_value + s11->modify_val); break; } } if (code & 2 && s11->flag0x10) - adlib_key_onoff(mc->_channel); + adlib_key_onoff(voice->_channel); } void MidiDriver_ADLIB::adlib_key_off(int chan){ @@ -1153,37 +1278,37 @@ int MidiDriver_ADLIB::random_nr(int a) { } void MidiDriver_ADLIB::part_key_off (AdlibPart *part, byte note) { - MidiChannelAdl *mc; + AdlibVoice *voice; - for (mc = part->_mc; mc; mc = mc->_next) { - if (mc->_note == note) { + for (voice = part->_voice; voice; voice = voice->_next) { + if (voice->_note == note) { if (part->_pedal) - mc->_waitforpedal = true; + voice->_waitforpedal = true; else - mc_off(mc); + mc_off(voice); } } } -void MidiDriver_ADLIB::part_key_on (AdlibPart *part, byte note, byte velocity) { - MidiChannelAdl *mc; +void MidiDriver_ADLIB::part_key_on (AdlibPart *part, AdlibInstrument *instr, byte note, byte velocity) { + AdlibVoice *voice; - mc = allocate_midichan(part->_pri_eff); - if (!mc) + voice = allocate_voice(part->_pri_eff); + if (!voice) return; - link_mc(part, mc); - mc_key_on(mc, note, velocity); + link_mc(part, voice); + mc_key_on(voice, instr, note, velocity); } -MidiChannelAdl *MidiDriver_ADLIB::allocate_midichan(byte pri) { - MidiChannelAdl *ac, *best = NULL; +AdlibVoice *MidiDriver_ADLIB::allocate_voice(byte pri) { + AdlibVoice *ac, *best = NULL; int i; for (i = 0; i < 9; i++) { - if (++_midichan_index >= 9) - _midichan_index = 0; - ac = &_midi_channels[_midichan_index]; + if (++_voice_index >= 9) + _voice_index = 0; + ac = &_voices[_voice_index]; if (!ac->_part) return ac; if (!ac->_next) { @@ -1199,59 +1324,57 @@ MidiChannelAdl *MidiDriver_ADLIB::allocate_midichan(byte pri) { return best; } -void MidiDriver_ADLIB::link_mc (AdlibPart *part, MidiChannelAdl *mc) { - mc->_part = part; - mc->_next = (MidiChannelAdl *)part->_mc; - part->_mc = mc; - mc->_prev = NULL; +void MidiDriver_ADLIB::link_mc (AdlibPart *part, AdlibVoice *voice) { + voice->_part = part; + voice->_next = (AdlibVoice *)part->_voice; + part->_voice = voice; + voice->_prev = NULL; - if (mc->_next) - mc->_next->_prev = mc; + if (voice->_next) + voice->_next->_prev = voice; } -void MidiDriver_ADLIB::mc_key_on (MidiChannelAdl *mc2, byte note, byte velocity) { - MidiChannelAdl *mc = (MidiChannelAdl *)mc2; - AdlibPart *part = mc->_part; - AdlibInstrument *instr = &part->_part_instr; +void MidiDriver_ADLIB::mc_key_on (AdlibVoice *voice, AdlibInstrument *instr, byte note, byte velocity) { + AdlibPart *part = voice->_part; int c; byte vol_1, vol_2; - mc->_twochan = instr->feedback & 1; - mc->_note = note; - mc->_waitforpedal = false; - mc->_duration = instr->duration; - if (mc->_duration != 0) - mc->_duration *= 63; + voice->_twochan = instr->feedback & 1; + voice->_note = note; + voice->_waitforpedal = false; + voice->_duration = instr->duration; + if (voice->_duration != 0) + voice->_duration *= 63; vol_1 = (instr->oplvl_1 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_1 >> 2]; if (vol_1 > 0x3F) vol_1 = 0x3F; - mc->_vol_1 = vol_1; + voice->_vol_1 = vol_1; vol_2 = (instr->oplvl_2 & 0x3F) + lookup_table[velocity >> 1][instr->waveform_2 >> 2]; if (vol_2 > 0x3F) vol_2 = 0x3F; - mc->_vol_2 = vol_2; + voice->_vol_2 = vol_2; c = part->_vol_eff >> 2; vol_2 = volume_table[lookup_table[vol_2][c]]; - if (mc->_twochan) + if (voice->_twochan) vol_1 = volume_table[lookup_table[vol_1][c]]; - adlib_setup_channel(mc->_channel, instr, vol_1, vol_2); - adlib_note_on_ex(mc->_channel, part->_transpose_eff + note, part->_detune_eff + (part->_pitchbend * part->_pitchbend_factor >> 6)); + adlib_setup_channel(voice->_channel, instr, vol_1, vol_2); + adlib_note_on_ex(voice->_channel, part->_transpose_eff + note, part->_detune_eff + (part->_pitchbend * part->_pitchbend_factor >> 6)); if (instr->flags_a & 0x80) { - mc_init_stuff(mc, &mc->_s10a, &mc->_s11a, instr->flags_a, &instr->extra_a); + mc_init_stuff(voice, &voice->_s10a, &voice->_s11a, instr->flags_a, &instr->extra_a); } else { - mc->_s10a.active = 0; + voice->_s10a.active = 0; } if (instr->flags_b & 0x80) { - mc_init_stuff(mc, &mc->_s10b, &mc->_s11b, instr->flags_b, &instr->extra_b); + mc_init_stuff(voice, &voice->_s10b, &voice->_s11b, instr->flags_b, &instr->extra_b); } else { - mc->_s10b.active = 0; + voice->_s10b.active = 0; } } @@ -1292,9 +1415,9 @@ void MidiDriver_ADLIB::adlib_note_on_ex(int chan, byte note, int mod) adlib_playnote(chan, code); } -void MidiDriver_ADLIB::mc_init_stuff (MidiChannelAdl *mc, Struct10 * s10, +void MidiDriver_ADLIB::mc_init_stuff (AdlibVoice *voice, Struct10 * s10, Struct11 * s11, byte flags, InstrumentExtra * ie) { - AdlibPart *part = mc->_part; + AdlibPart *part = voice->_part; s11->modify_val = 0; s11->flag0x40 = flags & 0x40; s10->loop = flags & 0x20; @@ -1310,10 +1433,10 @@ void MidiDriver_ADLIB::mc_init_stuff (MidiChannelAdl *mc, Struct10 * s10, switch (s11->param) { case 0: - s10->start_value = mc->_vol_2; + s10->start_value = voice->_vol_2; break; case 13: - s10->start_value = mc->_vol_1; + s10->start_value = voice->_vol_1; break; case 30: s10->start_value = 31; @@ -1324,7 +1447,7 @@ void MidiDriver_ADLIB::mc_init_stuff (MidiChannelAdl *mc, Struct10 * s10, s11->s10->unk3 = 0; break; default: - s10->start_value = adlib_read_param(mc->_channel, s11->param); + s10->start_value = adlib_read_param(voice->_channel, s11->param); } struct10_init(s10, ie); @@ -1390,8 +1513,3 @@ void MidiDriver_ADLIB::adlib_note_on(int chan, byte note, int mod) { curnote_table[chan] = code; adlib_playnote(chan, channel_table_2[chan] + code); } - -void MidiDriver_ADLIB::part_set_instrument(AdlibPart *part, AdlibInstrument *instr) { - AdlibInstrument *i = &part->_part_instr; - memcpy(i, instr, sizeof(AdlibInstrument)); -} |