From 84d2414a7dceca9d5140936667aae05fbbfdcf99 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Thu, 2 Oct 2014 18:22:41 +0200 Subject: SCI: Avoid resetting already unused channels --- engines/sci/sound/music.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 7a6eaf62b4..5a37357045 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -1063,7 +1063,7 @@ void SciMusic::remapChannels() { // And finally, stop any empty channels for (int i = _driverFirstChannel; i <= _driverLastChannel; ++i) { - if (!_channelMap[i]._song) + if (!_channelMap[i]._song && currentMap[i]._song) resetDeviceChannel(i); } -- cgit v1.2.3 From f1e34f11d742ef32ed48926092d93f3448732f2e Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Thu, 2 Oct 2014 18:23:00 +0200 Subject: SCI: Initialize voice counts in SCI1+ --- engines/sci/sound/midiparser_sci.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'engines') diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index c0b4f3122e..7ee9cc9d28 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -360,6 +360,13 @@ void MidiParser_SCI::sendInitCommands() { sendToDriver(0xB0 | i, 0x4B, voiceCount); } } + } else { + for (int i = 0; i < _track->channelCount; ++i) { + byte voiceCount = _track->channels[i].poly; + byte num = _track->channels[i].number; + // TODO: Should we skip the control channel? + sendToDriver(0xB0 | num, 0x4B, voiceCount); + } } } -- cgit v1.2.3 From 26d55b09a8b198b0a9b9349d684eec6376d98c8c Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Thu, 2 Oct 2014 18:24:14 +0200 Subject: SCI: Match SSCI channel reset order It may or may not matter for a driver's voice mapping. --- engines/sci/sound/music.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 5a37357045..05605c0c45 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -1062,7 +1062,7 @@ void SciMusic::remapChannels() { } // And finally, stop any empty channels - for (int i = _driverFirstChannel; i <= _driverLastChannel; ++i) { + for (int i = _driverLastChannel; i >= _driverFirstChannel; --i) { if (!_channelMap[i]._song && currentMap[i]._song) resetDeviceChannel(i); } -- cgit v1.2.3 From 58ef44eb8d9d3eb78eb013441a8d6d12940ee5e3 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 7 Oct 2014 19:48:18 +0200 Subject: SCI: Register and save playBed option to PlaySound The playBed option is not handled yet, only stored. This increases the savegame format version. --- engines/sci/console.cpp | 8 +++++--- engines/sci/engine/kernel_tables.h | 4 ---- engines/sci/engine/savegame.cpp | 6 +++++- engines/sci/engine/savegame.h | 3 ++- engines/sci/sound/music.cpp | 2 ++ engines/sci/sound/music.h | 1 + engines/sci/sound/soundcmd.cpp | 16 +++++++++++----- engines/sci/sound/soundcmd.h | 2 +- 8 files changed, 27 insertions(+), 15 deletions(-) (limited to 'engines') diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index e233c4cba4..a3abf606d0 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -2172,6 +2172,7 @@ bool Console::cmdStartSound(int argc, const char **argv) { return true; } + // TODO: Maybe also add a playBed option. g_sci->_soundCmd->startNewSound(number); return cmdExit(0, 0); } @@ -2198,9 +2199,10 @@ bool Console::cmdToggleSound(int argc, const char **argv) { Common::String newState = argv[2]; newState.toLowercase(); - if (newState == "play") - g_sci->_soundCmd->processPlaySound(id); - else if (newState == "stop") + if (newState == "play") { + // Maybe also have a 'playbed' option. (Second argument to processPlaySound.) + g_sci->_soundCmd->processPlaySound(id, false); + } else if (newState == "stop") g_sci->_soundCmd->processStopSound(id, false); else debugPrintf("New state can either be 'play' or 'stop'"); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 0c2fd4e3ea..2cbd79366d 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -105,10 +105,6 @@ static const SciKernelMapSubEntry kDoSound_subops[] = { { SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL }, { SIG_SOUNDSCI1EARLY, 6, MAP_CALL(DoSoundDispose), NULL, NULL }, { SIG_SOUNDSCI1EARLY, 7, MAP_CALL(DoSoundPlay), "oi", NULL }, - // ^^ TODO: In SCI1-SCI1.1 DoSound (play) is called by 2 methods of the Sound object: play and - // playBed. The methods are the same, apart from the second integer parameter: it's 0 in - // play and 1 in playBed, to distinguish the caller. It's passed on, we should find out what - // it actually does internally { SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL }, { SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL }, { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds }, diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 0b55425406..692fa77a80 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -617,6 +617,10 @@ void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsSint32LE(fadeTicker); s.syncAsSint32LE(fadeTickerStep); s.syncAsByte(status); + if (s.getVersion() >= 32) + s.syncAsByte(playBed); + else if (s.isLoading()) + playBed = false; // pMidiParser and pStreamAud will be initialized when the // sound list is reconstructed in gamestate_restore() @@ -650,7 +654,7 @@ void SoundCommandParser::reconstructPlayList() { if (_soundVersion >= SCI_VERSION_1_EARLY) writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol), (*i)->volume); - processPlaySound((*i)->soundObj); + processPlaySound((*i)->soundObj, (*i)->playBed); } } } diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index 8f2835654b..be6d05cdc5 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -37,6 +37,7 @@ struct EngineState; * * Version - new/changed feature * ============================= + * 32 - new playBed flag in MusicEntry * 31 - priority for sound effects/music is now a signed int16, instead of a byte * 30 - synonyms * 29 - system strings @@ -56,7 +57,7 @@ struct EngineState; */ enum { - CURRENT_SAVEGAME_VERSION = 31, + CURRENT_SAVEGAME_VERSION = 32, MINIMUM_SAVEGAME_VERSION = 14 }; diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 05605c0c45..4606d66ace 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -334,6 +334,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { pSnd->pLoopStream = 0; pSnd->soundType = Audio::Mixer::kSFXSoundType; pSnd->hCurrentAud = Audio::SoundHandle(); + pSnd->playBed = false; } else { // play MIDI track Common::StackLock lock(_mutex); @@ -380,6 +381,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { int16 prevHold = pSnd->hold; pSnd->loop = 0; pSnd->hold = -1; + pSnd->playBed = false; pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); pSnd->reverb = pSnd->pMidiParser->getSongReverb(); diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 4e44074630..0fbd5a0c0e 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -85,6 +85,7 @@ public: int16 volume; int16 hold; int8 reverb; + bool playBed; int16 pauseCounter; uint sampleLoopCounter; diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 73e0a23a6a..47ab9bdc71 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -142,11 +142,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)); @@ -185,11 +188,12 @@ void SoundCommandParser::processPlaySound(reg_t obj) { // 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); @@ -777,6 +781,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 +791,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) { diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h index 4effda68e4..5bb7cf2cb1 100644 --- a/engines/sci/sound/soundcmd.h +++ b/engines/sci/sound/soundcmd.h @@ -63,7 +63,7 @@ public: void printPlayList(Console *con); void printSongInfo(reg_t obj, Console *con); - void processPlaySound(reg_t obj); + void processPlaySound(reg_t obj, bool playBed); void processStopSound(reg_t obj, bool sampleFinishedPlaying); void initSoundResource(MusicEntry *newSound); -- cgit v1.2.3 From 5964cc239b920a4a5d3b8475cb6c0b111e968e03 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 7 Oct 2014 21:24:49 +0200 Subject: SCI: Always re-sort playlist in soundPlay Previously, it would only sort if a song wasn't already in the playlist. Since initSound already adds it, this effectively prevented the list from being sorted. --- engines/sci/engine/savegame.cpp | 8 ++++++-- engines/sci/sound/music.cpp | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'engines') diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 692fa77a80..eee4c49729 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -639,8 +639,12 @@ void SoundCommandParser::syncPlayList(Common::Serializer &s) { void SoundCommandParser::reconstructPlayList() { Common::StackLock lock(_music->_mutex); - const MusicList::iterator end = _music->getPlayListEnd(); - for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) { + // We store all songs here because starting songs may re-shuffle their order + MusicList songs; + for (MusicList::iterator i = _music->getPlayListStart(); i != _music->getPlayListEnd(); ++i) + songs.push_back(*i); + + for (MusicList::iterator i = songs.begin(); i != songs.end(); ++i) { initSoundResource(*i); if ((*i)->status == kSoundPlaying) { diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 4606d66ace..5b205c82d7 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -410,9 +410,10 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { } if (playListNo == playListCount) { // not found _playList.push_back(pSnd); - sortPlayList(); } + sortPlayList(); + _mutex.unlock(); // unlock to perform mixer-related calls if (pSnd->pMidiParser) { -- cgit v1.2.3 From e42a5123572cabf435a90eee2f9c01ababbe8528 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 7 Oct 2014 21:30:45 +0200 Subject: SCI: Don't remap channels from playBed songs --- engines/sci/sound/music.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 5b205c82d7..d58479f18e 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -397,6 +397,9 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { void SciMusic::soundPlay(MusicEntry *pSnd) { _mutex.lock(); + // TODO: if pSnd->playBed, and version <= SCI1_EARLY, then kill + // existing sounds with playBed enabled. + uint playListCount = _playList.size(); uint playListNo = playListCount; MusicEntry *alreadyPlaying = NULL; @@ -1126,8 +1129,10 @@ ChannelRemapping *SciMusic::determineChannelMap() { if (channel._mute) continue; + bool dontRemap = channel._dontRemap || song->playBed; + #ifdef DEBUG_REMAP - debug(" Channel %d: prio %d, %d voice%s%s", c, channel._prio, channel._voices, channel._voices == 1 ? "" : "s", channel._dontRemap ? ", dontRemap" : "" ); + debug(" Channel %d: prio %d, %d voice%s%s", c, channel._prio, channel._voices, channel._voices == 1 ? "" : "s", dontRemap ? ", dontRemap" : "" ); #endif DeviceChannelUsage dc = { song, c }; @@ -1135,7 +1140,7 @@ ChannelRemapping *SciMusic::determineChannelMap() { // our target int devChannel = -1; - if (channel._dontRemap && map->_map[c]._song == 0) { + if (dontRemap && map->_map[c]._song == 0) { // unremappable channel, with channel still free devChannel = c; } @@ -1232,10 +1237,10 @@ ChannelRemapping *SciMusic::determineChannelMap() { map->_map[devChannel] = dc; map->_voices[devChannel] = neededVoices; map->_prio[devChannel] = prio; - map->_dontRemap[devChannel] = channel._dontRemap; + map->_dontRemap[devChannel] = dontRemap; map->_freeVoices -= neededVoices; - if (!channel._dontRemap || devChannel == c) { + if (!dontRemap || devChannel == c) { // If this channel fits here, we're done. #ifdef DEBUG_REMAP debug(" OK"); -- cgit v1.2.3 From b80e74af5dec7675a2bf4a3f51da8501518c2be2 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sat, 11 Oct 2014 17:31:12 +0200 Subject: SCI: Handle voice limits differently For playBed songs, SCI1early remappers didn't unmap the entire song when there weren't enough voices for a channel. Thanks waltervn. --- engines/sci/sound/music.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index d58479f18e..f69f40eeca 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -1200,8 +1200,12 @@ ChannelRemapping *SciMusic::determineChannelMap() { int neededVoices = channel._voices; // do we have enough free voices? if (map->_freeVoices < neededVoices) { - // We only care for essential channels - if (prio > 0) { + // We only care for essential channels. + // Note: In early SCI1 interpreters, a song started by 'playBed' + // would not be skipped even if some channels couldn't be + // mapped due to voice limits. So, we treat all channels as + // non-essential here for playBed songs. + if (prio > 0 || (song->playBed && _soundVersion <= SCI_VERSION_1_EARLY)) { #ifdef DEBUG_REMAP debug(" not enough voices; need %d, have %d. Skipping this channel.", neededVoices, map->_freeVoices); #endif -- cgit v1.2.3 From 0aadd20aeaac1d241087e913a2bf8171bb0def68 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sun, 19 Oct 2014 11:34:14 +0200 Subject: SCI: Add debugging output --- engines/sci/sound/midiparser_sci.cpp | 2 ++ engines/sci/sound/music.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 7ee9cc9d28..7ebe47633a 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -487,6 +487,8 @@ void MidiParser_SCI::trackState(uint32 b) { s._sustain = (op2 != 0); break; case 0x4B: // voices + if (s._voices != op2) + warning("Voice change (%d to %d) without remapping", s._voices, op2); s._voices = op2; _pSnd->_chan[channel]._voices = op2; // Also sync our MusicEntry break; diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index f69f40eeca..62b17b2064 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -1111,7 +1111,8 @@ ChannelRemapping *SciMusic::determineChannelMap() { #ifdef DEBUG_REMAP - debug(" Song %d (%p), prio %d", songIndex, (void*)song, song->priority); + const char* name = g_sci->getEngineState()->_segMan->getObjectName(song->soundObj); + debug(" Song %d (%p) [%s], prio %d%s", songIndex, (void*)song, name, song->priority, song->playBed ? ", bed" : ""); #endif // Store backup. If we fail to map this song, we will revert to this. -- cgit v1.2.3 From 0018bb0f6f36fd1798ec92d2e7e6654e026fe19b Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sun, 19 Oct 2014 13:01:56 +0200 Subject: SCI: Give songs that start playing later higher priority --- engines/sci/sound/music.cpp | 9 ++++++++- engines/sci/sound/music.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 62b17b2064..2b73bcf8b3 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -144,6 +144,7 @@ void SciMusic::init() { _globalReverb = _pMidiDrv->getReverb(); // Init global reverb for SCI0 _currentlyPlayingSample = NULL; + _timeCounter = 0; } void SciMusic::miditimerCallback(void *p) { @@ -285,8 +286,10 @@ byte SciMusic::getCurrentReverb() { return _pMidiDrv->getReverb(); } +// A larger priority value has higher priority. For equal priority values, +// songs that have been added later have higher priority. static bool musicEntryCompare(const MusicEntry *l, const MusicEntry *r) { - return (l->priority > r->priority); + return (l->priority > r->priority) || (l->priority == r->priority && l->time > r->time); } void SciMusic::sortPlayList() { @@ -317,6 +320,8 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { track = digital; } + pSnd->time = ++_timeCounter; + if (track) { // Play digital sample if (track->digitalChannelNr != -1) { @@ -415,6 +420,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { _playList.push_back(pSnd); } + pSnd->time = ++_timeCounter; sortPlayList(); _mutex.unlock(); // unlock to perform mixer-related calls @@ -560,6 +566,7 @@ void SciMusic::soundSetPriority(MusicEntry *pSnd, byte prio) { Common::StackLock lock(_mutex); pSnd->priority = prio; + pSnd->time = ++_timeCounter; sortPlayList(); } diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 0fbd5a0c0e..1347177054 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -75,6 +75,8 @@ public: SoundResource *soundRes; uint16 resourceId; + int time; // "tim"estamp to indicate in which order songs have been added + bool isQueued; // for SCI0 only! uint16 dataInc; @@ -267,6 +269,9 @@ private: int _driverLastChannel; MusicEntry *_currentlyPlayingSample; + + int _timeCounter; // Used to keep track of the order in which MusicEntries + // are added, for priority purposes. }; } // End of namespace Sci -- cgit v1.2.3 From 5028487038fd3572d68af3cd253fc28917245e63 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sat, 14 Feb 2015 15:20:23 +0100 Subject: SCI: Use sound resource priority by default for songs SCI1 sound resources can have an embedded priority. We now use that by default, unless an explicit DoSound/SetPriority call overrides it. Thanks waltervn. This fixes relative priority of songs in at least PQ3 room 29. Also increase savegame version to 33. --- engines/sci/engine/savegame.cpp | 4 ++++ engines/sci/engine/savegame.h | 3 ++- engines/sci/resource.h | 2 ++ engines/sci/resource_audio.cpp | 4 ++++ engines/sci/sound/music.cpp | 2 ++ engines/sci/sound/music.h | 1 + engines/sci/sound/soundcmd.cpp | 26 +++++++++++++++----------- 7 files changed, 30 insertions(+), 12 deletions(-) (limited to 'engines') diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index eee4c49729..61f8058e45 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -621,6 +621,10 @@ void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) { s.syncAsByte(playBed); else if (s.isLoading()) playBed = false; + if (s.getVersion() >= 33) + s.syncAsByte(overridePriority); + else if (s.isLoading()) + overridePriority = false; // pMidiParser and pStreamAud will be initialized when the // sound list is reconstructed in gamestate_restore() diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index be6d05cdc5..7f482ed0a1 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -37,6 +37,7 @@ struct EngineState; * * Version - new/changed feature * ============================= + * 33 - new overridePriority flag in MusicEntry * 32 - new playBed flag in MusicEntry * 31 - priority for sound effects/music is now a signed int16, instead of a byte * 30 - synonyms @@ -57,7 +58,7 @@ struct EngineState; */ enum { - CURRENT_SAVEGAME_VERSION = 32, + CURRENT_SAVEGAME_VERSION = 33, MINIMUM_SAVEGAME_VERSION = 14 }; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 62f3c584ac..ef48998b04 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -596,6 +596,7 @@ public: Track *getDigitalTrack(); int getChannelFilterMask(int hardwareMask, bool wantsRhythm); byte getInitialVoiceCount(byte channel); + byte getSoundPriority() const { return _soundPriority; } private: SciVersion _soundVersion; @@ -603,6 +604,7 @@ private: Track *_tracks; Resource *_innerResource; ResourceManager *_resMan; + byte _soundPriority; }; } // End of namespace Sci diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index c775f502c5..3a43774492 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -579,6 +579,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers return; _innerResource = resource; + _soundPriority = 0xFF; byte *data, *data2; byte *dataEnd; @@ -725,6 +726,9 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers data += 6; } } else { + // The first byte of the 0xF0 track's channel list is priority + _soundPriority = *data; + // Skip over digital track data += 6; } diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 2b73bcf8b3..dab02c9eb7 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -340,6 +340,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { pSnd->soundType = Audio::Mixer::kSFXSoundType; pSnd->hCurrentAud = Audio::SoundHandle(); pSnd->playBed = false; + pSnd->overridePriority = false; } else { // play MIDI track Common::StackLock lock(_mutex); @@ -387,6 +388,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { pSnd->loop = 0; pSnd->hold = -1; pSnd->playBed = false; + pSnd->overridePriority = false; pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); pSnd->reverb = pSnd->pMidiParser->getSongReverb(); diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 1347177054..8770748c3d 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -88,6 +88,7 @@ public: int16 hold; int8 reverb; bool playBed; + bool overridePriority; // Use soundObj's priority instead of resource's int16 pauseCounter; uint sampleLoopCounter; diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 47ab9bdc71..682c88f382 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -184,7 +184,15 @@ void SoundCommandParser::processPlaySound(reg_t obj, bool playBed) { } musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); - musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); + + // Get song priority from either obj or soundRes + byte 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; @@ -677,23 +685,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; } -- cgit v1.2.3 From 1c5722f014d1f5a34c79d8d1cb7f5ed86e0b822d Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sat, 14 Feb 2015 15:58:47 +0100 Subject: SCI: Allow channel remapping from audio thread too --- engines/sci/sound/midiparser_sci.cpp | 12 +++++++---- engines/sci/sound/music.cpp | 42 ++++++++++++++++++++++-------------- engines/sci/sound/music.h | 7 ++++-- 3 files changed, 39 insertions(+), 22 deletions(-) (limited to 'engines') diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 7ebe47633a..25facacced 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -487,8 +487,11 @@ void MidiParser_SCI::trackState(uint32 b) { s._sustain = (op2 != 0); break; case 0x4B: // voices - if (s._voices != op2) - warning("Voice change (%d to %d) without remapping", s._voices, op2); + if (s._voices != op2) { + // CHECKME: Should we directly call remapChannels() if _mainThreadCalled? + debugC(2, kDebugLevelSound, "Dynamic voice change (%d to %d)", s._voices, op2); + _music->needsRemap(); + } s._voices = op2; _pSnd->_chan[channel]._voices = op2; // Also sync our MusicEntry break; @@ -500,8 +503,9 @@ void MidiParser_SCI::trackState(uint32 b) { bool m = op2; if (_pSnd->_chan[channel]._mute != m) { _pSnd->_chan[channel]._mute = m; - // TODO: If muting/unmuting a channel, remap channels. - warning("Mute change without immediate remapping (mainThread = %d)", _mainThreadCalled); + // CHECKME: Should we directly call remapChannels() if _mainThreadCalled? + _music->needsRemap(); + debugC(2, kDebugLevelSound, "Dynamic mute change (mainThread = %d)", _mainThreadCalled); } } break; diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index dab02c9eb7..37bf6a7b1b 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -145,6 +145,7 @@ void SciMusic::init() { _currentlyPlayingSample = NULL; _timeCounter = 0; + _needsRemap = false; } void SciMusic::miditimerCallback(void *p) { @@ -159,6 +160,11 @@ void SciMusic::onTimer() { // sending out queued commands that were "sent" via main thread sendMidiCommandsFromQueue(); + // remap channels, if requested + if (_needsRemap) + remapChannels(false); + _needsRemap = false; + for (MusicList::iterator i = _playList.begin(); i != end; ++i) (*i)->onTimer(); } @@ -920,12 +926,12 @@ int ChannelRemapping::lowestPrio() const { } -void SciMusic::remapChannels() { +void SciMusic::remapChannels(bool mainThread) { if (_soundVersion <= SCI_VERSION_0_LATE) return; - // NB: This function should only be called from the main thread, - // with _mutex locked + // NB: This function should only be called with _mutex locked + // Make sure to set the mainThread argument correctly. ChannelRemapping *map = determineChannelMap(); @@ -978,9 +984,9 @@ void SciMusic::remapChannels() { for (int j = 0; j < 16; ++j) { if (!channelMapped[j]) { - song->pMidiParser->mainThreadBegin(); + if (mainThread) song->pMidiParser->mainThreadBegin(); song->pMidiParser->remapChannel(j, -1); - song->pMidiParser->mainThreadEnd(); + if (mainThread) song->pMidiParser->mainThreadEnd(); #ifdef DEBUG_REMAP if (channelUsed[j]) debug(" Unmapping song %d, channel %d", songIndex, j); @@ -1012,9 +1018,9 @@ void SciMusic::remapChannels() { #ifdef DEBUG_REMAP debug(" Mapping (dontRemap) song %d, channel %d to device channel %d", songIndex, _channelMap[i]._channel, i); #endif - _channelMap[i]._song->pMidiParser->mainThreadBegin(); + if (mainThread) _channelMap[i]._song->pMidiParser->mainThreadBegin(); _channelMap[i]._song->pMidiParser->remapChannel(_channelMap[i]._channel, i); - _channelMap[i]._song->pMidiParser->mainThreadEnd(); + if (mainThread) _channelMap[i]._song->pMidiParser->mainThreadEnd(); } } @@ -1067,9 +1073,9 @@ void SciMusic::remapChannels() { #ifdef DEBUG_REMAP debug(" Mapping song %d, channel %d to device channel %d", songIndex, _channelMap[j]._channel, j); #endif - _channelMap[j]._song->pMidiParser->mainThreadBegin(); + if (mainThread) _channelMap[j]._song->pMidiParser->mainThreadBegin(); _channelMap[j]._song->pMidiParser->remapChannel(_channelMap[j]._channel, j); - _channelMap[j]._song->pMidiParser->mainThreadEnd(); + if (mainThread) _channelMap[j]._song->pMidiParser->mainThreadEnd(); break; } } @@ -1079,7 +1085,7 @@ void SciMusic::remapChannels() { // And finally, stop any empty channels for (int i = _driverLastChannel; i >= _driverFirstChannel; --i) { if (!_channelMap[i]._song && currentMap[i]._song) - resetDeviceChannel(i); + resetDeviceChannel(i, mainThread); } delete map; @@ -1307,14 +1313,18 @@ ChannelRemapping *SciMusic::determineChannelMap() { return map; } -void SciMusic::resetDeviceChannel(int devChannel) { - // NB: This function should only be called from the main thread - +void SciMusic::resetDeviceChannel(int devChannel, bool mainThread) { assert(devChannel >= 0 && devChannel <= 0x0F); - putMidiCommandInQueue(0x0040B0 | devChannel); // sustain off - putMidiCommandInQueue(0x007BB0 | devChannel); // notes off - putMidiCommandInQueue(0x004BB0 | devChannel); // release voices + if (mainThread) { + putMidiCommandInQueue(0x0040B0 | devChannel); // sustain off + putMidiCommandInQueue(0x007BB0 | devChannel); // notes off + putMidiCommandInQueue(0x004BB0 | devChannel); // release voices + } else { + _pMidiDrv->send(0x0040B0 | devChannel); // sustain off + _pMidiDrv->send(0x007BB0 | devChannel); // notes off + _pMidiDrv->send(0x004BB0 | devChannel); // release voices + } } diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 8770748c3d..a610f32d89 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -228,6 +228,8 @@ public: byte getCurrentReverb(); + void needsRemap() { _needsRemap = true; } + virtual void saveLoadWithSerializer(Common::Serializer &ser); // Mutex for music code. Used to guard access to the song playlist, to the @@ -249,9 +251,9 @@ protected: bool _useDigitalSFX; // remapping: - void remapChannels(); + void remapChannels(bool mainThread = true); ChannelRemapping *determineChannelMap(); - void resetDeviceChannel(int devChannel); + void resetDeviceChannel(int devChannel, bool mainThread); private: MusicList _playList; @@ -260,6 +262,7 @@ private: MusicEntry *_usedChannel[16]; int8 _channelRemap[16]; int8 _globalReverb; + bool _needsRemap; DeviceChannelUsage _channelMap[16]; -- cgit v1.2.3 From d0cb5f51fddcd74461914fb28ef4fbd685833eae Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sun, 15 Feb 2015 10:28:06 +0100 Subject: SCI: Only allow a single 'playBed' song in SCI1early --- engines/sci/sound/music.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'engines') diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 37bf6a7b1b..7156e3c099 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -410,8 +410,22 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { void SciMusic::soundPlay(MusicEntry *pSnd) { _mutex.lock(); - // TODO: if pSnd->playBed, and version <= SCI1_EARLY, then kill - // existing sounds with playBed enabled. + if (_soundVersion <= SCI_VERSION_1_EARLY && pSnd->playBed) { + // If pSnd->playBed, and version <= SCI1_EARLY, then kill + // existing sounds with playBed enabled. + + uint playListCount = _playList.size(); + for (uint i = 0; i < playListCount; i++) { + if (_playList[i] != pSnd && _playList[i]->playBed) { + debugC(2, kDebugLevelSound, "Automatically stopping old playBed song from soundPlay"); + MusicEntry *old = _playList[i]; + _mutex.unlock(); + soundStop(old); + _mutex.lock(); + break; + } + } + } uint playListCount = _playList.size(); uint playListNo = playListCount; -- cgit v1.2.3 From 2b49b5f95e8d6bd5ea3ab8ffb20ebad2ae7fc95e Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sun, 15 Feb 2015 14:14:46 +0100 Subject: SCI: Fix sound object frame selector rate Thanks waltervn. Verified against asm (QfG2, KQ6CD) --- engines/sci/sound/soundcmd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines') diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 682c88f382..64991cbf5c 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -550,7 +550,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); } } -- cgit v1.2.3