aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamieson Christian2003-05-15 00:05:32 +0000
committerJamieson Christian2003-05-15 00:05:32 +0000
commit979b4654152e0b8ac2a6282844700d1d098a3dbf (patch)
tree178824c226df2faaa15ac281cdc5c61ae5934897
parentf3a5fc79c1d22338a8ed60a63b9571162a5dd581 (diff)
downloadscummvm-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
-rw-r--r--backends/midi/adlib.cpp430
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));
-}