From 1615278ecc376f7de5136e72239e86363cd96134 Mon Sep 17 00:00:00 2001 From: Jamieson Christian Date: Wed, 6 Aug 2003 18:20:15 +0000 Subject: Upgraded IMuse::doCommand() to support more than 8 parameters. V6 scripts can specify up to 16 parameters to be passed to doCommand(). In most cases 8 or fewer parameters were used, but occasional uses of 9 or 10 parameters resulted in incorrect iMuse behavior due to lost doCommand() data. ImTrigger was also upgraded to support 8 parameters instead of 4, since the incorrect behavior that was observed involved the use of triggered commands that required more than 4 parameters. Since ImTrigger data is not currently being saved (which is bad), we do not at this time have to go to another savegame format to support the additional ImTrigger data (which is good). This fix corrects a problem in the Tunnel of Love. When the "execution scene" music finishes and the hidden door opens, the Tunnel of Love music is supposed to start up again. In ScummVM, it never would, do to the loss of parameters for a trigger-based "Parameter Fade" command. A bit of miscellaneous cleanup has also been made. svn-id: r9579 --- scumm/imuse.cpp | 165 ++++++++++++++++++++++++++++--------------------- scumm/imuse.h | 3 +- scumm/imuse_internal.h | 7 ++- scumm/imuse_player.cpp | 65 ++++++++++--------- scumm/script_v6.cpp | 2 +- scumm/sound.cpp | 9 +-- 6 files changed, 142 insertions(+), 109 deletions(-) (limited to 'scumm') diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp index 0b3e32774e..7ce26fb628 100644 --- a/scumm/imuse.cpp +++ b/scumm/imuse.cpp @@ -643,120 +643,145 @@ int IMuseInternal::enqueue_trigger(int sound, int marker) { } int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) { + int args[8]; + args[0] = a; + args[1] = b; + args[2] = c; + args[3] = d; + args[4] = e; + args[5] = f; + args[6] = g; + args[7] = h; + return doCommand (8, args); +} + +int32 IMuseInternal::doCommand (int numargs, int a[]) { int i; - byte cmd = a & 0xFF; - byte param = a >> 8; + + if (numargs < 1) return -1; + byte cmd = a[0] & 0xFF; + byte param = a[0] >> 8; Player *player = NULL; 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); + { + char string[128]; + sprintf (string, "doCommand - %d (%d/%d)", a[0], (int) param, (int) cmd); + for (i = 1; i < numargs; ++i) + sprintf (string + strlen(string), ", %d", a[i]); + debug (0, string); + } #endif if (param == 0) { switch (cmd) { case 6: - if (b > 127) + if (a[1] > 127) return -1; else - return set_master_volume((b << 1) |(b ? 0 : 1)); // Convert b from 0-127 to 0-255 + return set_master_volume((a[1] << 1) |(a[1] ? 0 : 1)); // Convert from 0-127 to 0-255 case 7: return _master_volume >> 1; // Convert from 0-255 to 0-127 case 8: - return startSound(b) ? 0 : -1; + return startSound(a[1]) ? 0 : -1; case 9: - return stopSound(b); + return stopSound(a[1]); case 10: // FIXME: Sam and Max - Not sure if this is correct return stop_all_sounds(); case 11: return stop_all_sounds(); case 12: // Sam & Max: Player-scope commands - player = findActivePlayer(b); + player = findActivePlayer(a[1]); if (!player) return -1; - switch (d) { + switch (a[3]) { case 6: // Set player volume. - return player->setVolume(e); + return player->setVolume(a[4]); default: - warning("IMuseInternal::doCommand(6) unsupported sub-command %d", d); + warning("IMuseInternal::doCommand(12) unsupported sub-command %d", a[3]); } return -1; case 13: - return getSoundStatus(b); + return getSoundStatus(a[1]); case 14: // Sam and Max: Parameter fade - player = this->findActivePlayer(b); + player = this->findActivePlayer(a[1]); if (player) - return player->addParameterFader(d, e, f); + return player->addParameterFader(a[3], a[4], a[5]); return -1; case 15: // Sam & Max: Set hook for a "maybe" jump - player = findActivePlayer(b); + player = findActivePlayer(a[1]); if (player) { - player->setHook(0, d, 0); + player->setHook(0, a[3], 0); return 0; } return -1; case 16: - return set_volchan(b, c); + return set_volchan(a[1], a[2]); case 17: if (g_scumm->_gameId != GID_SAMNMAX) { - return set_channel_volume(b, c); + return set_channel_volume(a[1], a[2]); } else { - if (e || f || g || h) - return ImSetTrigger(b, d, e, f, g, h); - else - return ImClearTrigger(b, d); + if (a[4]) { + int b[16]; + memset (b, 0, sizeof(b)); + for (i = 0; i < numargs; ++i) + b[i] = a[i]; + return ImSetTrigger (b[1], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11]); + } else { + return ImClearTrigger(a[1], a[3]); + } } case 18: if (g_scumm->_gameId != GID_SAMNMAX) { - return set_volchan_entry(b, c); + return set_volchan_entry(a[1], a[2]); } else { // Sam & Max: ImCheckTrigger. // According to Mike's notes to Ender, // this function returns the number of triggers // associated with a particular player ID and // trigger ID. - a = 0; + a[0] = 0; for (i = 0; i < 16; ++i) { - if (_snm_triggers [i].sound == b && _snm_triggers [i].id && - (d == -1 || _snm_triggers [i].id == d)) + if (_snm_triggers [i].sound == a[1] && _snm_triggers [i].id && + (a[3] == -1 || _snm_triggers [i].id == a[3])) { - ++a; + ++a[0]; } } - return a; + return a[0]; } case 19: // Sam & Max: ImClearTrigger // This should clear a trigger that's been set up // with ImSetTrigger(cmd == 17). Seems to work.... - return ImClearTrigger(b, d); + return ImClearTrigger(a[1], a[3]); case 20: // Sam & Max: Deferred Command - // warning("[--] doCommand(20): %3d %3d %3d %3d %3d %3d (%d)", c, d, e, f, g, h, b); - addDeferredCommand(b, c, d, e, f, g, h); + addDeferredCommand(a[1], a[2], a[3], a[4], a[5], a[6], a[7]); return 0; case 2: case 3: return 0; default: - warning("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a, param, cmd, b, c, d, e, f, g, h); + warning("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]); } } else if (param == 1) { if ((1 << cmd) &(0x783FFF)) { - player = findActivePlayer(b); + player = findActivePlayer(a[1]); if (!player) return -1; if ((1 << cmd) &(1 << 11 | 1 << 22)) { - assert(c >= 0 && c <= 15); - player = (Player *) player->getPart(c); + assert(a[2] >= 0 && a[2] <= 15); + player = (Player *) player->getPart(a[2]); if (!player) return -1; } @@ -765,70 +790,70 @@ int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, switch (cmd) { case 0: if (g_scumm->_gameId == GID_SAMNMAX) { - if (d == 1) // Measure number + if (a[3] == 1) // Measure number return ((player->getBeatIndex() - 1) >> 2) + 1; - else if (d == 2) // Beat number + else if (a[3] == 2) // Beat number return player->getBeatIndex(); return -1; } else { - return player->getParam(c, d); + return player->getParam(a[2], a[3]); } case 1: if (g_scumm->_gameId == GID_SAMNMAX) - player->jump(d - 1, (e - 1) * 4 + f, ((g * player->getTicksPerBeat()) >> 2) + h); + player->jump(a[3] - 1, (a[4] - 1) * 4 + a[5], ((a[6] * player->getTicksPerBeat()) >> 2) + a[7]); else - player->setPriority(c); + player->setPriority(a[2]); return 0; case 2: - return player->setVolume(c); + return player->setVolume(a[2]); case 3: - player->setPan(c); + player->setPan(a[2]); return 0; case 4: - return player->setTranspose(c, d); + return player->setTranspose(a[2], a[3]); case 5: - player->setDetune(c); + player->setDetune(a[2]); return 0; case 6: - player->setSpeed(c); + player->setSpeed(a[2]); return 0; case 7: - return player->jump(c, d, e) ? 0 : -1; + return player->jump(a[2], a[3], a[4]) ? 0 : -1; case 8: - return player->scan(c, d, e); + return player->scan(a[2], a[3], a[4]); case 9: - return player->setLoop(c, d, e, f, g) ? 0 : -1; + return player->setLoop(a[2], a[3], a[4], a[5], a[6]) ? 0 : -1; case 10: player->clearLoop(); return 0; case 11: - ((Part *)player)->set_onoff(d != 0); + ((Part *)player)->set_onoff(a[3] != 0); return 0; case 12: - return player->setHook(c, d, e); + return player->setHook(a[2], a[3], a[4]); case 13: - return player->addParameterFader(ParameterFader::pfVolume, c, d); + return player->addParameterFader (ParameterFader::pfVolume, a[2], a[3]); case 14: - return enqueue_trigger(b, c); + return enqueue_trigger(a[1], a[2]); case 15: - return enqueue_command(b, c, d, e, f, g, h); + return enqueue_command(a[1], a[2], a[3], a[4], a[5], a[6], a[7]); case 16: return clear_queue(); case 19: - return player->getParam(c, d); + return player->getParam(a[2], a[3]); case 20: - return player->setHook(c, d, e); + return player->setHook(a[2], a[3], a[4]); case 21: return -1; case 22: - ((Part *)player)->setVolume(d); + ((Part *)player)->setVolume(a[3]); return 0; case 23: - return query_queue(b); + return query_queue(a[1]); case 24: return 0; default: - warning("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a, param, cmd, b, c, d, e, f, g, h); + warning("doCommand(%d [%d/%d], %d, %d, %d, %d, %d, %d, %d) unsupported", a[0], param, cmd, a[1], a[2], a[3], a[4], a[5], a[6], a[7]); return -1; } } @@ -836,7 +861,7 @@ int32 IMuseInternal::doCommand(int a, int b, int c, int d, int e, int f, int g, return -1; } -int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d) { +int32 IMuseInternal::ImSetTrigger (int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h) { // Sam & Max: ImSetTrigger. // Sets a trigger for a particular player and // marker ID, along with doCommand parameters @@ -880,6 +905,10 @@ int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d) trig->command [1] = b; trig->command [2] = c; trig->command [3] = d; + trig->command [4] = e; + trig->command [5] = f; + trig->command [6] = g; + trig->command [7] = h; // If the command is to start a sound, stop that sound if it's already playing. // This fixes some carnival music problems. @@ -894,11 +923,12 @@ int32 IMuseInternal::ImSetTrigger(int sound, int id, int a, int b, int c, int d) int32 IMuseInternal::ImClearTrigger(int sound, int id) { int count = 0; int i; - for (i = 0; i < 16; ++i) { - if (_snm_triggers [i].sound == sound && _snm_triggers [i].id && - (id == -1 || _snm_triggers [i].id == id)) + ImTrigger *trig = _snm_triggers; + for (i = ARRAYSIZE(_snm_triggers); i; --i, ++trig) { + if ((sound == -1 || trig->sound == sound) && + trig->id && (id == -1 || trig->id == id)) { - _snm_triggers [i].sound = _snm_triggers [i].id = 0; + trig->sound = trig->id = 0; ++count; } } @@ -913,11 +943,7 @@ int32 IMuseInternal::ImFireAllTriggers(int sound) { if (_snm_triggers [i].sound == sound) { _snm_triggers [i].sound = _snm_triggers [i].id = 0; - doCommand(_snm_triggers [i].command [0], - _snm_triggers [i].command [1], - _snm_triggers [i].command [2], - _snm_triggers [i].command [3], - 0, 0, 0, 0); + doCommand (8, _snm_triggers[i].command); ++count; } } @@ -1735,7 +1761,8 @@ int IMuse::stopSound(int sound) { in(); int ret = _target->stopSound(sound); out int IMuse::stop_all_sounds() { in(); int ret = _target->stop_all_sounds(); out(); return ret; } int IMuse::getSoundStatus(int sound) { in(); int ret = _target->getSoundStatus(sound, true); out(); return ret; } bool IMuse::get_sound_active(int sound) { in(); bool ret = _target->getSoundStatus(sound, false) ? 1 : 0; out(); return ret; } -int32 IMuse::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) { in(); int32 ret = _target->doCommand(a,b,c,d,e,f,g,h); out(); return ret; } +int32 IMuse::doCommand (int a, int b, int c, int d, int e, int f, int g, int h) { in(); int32 ret = _target->doCommand(a,b,c,d,e,f,g,h); out(); return ret; } +int32 IMuse::doCommand (int numargs, int args[]) { in(); int32 ret = _target->doCommand (numargs, args); out(); return ret; } int IMuse::clear_queue() { in(); int ret = _target->clear_queue(); out(); return ret; } void IMuse::setBase(byte **base) { in(); _target->setBase(base); out(); } uint32 IMuse::property(int prop, uint32 value) { in(); uint32 ret = _target->property(prop, value); out(); return ret; } diff --git a/scumm/imuse.h b/scumm/imuse.h index 2b129e27f3..10280ee25b 100644 --- a/scumm/imuse.h +++ b/scumm/imuse.h @@ -67,7 +67,8 @@ public: int stop_all_sounds(); int getSoundStatus(int sound); bool get_sound_active(int sound); - int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h); + int32 doCommand (int a, int b, int c, int d, int e, int f, int g, int h); + int32 doCommand (int numargs, int args[]); int clear_queue(); void setBase(byte **base); uint32 property(int prop, uint32 value); diff --git a/scumm/imuse_internal.h b/scumm/imuse_internal.h index 330dd2ea6a..16a9dc11e7 100644 --- a/scumm/imuse_internal.h +++ b/scumm/imuse_internal.h @@ -139,7 +139,7 @@ struct ImTrigger { int sound; byte id; uint16 expire; - byte command [4]; + int command [8]; ImTrigger() { memset(this, 0, sizeof(ImTrigger)); } }; @@ -410,7 +410,7 @@ private: Player *allocate_player(byte priority); Part *allocate_part(byte pri, MidiDriver *midi); - int32 ImSetTrigger(int sound, int id, int a, int b, int c, int d); + int32 ImSetTrigger(int sound, int id, int a, int b, int c, int d, int e, int f, int g, int h); int32 ImClearTrigger(int sound, int id); int32 ImFireAllTriggers(int sound); @@ -461,7 +461,8 @@ public: int stopSound(int sound); int stop_all_sounds(); int getSoundStatus(int sound, bool ignoreFadeouts = true); - int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h); + int32 doCommand (int a, int b, int c, int d, int e, int f, int g, int h); + int32 doCommand (int numargs, int args[]); int clear_queue(); void setBase(byte **base); diff --git a/scumm/imuse_player.cpp b/scumm/imuse_player.cpp index 0e4ee34fdf..50cee4bae5 100644 --- a/scumm/imuse_player.cpp +++ b/scumm/imuse_player.cpp @@ -94,16 +94,7 @@ bool Player::startSound(int sound, MidiDriver *midi) { warning("Player::startSound(): Couldn't find start of sound %d!", sound); return false; } -/* - mdhd = _se->findTag(sound, MDHD_TAG, 0); - if (mdhd == NULL) { - mdhd = _se->findTag(sound, MDPG_TAG, 0); - if (mdhd == NULL) { - warning("P::startSound failed: Couldn't find %s", MDHD_TAG); - return false; - } - } -*/ + _isMT32 = _se->isMT32(sound); _isGM = _se->isGM(sound); @@ -128,6 +119,10 @@ bool Player::startSound(int sound, MidiDriver *midi) { _midi = NULL; return false; } + +#ifdef IMUSE_DEBUG + debug (0, "Starting music %d", sound); +#endif return true; } @@ -144,12 +139,20 @@ bool Player::isFadingOut() { } void Player::clear() { + if (!_active) + return; + +#ifdef IMUSE_DEBUG + debug (0, "Stopping music %d", _id); +#endif + if (_parser) _parser->unloadMusic(); uninit_parts(); _se->ImFireAllTriggers(_id); _active = false; _midi = NULL; + _id = 0; } void Player::hook_clear() { @@ -389,11 +392,7 @@ void Player::sysEx(byte *p, uint16 len) { _se->_snm_triggers [a].id == *p) { _se->_snm_triggers [a].sound = _se->_snm_triggers [a].id = 0; - _se->doCommand(_se->_snm_triggers [a].command [0], - _se->_snm_triggers [a].command [1], - _se->_snm_triggers [a].command [2], - _se->_snm_triggers [a].command [3], - 0, 0, 0, 0); + _se->doCommand (8, _se->_snm_triggers[a].command); break; } } @@ -979,7 +978,7 @@ void Player::onTimer() { // "time" is referenced as hundredths of a second. // IS THAT CORRECT?? -// We convert it to microseconds before prceeding +// We convert it to microseconds before proceeding int Player::addParameterFader(int param, int target, int time) { int start; @@ -1002,25 +1001,29 @@ int Player::addParameterFader(int param, int target, int time) { case ParameterFader::pfTranspose: // FIXME: Is this transpose? And what's the scale? // It's set to fade to -2400 in the tunnel of love. - warning("parameterTransition(3) outside Tunnel of Love?"); +// warning("parameterTransition(3) outside Tunnel of Love?"); start = _transpose; - target /= 200; +// target /= 200; break; - case ParameterFader::pfSpeed: + case ParameterFader::pfSpeed: // impSpeed // FIXME: Is the speed from 0-100? // Right now I convert it to 0-128. start = _speed; - target = target * 128 / 100; +// target = target * 128 / 100; break; case 127: - // FIXME: This MIGHT fade ALL supported parameters, - // but I'm not sure. - return 0; + { // FIXME? I *think* this clears all parameter faders. + ParameterFader *ptr = &_parameterFaders[0]; + int i; + for (i = ARRAYSIZE(_parameterFaders); i; --i, ++ptr) + ptr->param = 0; + return 0; + } default: - warning("Player::addParameterFader(): Unknown parameter %d", param); + warning("Player::addParameterFader (%d, %d, %d): Unknown parameter", param, target, time); return 0; // Should be -1, but we'll let the script think it worked. } @@ -1079,15 +1082,19 @@ void Player::transitionParameters() { setVolume((byte) value); break; - case ParameterFader::pfSpeed: + case ParameterFader::pfTranspose: + // FIXME: Is this really transpose? + setTranspose (0, value / 100); + setDetune (value % 100); + break; + + case ParameterFader::pfSpeed: // impSpeed: // Speed. setSpeed((byte) value); break; - case ParameterFader::pfTranspose: - // FIXME: Is this really transpose? - setTranspose(0, value); - break; + default: + ptr->param = 0; } if (ptr->current_time >= ptr->total_time) diff --git a/scumm/script_v6.cpp b/scumm/script_v6.cpp index b87ca12aa0..0c50b13ec3 100644 --- a/scumm/script_v6.cpp +++ b/scumm/script_v6.cpp @@ -2630,7 +2630,7 @@ void Scumm_v6::o6_kernelSetFunctions() { break; case 122: VAR(VAR_SOUNDRESULT) = - (short)_imuse->doCommand(args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + (short)_imuse->doCommand (num - 1, &args[1]); break; case 123: copyPalColor(args[2], args[1]); diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 2fc5816144..9a7f3e4b49 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -126,7 +126,7 @@ void Sound::addSoundToQueue2(int sound) { void Sound::processSoundQues() { int i = 0, d, num; - int16 data[16]; + int data[16]; processSfxQueues(); @@ -160,11 +160,8 @@ void Sound::processSoundQues() { if (_scumm->_imuseDigital) _scumm->_imuseDigital->doCommand(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); - } else { - if (_scumm->_imuse) - _scumm->VAR(_scumm->VAR_SOUNDRESULT) = - (short)_scumm->_imuse->doCommand(data[0], data[1], data[2], data[3], data[4], - data[5], data[6], data[7]); + } else if (_scumm->_imuse) { + _scumm->VAR(_scumm->VAR_SOUNDRESULT) = (short)_scumm->_imuse->doCommand (num, data); } } } -- cgit v1.2.3