From d6e0276119265f825bbd5ab4a418cf234d48ed82 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 23 Jan 2010 14:39:03 +0000 Subject: Added song manipulation debug commands: songinfo, startsound, togglesound and stopallsounds. is_sample now works with the new sound code svn-id: r47475 --- engines/sci/console.cpp | 238 ++++++++++++++++++++++++++++------------- engines/sci/console.h | 5 +- engines/sci/sound/music.cpp | 64 +++++++++-- engines/sci/sound/music.h | 2 + engines/sci/sound/soundcmd.cpp | 28 ++++- engines/sci/sound/soundcmd.h | 13 ++- 6 files changed, 264 insertions(+), 86 deletions(-) (limited to 'engines') diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 1ab8e2fbb1..2a1adb3fcf 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -132,10 +132,13 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { DCmd_Register("gc_normalize", WRAP_METHOD(Console, cmdGCNormalize)); // Music/SFX DCmd_Register("songlib", WRAP_METHOD(Console, cmdSongLib)); + DCmd_Register("songinfo", WRAP_METHOD(Console, cmdSongInfo)); DCmd_Register("is_sample", WRAP_METHOD(Console, cmdIsSample)); + DCmd_Register("startsound", WRAP_METHOD(Console, cmdStartSound)); + DCmd_Register("togglesound", WRAP_METHOD(Console, cmdToggleSound)); + DCmd_Register("stopallsounds", WRAP_METHOD(Console, cmdStopAllSounds)); DCmd_Register("sfx01_header", WRAP_METHOD(Console, cmdSfx01Header)); DCmd_Register("sfx01_track", WRAP_METHOD(Console, cmdSfx01Track)); - DCmd_Register("stop_sfx", WRAP_METHOD(Console, cmdStopSfx)); // Script DCmd_Register("addresses", WRAP_METHOD(Console, cmdAddresses)); DCmd_Register("registers", WRAP_METHOD(Console, cmdRegisters)); @@ -1380,6 +1383,165 @@ bool Console::cmdSongLib(int argc, const char **argv) { return true; } +bool Console::cmdSongInfo(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Shows information about a given song in the playlist\n"); + DebugPrintf("Usage: %s \n", argv[0]); + return true; + } + + reg_t addr; + + if (parse_reg_t(_vm->_gamestate, argv[1], &addr, false)) { + DebugPrintf("Invalid address passed.\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + + _vm->getEngineState()->_soundCmd->printSongInfo(addr, this); + + return true; +} + +bool Console::cmdStartSound(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Adds the requested sound resource to the playlist, and starts playing it\n"); + DebugPrintf("Usage: %s \n", argv[0]); + return true; + } + + int16 number = atoi(argv[1]); + + if (!_vm->getResourceManager()->testResource(ResourceId(kResourceTypeSound, number))) { + DebugPrintf("Unable to load this sound resource, most probably it has an equivalent audio resource (SCI1.1)\n"); + return true; + } + + _vm->getEngineState()->_soundCmd->startNewSound(number); + + return false; +} + +bool Console::cmdToggleSound(int argc, const char **argv) { + if (argc != 3) { + DebugPrintf("Plays or stops the specified sound in the playlist\n"); + DebugPrintf("Usage: %s
\n", argv[0]); + DebugPrintf("Where:\n"); + DebugPrintf("-
is the address of the sound to play or stop.\n"); + DebugPrintf("- is the new state (play or stop).\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + + reg_t id; + + if (parse_reg_t(_vm->_gamestate, argv[1], &id, false)) { + DebugPrintf("Invalid address passed.\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef USE_OLD_MUSIC_FUNCTIONS + int handle = id.segment << 16 | id.offset; // frobnicate handle + + if (id.segment) { + SegManager *segMan = _vm->_gamestate->_segMan; // for PUT_SEL32V + _vm->_gamestate->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); + _vm->_gamestate->_sound.sfx_remove_song(handle); + PUT_SEL32V(segMan, id, signal, SIGNAL_OFFSET); + PUT_SEL32V(segMan, id, nodePtr, 0); + PUT_SEL32V(segMan, id, handle, 0); + } +#else + + Common::String newState = argv[2]; + newState.toLowercase(); + + if (newState == "play") + _vm->_gamestate->_soundCmd->playSound(id); + else if (newState == "stop") + _vm->_gamestate->_soundCmd->stopSound(id); + else + DebugPrintf("New state can either be 'play' or 'stop'"); +#endif + + return true; +} + +bool Console::cmdStopAllSounds(int argc, const char **argv) { +#ifndef USE_OLD_MUSIC_FUNCTIONS + _vm->_gamestate->_soundCmd->stopAllSounds(); +#endif + + DebugPrintf("All sounds have been stopped\n"); + return true; +} + +bool Console::cmdIsSample(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Tests whether a given sound resource is a PCM sample, \n"); + DebugPrintf("and displays information on it if it is.\n"); + DebugPrintf("Usage: %s \n", argv[0]); + return true; + } + +#ifdef USE_OLD_MUSIC_FUNCTIONS + Resource *song = _vm->getResourceManager()->findResource(ResourceId(kResourceTypeSound, atoi(argv[1])), 0); + SongIterator *songit; + Audio::AudioStream *data; + + if (!song) { + DebugPrintf("Not a sound resource!\n"); + return true; + } + + songit = songit_new(song->data, song->size, SCI_SONG_ITERATOR_TYPE_SCI0, 0xcaffe /* What do I care about the ID? */); + + if (!songit) { + DebugPrintf("Could not convert to song iterator!\n"); + return true; + } + + if ((data = songit->getAudioStream())) { + // TODO +/* + DebugPrintf("\nIs sample (encoding %dHz/%s/%04x)", data->conf.rate, (data->conf.stereo) ? + ((data->conf.stereo == SFX_PCM_STEREO_LR) ? "stereo-LR" : "stereo-RL") : "mono", data->conf.format); +*/ + delete data; + } else + DebugPrintf("Valid song, but not a sample.\n"); + + delete songit; +#else + int16 number = atoi(argv[1]); + + if (!_vm->getResourceManager()->testResource(ResourceId(kResourceTypeSound, number))) { + DebugPrintf("Unable to load this sound resource, most probably it has an equivalent audio resource (SCI1.1)\n"); + return true; + } + + SoundResource *soundRes = new SoundResource(number, _vm->getResourceManager(), _vm->getEngineState()->detectDoSoundType()); + + if (!soundRes) { + DebugPrintf("Not a sound resource!\n"); + return true; + } + + SoundResource::Track *track = soundRes->getDigitalTrack(); + if (!track || track->digitalChannelNr == -1) { + DebugPrintf("Valid song, but not a sample.\n"); + delete soundRes; + return true; + } + + DebugPrintf("Sample size: %d, sample rate: %d, channels: %d, digital channel number: %d\n", + track->digitalSampleSize, track->digitalSampleRate, track->channelCount, track->digitalChannelNr); +#endif + + return true; +} + bool Console::cmdGCInvoke(int argc, const char **argv) { DebugPrintf("Performing garbage collection...\n"); run_gc(_vm->_gamestate); @@ -2278,47 +2440,6 @@ bool Console::cmdBreakpointExecFunction(int argc, const char **argv) { return true; } -bool Console::cmdIsSample(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Tests whether a given sound resource is a PCM sample, \n"); - DebugPrintf("and displays information on it if it is.\n"); - DebugPrintf("Usage: %s \n", argv[0]); - return true; - } - -#ifdef USE_OLD_MUSIC_FUNCTIONS - Resource *song = _vm->getResourceManager()->findResource(ResourceId(kResourceTypeSound, atoi(argv[1])), 0); - SongIterator *songit; - Audio::AudioStream *data; - - if (!song) { - DebugPrintf("Not a sound resource!\n"); - return true; - } - - songit = songit_new(song->data, song->size, SCI_SONG_ITERATOR_TYPE_SCI0, 0xcaffe /* What do I care about the ID? */); - - if (!songit) { - DebugPrintf("Could not convert to song iterator!\n"); - return true; - } - - if ((data = songit->getAudioStream())) { - // TODO -/* - DebugPrintf("\nIs sample (encoding %dHz/%s/%04x)", data->conf.rate, (data->conf.stereo) ? - ((data->conf.stereo == SFX_PCM_STEREO_LR) ? "stereo-LR" : "stereo-RL") : "mono", data->conf.format); -*/ - delete data; - } else - DebugPrintf("Valid song, but not a sample.\n"); - - delete songit; -#endif - - return true; -} - bool Console::cmdSfx01Header(int argc, const char **argv) { if (argc != 2) { DebugPrintf("Dumps the header of a SCI01 song\n"); @@ -2505,39 +2626,6 @@ bool Console::cmdSfx01Track(int argc, const char **argv) { return true; } -bool Console::cmdStopSfx(int argc, const char **argv) { - if (argc != 2) { - DebugPrintf("Stops a playing sound\n"); - DebugPrintf("Usage: %s
\n", argv[0]); - DebugPrintf("Where
is the address of the sound to stop.\n"); - DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); - return true; - } - - reg_t id; - - if (parse_reg_t(_vm->_gamestate, argv[1], &id, false)) { - DebugPrintf("Invalid address passed.\n"); - DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); - return true; - } - -#ifdef USE_OLD_MUSIC_FUNCTIONS - int handle = id.segment << 16 | id.offset; // frobnicate handle - - if (id.segment) { - SegManager *segMan = _vm->_gamestate->_segMan; // for PUT_SEL32V - _vm->_gamestate->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED); - _vm->_gamestate->_sound.sfx_remove_song(handle); - PUT_SEL32V(segMan, id, signal, SIGNAL_OFFSET); - PUT_SEL32V(segMan, id, nodePtr, 0); - PUT_SEL32V(segMan, id, handle, 0); - } -#endif - - return true; -} - bool Console::cmdExit(int argc, const char **argv) { if (argc != 2) { DebugPrintf("%s game - exit gracefully\n", argv[0]); diff --git a/engines/sci/console.h b/engines/sci/console.h index 6829208179..c42603273c 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -104,10 +104,13 @@ private: bool cmdGCNormalize(int argc, const char **argv); // Music/SFX bool cmdSongLib(int argc, const char **argv); + bool cmdSongInfo(int argc, const char **argv); bool cmdIsSample(int argc, const char **argv); + bool cmdStartSound(int argc, const char **argv); + bool cmdToggleSound(int argc, const char **argv); + bool cmdStopAllSounds(int argc, const char **argv); bool cmdSfx01Header(int argc, const char **argv); bool cmdSfx01Track(int argc, const char **argv); - bool cmdStopSfx(int argc, const char **argv); // Script bool cmdAddresses(int argc, const char **argv); bool cmdRegisters(int argc, const char **argv); diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index ef75ba96fc..a917e36ab3 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -108,6 +108,16 @@ void SciMusic::pauseAll(bool pause) { } } +void SciMusic::stopAll() { + Common::StackLock lock(_mutex); + + const MusicList::iterator end = _playList.end(); + for (MusicList::iterator i = _playList.begin(); i != end; ++i) { + soundStop(*i); + } +} + + void SciMusic::miditimerCallback(void *p) { SciMusic *aud = (SciMusic *)p; @@ -154,10 +164,8 @@ void SciMusic::sortPlayList() { qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare); } void SciMusic::soundInitSnd(MusicEntry *pSnd) { - SoundResource::Track *track = NULL; int channelFilterMask = 0; - - track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion)); + SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion)); if (track) { // If MIDI device is selected but there is no digital track in sound resource @@ -223,8 +231,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { if (pSnd->pStreamAud && !_pMixer->isSoundHandleActive(pSnd->hCurrentAud)) { if (pSnd->loop > 1) { pSnd->pLoopStream = new Audio::LoopingAudioStream(pSnd->pStreamAud, - pSnd->loop, DisposeAfterUse::NO - ); + pSnd->loop, DisposeAfterUse::NO); _pMixer->playInputStream(pSnd->soundType, &pSnd->hCurrentAud, pSnd->pLoopStream, -1, pSnd->volume, 0, DisposeAfterUse::NO); @@ -358,12 +365,53 @@ void SciMusic::printPlayList(Console *con) { const char *musicStatus[] = { "Stopped", "Initialized", "Paused", "Playing" }; + for (uint32 i = 0; i < _playList.size(); i++) { + MusicEntry *song = _playList[i]; + con->DebugPrintf("%d: %04x:%04x, resource id: %d, status: %s, %s type\n", i, + PRINT_REG(song->soundObj), song->resnum, + musicStatus[song->status], song->pMidiParser ? "MIDI" : "digital audio"); + } +} + +void SciMusic::printSongInfo(reg_t obj, Console *con) { + Common::StackLock lock(_mutex); + + const char *musicStatus[] = { "Stopped", "Initialized", "Paused", "Playing" }; + const MusicList::iterator end = _playList.end(); for (MusicList::iterator i = _playList.begin(); i != end; ++i) { - con->DebugPrintf("%d: %04x:%04x, priority: %d, status: %s\n", i, - PRINT_REG((*i)->soundObj), (*i)->prio, - musicStatus[(*i)->status]); + MusicEntry *song = *i; + if (song->soundObj == obj) { + con->DebugPrintf("Resource id: %d, status: %s\n", song->resnum, musicStatus[song->status]); + con->DebugPrintf("dataInc: %d, hold: %d, loop: %d\n", song->dataInc, song->hold, song->loop); + con->DebugPrintf("signal: %d, priority: %d\n", song->signal, song->prio); + con->DebugPrintf("ticker: %d, volume: %d\n", song->ticker, song->volume); + + if (song->pMidiParser) { + con->DebugPrintf("Type: MIDI\n"); + if (song->soundRes) { + SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion)); + con->DebugPrintf("Channels: %d\n", track->channelCount); + } + } else if (song->pStreamAud || song->pLoopStream) { + con->DebugPrintf("Type: digital audio (%s), sound active: %s\n", + song->pStreamAud ? "non looping" : "looping", + _pMixer->isSoundHandleActive(song->hCurrentAud) ? "yes" : "no"); + if (song->soundRes) { + con->DebugPrintf("Sound resource information:\n"); + SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion)); + if (track && track->digitalChannelNr != -1) { + con->DebugPrintf("Sample size: %d, sample rate: %d, channels: %d, digital channel number: %d\n", + track->digitalSampleSize, track->digitalSampleRate, track->channelCount, track->digitalChannelNr); + } + } + } + + return; + } } + + con->DebugPrintf("Song object not found in playlist"); } MusicEntry::MusicEntry() { diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 660aef9cad..39b6ad0d74 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -140,6 +140,7 @@ public: void onTimer(); void clearPlayList(); void pauseAll(bool pause); + void stopAll(); // sound and midi functions void soundInitSnd(MusicEntry *pSnd); @@ -176,6 +177,7 @@ public: } void printPlayList(Console *con); + void printSongInfo(reg_t obj, Console *con); // The following two methods are NOT thread safe - make sure that // the mutex is always locked before calling them diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index f5fb5b4e4f..dcf4b33553 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -248,7 +248,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) { if (!obj.segment) return; - int number = obj.segment ? GET_SEL32V(_segMan, obj, number) : 0; + int number = GET_SEL32V(_segMan, obj, number); #ifdef USE_OLD_MUSIC_FUNCTIONS @@ -1072,6 +1072,32 @@ void SoundCommandParser::printPlayList(Console *con) { #endif } +void SoundCommandParser::printSongInfo(reg_t obj, Console *con) { +#ifndef USE_OLD_MUSIC_FUNCTIONS + _music->printSongInfo(obj, con); +#endif +} + +void SoundCommandParser::stopAllSounds() { +#ifndef USE_OLD_MUSIC_FUNCTIONS + _music->stopAll(); +#endif +} + +void SoundCommandParser::startNewSound(int number) { +#ifndef USE_OLD_MUSIC_FUNCTIONS + Common::StackLock lock(_music->_mutex); + + // Overwrite the first sound in the playlist + MusicEntry *song = *_music->getPlayListStart(); + reg_t soundObj = song->soundObj; + cmdDisposeSound(soundObj, 0); + PUT_SEL32V(_segMan, soundObj, number, number); + cmdInitSound(soundObj, 0); + cmdPlaySound(soundObj, 0); +#endif +} + void SoundCommandParser::setMasterVolume(int vol) { #ifndef USE_OLD_MUSIC_FUNCTIONS _music->soundSetMasterVolume(vol); diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h index fc80b6b3fa..41ce9517a9 100644 --- a/engines/sci/sound/soundcmd.h +++ b/engines/sci/sound/soundcmd.h @@ -58,13 +58,24 @@ public: #endif reg_t parseCommand(int argc, reg_t *argv, reg_t acc); + + // Functions used for game state loading void clearPlayList(); void syncPlayList(Common::Serializer &s); void reconstructPlayList(int savegame_version); - void printPlayList(Console *con); + + // Functions used for the ScummVM menus void setMasterVolume(int vol); void pauseAll(bool pause); + // Debug console functions + void playSound(reg_t obj) { cmdPlaySound(obj, 0); } + void stopSound(reg_t obj) { cmdStopSound(obj, 0); } + void startNewSound(int number); + void stopAllSounds(); + void printPlayList(Console *con); + void printSongInfo(reg_t obj, Console *con); + #ifndef USE_OLD_MUSIC_FUNCTIONS /** * Synchronizes the current state of the music list to the rest of the engine, so that -- cgit v1.2.3