diff options
author | Colin Snover | 2017-09-10 01:34:35 -0500 |
---|---|---|
committer | Colin Snover | 2017-09-19 19:54:29 -0500 |
commit | 836f1bdf441a199e16ef4583975eab8fe377e863 (patch) | |
tree | b5e92581c6e035c16a46113ed3bd95ff760d2405 /engines/sci | |
parent | 301d0403cb46cbb268c914c3fdcf070c31781e07 (diff) | |
download | scummvm-rg350-836f1bdf441a199e16ef4583975eab8fe377e863.tar.gz scummvm-rg350-836f1bdf441a199e16ef4583975eab8fe377e863.tar.bz2 scummvm-rg350-836f1bdf441a199e16ef4583975eab8fe377e863.zip |
SCI32: Add audio dump debugger command
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/console.cpp | 140 | ||||
-rw-r--r-- | engines/sci/console.h | 1 | ||||
-rw-r--r-- | engines/sci/sound/audio32.cpp | 77 | ||||
-rw-r--r-- | engines/sci/sound/audio32.h | 5 |
4 files changed, 186 insertions, 37 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 4d8ff17c10..4c4dfb3260 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -53,9 +53,11 @@ #include "video/avi_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 +#include "common/memstream.h" #include "sci/graphics/frameout.h" #include "sci/graphics/paint32.h" #include "sci/graphics/palette32.h" +#include "sci/sound/decoders/sol.h" #include "video/coktel_decoder.h" #endif @@ -173,6 +175,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), registerCmd("show_instruments", WRAP_METHOD(Console, cmdShowInstruments)); registerCmd("map_instrument", WRAP_METHOD(Console, cmdMapInstrument)); registerCmd("audio_list", WRAP_METHOD(Console, cmdAudioList)); + registerCmd("audio_dump", WRAP_METHOD(Console, cmdAudioDump)); // Script registerCmd("addresses", WRAP_METHOD(Console, cmdAddresses)); registerCmd("registers", WRAP_METHOD(Console, cmdRegisters)); @@ -426,6 +429,7 @@ bool Console::cmdHelp(int argc, const char **argv) { debugPrintf(" show_instruments - Shows the instruments of a specific song, or all songs\n"); debugPrintf(" map_instrument - Dynamically maps an MT-32 instrument to a GM instrument\n"); debugPrintf(" audio_list - Lists currently active digital audio samples (SCI2+)\n"); + debugPrintf(" audio_dump - Dumps the requested audio resource as an uncompressed wave file (SCI2+)\n"); debugPrintf("\n"); debugPrintf("Script:\n"); debugPrintf(" addresses - Provides information on how to pass addresses\n"); @@ -1452,6 +1456,142 @@ bool Console::cmdAudioList(int argc, const char **argv) { return true; } +bool Console::cmdAudioDump(int argc, const char **argv) { +#ifdef ENABLE_SCI32 + if (argc != 2 && argc != 6) { + debugPrintf("Dumps the requested audio resource as an uncompressed wave file.\n"); + debugPrintf("Usage (audio): %s <audio resource id>\n", argv[0]); + debugPrintf("Usage (audio36): %s <audio map id> <noun> <verb> <cond> <seq>\n", argv[0]); + return true; + } + + ResourceId id; + if (argc == 2) { + id = ResourceId(kResourceTypeAudio, atoi(argv[1])); + } else { + id = ResourceId(kResourceTypeAudio36, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])); + } + + Resource *resource = _engine->_resMan->findResource(id, false); + if (!resource) { + debugPrintf("Not found.\n"); + return true; + } + + Common::MemoryReadStream stream = resource->toStream(); + + Common::DumpFile outFile; + const Common::String fileName = Common::String::format("%s.wav", id.toString().c_str()); + if (!outFile.open(fileName)) { + debugPrintf("Could not open dump file %s.\n", fileName.c_str()); + return true; + } + + const bool isSol = detectSolAudio(stream); + const bool isWave = !isSol && detectWaveAudio(stream); + const bool isRaw = !isSol && !isWave; + + if (isSol || isRaw) { + uint16 sampleRate = 11025; + int numChannels = 1; + int bytesPerSample = 1; + bool sourceIs8Bit = true; + uint32 compressedSize; + uint32 decompressedSize; + + if (isSol) { + stream.seek(6, SEEK_SET); + sampleRate = stream.readUint16LE(); + const byte flags = stream.readByte(); + compressedSize = stream.readUint32LE(); + + // All AudioStreams must output 16-bit samples + bytesPerSample = 2; + decompressedSize = compressedSize * bytesPerSample; + + if (flags & kCompressed) { + decompressedSize *= 2; + } + if (flags & k16Bit) { + sourceIs8Bit = false; + } + if (flags & kStereo) { + numChannels = 2; + } + } else { + decompressedSize = resource->size(); + } + + enum { + kWaveHeaderSize = 36 + }; + + outFile.writeString("RIFF"); + outFile.writeUint32LE(kWaveHeaderSize + decompressedSize); + outFile.writeString("WAVEfmt "); + outFile.writeUint32LE(16); + outFile.writeUint16LE(1); + outFile.writeUint16LE(numChannels); + outFile.writeUint32LE(sampleRate); + outFile.writeUint32LE(sampleRate * bytesPerSample * numChannels); + outFile.writeUint16LE(bytesPerSample * numChannels); + outFile.writeUint16LE(bytesPerSample * 8); + outFile.writeString("data"); + outFile.writeUint32LE(decompressedSize); + + if (isSol) { + stream.seek(0, SEEK_SET); + Common::ScopedPtr<Audio::SeekableAudioStream> audioStream(makeSOLStream(&stream, DisposeAfterUse::NO)); + + if (!audioStream) { + debugPrintf("Could not create SOL stream.\n"); + return true; + } + + byte buffer[4096]; + const int samplesToRead = ARRAYSIZE(buffer) / 2; + uint bytesWritten = 0; + int samplesRead; + while ((samplesRead = audioStream->readBuffer((int16 *)buffer, samplesToRead))) { + uint bytesToWrite = samplesRead * bytesPerSample; + outFile.write(buffer, bytesToWrite); + bytesWritten += bytesToWrite; + } + + if (bytesWritten != decompressedSize) { + debugPrintf("WARNING: Should have written %u bytes but wrote %u bytes!\n", decompressedSize, bytesWritten); + while (bytesWritten < decompressedSize) { + outFile.writeByte(0); + ++bytesWritten; + } + } + + const char *bits; + if (sourceIs8Bit) { + bits = "upconverted 16"; + } else { + bits = "16"; + } + + debugPrintf("%s-bit %uHz %d-channel SOL audio, %u -> %u bytes\n", bits, sampleRate, numChannels, compressedSize, decompressedSize); + } else { + outFile.write(resource->data(), resource->size()); + debugPrintf("%d-bit %uHz %d-channel raw audio, %u bytes\n", bytesPerSample * 8, sampleRate, numChannels, decompressedSize); + } + } else if (isWave) { + outFile.write(resource->data(), resource->size()); + debugPrintf("Raw wave file\n"); + } else { + error("Impossible situation"); + } + + debugPrintf("Written to %s successfully.\n", fileName.c_str()); +#else + debugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} + bool Console::cmdSaveGame(int argc, const char **argv) { if (argc != 2) { debugPrintf("Saves the current game state to the hard disk\n"); diff --git a/engines/sci/console.h b/engines/sci/console.h index 3cc19ad254..d5b80b695b 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -122,6 +122,7 @@ private: bool cmdShowInstruments(int argc, const char **argv); bool cmdMapInstrument(int argc, const char **argv); bool cmdAudioList(int argc, const char **argv); + bool cmdAudioDump(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/audio32.cpp b/engines/sci/sound/audio32.cpp index 1b521cd023..2f30f7dd79 100644 --- a/engines/sci/sound/audio32.cpp +++ b/engines/sci/sound/audio32.cpp @@ -46,6 +46,46 @@ namespace Sci { +bool detectSolAudio(Common::SeekableReadStream &stream) { + const size_t initialPosition = stream.pos(); + + byte header[6]; + if (stream.read(header, sizeof(header)) != sizeof(header)) { + stream.seek(initialPosition); + return false; + } + + stream.seek(initialPosition); + + if ((header[0] & 0x7f) != kResourceTypeAudio || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) { + return false; + } + + return true; +} + +bool detectWaveAudio(Common::SeekableReadStream &stream) { + const size_t initialPosition = stream.pos(); + + byte blockHeader[8]; + if (stream.read(blockHeader, sizeof(blockHeader)) != sizeof(blockHeader)) { + stream.seek(initialPosition); + return false; + } + + stream.seek(initialPosition); + const uint32 headerType = READ_BE_UINT32(blockHeader); + + if (headerType != MKTAG('R', 'I', 'F', 'F')) { + return false; + } + + return true; +} + +#pragma mark - +#pragma mark MutableLoopAudioStream + class MutableLoopAudioStream : public Audio::AudioStream { public: MutableLoopAudioStream(Audio::RewindableAudioStream *stream, const bool loop_, const DisposeAfterUse::Flag dispose = DisposeAfterUse::YES) : @@ -105,43 +145,6 @@ private: bool _loop; }; -bool detectSolAudio(Common::SeekableReadStream &stream) { - const size_t initialPosition = stream.pos(); - - byte header[6]; - if (stream.read(header, sizeof(header)) != sizeof(header)) { - stream.seek(initialPosition); - return false; - } - - stream.seek(initialPosition); - - if ((header[0] & 0x7f) != kResourceTypeAudio || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) { - return false; - } - - return true; -} - -bool detectWaveAudio(Common::SeekableReadStream &stream) { - const size_t initialPosition = stream.pos(); - - byte blockHeader[8]; - if (stream.read(blockHeader, sizeof(blockHeader)) != sizeof(blockHeader)) { - stream.seek(initialPosition); - return false; - } - - stream.seek(initialPosition); - const uint32 headerType = READ_BE_UINT32(blockHeader); - - if (headerType != MKTAG('R', 'I', 'F', 'F')) { - return false; - } - - return true; -} - #pragma mark - Audio32::Audio32(ResourceManager *resMan) : diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h index a994113e32..8b8ec2a6b5 100644 --- a/engines/sci/sound/audio32.h +++ b/engines/sci/sound/audio32.h @@ -35,6 +35,9 @@ namespace Sci { class Console; +bool detectSolAudio(Common::SeekableReadStream &stream); +bool detectWaveAudio(Common::SeekableReadStream &stream); + #pragma mark AudioChannel /** @@ -130,6 +133,8 @@ struct AudioChannel { int pan; }; +#pragma mark - + /** * Special audio channel indexes used to select a channel * for digital audio playback. |