aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorColin Snover2017-09-10 01:34:35 -0500
committerColin Snover2017-09-19 19:54:29 -0500
commit836f1bdf441a199e16ef4583975eab8fe377e863 (patch)
treeb5e92581c6e035c16a46113ed3bd95ff760d2405 /engines/sci
parent301d0403cb46cbb268c914c3fdcf070c31781e07 (diff)
downloadscummvm-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.cpp140
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/sound/audio32.cpp77
-rw-r--r--engines/sci/sound/audio32.h5
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.