diff options
-rw-r--r-- | backends/midi/adlib.cpp | 388 | ||||
-rw-r--r-- | scumm/imuse.cpp | 219 | ||||
-rw-r--r-- | sound/mididrv.cpp | 93 | ||||
-rw-r--r-- | sound/mididrv.h | 39 | ||||
-rw-r--r-- | sound/midistreamer.h | 3 |
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 |