diff options
-rw-r--r-- | scumm/imuse.cpp | 146 | ||||
-rw-r--r-- | scumm/instrument.cpp | 43 | ||||
-rw-r--r-- | scumm/instrument.h | 2 | ||||
-rw-r--r-- | scumm/resource.cpp | 5 |
4 files changed, 127 insertions, 69 deletions
diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp index 07ac0d758a..12432423f0 100644 --- a/scumm/imuse.cpp +++ b/scumm/imuse.cpp @@ -29,6 +29,10 @@ #include "scumm/sound.h" #include "common/util.h" +// Unremark this statement to activate some of +// the most common iMuse diagnostic messages. +// #define IMUSE_DEBUG + // // Some constants // @@ -229,6 +233,7 @@ struct Part { // New abstract instrument definition Instrument _instrument; + bool _unassigned_instrument; // For diagnostic reporting purposes only // Used to be in MidiDriver uint16 _actives[8]; @@ -302,7 +307,7 @@ private: MidiDriver *_md; Instrument _glob_instr[32]; // Adlib custom instruments - byte _midi_program_last[16]; + Instrument _midi_instrument_last[16]; int16 _midi_pitchbend_last[16]; byte _midi_pitchbend_factor_last[16]; uint8 _midi_volume_last[16]; @@ -340,13 +345,14 @@ public: void set_instrument(uint slot, byte *instr); void part_load_global_instrument (Part *part, byte slot); void part_set_param(Part *part, byte param, int value) {} - void part_key_on(Part *part, byte note, byte velocity); - void part_key_off(Part *part, byte note); +// void part_key_on(Part *part, byte note, byte velocity); +// void part_key_off(Part *part, byte note); void part_changed(Part *part, uint16 what); - byte get_channel_program (byte channel) { return _midi_program_last [channel]; } + void get_channel_instrument (byte channel, Instrument *instrument) { _midi_instrument_last[channel].copy_to (instrument); } static int midi_driver_thread(void *param); + MidiChannel *getPercussionChannel() { return _md->getPercussionChannel(); } uint32 get_base_tempo() { return _md->getBaseTempo(); } byte get_hardware_type() { return 5; } }; @@ -471,7 +477,7 @@ public: int get_music_volume(); int set_master_volume(uint vol); int get_master_volume(); - byte get_channel_program (byte channel) { return _driver->get_channel_program (channel); } + void get_channel_instrument (byte channel, Instrument *instrument) { _driver->get_channel_instrument (channel, instrument); } bool startSound(int sound); int stopSound(int sound); int stop_all_sounds(); @@ -714,7 +720,7 @@ bool IMuseInternal::startSound(int sound) { if (!mdhd) { mdhd = findTag(sound, MDPG_TAG, 0); if (!mdhd) { - warning("SE::startSound failed: Couldn't find sound %d", sound); + debug (2, "SE::startSound failed: Couldn't find sound %d", sound); return false; } } @@ -737,7 +743,6 @@ bool IMuseInternal::startSound(int sound) { return false; player->clear(); - return player->startSound(sound); } @@ -860,14 +865,25 @@ void IMuseInternal::handle_marker(uint id, byte data) { uint16 *p; uint pos; - pos = _queue_end; - if (pos == _queue_pos) - return; - if (_queue_adding && _queue_sound == id && data == _queue_marker) return; - p = _cmd_queue[pos].array; + // Fix for bug #733401: It would seem that sometimes the + // queue read position gets out of sync (possibly just + // reset to zero). Therefore, the read position should + // skip over any empty (i.e. all zeros) queue entries + // until it finds a legit entry to review. + pos = _queue_end; + while (pos != _queue_pos) { + p = _cmd_queue[pos].array; + if ((p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) != 0) + break; + warning ("Skipping empty command queue entry at position %d", pos); + pos = (pos + 1) & (ARRAYSIZE(_cmd_queue) - 1); + } + + if (pos == _queue_pos) + return; if (p[0] != TRIGGER_ID || p[1] != id || p[2] != data) return; @@ -1269,6 +1285,10 @@ int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, if (!_initialized && (cmd || param)) return -1; +#ifdef IMUSE_DEBUG + debug (0, "doCommand - %d (%d/%d), %d, %d, %d, %d, %d, %d, %d", a, (int) param, (int) cmd, b, c, d, e, f, g, h); +#endif + if (param == 0) { switch (cmd) { case 6: @@ -2057,6 +2077,18 @@ void Player::parse_sysex(byte *p, uint len) { if (len >= sizeof(buf) * 2) return; +#ifdef IMUSE_DEBUG + for (a = 0; a < len + 1 && a < 20; ++a) { + sprintf ((char *)&buf[a*3], " %02X", p[a]); + } // next for + if (a < len + 1) { + buf[a*3] = buf[a*3+1] = buf[a*3+2] = '.'; + ++a; + } // end if + buf[a*3] = '\0'; + debug (0, "SysEx:%s", buf); +#endif + switch (code = *p++) { case 0: if (g_scumm->_gameId != GID_SAMNMAX) { @@ -2118,10 +2150,16 @@ void Player::parse_sysex(byte *p, uint len) { a = *p++ & 0x0F; if (_se->_hardware_type != *p++ && false) break; - decode_sysex_bytes(p, buf, len - 3); part = get_part(a); - if (part) - part->set_instrument((byte *) buf); + if (part) { + if (len == 63) { + decode_sysex_bytes(p, buf, len - 3); + part->set_instrument((byte *) buf); + } else { + // SPK tracks have len == 49 here, and are not supported + part->set_program (254); // Must be invalid, but not 255 (which is reserved) + } + } break; case 17: // Adlib instrument definition (Global) @@ -2909,6 +2947,7 @@ int IMuseInternal::save_or_load(Serializer *ser, Scumm *scumm) { MKLINE(IMuseInternal, _trigger_count, sleUint16, VER_V8), MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER_V8), MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER_V8), + // TODO: Add _cmd_queue in here MKEND() }; @@ -3149,11 +3188,38 @@ void Part::load_global_instrument (byte slot) { } void Part::key_on(byte note, byte velocity) { - _drv->part_key_on(this, note, velocity); + MidiChannel *mc = _mc; + _actives[note >> 4] |= (1 << (note & 0xF)); + + // DEBUG + if (_unassigned_instrument && !_percussion) { + warning ("[%02d] No instrument specified", (int) _chan); + _unassigned_instrument = false; + return; + } + + if (mc && _instrument.isValid()) { + mc->noteOn (note, velocity); + } else if (_percussion) { + mc = _drv->getPercussionChannel(); + if (!mc) + return; + mc->volume (_vol_eff); + mc->programChange (_bank); + mc->noteOn (note, velocity); + } } void Part::key_off(byte note) { - _drv->part_key_off(this, note); + MidiChannel *mc = _mc; + _actives[note >> 4] &= ~(1 << (note & 0xF)); + if (mc) { + mc->noteOff (note); + } else if (_percussion) { + mc = _drv->getPercussionChannel(); + if (mc) + mc->noteOff (note); + } } void Part::init(IMuseDriver * driver) { @@ -3189,17 +3255,17 @@ void Part::setup(Player *player) { _pitchbend_factor = 2; _pitchbend = 0; _effect_level = 64; -// _program = player->_se->get_channel_program (_chan); -// _instrument.program (_program, player->_mt32emulate); _program = 255; _instrument.clear(); + _unassigned_instrument = true; +// player->_se->get_channel_instrument (_chan, &_instrument); _chorus = 0; _modwheel = 0; _bank = 0; _pedal = false; _mc = NULL; - if (_program < 128) + if (_instrument.isValid()) changed (IMuseDriver::pcAll); } @@ -3272,7 +3338,6 @@ IMuseDriver::IMuseDriver (MidiDriver *midi) { // any changes that are sent (which would cause // the changes to be ignored). for (i = 0; i < 16; ++i) { - _midi_program_last [i] = _midi_pitchbend_factor_last [i] = _midi_volume_last [i] = _midi_modwheel_last [i] = @@ -3360,36 +3425,6 @@ void IMuseDriver::midiSilence(byte chan) { _md->send((123 << 8) | 0xB0 | chan); } - -void IMuseDriver::part_key_on(Part *part, byte note, byte velocity) { - MidiChannel *mc = part->_mc; - - part->_actives[note >> 4] |= (1 << (note & 0xF)); - if (mc) { - mc->noteOn (note, velocity); - } else if (part->_percussion) { - mc = _md->getPercussionChannel(); - if (!mc) - return; - mc->volume (part->_vol_eff); - mc->programChange (part->_bank); - mc->noteOn (note, velocity); - } -} - -void IMuseDriver::part_key_off(Part *part, byte note) { - MidiChannel *mc = part->_mc; - - part->_actives[note >> 4] &= ~(1 << (note & 0xF)); - if (mc) { - mc->noteOff (note); - } else if (part->_percussion) { - mc = _md->getPercussionChannel(); - if (mc) - mc->noteOff (note); - } -} - void IMuseDriver::init(IMuseInternal *eng, OSystem *syst) { int i; @@ -3404,8 +3439,8 @@ void IMuseDriver::init(IMuseInternal *eng, OSystem *syst) { _se = eng; _md->setTimerCallback (NULL, &IMuseDriver::timer_callback); - for (i = 0; i != ARRAYSIZE(_midi_program_last); i++) { - _midi_program_last [i] = 255; + for (i = 0; i != ARRAYSIZE(_midi_instrument_last); i++) { + _midi_instrument_last [i].clear(); } } @@ -3536,8 +3571,11 @@ void IMuseDriver::part_changed(Part *part, uint16 what) { if (what & pcEffectLevel) mc->effectLevel (part->_effect_level); - if (what & pcProgram) + if (what & pcProgram && part->_instrument.isValid()) { part->_instrument.send (mc); + part->_unassigned_instrument = false; +// part->_instrument.copy_to (&_midi_instrument_last [part->_chan]); + } if (what & pcChorus) mc->chorusLevel (part->_effect_level); diff --git a/scumm/instrument.cpp b/scumm/instrument.cpp index da6fc2865d..169ab67e35 100644 --- a/scumm/instrument.cpp +++ b/scumm/instrument.cpp @@ -135,6 +135,7 @@ public: void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->program (_program, _mt32); } + bool is_valid() { return (_program < 128); } }; class Instrument_Adlib : public InstrumentInternal { @@ -164,6 +165,7 @@ public: void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->adlib ((byte *) &_instrument); } + bool is_valid() { return true; } }; class Instrument_Roland : public InstrumentInternal { @@ -228,12 +230,15 @@ private: char _instrument_name [11]; + uint8 getEquivalentGM(); + public: Instrument_Roland (byte *data); Instrument_Roland (Serializer *s); void saveOrLoad (Serializer *s); void send (MidiChannel *mc); void copy_to (Instrument *dest) { dest->roland ((byte *) &_instrument); } + bool is_valid() { return (NATIVE_MT32 ? true : (_instrument_name[0] != '\0')); } }; //////////////////////////////////////// @@ -377,6 +382,10 @@ Instrument_Roland::Instrument_Roland (byte *data) { memcpy (&_instrument, data, sizeof (_instrument)); memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name)); _instrument_name[10] = '\0'; + if (!NATIVE_MT32 && getEquivalentGM() >= 128) { + warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name); + _instrument_name[0] = '\0'; + } } Instrument_Roland::Instrument_Roland (Serializer *s) { @@ -388,12 +397,17 @@ Instrument_Roland::Instrument_Roland (Serializer *s) { } void Instrument_Roland::saveOrLoad (Serializer *s) { - if (s->isSaving()) + if (s->isSaving()) { s->saveBytes (&_instrument, sizeof (_instrument)); - else + } else { s->loadBytes (&_instrument, sizeof (_instrument)); - memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name)); - _instrument_name[10] = '\0'; + memcpy (&_instrument_name, &_instrument.common.name, sizeof (_instrument.common.name)); + _instrument_name[10] = '\0'; + if (!NATIVE_MT32 && getEquivalentGM() >= 128) { + warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name); + _instrument_name[0] = '\0'; + } + } // end if } void Instrument_Roland::send (MidiChannel *mc) { @@ -402,14 +416,17 @@ void Instrument_Roland::send (MidiChannel *mc) { mc->device()->sysEx ((byte *) &_instrument, sizeof (_instrument)); } else { // Convert to a GM program change. - byte i; - for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) { - if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10)) { - mc->programChange (roland_to_gm_map[i].program); - return; - } - } - warning ("MT-32 instrument \"%s\" not supported yet", _instrument_name); - mc->programChange (0); + byte program = getEquivalentGM(); + if (program < 128) + mc->programChange (program); + } +} + +uint8 Instrument_Roland::getEquivalentGM() { + byte i; + for (i = 0; i != ARRAYSIZE(roland_to_gm_map); ++i) { + if (!memcmp (roland_to_gm_map[i].name, _instrument.common.name, 10)) + return roland_to_gm_map[i].program; } + return 255; } diff --git a/scumm/instrument.h b/scumm/instrument.h index 1d021466ad..f3607eab4d 100644 --- a/scumm/instrument.h +++ b/scumm/instrument.h @@ -34,6 +34,7 @@ public: virtual void saveOrLoad (Serializer *s) = 0; virtual void send (MidiChannel *mc) = 0; virtual void copy_to (Instrument *dest) = 0; + virtual bool is_valid() = 0; }; class Instrument { @@ -58,6 +59,7 @@ public: void roland (byte *instrument); byte getType() { return _type; } + bool isValid() { return (_instrument ? _instrument->is_valid() : false); } void saveOrLoad (Serializer *s); void send (MidiChannel *mc) { if (_instrument) _instrument->send (mc); } }; diff --git a/scumm/resource.cpp b/scumm/resource.cpp index f9fd93651e..1ca9b5e1e0 100644 --- a/scumm/resource.cpp +++ b/scumm/resource.cpp @@ -724,8 +724,9 @@ int Scumm::readSoundResource(int type, int idx) { pri = 2; break; case MKID('SPK '): - if (!_use_adlib) - pri = 0; + pri = -1; +// if (!_use_adlib) +// pri = 0; break; } |