diff options
Diffstat (limited to 'engines/sci/sound/soundcmd.cpp')
-rw-r--r-- | engines/sci/sound/soundcmd.cpp | 166 |
1 files changed, 126 insertions, 40 deletions
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 73e0a23a6a..b9a764c93a 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -21,6 +21,9 @@ */ #include "common/config-manager.h" +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "sci/resource.h" #include "sci/sound/audio.h" #include "sci/sound/music.h" #include "sci/sound/soundcmd.h" @@ -44,7 +47,7 @@ SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segM // resource number, but it's totally unrelated to the menu music). // The GK1 demo (very late SCI1.1) does the same thing // TODO: Check the QFG4 demo - _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1 || ConfMan.getBool("prefer_digitalsfx")); + _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1DEMO || ConfMan.getBool("prefer_digitalsfx")); _music = new SciMusic(_soundVersion, _useDigitalSFX); _music->init(); @@ -95,12 +98,21 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) { // user wants the digital version. if (_useDigitalSFX || !newSound->soundRes) { int sampleLen; - newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); - newSound->soundType = Audio::Mixer::kSFXSoundType; +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY) { + newSound->isSample = g_sci->getResMan()->testResource(ResourceId(kResourceTypeAudio, newSound->resourceId)); + } else { +#endif + newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); + newSound->soundType = Audio::Mixer::kSFXSoundType; + newSound->isSample = newSound->pStreamAud != nullptr; +#ifdef ENABLE_SCI32 + } +#endif } } - if (!newSound->pStreamAud && newSound->soundRes) + if (!newSound->isSample && newSound->soundRes) _music->soundInitSnd(newSound); } @@ -116,6 +128,7 @@ void SoundCommandParser::processInitSound(reg_t obj) { newSound->resourceId = resourceId; newSound->soundObj = obj; newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); + newSound->overridePriority = false; if (_soundVersion <= SCI_VERSION_0_LATE) newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); else @@ -131,7 +144,7 @@ void SoundCommandParser::processInitSound(reg_t obj) { _music->pushBackSlot(newSound); - if (newSound->soundRes || newSound->pStreamAud) { + if (newSound->soundRes || newSound->isSample) { // Notify the engine if (_soundVersion <= SCI_VERSION_0_LATE) writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized); @@ -142,11 +155,14 @@ void SoundCommandParser::processInitSound(reg_t obj) { reg_t SoundCommandParser::kDoSoundPlay(int argc, reg_t *argv, reg_t acc) { debugC(kDebugLevelSound, "kDoSound(play): %04x:%04x", PRINT_REG(argv[0])); - processPlaySound(argv[0]); + bool playBed = false; + if (argc >= 2 && !argv[1].isNull()) + playBed = true; + processPlaySound(argv[0], playBed); return acc; } -void SoundCommandParser::processPlaySound(reg_t obj) { +void SoundCommandParser::processPlaySound(reg_t obj, bool playBed) { MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { warning("kDoSound(play): Slot not found (%04x:%04x), initializing it manually", PRINT_REG(obj)); @@ -181,15 +197,26 @@ void SoundCommandParser::processPlaySound(reg_t obj) { } musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); - musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); + + // Get song priority from either obj or soundRes + byte resourcePriority = 0xFF; + if (musicSlot->soundRes) + resourcePriority = musicSlot->soundRes->getSoundPriority(); + if (!musicSlot->overridePriority && resourcePriority != 0xFF) { + musicSlot->priority = resourcePriority; + } else { + musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); + } + // Reset hold when starting a new song. kDoSoundSetHold is always called after // kDoSoundPlay to set it properly, if needed. Fixes bug #3413589. musicSlot->hold = -1; + musicSlot->playBed = playBed; if (_soundVersion >= SCI_VERSION_1_EARLY) musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol)); - debugC(kDebugLevelSound, "kDoSound(play): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj), - resourceId, musicSlot->loop, musicSlot->priority, musicSlot->volume); + debugC(kDebugLevelSound, "kDoSound(play): %04x:%04x number %d, loop %d, prio %d, vol %d, bed %d", PRINT_REG(obj), + resourceId, musicSlot->loop, musicSlot->priority, musicSlot->volume, playBed ? 1 : 0); _music->soundPlay(musicSlot); @@ -198,17 +225,6 @@ void SoundCommandParser::processPlaySound(reg_t obj) { musicSlot->fadeStep = 0; } -reg_t SoundCommandParser::kDoSoundRestore(int argc, reg_t *argv, reg_t acc) { - // Called after loading, to restore the playlist - // We don't really use or need this - return acc; -} - -reg_t SoundCommandParser::kDoSoundDummy(int argc, reg_t *argv, reg_t acc) { - warning("cmdDummy invoked"); // not supposed to occur - return acc; -} - reg_t SoundCommandParser::kDoSoundDispose(int argc, reg_t *argv, reg_t acc) { debugC(kDebugLevelSound, "kDoSound(dispose): %04x:%04x", PRINT_REG(argv[0])); processDisposeSound(argv[0]); @@ -297,10 +313,22 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) { } reg_t obj = argv[0]; - uint16 value = argc > 1 ? argv[1].toUint16() : 0; - if (!obj.getSegment()) { // pause the whole playlist - _music->pauseAll(value); - } else { // pause a playlist slot + const bool shouldPause = argc > 1 ? argv[1].toUint16() : false; + if ( + (_soundVersion < SCI_VERSION_2_1_EARLY && !obj.getSegment()) || + (_soundVersion >= SCI_VERSION_2_1_EARLY && obj.isNull()) + ) { + _music->pauseAll(shouldPause); +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY) { + if (shouldPause) { + g_sci->_audio32->pause(kAllChannels); + } else { + g_sci->_audio32->resume(kAllChannels); + } + } +#endif + } else { MusicEntry *musicSlot = _music->getSlot(obj); if (!musicSlot) { // This happens quite frequently @@ -308,7 +336,23 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) { return acc; } - _music->soundToggle(musicSlot, value); +#ifdef ENABLE_SCI32 + // NOTE: The original engine also expected a global + // "kernel call" flag to be true in order to perform + // this action, but the architecture of the ScummVM + // implementation is so different that it doesn't + // matter here + if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) { + const int16 channelIndex = g_sci->_audio32->findChannelById(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj); + + if (shouldPause) { + g_sci->_audio32->pause(channelIndex); + } else { + g_sci->_audio32->resume(channelIndex); + } + } else +#endif + _music->soundToggle(musicSlot, shouldPause); } return acc; } @@ -338,7 +382,11 @@ reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc) int vol = CLIP<int16>(argv[0].toSint16(), 0, MUSIC_MASTERVOLUME_MAX); vol = vol * Audio::Mixer::kMaxMixerVolume / MUSIC_MASTERVOLUME_MAX; ConfMan.setInt("music_volume", vol); - ConfMan.setInt("sfx_volume", vol); + // In SCI32, digital audio volume is controlled separately by + // kDoAudioVolume + if (_soundVersion < SCI_VERSION_2_1_EARLY) { + ConfMan.setInt("sfx_volume", vol); + } g_engine->syncSoundSettings(); } return acc; @@ -361,6 +409,13 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) { int volume = musicSlot->volume; +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) { + g_sci->_audio32->fadeChannel(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj, argv[1].toSint16(), argv[2].toSint16(), argv[3].toSint16(), argc > 4 ? (bool)argv[4].toSint16() : false); + return acc; + } +#endif + // If sound is not playing currently, set signal directly if (musicSlot->status != kSoundPlaying) { debugC(kDebugLevelSound, "kDoSound(fade): %04x:%04x fading requested, but sound is currently not playing", PRINT_REG(obj)); @@ -449,7 +504,18 @@ void SoundCommandParser::processUpdateCues(reg_t obj) { return; } - if (musicSlot->pStreamAud) { + if (musicSlot->isSample) { +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY) { + const int position = g_sci->_audio32->getPosition(g_sci->_audio32->findChannelById(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj)); + + if (position == -1) { + processStopSound(musicSlot->soundObj, true); + } + + return; + } +#endif // Update digital sound effect slots uint currentLoopCounter = 0; @@ -538,7 +604,7 @@ void SoundCommandParser::processUpdateCues(reg_t obj) { if (_soundVersion >= SCI_VERSION_1_EARLY) { writeSelectorValue(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600); writeSelectorValue(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60); - writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker); + writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker % 60 / 2); } } @@ -652,6 +718,12 @@ reg_t SoundCommandParser::kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc) { value = CLIP<int>(value, 0, MUSIC_VOLUME_MAX); +#ifdef ENABLE_SCI32 + // SSCI unconditionally sets volume if it is digital audio + if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) { + _music->soundSetVolume(musicSlot, value); + } +#endif if (musicSlot->volume != value) { musicSlot->volume = value; _music->soundSetVolume(musicSlot, value); @@ -673,23 +745,19 @@ reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc) } if (value == -1) { - uint16 resourceId = musicSlot->resourceId; + musicSlot->overridePriority = false; + musicSlot->priority = 0; - // Set priority from the song data - Resource *song = _resMan->findResource(ResourceId(kResourceTypeSound, resourceId), 0); - if (song->data[0] == 0xf0) - _music->soundSetPriority(musicSlot, song->data[1]); - else - warning("kDoSound(setPriority): Attempt to unset song priority when there is no built-in value"); + // NB: It seems SSCI doesn't actually reset the priority here. - //pSnd->prio=0;field_15B=0 writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD); } else { // Scripted priority + musicSlot->overridePriority = true; - //pSnd->field_15B=1; writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2); - //DoSOund(0xF,hobj,w) + + _music->soundSetPriority(musicSlot, value); } return acc; } @@ -714,6 +782,15 @@ reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) { } return acc; } + +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY) { + if (value != -1) { + value = 1; + } + } +#endif + if (value == -1) { musicSlot->loop = 0xFFFF; } else { @@ -721,6 +798,13 @@ reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) { } writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop); + +#ifdef ENABLE_SCI32 + if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) { + g_sci->_audio32->setLoop(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj, value == -1); + } +#endif + return acc; } @@ -777,6 +861,8 @@ void SoundCommandParser::stopAllSounds() { } void SoundCommandParser::startNewSound(int number) { + // NB: This is only used by the debugging console. + Common::StackLock lock(_music->_mutex); // Overwrite the first sound in the playlist @@ -785,7 +871,7 @@ void SoundCommandParser::startNewSound(int number) { processDisposeSound(soundObj); writeSelectorValue(_segMan, soundObj, SELECTOR(number), number); processInitSound(soundObj); - processPlaySound(soundObj); + processPlaySound(soundObj, false); } void SoundCommandParser::setMasterVolume(int vol) { |