aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/midi/adlib.cpp388
-rw-r--r--scumm/imuse.cpp219
-rw-r--r--sound/mididrv.cpp93
-rw-r--r--sound/mididrv.h39
-rw-r--r--sound/midistreamer.h3
5 files changed, 494 insertions, 248 deletions
diff --git a/backends/midi/adlib.cpp b/backends/midi/adlib.cpp
index d52f9412a6..67e94fba61 100644
--- a/backends/midi/adlib.cpp
+++ b/backends/midi/adlib.cpp
@@ -61,10 +61,11 @@ struct Instrument {
byte duration;
};
-struct AdlibPart {
- byte _chan;
- AdlibPart *_prev, *_next;
- MidiDriver_ADLIB *_drv;
+class AdlibPart : public MidiChannel {
+ friend MidiDriver_ADLIB;
+
+private:
+// AdlibPart *_prev, *_next;
MidiChannelAdl *_mc;
int16 _pitchbend;
byte _pitchbend_factor;
@@ -76,6 +77,39 @@ struct AdlibPart {
byte _program;
byte _pri_eff;
Instrument _part_instr;
+
+private:
+ MidiDriver_ADLIB *_owner;
+ bool _allocated;
+ byte _channel;
+
+ void init (MidiDriver_ADLIB *owner);
+ void allocate() { _allocated = true; }
+
+public:
+ void release() { _allocated = false; }
+
+ // Regular messages
+ 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 volume (byte value);
+ void panPosition (byte value) { return; } // Not supported
+ void pitchBendFactor (byte value);
+ void detune (byte value);
+ void priority (byte value);
+ void sustain (bool value);
+ void effectLevel (byte value) { return; } // Not supported
+ void chorusLevel (byte value) { return; } // Not supported
+ void allNotesOff();
+
+ // SysEx messages
+ void sysEx_customInstrument (uint32 type, byte *instr);
};
struct Struct10 {
@@ -459,6 +493,8 @@ typedef void TimerCallback (void *);
////////////////////////////////////////
class MidiDriver_ADLIB : public MidiDriver {
+ friend AdlibPart;
+
public:
MidiDriver_ADLIB();
@@ -479,6 +515,9 @@ public:
#endif //_WIN32_WCE
}
+ MidiChannel *allocateChannel();
+ MidiChannel *getPercussionChannel() { return NULL; } // Percussion currently not supported
+
private:
int _mode;
@@ -496,13 +535,15 @@ private:
int _next_tick;
uint16 curnote_table[9];
MidiChannelAdl _midi_channels[9];
- AdlibPart _parts[16];
+ AdlibPart _parts[32];
+
+ void sysEx_customInstrument (AdlibPart *part, uint32 type, byte *instr);
void generate_samples(int16 *buf, int len);
void on_timer();
void part_set_instrument (AdlibPart *part, Instrument * instr);
- void part_key_on (byte chan, byte note, byte velocity);
- void part_key_off (byte chan, byte note);
+ void part_key_on (AdlibPart *part, byte note, byte velocity);
+ void part_key_off (AdlibPart *part, byte note);
void adlib_key_off(int chan);
void adlib_note_on(int chan, byte note, int mod);
@@ -523,9 +564,9 @@ private:
void mc_off(MidiChannelAdl * mc);
static void link_mc (AdlibPart *part, MidiChannelAdl *mc);
- static void mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11);
- static void mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11, byte flags,
- InstrumentExtra * ie);
+ void mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11);
+ void mc_init_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11 * s11, byte flags,
+ InstrumentExtra * ie);
static void struct10_init(Struct10 * s10, InstrumentExtra * ie);
static byte struct10_ontimer(Struct10 * s10, Struct11 * s11);
@@ -538,16 +579,152 @@ private:
+// MidiChannel method implementations
+
+void AdlibPart::init (MidiDriver_ADLIB *owner) {
+ _owner = owner;
+
+}
+
+void AdlibPart::noteOff (byte note)
+{
+ _owner->part_key_off (this, note);
+}
+
+void AdlibPart::noteOn (byte note, byte velocity)
+{
+ _owner->part_key_on (this, note, velocity);
+}
+
+void AdlibPart::programChange (byte program)
+{
+ if (program > 127) return;
+
+ uint i;
+ uint count = 0;
+ for (i = 0; i < ARRAYSIZE(map_gm_to_fm[0]); ++i)
+ count += map_gm_to_fm[program][i];
+ if (!count)
+ warning ("No Adlib instrument defined for GM program %d", (int) program);
+ _program = program;
+ _owner->part_set_instrument (this, (Instrument *) &map_gm_to_fm [program]);
+}
+
+void AdlibPart::pitchBend (int16 bend)
+{
+ MidiChannelAdl *mc;
+
+ _pitchbend = bend;
+ for (mc = _mc; mc; mc = mc->_next) {
+ _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff,
+ (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
+ }
+}
+
+void AdlibPart::controlChange (byte control, byte value)
+{
+ switch (control) {
+ case 1: modulationWheel (value); break;
+ case 7: volume (value); break;
+ case 10: break; // Pan position. Not supported.
+ case 16: pitchBendFactor (value); break;
+ case 17: detune (value); break;
+ case 18: priority (value); break;
+ case 64: sustain (value > 0); break;
+ case 91: break; // Effects level. Not supported.
+ case 93: break; // Chorus level. Not supported.
+ case 123: allNotesOff(); break;
+ default:
+ warning ("Adlib: Unknown control change message %d", (int) control);
+ }
+}
+
+void AdlibPart::modulationWheel (byte value)
+{
+ MidiChannelAdl *mc;
+
+ _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;
+ }
+}
+
+void AdlibPart::volume (byte value)
+{
+ MidiChannelAdl *mc;
+
+ _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]]);
+ }
+ }
+}
+
+void AdlibPart::pitchBendFactor (byte value)
+{
+ MidiChannelAdl *mc;
+
+ _pitchbend_factor = value;
+ for (mc = _mc; mc; mc = mc->_next) {
+ _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff,
+ (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
+ }
+}
+
+void AdlibPart::detune (byte value)
+{
+ MidiChannelAdl *mc;
+
+ _detune_eff = value;
+ for (mc = _mc; mc; mc = mc->_next) {
+ _owner->adlib_note_on(mc->_channel, mc->_note + _transpose_eff,
+ (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
+ }
+}
+
+void AdlibPart::priority (byte value)
+{
+ _pri_eff = value;
+}
+
+void AdlibPart::sustain (bool value)
+{
+ MidiChannelAdl *mc;
+
+ _pedal = value;
+ if (!value) {
+ for (mc = _mc; mc; mc = mc->_next) {
+ if (mc->_waitforpedal)
+ _owner->mc_off(mc);
+ }
+ }
+}
+
+void AdlibPart::allNotesOff()
+{
+ while (_mc)
+ _owner->mc_off (_mc);
+}
+
+void AdlibPart::sysEx_customInstrument (uint32 type, byte *instr)
+{
+ _owner->sysEx_customInstrument (this, type, instr);
+}
+
+
+
// MidiDriver method implementations
MidiDriver_ADLIB::MidiDriver_ADLIB()
{
uint i;
for (i = 0; i < ARRAYSIZE(_parts); ++i) {
- _parts [i]._chan = i;
- _parts [i]._prev = (i ? &_parts[i-1] : 0);
- _parts [i]._next = ((i < ARRAYSIZE(_parts) - 1) ? &_parts[i+1] : 0);
- _parts [i]._drv = this;
+ _parts[i].init (this);
}
}
@@ -599,8 +776,6 @@ void MidiDriver_ADLIB::send (uint32 b)
if (_mode != MO_SIMPLE)
error("MidiDriver_ADLIB::send called but driver is not in simple mode");
- MidiChannelAdl *mc;
-
//byte param3 = (byte) ((b >> 24) & 0xFF);
byte param2 = (byte) ((b >> 16) & 0xFF);
byte param1 = (byte) ((b >> 8) & 0xFF);
@@ -610,112 +785,21 @@ void MidiDriver_ADLIB::send (uint32 b)
switch (cmd) {
case 0x80:// Note Off
- part_key_off (chan, param1);
- break;
-
+ part_key_off (part, param1); break;
case 0x90: // Note On
- part_key_on (chan, param1, param2);
- break;
-
+ part_key_on (part, param1, param2); break;
case 0xA0: // Aftertouch
- // Not supported.
- break;
-
+ break; // Not supported.
case 0xB0: // Control Change
- switch (param1) {
- case 01: // Modulation wheel
- part->_modwheel = param2;
- for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) {
- if (mc->_s10a.active && mc->_s11a.flag0x40)
- mc->_s10a.modwheel = part->_modwheel >> 2;
- if (mc->_s10b.active && mc->_s11b.flag0x40)
- mc->_s10b.modwheel = part->_modwheel >> 2;
- }
- break;
-
- case 07: // Volume
- part->_vol_eff = param2;
- for (mc = part->_mc; mc; mc = mc->_next) {
- adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2][part->_vol_eff >> 2]]);
- if (mc->_twochan) {
- adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1][part->_vol_eff >> 2]]);
- }
- }
- break;
-
- case 10: // Pan position
- // Not supported in Adlib (OPL2)
- break;
-
- case 16: // Pitchbend factor
- part->_pitchbend_factor = param2;
- for (mc = part->_mc; mc; mc = mc->_next) {
- adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff,
- (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff);
- }
- break;
-
- case 17: // GP slider 2 (detune)
- part->_detune_eff = param2;
- for (mc = part->_mc; mc; mc = mc->_next) {
- adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff,
- (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff);
- }
- break;
-
- case 18: // GP slider 3 (priority)
- part->_pri_eff = param2;
- break;
-
- case 64: // Sustain pedal
- part->_pedal = (param2 > 0);
- if (!part->_pedal) {
- for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) {
- if (mc->_waitforpedal)
- mc_off(mc);
- }
- }
- break;
-
- case 91: // Effects level
- // Not supported in Adlib (OPL2)
- break;
-
- case 93: // Chorus
- // Not supported in Adlib (OPL2)
- break;
-
- case 123: // All Notes Off
- while (part->_mc)
- mc_off (part->_mc);
- break;
-
- default:
- warning ("MidiDriver_ADLIB: Unknown control change message %d", param1);
- }
- break;
-
+ part->controlChange (param1, param2); break;
case 0xC0: // Program Change
- if (chan != 9) {
- if (!map_gm_to_fm [part->_program][0])
- warning ("No Adlib instrument defined for GM program %d", (int) param1);
- part->_program = param1;
- part_set_instrument (&_parts[chan], (Instrument *) &map_gm_to_fm[part->_program]);
- }
+ if (chan != 9)
+ part->programChange (param1);
break;
-
case 0xD0: // Channel Pressure
- // Not supported.
- break;
-
+ break; // Not supported.
case 0xE0: // Pitch Bend
- part->_pitchbend = (param1 | (param2 << 7)) - 0x2000;
- for (mc = part->_mc; mc; mc = mc->_next) {
- adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff,
- (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff);
- }
- break;
-
+ part->pitchBend ((param1 | (param2 << 7)) - 0x2000); break;
case 0xF0: // SysEx
// We should never get here! SysEx information has to be
// sent via high-level semantic methods.
@@ -741,8 +825,13 @@ void MidiDriver_ADLIB::setPitchBendRange (byte channel, uint range)
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 ') {
- Instrument *i = &_parts[channel]._part_instr;
+ Instrument *i = &part->_part_instr;
memcpy(i, instr, sizeof(Instrument));
}
}
@@ -753,6 +842,21 @@ void MidiDriver_ADLIB::setTimerCallback (void *timer_param, void (*timer_proc) (
_timer_param = timer_param;
}
+MidiChannel *MidiDriver_ADLIB::allocateChannel()
+{
+ AdlibPart *part;
+ uint i;
+
+ for (i = 0; i < ARRAYSIZE(_parts); ++i) {
+ part = &_parts[i];
+ if (!part->_allocated) {
+ part->allocate();
+ return (part);
+ }
+ }
+ return NULL;
+}
+
MidiDriver *MidiDriver_ADLIB_create()
{
return new MidiDriver_ADLIB();
@@ -860,18 +964,18 @@ void MidiDriver_ADLIB::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11
switch (s11->param) {
case 0:
mc->_vol_2 = s10->start_value + s11->modify_val;
- ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 0,
- volume_table[lookup_table[mc->_vol_2]
- [part->_vol_eff >> 2]]);
+ adlib_set_param(mc->_channel, 0,
+ volume_table[lookup_table[mc->_vol_2]
+ [part->_vol_eff >> 2]]);
break;
case 13:
mc->_vol_1 = s10->start_value + s11->modify_val;
if (mc->_twochan) {
- ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 13,
- volume_table[lookup_table[mc->_vol_1]
- [part->_vol_eff >> 2]]);
+ adlib_set_param(mc->_channel, 13,
+ volume_table[lookup_table[mc->_vol_1]
+ [part->_vol_eff >> 2]]);
} else {
- ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, 13, mc->_vol_1);
+ adlib_set_param(mc->_channel, 13, mc->_vol_1);
}
break;
case 30:
@@ -881,14 +985,14 @@ void MidiDriver_ADLIB::mc_inc_stuff(MidiChannelAdl *mc, Struct10 * s10, Struct11
s11->s10->unk3 = (char)s11->modify_val;
break;
default:
- ((MidiDriver_ADLIB *) part->_drv)->adlib_set_param(mc->_channel, s11->param,
- s10->start_value + s11->modify_val);
+ adlib_set_param(mc->_channel, s11->param,
+ s10->start_value + s11->modify_val);
break;
}
}
if (code & 2 && s11->flag0x10)
- ((MidiDriver_ADLIB *) part->_drv)->adlib_key_onoff(mc->_channel);
+ adlib_key_onoff(mc->_channel);
}
void MidiDriver_ADLIB::adlib_key_off(int chan)
@@ -1081,23 +1185,11 @@ int MidiDriver_ADLIB::random_nr(int a)
return _rand_seed * a >> 8;
}
-void MidiDriver_ADLIB::part_key_off (byte chan, byte note)
+void MidiDriver_ADLIB::part_key_off (AdlibPart *part, byte note)
{
MidiChannelAdl *mc;
- // Percussion is not implemented; filter that channel
- if (chan == 9)
- return;
-
- AdlibPart *part;
- for (part = _parts; part; part = part->_next) {
- if (part->_chan == chan)
- break;
- }
- if (!part)
- return;
-
- for (mc = (MidiChannelAdl *)part->_mc; mc; mc = mc->_next) {
+ for (mc = part->_mc; mc; mc = mc->_next) {
if (mc->_note == note) {
if (part->_pedal)
mc->_waitforpedal = true;
@@ -1107,22 +1199,10 @@ void MidiDriver_ADLIB::part_key_off (byte chan, byte note)
}
}
-void MidiDriver_ADLIB::part_key_on (byte chan, byte note, byte velocity)
+void MidiDriver_ADLIB::part_key_on (AdlibPart *part, byte note, byte velocity)
{
MidiChannelAdl *mc;
- // Percussion is not implemented; filter that channel
- if (chan == 9)
- return;
-
- AdlibPart *part;
- for (part = _parts; part; part = part->_next) {
- if (part->_chan == chan)
- break;
- }
- if (!part)
- return;
-
mc = allocate_midichan(part->_pri_eff);
if (!mc)
return;
@@ -1287,7 +1367,7 @@ void MidiDriver_ADLIB::mc_init_stuff (MidiChannelAdl *mc, Struct10 * s10,
s11->s10->unk3 = 0;
break;
default:
- s10->start_value = ((MidiDriver_ADLIB *) part->_drv)->adlib_read_param(mc->_channel, s11->param);
+ s10->start_value = adlib_read_param(mc->_channel, s11->param);
}
struct10_init(s10, ie);
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp
index 09b069bd7d..1c529fc57a 100644
--- a/scumm/imuse.cpp
+++ b/scumm/imuse.cpp
@@ -112,8 +112,8 @@ public:
class IMuseDriver;
struct Part;
-struct MidiChannelAdl;
-struct MidiChannelGM;
+// struct MidiChannelAdl;
+// struct MidiChannelGM;
struct Instrument;
@@ -262,7 +262,7 @@ struct IsNoteCmdData {
};
-
+/*
struct MidiChannel {
Part *_part;
MidiChannel() : _part(0) {}
@@ -273,10 +273,10 @@ struct MidiChannel {
struct MidiChannelGM : MidiChannel {
byte _chan;
- uint16 _actives[8];
- MidiChannelGM() : _chan(0) { memset(_actives, 0, 16); }
+// uint16 _actives[8];
+// MidiChannelGM() : _chan(0) { memset(_actives, 0, 16); }
};
-
+*/
struct Part {
int _slot;
@@ -302,6 +302,9 @@ struct Part {
byte _percussion;
byte _bank;
+ // Used to be in MidiDriverGM.
+ uint16 _actives[8];
+
void key_on(byte note, byte velocity);
void key_off(byte note);
void set_param(byte param, int value);
@@ -577,7 +580,7 @@ struct MidiChannelAdl : MidiChannel {
MidiChannelAdl() : _next(0), _prev(0) {}
};
-
+/*
class IMuseAdlib : public IMuseDriver {
private:
FM_OPL *_opl;
@@ -661,7 +664,7 @@ public:
return 1;
}
};
-
+*/
/* IMuseGM classes */
@@ -669,7 +672,7 @@ class IMuseGM : public IMuseDriver {
IMuseInternal *_se;
OSystem *_system;
MidiDriver *_md;
- MidiChannelGM _midi_channels[16];
+// MidiChannelGM _midi_channels[16];
Instrument _part_instr[32]; // Adlib custom instruments
Instrument _glob_instr[32]; // Adlib custom instruments
@@ -1937,7 +1940,8 @@ int IMuseInternal::initialize(OSystem *syst, MidiDriver *midi, SoundMixer *mixer
IMuseDriver *driv;
if (midi == NULL) {
- driv = new IMuseAdlib(mixer);
+// driv = new IMuseAdlib(mixer);
+ driv = NULL;
} else {
driv = new IMuseGM(midi);
}
@@ -3559,6 +3563,7 @@ void Part::init(IMuseDriver * driver)
_next = NULL;
_prev = NULL;
_mc = NULL;
+ memset(_actives, 0, sizeof (_actives));
}
void Part::setup(Player *player)
@@ -3663,7 +3668,7 @@ void Part::set_instrument(uint b)
//***** ADLIB PART OF IMUSE STARTS HERE ******
//********************************************
-
+/*
static byte lookup_table[64][32];
const byte volume_table[] = {
0, 4, 7, 11,
@@ -3814,21 +3819,21 @@ static const byte channel_mappings_2[9] = {
};
static const AdlibSetParams adlib_setparam_table[] = {
- {0x40, 0, 63, 63}, /* level */
- {0xE0, 2, 0, 0}, /* unused */
- {0x40, 6, 192, 0}, /* level key scaling */
- {0x20, 0, 15, 0}, /* modulator frequency multiple */
- {0x60, 4, 240, 15}, /* attack rate */
- {0x60, 0, 15, 15}, /* decay rate */
- {0x80, 4, 240, 15}, /* sustain level */
- {0x80, 0, 15, 15}, /* release rate */
- {0xE0, 0, 3, 0}, /* waveform select */
- {0x20, 7, 128, 0}, /* amp mod */
- {0x20, 6, 64, 0}, /* vib */
- {0x20, 5, 32, 0}, /* eg typ */
- {0x20, 4, 16, 0}, /* ksr */
- {0xC0, 0, 1, 0}, /* decay alg */
- {0xC0, 1, 14, 0} /* feedback */
+ {0x40, 0, 63, 63}, // level
+ {0xE0, 2, 0, 0}, // unused
+ {0x40, 6, 192, 0}, // level key scaling
+ {0x20, 0, 15, 0}, // modulator frequency multiple
+ {0x60, 4, 240, 15}, // attack rate
+ {0x60, 0, 15, 15}, // decay rate
+ {0x80, 4, 240, 15}, // sustain level
+ {0x80, 0, 15, 15}, // release rate
+ {0xE0, 0, 3, 0}, // waveform select
+ {0x20, 7, 128, 0}, // amp mod
+ {0x20, 6, 64, 0}, // vib
+ {0x20, 5, 32, 0}, // eg typ
+ {0x20, 4, 16, 0}, // ksr
+ {0xC0, 0, 1, 0}, // decay alg
+ {0xC0, 1, 14, 0} // feedback
};
void IMuseAdlib::adlib_set_param(int channel, byte param, int value)
@@ -4762,7 +4767,7 @@ int IMuseAdlib::part_update_active(Part *part, uint16 *active)
}
return count;
}
-
+*/
//********************************************
//** GENERAL MIDI PART OF IMUSE STARTS HERE **
//********************************************
@@ -4889,27 +4894,40 @@ void IMuseGM::midiSilence(byte chan)
void IMuseGM::part_key_on(Part *part, byte note, byte velocity)
{
- MidiChannelGM *mc = part->_mc->gm();
+ MidiChannel/*GM*/ *mc = part->_mc;//->gm();
+ part->_actives[note >> 4] |= (1 << (note & 0xF));
if (mc) {
- mc->_actives[note >> 4] |= (1 << (note & 0xF));
- midiNoteOn(mc->_chan, note, velocity);
+// mc->_actives[note >> 4] |= (1 << (note & 0xF));
+// midiNoteOn(mc->_chan, note, velocity);
+ mc->noteOn (note, velocity);
} else if (part->_percussion) {
- midiVolume(PERCUSSION_CHANNEL, part->_vol_eff);
- midiProgram(PERCUSSION_CHANNEL, part->_bank, part->_player->_mt32emulate);
- midiNoteOn(PERCUSSION_CHANNEL, note, velocity);
+// midiVolume(PERCUSSION_CHANNEL, part->_vol_eff);
+// midiProgram(PERCUSSION_CHANNEL, part->_bank, part->_player->_mt32emulate);
+// midiNoteOn(PERCUSSION_CHANNEL, note, velocity);
+ mc = _md->getPercussionChannel();
+ if (!mc)
+ return;
+ mc->volume (part->_vol_eff);
+ mc->programChange (part->_bank /*, part->_player->_mt32emulate*/);
+ mc->noteOn (note, velocity);
}
}
void IMuseGM::part_key_off(Part *part, byte note)
{
- MidiChannelGM *mc = part->_mc->gm();
+ MidiChannel/*GM*/ *mc = part->_mc;//->gm();
+ part->_actives[note >> 4] &= ~(1 << (note & 0xF));
if (mc) {
- mc->_actives[note >> 4] &= ~(1 << (note & 0xF));
- midiNoteOff(mc->_chan, note);
+// mc->_actives[note >> 4] &= ~(1 << (note & 0xF));
+// midiNoteOff(mc->_chan, note);
+ mc->noteOff (note);
} else if (part->_percussion) {
- midiNoteOff(PERCUSSION_CHANNEL, note);
+// midiNoteOff(PERCUSSION_CHANNEL, note);
+ mc = _md->getPercussionChannel();
+ if (mc)
+ mc->noteOff (note);
}
}
@@ -4984,22 +5002,22 @@ int IMuseGM::midi_driver_thread(void *param)
void IMuseGM::init(IMuseInternal *eng, OSystem *syst)
{
int i;
- MidiChannelGM *mc;
+// MidiChannel/*GM*/ *mc;
_system = syst;
- /* open midi driver */
+ // Open MIDI driver
int result = _md->open(MidiDriver::MO_SIMPLE);
if (result)
error("IMuseGM::error = %s", MidiDriver::get_error_name(result));
- /* Install the on_timer thread */
+ // Connect to the driver's timer
_se = eng;
// syst->create_thread(midi_driver_thread, this);
_md->setTimerCallback (NULL, &IMuseGM::timer_callback);
- for (i = 0, mc = _midi_channels; i != ARRAYSIZE(_midi_channels); i++, mc++) {
- mc->_chan = i;
+ for (i = 0; i != ARRAYSIZE(_midi_program_last); i++) {
+// mc->_chan = i;
_midi_program_last [i] = 255;
}
}
@@ -5018,7 +5036,8 @@ void IMuseGM::update_pris()
Part *part, *hipart;
int i;
byte hipri, lopri;
- MidiChannelGM *mc, *lomc;
+// MidiChannel/*GM*/ *mc, *lomc;
+ Part *lopart;
while (true) {
hipri = 0;
@@ -5033,30 +5052,26 @@ void IMuseGM::update_pris()
if (!hipart)
return;
- lopri = 255;
- lomc = NULL;
- for (i = ARRAYSIZE(_midi_channels), mc = _midi_channels;; mc++) {
- if (mc->_chan != 9) {
- if (!mc->_part) {
- lomc = mc;
- break;
- }
- if (mc->_part->_pri_eff <= lopri) {
- lopri = mc->_part->_pri_eff;
- lomc = mc;
- }
- }
+ if ((hipart->_mc = _md->allocateChannel()) != NULL) {
+ hipart->changed (pcAll);
+ return;
+ }
- if (!--i) {
- if (lopri >= hipri)
- return;
- lomc->_part->off();
- break;
+ lopri = 255;
+ lopart = NULL;
+ for (i = 32, part = _se->parts_ptr(); i; i--, part++) {
+ if (part->_mc && part->_pri_eff <= lopri) {
+ lopri = part->_pri_eff;
+ lopart = part;
}
}
- hipart->_mc = lomc;
- lomc->_part = hipart;
+ if (lopart == NULL || lopri >= hipri)
+ return;
+ lopart->off();
+
+ if ((hipart->_mc = _md->allocateChannel()) == NULL)
+ return;
hipart->changed(pcAll);
}
}
@@ -5069,7 +5084,8 @@ int IMuseGM::part_update_active(Part *part, uint16 *active)
bits = 1 << part->_chan;
- act = part->_mc->gm()->_actives;
+// act = part->_mc->gm()->_actives;
+ act = part->_actives;
for (i = 8; i; i--) {
mask = *act++;
@@ -5102,83 +5118,104 @@ void IMuseGM::set_instrument(uint slot, byte *data)
void IMuseGM::part_changed(Part *part, uint16 what)
{
- MidiChannelGM *mc;
+ MidiChannel/*GM*/ *mc;
- /* Mark for re-schedule if program changed when in pre-state */
+ // Mark for re-schedule if program changed when in pre-state
if (what & pcProgram && !part->_percussion && !part->_mc) {
update_pris();
}
- if (!(mc = part->_mc->gm()))
+ if (!(mc = part->_mc/*->gm()*/))
return;
- if (part->_player == NULL) { /* No player, so dump phantom channel */
+ if (part->_player == NULL) { // No player, so dump phantom channel
+ part->_mc->release();
part->_mc = NULL;
- mc->_part = NULL;
- memset(mc->_actives, 0, sizeof(mc->_actives));
+// mc->_part = NULL;
+// memset(mc->_actives, 0, sizeof(mc->_actives));
+ memset(part->_actives, 0, sizeof(part->_actives));
return;
}
if (what & pcPitchBendFactor)
- midiPitchBendFactor (mc->_chan, part->_pitchbend_factor);
+// midiPitchBendFactor (mc->_chan, part->_pitchbend_factor);
+ mc->pitchBendFactor (part->_pitchbend_factor);
if (what & pcMod)
- midiPitchBend(mc->_chan,
- clamp(part->_pitchbend +
- (part->_detune_eff * 64 / 12) +
- (part->_transpose_eff * 8192 / 12), -8192, 8191));
+// midiPitchBend(mc->_chan,
+// clamp(part->_pitchbend +
+// (part->_detune_eff * 64 / 12) +
+// (part->_transpose_eff * 8192 / 12), -8192, 8191));
+ mc->pitchBend (clamp(part->_pitchbend +
+ (part->_detune_eff * 64 / 12) +
+ (part->_transpose_eff * 8192 / 12), -8192, 8191));
if (what & pcVolume)
- midiVolume(mc->_chan, part->_vol_eff);
+// midiVolume(mc->_chan, part->_vol_eff);
+ mc->volume (part->_vol_eff);
if (what & pcPedal)
- midiPedal(mc->_chan, part->_pedal);
+// midiPedal(mc->_chan, part->_pedal);
+ mc->sustain (part->_pedal);
if (what & pcModwheel)
- midiModWheel(mc->_chan, part->_modwheel);
+// midiModWheel(mc->_chan, part->_modwheel);
+ mc->modulationWheel (part->_modwheel);
if (what & pcPan)
- midiPan(mc->_chan, part->_pan_eff);
+// midiPan(mc->_chan, part->_pan_eff);
+ mc->panPosition (part->_pan_eff);
if (what & pcEffectLevel)
- midiEffectLevel(mc->_chan, part->_effect_level);
+// midiEffectLevel(mc->_chan, part->_effect_level);
+ mc->effectLevel (part->_effect_level);
if (what & pcProgram) {
if (part->_player->_isGM) {
if (part->_program < 128) {
_midi_program_last [part->_chan] = part->_program;
if (part->_bank) {
- midiControl0(mc->_chan, part->_bank);
- midiProgram(mc->_chan, part->_program, part->_player->_mt32emulate);
- midiControl0(mc->_chan, 0);
+// midiControl0(mc->_chan, part->_bank);
+// midiProgram(mc->_chan, part->_program, part->_player->_mt32emulate);
+// midiControl0(mc->_chan, 0);
+ mc->controlChange (0, part->_bank);
+ mc->programChange (part->_program /*, part->_player->_mt32emulate*/);
+ mc->controlChange (0, 0);
} else {
- midiProgram(mc->_chan, part->_program, part->_player->_mt32emulate);
+// midiProgram(mc->_chan, part->_program, part->_player->_mt32emulate);
+ mc->programChange (part->_program /*, part->_player->_mt32emulate*/);
}
}
} else {
if (part->_program < 32) {
memcpy (&_part_instr [part->_slot], &_glob_instr[part->_program], sizeof (Instrument));
}
- _md->sysEx_customInstrument (mc->_chan, 'ADL ', (byte *) (&_part_instr [part->_slot]));
+// _md->sysEx_customInstrument (mc->_chan, 'ADL ', (byte *) (&_part_instr [part->_slot]));
+ mc->sysEx_customInstrument ('ADL ', (byte *) (&_part_instr [part->_slot]));
}
}
if (what & pcChorus)
- midiChorus(mc->_chan, part->_effect_level);
+// midiChorus(mc->_chan, part->_effect_level);
+ mc->chorusLevel (part->_effect_level);
if (what & pcPriority)
- _md->send ((part->_pri_eff << 16) | (18 << 8) | 0xB0 | mc->_chan);
+// _md->send ((part->_pri_eff << 16) | (18 << 8) | 0xB0 | mc->_chan);
+ mc->priority (part->_pri_eff);
}
void IMuseGM::part_off(Part *part)
{
- MidiChannelGM *mc = part->_mc->gm();
+ MidiChannel/*GM*/ *mc = part->_mc/*->gm()*/;
if (mc) {
+ mc->allNotesOff();
+ mc->release();
part->_mc = NULL;
- mc->_part = NULL;
- memset(mc->_actives, 0, sizeof(mc->_actives));
- midiSilence(mc->_chan);
+// mc->_part = NULL;
+// memset(mc->_actives, 0, sizeof(mc->_actives));
+ memset(part->_actives, 0, sizeof(part->_actives));
+// midiSilence(mc->_chan);
}
}
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index baf3427cfb..10f766ea17 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -45,8 +45,50 @@
typedef void TimerCallback (void *);
+class MidiDriver_MPU401;
+
+class MidiChannel_MPU401 : public MidiChannel {
+ friend MidiDriver_MPU401;
+
+private:
+ MidiDriver_MPU401 *_owner;
+ bool _allocated;
+ byte _channel;
+
+ void init (MidiDriver_MPU401 *owner, byte channel);
+ void allocate() { _allocated = true; }
+
+public:
+ void release() { _allocated = false; }
+
+ // Regular messages
+ 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) { controlChange (1, value); }
+ void volume (byte value) { controlChange (7, value); }
+ void panPosition (byte value) { controlChange (10, value); }
+ void pitchBendFactor (byte value) { controlChange (16, value); }
+ void detune (byte value) { controlChange (17, value); }
+ void priority (byte value) { controlChange (18, value); }
+ void sustain (bool value) { controlChange (64, value ? 1 : 0); }
+ void effectLevel (byte value) { controlChange (91, value); }
+ void chorusLevel (byte value) { controlChange (93, value); }
+ void allNotesOff() { controlChange (123, 0); }
+
+ // SysEx messages
+ void sysEx_customInstrument (uint32 type, byte *instr);
+};
+
+
+
class MidiDriver_MPU401 : public MidiDriver {
private:
+ MidiChannel_MPU401 _midi_channels [16];
bool _started_thread;
TimerCallback *_timer_proc;
void *_timer_param;
@@ -54,10 +96,60 @@ private:
static int midi_driver_thread (void *param);
public:
+ MidiDriver_MPU401();
+
virtual void setTimerCallback (void *timer_param, void (*timer_proc) (void *));
virtual uint32 getBaseTempo (void) { return 0x4A0000; }
+
+ virtual MidiChannel *allocateChannel();
+ virtual MidiChannel *getPercussionChannel() { return &_midi_channels [9]; }
};
+
+
+void MidiChannel_MPU401::init (MidiDriver_MPU401 *owner, byte channel)
+{
+ _owner = owner;
+ _channel = channel;
+ _allocated = false;
+}
+
+void MidiChannel_MPU401::noteOff (byte note) { _owner->send(note << 8 | 0x80 | _channel); }
+void MidiChannel_MPU401::noteOn (byte note, byte velocity) { _owner->send (velocity << 16 | note << 8 | 0x90 | _channel); }
+void MidiChannel_MPU401::programChange (byte program) { _owner->send(program << 8 | 0xC0 | _channel); }
+void MidiChannel_MPU401::pitchBend (int16 bend) { _owner->send((((bend + 0x2000) >> 7) & 0x7F) << 16 | ((bend + 0x2000) & 0x7F) << 8 | 0xE0 | _channel); }
+void MidiChannel_MPU401::controlChange (byte control, byte value) { _owner->send(value << 16 | control << 8 | 0xB0 | _channel); }
+void MidiChannel_MPU401::sysEx_customInstrument (uint32 type, byte *instr) { _owner->sysEx_customInstrument (_channel, type, instr); }
+
+
+
+MidiDriver_MPU401::MidiDriver_MPU401() : MidiDriver()
+{
+ int i;
+ for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
+ _midi_channels [i].init (this, i);
+ }
+}
+
+
+
+MidiChannel *MidiDriver_MPU401::allocateChannel()
+{
+ MidiChannel_MPU401 *chan;
+ uint i;
+
+ for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
+ if (i == 9) continue;
+ chan = &_midi_channels[i];
+ if (!chan->_allocated) {
+ chan->allocate();
+ return (chan);
+ }
+ }
+ return NULL;
+}
+
+
void MidiDriver_MPU401::setTimerCallback (void *timer_param, void (*timer_proc) (void *))
{
if (!_timer_proc || !timer_proc) {
@@ -95,7 +187,6 @@ int MidiDriver_MPU401::midi_driver_thread(void *param)
-
// FIXME - the following disables reverb support in the QuickTime / CoreAudio
// midi backends. For some reasons, reverb will suck away a *lot* of CPU time.
// Until we know for sure what is causing this and if there is a better way to
diff --git a/sound/mididrv.h b/sound/mididrv.h
index 49fff19fd5..2c47344586 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -25,12 +25,14 @@
#include "scummsys.h"
+class MidiChannel;
+
struct MidiEvent {
uint32 delta;
uint32 event;
};
-/* Lowlevel Abstract Midi Driver Class */
+// Abstract MIDI Driver Class
class MidiDriver {
public:
@@ -112,11 +114,44 @@ public:
// Timing functions - MidiDriver now operates timers
virtual void setTimerCallback (void *timer_param, void (*timer_proc) (void *)) = 0;
virtual uint32 getBaseTempo (void) = 0;
+
+ // Channel allocation functions
+ virtual MidiChannel *allocateChannel() = 0;
+ virtual MidiChannel *getPercussionChannel() = 0;
+};
+
+
+
+class MidiChannel {
+public:
+ virtual void release() = 0;
+
+ // Regular messages
+ virtual void noteOff (byte note) = 0;
+ virtual void noteOn (byte note, byte velocity) = 0;
+ virtual void programChange (byte program) = 0;
+ virtual void pitchBend (int16 bend) = 0; // -0x2000 to +0x1FFF
+
+ // Control Change messages
+ virtual void controlChange (byte control, byte value) = 0;
+ virtual void modulationWheel (byte value) = 0;
+ virtual void volume (byte value) = 0;
+ virtual void panPosition (byte value) = 0;
+ virtual void pitchBendFactor (byte value) = 0;
+ virtual void detune (byte value) = 0;
+ virtual void priority (byte value) = 0;
+ virtual void sustain (bool value) = 0;
+ virtual void effectLevel (byte value) = 0;
+ virtual void chorusLevel (byte value) = 0;
+ virtual void allNotesOff() = 0;
+
+ // SysEx messages
+ virtual void sysEx_customInstrument (uint32 type, byte *instr) = 0;
};
-/* driver types */
+// MIDI Driver Types
enum {
MD_AUTO = 0,
MD_NULL = 1,
diff --git a/sound/midistreamer.h b/sound/midistreamer.h
index 62f95db70b..d2b70bed86 100644
--- a/sound/midistreamer.h
+++ b/sound/midistreamer.h
@@ -59,6 +59,9 @@ public:
void setTimerCallback (void *timer_param, void (*timer_proc) (void *)) { }
uint32 getBaseTempo (void) { return _target->getBaseTempo(); }
+
+ MidiChannel *allocateChannel() { return NULL; }
+ MidiChannel *getPercussionChannel() { return NULL; }
};
#endif