/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "scumm/imuse_digi/dimuse_engine.h" namespace Scumm { #define DIG_STATE_OFFSET 11 #define DIG_SEQ_OFFSET (DIG_STATE_OFFSET + 65) #define COMI_STATE_OFFSET 3 int IMuseDigital::scriptParse(int cmd, int a, int b) { if (_scriptInitializedFlag || !cmd) { switch (cmd) { case DIMUSE_C_SCRIPT_INIT: if (_scriptInitializedFlag) { debug(5, "IMuseDigital::scriptParse(): script module already initialized"); return -1; } else { _scriptInitializedFlag = 1; return scriptInit(); } case DIMUSE_C_SCRIPT_TERMINATE: _scriptInitializedFlag = 0; return scriptTerminate(); case DIMUSE_C_SCRIPT_SAVE: case DIMUSE_C_SCRIPT_RESTORE: break; case DIMUSE_C_SCRIPT_REFRESH: scriptRefresh(); return 0; case DIMUSE_C_SCRIPT_SET_STATE: scriptSetState(a); return 0; case DIMUSE_C_SCRIPT_SET_SEQUENCE: scriptSetSequence(a); return 0; case DIMUSE_C_SCRIPT_CUE_POINT: scriptSetCuePoint(a); return 0; case DIMUSE_C_SCRIPT_SET_ATTRIBUTE: return scriptSetAttribute(a, b); default: debug(5, "IMuseDigital::scriptParse(): unrecognized opcode (%d)", cmd); return -1; } } else { debug(5, "IMuseDigital::scriptParse(): script module not initialized"); return -1; } return -1; } int IMuseDigital::scriptInit() { _curMusicState = 0; _curMusicSeq = 0; _nextSeqToPlay = 0; _curMusicCue = 0; memset(_attributes, 0, sizeof(_attributes)); return 0; } int IMuseDigital::scriptTerminate() { diMUSETerminate(); _curMusicState = 0; _curMusicSeq = 0; _nextSeqToPlay = 0; _curMusicCue = 0; memset(_attributes, 0, sizeof(_attributes)); return 0; } void IMuseDigital::scriptRefresh() { int soundId; int nextSound; if (_stopSequenceFlag) { scriptSetSequence(0); _stopSequenceFlag = 0; } soundId = 0; while (1) { nextSound = diMUSEGetNextSound(soundId); soundId = nextSound; if (!nextSound) break; if (diMUSEGetParam(nextSound, DIMUSE_P_SND_HAS_STREAM) && diMUSEGetParam(soundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC) { if (soundId) return; break; } } if (_curMusicSeq) scriptSetSequence(0); flushTracks(); } void IMuseDigital::scriptSetState(int soundId) { if (_vm->_game.id == GID_DIG && !_isEarlyDiMUSE) { setDigMusicState(soundId); } else if (_vm->_game.id == GID_CMI) { setComiMusicState(soundId); } else { setFtMusicState(soundId); } } void IMuseDigital::scriptSetSequence(int soundId) { if (_vm->_game.id == GID_DIG && !_isEarlyDiMUSE) { setDigMusicSequence(soundId); } else if (_vm->_game.id == GID_CMI) { setComiMusicSequence(soundId); } else { setFtMusicSequence(soundId); } } void IMuseDigital::scriptSetCuePoint(int cueId) { if (!_isEarlyDiMUSE) return; if (cueId > 3) return; debug(5, "IMuseDigital::scriptSetCuePoint(): Cue point sequence: %d", cueId); if (_curMusicSeq && _curMusicCue != cueId) { if (cueId == 0) playFtMusic(nullptr, 0, 0); else { int seq = ((_curMusicSeq - 1) * 4) + cueId; playFtMusic(_ftSeqMusicTable[seq].audioName, _ftSeqMusicTable[seq].transitionType, _ftSeqMusicTable[seq].volume); } } _curMusicCue = cueId; } int IMuseDigital::scriptSetAttribute(int attrIndex, int attrVal) { // FT appears to set a single attribute to 1 at start-up and // never use it again, so we currently ignore that behavior if (_vm->_game.id == GID_DIG) { _attributes[attrIndex] = attrVal; } return 0; } int IMuseDigital::scriptTriggerCallback(char *marker) { if (marker[0] != '_') { debug(5, "IMuseDigital::scriptTriggerCallback(): got marker != '_end', callback ignored"); return -1; } _stopSequenceFlag = 1; return 0; } void Scumm::IMuseDigital::setFtMusicState(int stateId) { if (stateId > 48) return; debug(5, "IMuseDigital::setFtMusicState(): State music: %s, %s", _ftStateMusicTable[stateId].name, _ftStateMusicTable[stateId].audioName); if (_curMusicState == stateId) return; if (_curMusicSeq == 0) { if (stateId == 0) { playFtMusic(nullptr, 0, 0); } else { playFtMusic(_ftStateMusicTable[stateId].audioName, _ftStateMusicTable[stateId].transitionType, _ftStateMusicTable[stateId].volume); } } _curMusicState = stateId; } void IMuseDigital::setFtMusicSequence(int seqId) { if (seqId > 52) return; debug(5, "IMuseDigital::setFtMusicSequence(): Sequence music: %s", _ftSeqNames[seqId].name); if (_curMusicSeq != seqId) { if (seqId == 0) { if (_curMusicState == 0) { playFtMusic(nullptr, 0, 0); } else { playFtMusic(_ftStateMusicTable[_curMusicState].audioName, _ftStateMusicTable[_curMusicState].transitionType, _ftStateMusicTable[_curMusicState].volume); } } else { int seq = (seqId - 1) * 4; playFtMusic(_ftSeqMusicTable[seq].audioName, _ftSeqMusicTable[seq].transitionType, _ftSeqMusicTable[seq].volume); } } _curMusicSeq = seqId; _curMusicCue = 0; } void IMuseDigital::setDigMusicState(int stateId) { int l, num = -1; for (l = 0; _digStateMusicTable[l].soundId != -1; l++) { if ((_digStateMusicTable[l].soundId == stateId)) { debug(5, "IMuseDigital::setDigMusicState(): Set music state: %s, %s", _digStateMusicTable[l].name, _digStateMusicTable[l].filename); num = l; break; } } if (num == -1) { for (l = 0; _digStateMusicMap[l].roomId != -1; l++) { if ((_digStateMusicMap[l].roomId == stateId)) { break; } } num = l; int offset = _attributes[_digStateMusicMap[num].offset]; if (offset == 0) { if (_attributes[_digStateMusicMap[num].attribPos] != 0) { num = _digStateMusicMap[num].stateIndex3; } else { num = _digStateMusicMap[num].stateIndex1; } } else { int stateIndex2 = _digStateMusicMap[num].stateIndex2; if (stateIndex2 == 0) { num = _digStateMusicMap[num].stateIndex1 + offset; } else { num = stateIndex2; } } } debug(5, "IMuseDigital::setDigMusicState(): Set music state: %s, %s", _digStateMusicTable[num].name, _digStateMusicTable[num].filename); if (_curMusicState == num) return; if (_curMusicSeq == 0) { if (num == 0) playDigMusic(nullptr, &_digStateMusicTable[0], num, false); else playDigMusic(_digStateMusicTable[num].name, &_digStateMusicTable[num], num, false); } _curMusicState = num; } void IMuseDigital::setDigMusicSequence(int seqId) { int l, num = -1; if (seqId == 0) seqId = 2000; for (l = 0; _digSeqMusicTable[l].soundId != -1; l++) { if ((_digSeqMusicTable[l].soundId == seqId)) { debug(5, "IMuseDigital::setDigMusicSequence(): Set music sequence: %s, %s", _digSeqMusicTable[l].name, _digSeqMusicTable[l].filename); num = l; break; } } if (num == -1) return; if (_curMusicSeq == num) return; if (num != 0) { if (_curMusicSeq && ((_digSeqMusicTable[_curMusicSeq].transitionType == 4) || (_digSeqMusicTable[_curMusicSeq].transitionType == 6))) { _nextSeqToPlay = num; return; } else { playDigMusic(_digSeqMusicTable[num].name, &_digSeqMusicTable[num], 0, true); _nextSeqToPlay = 0; _attributes[DIG_SEQ_OFFSET + num] = 1; } } else { if (_nextSeqToPlay != 0) { playDigMusic(_digSeqMusicTable[_nextSeqToPlay].name, &_digSeqMusicTable[_nextSeqToPlay], 0, true); _attributes[DIG_SEQ_OFFSET + _nextSeqToPlay] = 1; num = _nextSeqToPlay; _nextSeqToPlay = 0; } else { if (_curMusicState != 0) { playDigMusic(_digStateMusicTable[_curMusicState].name, &_digStateMusicTable[_curMusicState], _curMusicState, true); } else { playDigMusic(nullptr, &_digStateMusicTable[0], _curMusicState, true); } num = 0; } } _curMusicSeq = num; } void IMuseDigital::setComiMusicState(int stateId) { int l, num = -1; if (stateId == 0) stateId = 1000; if ((_vm->_game.features & GF_DEMO) && stateId == 1000) stateId = 0; if (!(_vm->_game.features & GF_DEMO)) { for (l = 0; _comiStateMusicTable[l].soundId != -1; l++) { if ((_comiStateMusicTable[l].soundId == stateId)) { debug(5, "IMuseDigital::setComiMusicState(): Set music state: %s, %s", _comiStateMusicTable[l].name, _comiStateMusicTable[l].filename); num = l; break; } } } if (num == -1 && !(_vm->_game.features & GF_DEMO)) return; if (!(_vm->_game.features & GF_DEMO) && _curMusicState == num) { return; } else if ((_vm->_game.features & GF_DEMO) && _curMusicState == stateId) { return; } if (_curMusicSeq == 0) { if (_vm->_game.features & GF_DEMO) { if (_curMusicSeq == 0) { if (stateId == 0) playComiDemoMusic(nullptr, &_comiDemoStateMusicTable[0], stateId, false); else playComiDemoMusic(_comiDemoStateMusicTable[stateId].name, &_comiDemoStateMusicTable[stateId], stateId, false); } } else { if (num == 0) playComiMusic(nullptr, &_comiStateMusicTable[0], num, false); else playComiMusic(_comiStateMusicTable[num].name, &_comiStateMusicTable[num], num, false); } } if (!(_vm->_game.features & GF_DEMO)) { _curMusicState = num; } else { _curMusicState = stateId; } } void IMuseDigital::setComiMusicSequence(int seqId) { int l, num = -1; if (seqId == 0) seqId = 2000; for (l = 0; _comiSeqMusicTable[l].soundId != -1; l++) { if ((_comiSeqMusicTable[l].soundId == seqId)) { debug(5, "IMuseDigital::setComiMusicSequence(): Set music sequence: %s, %s", _comiSeqMusicTable[l].name, _comiSeqMusicTable[l].filename); num = l; break; } } if (num == -1) return; if (_curMusicSeq == num) return; if (num != 0) { if (_curMusicSeq && ((_comiSeqMusicTable[_curMusicSeq].transitionType == 4) || (_comiSeqMusicTable[_curMusicSeq].transitionType == 6))) { _nextSeqToPlay = num; return; } else { playComiMusic(_comiSeqMusicTable[num].name, &_comiSeqMusicTable[num], 0, true); _nextSeqToPlay = 0; } } else { if (_nextSeqToPlay != 0) { playComiMusic(_comiSeqMusicTable[_nextSeqToPlay].name, &_comiSeqMusicTable[_nextSeqToPlay], 0, true); num = _nextSeqToPlay; _nextSeqToPlay = 0; } else { if (_curMusicState != 0) { playComiMusic(_comiStateMusicTable[_curMusicState].name, &_comiStateMusicTable[_curMusicState], _curMusicState, true); } else { playComiMusic(nullptr, &_comiStateMusicTable[0], _curMusicState, true); } num = 0; } } _curMusicSeq = num; } void IMuseDigital::playFtMusic(const char *songName, int transitionType, int volume) { int oldSoundId = 0; int soundId; if (!_spooledMusicEnabled) return; // Check for any music piece which is played as a SFX (without an associated stream) // and fade it out for (int i = diMUSEGetNextSound(0); i; i = diMUSEGetNextSound(i)) { if (diMUSEGetParam(i, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(i, DIMUSE_P_SND_HAS_STREAM)) diMUSEFadeParam(i, DIMUSE_P_VOLUME, 0, 200); } // Now grab the current standard music soundId: it will either be crossfaded by SwitchStream, // or faded out for (int j = diMUSEGetNextSound(0); j; j = diMUSEGetNextSound(j)) { if (diMUSEGetParam(j, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && diMUSEGetParam(j, DIMUSE_P_SND_HAS_STREAM)) oldSoundId = j; } if (songName) { switch (transitionType) { case 0: debug(5, "IMuseDigital::playFtMusic(): NULL transition, ignored"); return; case 1: soundId = getSoundIdByName(songName); if (_filesHandler->openSound(soundId)) return; if (!soundId) { debug(5, "IMuseDigital::playFtMusic(): failed to retrieve soundId for sound \"%s\"", songName); break; } if (diMUSEStartSound(soundId, 126)) debug(5, "IMuseDigital::playFtMusic(): transition 1, failed to start sound \"%s\"(%d)", songName, soundId); _filesHandler->closeSound(soundId); diMUSESetParam(soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetParam(soundId, DIMUSE_P_VOLUME, volume); break; case 2: case 3: soundId = getSoundIdByName(songName); if (soundId) if (_filesHandler->openSound(soundId)) return; if (soundId) { if (oldSoundId) { if (oldSoundId != soundId || transitionType == 2) { diMUSESwitchStream(oldSoundId, soundId, _ftCrossfadeBuffer, sizeof(_ftCrossfadeBuffer), 0); } // WORKAROUND for bug in the original: at the beginning of the game, going in // and out of the bar a couple of times breaks and temporarily stops the music // Here, we override the fade out, just like the remastered does if (oldSoundId == soundId && soundId == 622 && _vm->enhancementEnabled(kEnhAudioChanges)) { diMUSEFadeParam(soundId, DIMUSE_P_VOLUME, volume, 200); } } else if (diMUSEStartStream(soundId, 126, DIMUSE_BUFFER_MUSIC)) { debug(5, "IMuseDigital::playFtMusic(): failed to start the stream for \"%s\" (%d)", songName, soundId); } _filesHandler->closeSound(soundId); diMUSESetParam(soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetParam(soundId, DIMUSE_P_VOLUME, volume); } else { debug(5, "IMuseDigital::playFtMusic(): failed to retrieve soundId for sound \"%s\" (%d)", songName, soundId); } break; case 4: if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 200); return; default: debug(5, "IMuseDigital::playFtMusic(): bogus transition type, ignored"); return; } } else { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 200); } } void IMuseDigital::playDigMusic(const char *songName, const imuseDigTable *table, int attribPos, bool sequence) { int hookId = 0; if (songName != nullptr) { if ((_attributes[DIG_SEQ_OFFSET + 38]) && (!_attributes[DIG_SEQ_OFFSET + 41])) { if ((attribPos == 43) || (attribPos == 44)) hookId = 3; } if ((_attributes[DIG_SEQ_OFFSET + 46] != 0) && (_attributes[DIG_SEQ_OFFSET + 48] == 0)) { if ((attribPos == 38) || (attribPos == 39)) hookId = 3; } if ((_attributes[DIG_SEQ_OFFSET + 53] != 0)) { if ((attribPos == 50) || (attribPos == 51)) hookId = 3; } if ((attribPos != 0) && (hookId == 0)) { if (table->attribPos != 0) attribPos = table->attribPos; hookId = _attributes[DIG_STATE_OFFSET + attribPos]; if (table->hookId != 0) { if ((hookId != 0) && (table->hookId > 1)) { _attributes[DIG_STATE_OFFSET + attribPos] = 2; } else { _attributes[DIG_STATE_OFFSET + attribPos] = hookId + 1; if (table->hookId < hookId + 1) _attributes[DIG_STATE_OFFSET + attribPos] = 1; } } } } int nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; // If a sound is found (and its stream is active), fade it out if it's a music track if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM)) diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120); } int oldSoundId = 0; nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) { oldSoundId = nextSoundId; break; } } if (!songName) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120); return; } switch (table->transitionType) { case 0: debug(5, "IMuseDigital::playDigMusic(): NULL transition, ignored"); break; case 1: if (_filesHandler->openSound(table->soundId)) return; if (table->soundId) { if (diMUSEStartSound(table->soundId, 126)) debug(5, "IMuseDigital::playDigMusic(): transition 1, failed to start the sound (%d)", table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 1); diMUSEFadeParam(table->soundId, DIMUSE_P_VOLUME, 127, 120); _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); } else { debug(5, "IMuseDigital::playDigMusic(): transition 1, empty soundId, ignored"); } break; case 2: case 3: case 4: if (_filesHandler->openSound(table->soundId)) return; if (table->filename[0] == 0 || table->soundId == 0) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60); return; } if (table->transitionType == 4) { _stopSequenceFlag = 0; diMUSESetTrigger(table->soundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK); } if (oldSoundId) { if (table->transitionType == 2) { diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); diMUSEProcessStreams(); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally return; } if (oldSoundId != table->soundId) { if ((!sequence) && (table->attribPos != 0) && (table->attribPos == _digStateMusicTable[_curMusicState].attribPos)) { diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 1); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSEProcessStreams(); } else { diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); diMUSEProcessStreams(); _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally } } } else { if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC)) debug(5, "IMuseDigital::playDigMusic(): failed to start the stream for sound %d", table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); } _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally break; case 5: debug(5, "IMuseDigital::playDigMusic(): no-op transition type (5), ignored"); break; case 6: _stopSequenceFlag = 0; diMUSESetTrigger(DIMUSE_SMUSH_SOUNDID + DIMUSE_BUFFER_MUSIC, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK); break; case 7: if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60); break; default: debug(5, "IMuseDigital::playDigMusic(): bogus transition type, ignored"); break; } } void IMuseDigital::playComiDemoMusic(const char *songName, const imuseComiTable *table, int attribPos, bool sequence) { // This is a stripped down version of playDigMusic int hookId = 0; if (songName != nullptr) { if (attribPos != 0) { if (table->attribPos != 0) attribPos = table->attribPos; } } int nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; // If a sound is found (and its stream is active), fade it out if it's a music track if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM)) diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120); } int oldSoundId = 0; nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) { oldSoundId = nextSoundId; break; } } if (!songName) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120); return; } switch (table->transitionType) { case 3: if (_filesHandler->openSound(table->soundId)) return; if (table->filename[0] == 0 || table->soundId == 0) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60); return; } if (oldSoundId) { if (oldSoundId != table->soundId) { if ((!sequence) && (table->attribPos != 0) && (table->attribPos == _comiDemoStateMusicTable[_curMusicState].attribPos)) { diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 1); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSEProcessStreams(); } else { diMUSESwitchStream(oldSoundId, table->soundId, 1800, 0, 0); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); diMUSEProcessStreams(); _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally } } } else { if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC)) debug(5, "IMuseDigital::playComiDemoMusic(): failed to start the stream for sound %d", table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); } _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); // Repeated intentionally break; default: debug(5, "IMuseDigital::playComiDemoMusic(): bogus or unused transition type, ignored"); break; } } void IMuseDigital::playComiMusic(const char *songName, const imuseComiTable *table, int attribPos, bool sequence) { int hookId = 0; int fadeDelay = 0; // This flag is not set in the original, // but since we're not using DirectSound and this is pretty much timing related // please see IMuseDigital::waveOutWrite() for more context... Common::StackLock lock(*_mutex); _waveOutXorTrigger = 1; if ((songName != nullptr) && (attribPos != 0)) { if (table->attribPos != 0) attribPos = table->attribPos; hookId = _attributes[COMI_STATE_OFFSET + attribPos]; if (table->hookId != 0) { if ((hookId != 0) && (table->hookId > 1)) { _attributes[COMI_STATE_OFFSET + attribPos] = 2; } else { _attributes[COMI_STATE_OFFSET + attribPos] = hookId + 1; if (table->hookId < hookId + 1) _attributes[COMI_STATE_OFFSET + attribPos] = 1; } } } int nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; // If a sound is found (and its stream is active), fade it out if it's a music track if (diMUSEGetParam(nextSoundId, DIMUSE_P_GROUP) == DIMUSE_GROUP_MUSICEFF && !diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM)) diMUSEFadeParam(nextSoundId, DIMUSE_P_VOLUME, 0, 120); } int oldSoundId = 0; nextSoundId = 0; while (1) { nextSoundId = diMUSEGetNextSound(nextSoundId); if (!nextSoundId) break; if (diMUSEGetParam(nextSoundId, DIMUSE_P_SND_HAS_STREAM) && (diMUSEGetParam(nextSoundId, DIMUSE_P_STREAM_BUFID) == DIMUSE_BUFFER_MUSIC)) { oldSoundId = nextSoundId; break; } } if (!songName) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 120); return; } switch (table->transitionType) { case 0: debug(5, "IMuseDigital::playComiMusic(): NULL transition, ignored"); break; case 1: if (_filesHandler->openSound(table->soundId)) return; if (table->soundId) { if (diMUSEStartSound(table->soundId, 126)) debug(5, "IMuseDigital::playComiMusic(): transition 1, failed to start the sound (%d)", table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 1); diMUSEFadeParam(table->soundId, DIMUSE_P_VOLUME, 127, 120); _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); } else { debug(5, "IMuseDigital::playComiMusic(): transition 1, empty soundId, ignored"); } break; case 2: case 3: case 4: case 12: if (_filesHandler->openSound(table->soundId)) return; if (table->filename[0] == 0 || table->soundId == 0) { if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60); break; } if (table->transitionType == 4) { _stopSequenceFlag = 0; diMUSESetTrigger(table->soundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK); } if (oldSoundId) { fadeDelay = table->fadeOutDelay; if (!fadeDelay) fadeDelay = 1000; else fadeDelay = (fadeDelay * 100) / 6; // Set dimuse_table fade out time to millisecond scale if (table->transitionType == 2) { diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 0); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, table->hookId); diMUSEProcessStreams(); } else if (oldSoundId != table->soundId) { if ((!sequence) && (table->attribPos != 0) && (table->attribPos == _comiStateMusicTable[_curMusicState].attribPos)) { debug(5, "IMuseDigital::playComiMusic(): Starting new sound (%s) with same attribute as old sound (%s)", table->name, _comiStateMusicTable[_curMusicState].name); diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 1); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSEProcessStreams(); } else { switch (table->transitionType) { case 12: diMUSESetHook(oldSoundId, table->hookId); diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SWITCH_STREAM, oldSoundId, table->soundId, fadeDelay, 1, 0); diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_PARAM, table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_PARAM, table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetTrigger(oldSoundId, MKTAG('e', 'x', 'i', 't'), DIMUSE_C_SET_HOOK, table->soundId, hookId); diMUSEProcessStreams(); break; default: diMUSESwitchStream(oldSoundId, table->soundId, fadeDelay, 0, 0); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); diMUSEProcessStreams(); break; } } } } else { if (diMUSEStartStream(table->soundId, 126, DIMUSE_BUFFER_MUSIC)) debug(5, "IMuseDigital::playComiMusic(): failed to start the stream for sound %d", table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_VOLUME, 127); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); diMUSESetHook(table->soundId, hookId); } _filesHandler->closeSound(table->soundId); diMUSESetParam(table->soundId, DIMUSE_P_GROUP, DIMUSE_GROUP_MUSICEFF); break; case 5: debug(5, "IMuseDigital::playComiMusic(): no-op transition type (5), ignored"); break; case 6: _stopSequenceFlag = 0; diMUSESetTrigger(DIMUSE_SMUSH_SOUNDID + DIMUSE_BUFFER_MUSIC, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK); break; case 7: if (oldSoundId) diMUSEFadeParam(oldSoundId, DIMUSE_P_VOLUME, 0, 60); break; case 8: if (oldSoundId) diMUSESetHook(oldSoundId, table->hookId); break; case 9: if (oldSoundId) diMUSESetHook(oldSoundId, table->hookId); _stopSequenceFlag = 0; diMUSESetTrigger(oldSoundId, MKTAG('_', 'e', 'n', 'd'), DIMUSE_C_SCRIPT_CALLBACK); break; default: debug(5, "IMuseDigital::playComiMusic(): bogus transition type, ignored"); break; } } } // End of namespace Scumm