From 97813f89ecd2a06c74f776708a3d1852c96811a7 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sat, 6 Jun 2015 22:50:36 +0200 Subject: SHERLOCK: rework 3DO audio, add AIFC file support - rework 3DO audio decoders to decode into buffer only - 3DO audio decoders also use streams without separate size arg now - add support for ADP4 + SDX2 inside AIFC files - add debug command "3do_playaudio" to play AIFC files - remove audio flags and replace with stereo bool --- audio/decoders/3do.cpp | 420 ++++++++++++++++++++++++++++-------------------- audio/decoders/3do.h | 96 +++++++++-- audio/decoders/aiff.cpp | 21 ++- audio/decoders/aiff.h | 5 + 4 files changed, 346 insertions(+), 196 deletions(-) (limited to 'audio') diff --git a/audio/decoders/3do.cpp b/audio/decoders/3do.cpp index ab98aa2ba2..32e48005be 100644 --- a/audio/decoders/3do.cpp +++ b/audio/decoders/3do.cpp @@ -26,250 +26,318 @@ #include "audio/decoders/3do.h" #include "audio/decoders/raw.h" +#include "audio/decoders/adpcm_intern.h" namespace Audio { -#define AUDIO_3DO_ADP4_STEPSIZETABLE_MAX 88 - -static int16 audio_3DO_ADP4_stepSizeTable[AUDIO_3DO_ADP4_STEPSIZETABLE_MAX + 1] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, - 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, - 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 -}; +// Reuses ADPCM table +#define audio_3DO_ADP4_stepSizeTable Ima_ADPCMStream::_imaTable +#define audio_3DO_ADP4_stepSizeIndex ADPCMStream::_stepAdjustTable + +RewindableAudioStream *make3DO_ADP4AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace) { + if (stereo) { + warning("make3DO_ADP4Stream(): stereo currently not supported"); + return 0; + } + + if (audioLengthMSecsPtr) { + // Caller requires the milliseconds of audio + uint32 audioLengthMSecs = stream->size() * 2 * 1000 / sampleRate; // 1 byte == 2 16-bit sample + if (stereo) { + audioLengthMSecs /= 2; + } + *audioLengthMSecsPtr = audioLengthMSecs; + } + + return new Audio3DO_ADP4_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace); +} + +Audio3DO_ADP4_Stream::Audio3DO_ADP4_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace) + : _sampleRate(sampleRate), _stereo(stereo), + _stream(stream, disposeAfterUse) { + + _callerDecoderData = persistentSpace; + memset(&_initialDecoderData, 0, sizeof(_initialDecoderData)); + _initialRead = true; -static int16 audio_3DO_ADP4_stepSizeIndex[] = { - -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 + reset(); }; -int16 audio_3DO_ADP4_DecodeSample(uint8 dataNibble, int16 &decoderLastSample, int16 &decoderStepIndex) { - int16 currentStep = audio_3DO_ADP4_stepSizeTable[decoderStepIndex]; - int32 decodedSample = decoderLastSample; +void Audio3DO_ADP4_Stream::reset() { + memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData)); + _streamBytesLeft = _stream->size(); + _stream->seek(0); +} + +bool Audio3DO_ADP4_Stream::rewind() { + reset(); + return true; +} + +int16 Audio3DO_ADP4_Stream::decodeSample(byte compressedNibble) { + int16 currentStep = audio_3DO_ADP4_stepSizeTable[_curDecoderData.stepIndex]; + int32 decodedSample = _curDecoderData.lastSample; int16 delta = currentStep >> 3; - if (dataNibble & 1) + if (compressedNibble & 1) delta += currentStep >> 2; - if (dataNibble & 2) + if (compressedNibble & 2) delta += currentStep >> 1; - if (dataNibble & 4) + if (compressedNibble & 4) delta += currentStep; - if (dataNibble & 8) { + if (compressedNibble & 8) { decodedSample -= delta; } else { decodedSample += delta; } - decoderLastSample = CLIP(decodedSample, -32768, 32767); + _curDecoderData.lastSample = CLIP(decodedSample, -32768, 32767); - decoderStepIndex += audio_3DO_ADP4_stepSizeIndex[dataNibble & 0x07]; - decoderStepIndex = CLIP(decoderStepIndex, 0, AUDIO_3DO_ADP4_STEPSIZETABLE_MAX); + _curDecoderData.stepIndex += audio_3DO_ADP4_stepSizeIndex[compressedNibble & 0x07]; + _curDecoderData.stepIndex = CLIP(_curDecoderData.stepIndex, 0, ARRAYSIZE(audio_3DO_ADP4_stepSizeTable) - 1); - return decoderLastSample; + return _curDecoderData.lastSample; } -SeekableAudioStream *make3DO_ADP4Stream(Common::SeekableReadStream *stream, uint32 size, uint16 sampleRate, byte audioFlags, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace) { - int32 streamPos = 0; - int32 compressedSize = size; - int32 decompressedSize = 0; - int32 decompressedPos = 0; - byte compressedByte = 0; +// Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written +int Audio3DO_ADP4_Stream::readBuffer(int16 *buffer, const int numSamples) { + int8 byteCache[AUDIO_3DO_CACHE_SIZE]; + int8 *byteCachePtr = NULL; + int byteCacheSize = 0; + int requestedBytesLeft = 0; + int decodedSamplesCount = 0; - audio_3DO_ADP4_PersistentSpace decoderData; + int8 compressedByte = 0; - assert(compressedSize <= stream->size()); + if (endOfData()) + return 0; // no more bytes left - if (audioFlags & Audio::FLAG_UNSIGNED) { - // Unsigned data is not allowed - warning("make3DO_ADP4Stream(): sample data result is expected to be signed"); - return 0; - } - if (!(audioFlags & Audio::FLAG_16BITS)) { - // 8-bit sample data is not allowed - warning("make3DO_ADP4Stream(): sample data result is expected to be 16-bit"); - return 0; - } - if (audioFlags & Audio::FLAG_LITTLE_ENDIAN) { - // LE sample data is not allowed - warning("make3DO_ADP4Stream(): sample data result is expected to be Big Endian"); - return 0; - } - if (audioFlags & Audio::FLAG_STEREO) { - warning("make3DO_ADP4Stream(): stereo currently not supported"); - return 0; + if (_callerDecoderData) { + // copy caller decoder data over + memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData)); + if (_initialRead) { + _initialRead = false; + memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData)); + } } - if (persistentSpace) { - memcpy(&decoderData, persistentSpace, sizeof(decoderData)); - } else { - memset(&decoderData, 0, sizeof(decoderData)); - } + requestedBytesLeft = numSamples >> 1; // 1 byte for 2 16-bit sample + if (requestedBytesLeft > _streamBytesLeft) + requestedBytesLeft = _streamBytesLeft; // not enough bytes left - assert(compressedSize < 0x40000000); // safety check + // in case caller requests an uneven amount of samples, we will return an even amount - decompressedSize = compressedSize * 4; // 4 bits == 1 16-bit sample - byte *decompressedData = (byte *)malloc(decompressedSize); - assert(decompressedData); + // buffering, so that direct decoding of files and such runs way faster + while (requestedBytesLeft) { + if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) { + byteCacheSize = AUDIO_3DO_CACHE_SIZE; + } else { + byteCacheSize = requestedBytesLeft; + } - if (!(audioFlags & Audio::FLAG_STEREO)) { - // Mono - for (streamPos = 0; streamPos < compressedSize; streamPos++) { - compressedByte = stream->readByte(); + requestedBytesLeft -= byteCacheSize; + _streamBytesLeft -= byteCacheSize; + + // Fill our byte cache + _stream->read(byteCache, byteCacheSize); + + byteCachePtr = byteCache; - WRITE_BE_UINT16(decompressedData + decompressedPos, audio_3DO_ADP4_DecodeSample(compressedByte >> 4, decoderData.lastSample, decoderData.stepIndex)); - decompressedPos += 2; - WRITE_BE_UINT16(decompressedData + decompressedPos, audio_3DO_ADP4_DecodeSample(compressedByte & 0x0F, decoderData.lastSample, decoderData.stepIndex)); - decompressedPos += 2; + // Mono + while (byteCacheSize) { + compressedByte = *byteCachePtr++; + byteCacheSize--; + + buffer[decodedSamplesCount] = decodeSample(compressedByte >> 4); + decodedSamplesCount++; + buffer[decodedSamplesCount] = decodeSample(compressedByte & 0x0f); + decodedSamplesCount++; } } - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - - if (persistentSpace) { - memcpy(persistentSpace, &decoderData, sizeof(decoderData)); + if (_callerDecoderData) { + // copy caller decoder data back + memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData)); } - // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES. - return makeRawStream(decompressedData, decompressedSize, sampleRate, audioFlags); + return decodedSamplesCount; } +// ============================================================================ static int16 audio_3DO_SDX2_SquareTable[256] = { --32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322, --27848,-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762, --23328,-22898,-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602, --19208,-18818,-18432,-18050,-17672,-17298,-16928,-16562,-16200,-15842, --15488,-15138,-14792,-14450,-14112,-13778,-13448,-13122,-12800,-12482, --12168,-11858,-11552,-11250,-10952,-10658,-10368,-10082, -9800, -9522, - -9248, -8978, -8712, -8450, -8192, -7938, -7688, -7442, -7200, -6962, - -6728, -6498, -6272, -6050, -5832, -5618, -5408, -5202, -5000, -4802, - -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, -3200, -3042, - -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, -1682, - -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722, - -648, -578, -512, -450, -392, -338, -288, -242, -200, -162, - -128, -98, -72, -50, -32, -18, -8, -2, 0, 2, - 8, 18, 32, 50, 72, 98, 128, 162, 200, 242, - 288, 338, 392, 450, 512, 578, 648, 722, 800, 882, - 968, 1058, 1152, 1250, 1352, 1458, 1568, 1682, 1800, 1922, - 2048, 2178, 2312, 2450, 2592, 2738, 2888, 3042, 3200, 3362, - 3528, 3698, 3872, 4050, 4232, 4418, 4608, 4802, 5000, 5202, - 5408, 5618, 5832, 6050, 6272, 6498, 6728, 6962, 7200, 7442, - 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, 9800, 10082, - 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, 13122, - 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562, - 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, - 20808, 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, - 25088, 25538, 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, - 29768, 30258, 30752, 31250, 31752, 32258 + -32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322, + -27848,-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762, + -23328,-22898,-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602, + -19208,-18818,-18432,-18050,-17672,-17298,-16928,-16562,-16200,-15842, + -15488,-15138,-14792,-14450,-14112,-13778,-13448,-13122,-12800,-12482, + -12168,-11858,-11552,-11250,-10952,-10658,-10368,-10082, -9800, -9522, + -9248, -8978, -8712, -8450, -8192, -7938, -7688, -7442, -7200, -6962, + -6728, -6498, -6272, -6050, -5832, -5618, -5408, -5202, -5000, -4802, + -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, -3200, -3042, + -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, -1682, + -1568, -1458, -1352, -1250, -1152, -1058, -968, -882, -800, -722, + -648, -578, -512, -450, -392, -338, -288, -242, -200, -162, + -128, -98, -72, -50, -32, -18, -8, -2, 0, 2, + 8, 18, 32, 50, 72, 98, 128, 162, 200, 242, + 288, 338, 392, 450, 512, 578, 648, 722, 800, 882, + 968, 1058, 1152, 1250, 1352, 1458, 1568, 1682, 1800, 1922, + 2048, 2178, 2312, 2450, 2592, 2738, 2888, 3042, 3200, 3362, + 3528, 3698, 3872, 4050, 4232, 4418, 4608, 4802, 5000, 5202, + 5408, 5618, 5832, 6050, 6272, 6498, 6728, 6962, 7200, 7442, + 7688, 7938, 8192, 8450, 8712, 8978, 9248, 9522, 9800, 10082, + 10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, 13122, + 13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562, + 16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402, + 20808, 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642, + 25088, 25538, 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282, + 29768, 30258, 30752, 31250, 31752, 32258 }; -SeekableAudioStream *make3DO_SDX2Stream(Common::SeekableReadStream *stream, uint32 size, uint16 sampleRate, byte audioFlags, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace) { - int32 streamPos = 0; - int32 compressedSize = size; - int32 decompressedSize = 0; - int32 decompressedPos = 0; +Audio3DO_SDX2_Stream::Audio3DO_SDX2_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace) + : _sampleRate(sampleRate), _stereo(stereo), + _stream(stream, disposeAfterUse) { + + _callerDecoderData = persistentSpace; + memset(&_initialDecoderData, 0, sizeof(_initialDecoderData)); + _initialRead = true; + + reset(); +}; + +void Audio3DO_SDX2_Stream::reset() { + memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData)); + _streamBytesLeft = _stream->size(); + _stream->seek(0); +} + +bool Audio3DO_SDX2_Stream::rewind() { + reset(); + return true; +} + +// Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written +int Audio3DO_SDX2_Stream::readBuffer(int16 *buffer, const int numSamples) { + int8 byteCache[AUDIO_3DO_CACHE_SIZE]; + int8 *byteCachePtr = NULL; + int byteCacheSize = 0; + int requestedBytesLeft = numSamples; // 1 byte per 16-bit sample + int decodedSamplesCount = 0; int8 compressedByte = 0; uint8 squareTableOffset = 0; int16 decodedSample = 0; - audio_3DO_SDX2_PersistentSpace decoderData; - - assert(compressedSize <= stream->size()); + if (endOfData()) + return 0; // no more bytes left - if (audioFlags & Audio::FLAG_UNSIGNED) { - // Unsigned data is not allowed - warning("make3DO_SDX2Stream(): sample data result is expected to be signed"); - return 0; - } - if (!(audioFlags & Audio::FLAG_16BITS)) { - // 8-bit sample data is not allowed - warning("make3DO_SDX2Stream(): sample data result is expected to be 16-bit"); - return 0; - } - if (audioFlags & Audio::FLAG_LITTLE_ENDIAN) { - // LE sample data is not allowed - warning("make3DO_SDX2Stream(): sample data result is expected to be Big Endian"); - return 0; - } - if (audioFlags & Audio::FLAG_STEREO) { - if (compressedSize & 1) { - warning("make3DO_SDX2Stream(): stereo data is uneven size"); - return 0; - } + if (_stereo) { + // We expect numSamples to be even in case of Stereo audio + assert((numSamples & 1) == 0); } - if (persistentSpace) { - memcpy(&decoderData, persistentSpace, sizeof(decoderData)); - } else { - memset(&decoderData, 0, sizeof(decoderData)); + if (_callerDecoderData) { + // copy caller decoder data over + memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData)); + if (_initialRead) { + _initialRead = false; + memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData)); + } } - assert(compressedSize < 0x40000000); // safety check + requestedBytesLeft = numSamples; + if (requestedBytesLeft > _streamBytesLeft) + requestedBytesLeft = _streamBytesLeft; // not enough bytes left - decompressedSize = compressedSize * 2; // 1 byte == 1 16-bit sample - byte *decompressedData = (byte *)malloc(decompressedSize); - assert(decompressedData); + // buffering, so that direct decoding of files and such runs way faster + while (requestedBytesLeft) { + if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) { + byteCacheSize = AUDIO_3DO_CACHE_SIZE; + } else { + byteCacheSize = requestedBytesLeft; + } - if (!(audioFlags & Audio::FLAG_STEREO)) { - // Mono - for (streamPos = 0; streamPos < compressedSize; streamPos++) { - compressedByte = stream->readSByte(); - squareTableOffset = compressedByte + 128; + requestedBytesLeft -= byteCacheSize; + _streamBytesLeft -= byteCacheSize; - if (!(compressedByte & 1)) - decoderData.lastSample1 = 0; + // Fill our byte cache + _stream->read(byteCache, byteCacheSize); - decodedSample = decoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset]; - decoderData.lastSample1 = decodedSample; + byteCachePtr = byteCache; - WRITE_BE_UINT16(decompressedData + decompressedPos, decodedSample); - decompressedPos += 2; - } - - } else { - // Stereo - for (streamPos = 0; streamPos < compressedSize; streamPos++) { - compressedByte = stream->readSByte(); - squareTableOffset = compressedByte + 128; + if (!_stereo) { + // Mono + while (byteCacheSize) { + compressedByte = *byteCachePtr++; + byteCacheSize--; + squareTableOffset = compressedByte + 128; - if (!(streamPos & 1)) { - // First channel if (!(compressedByte & 1)) - decoderData.lastSample1 = 0; + _curDecoderData.lastSample1 = 0; - decodedSample = decoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset]; - decoderData.lastSample1 = decodedSample; - } else { - // Second channel - if (!(compressedByte & 1)) - decoderData.lastSample2 = 0; + decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset]; + _curDecoderData.lastSample1 = decodedSample; - decodedSample = decoderData.lastSample2 + audio_3DO_SDX2_SquareTable[squareTableOffset]; - decoderData.lastSample2 = decodedSample; + buffer[decodedSamplesCount] = decodedSample; + decodedSamplesCount++; + } + } else { + // Stereo + while (byteCacheSize) { + compressedByte = *byteCachePtr++; + byteCacheSize--; + squareTableOffset = compressedByte + 128; + + if (!(decodedSamplesCount & 1)) { + // First channel + if (!(compressedByte & 1)) + _curDecoderData.lastSample1 = 0; + + decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset]; + _curDecoderData.lastSample1 = decodedSample; + } else { + // Second channel + if (!(compressedByte & 1)) + _curDecoderData.lastSample2 = 0; + + decodedSample = _curDecoderData.lastSample2 + audio_3DO_SDX2_SquareTable[squareTableOffset]; + _curDecoderData.lastSample2 = decodedSample; + } + + buffer[decodedSamplesCount] = decodedSample; + decodedSamplesCount++; } - - WRITE_BE_UINT16(decompressedData + decompressedPos, decodedSample); - decompressedPos += 2; } } - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; + if (_callerDecoderData) { + // copy caller decoder data back + memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData)); + } - if (persistentSpace) { - memcpy(persistentSpace, &decoderData, sizeof(decoderData)); + return decodedSamplesCount; +} + +RewindableAudioStream *make3DO_SDX2AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace) { + if (stereo) { + if (stream->size() & 1) { + warning("make3DO_SDX2Stream(): stereo data is uneven size"); + return 0; + } + } + + if (audioLengthMSecsPtr) { + // Caller requires the milliseconds of audio + uint32 audioLengthMSecs = stream->size() * 1000 / sampleRate; // 1 byte == 1 16-bit sample + if (stereo) { + audioLengthMSecs /= 2; + } + *audioLengthMSecsPtr = audioLengthMSecs; } - // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES. - return makeRawStream(decompressedData, decompressedSize, sampleRate, audioFlags); + return new Audio3DO_SDX2_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace); } } // End of namespace Audio diff --git a/audio/decoders/3do.h b/audio/decoders/3do.h index 4d8412a4cb..7524358543 100644 --- a/audio/decoders/3do.h +++ b/audio/decoders/3do.h @@ -31,6 +31,10 @@ #include "common/scummsys.h" #include "common/types.h" +#include "common/substream.h" + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" namespace Common { class SeekableReadStream; @@ -40,6 +44,10 @@ namespace Audio { class SeekableAudioStream; +// amount of bytes to be used within the decoder classes as buffers +#define AUDIO_3DO_CACHE_SIZE 1024 + +// persistent spaces struct audio_3DO_ADP4_PersistentSpace { int16 lastSample; int16 stepIndex; @@ -50,25 +58,78 @@ struct audio_3DO_SDX2_PersistentSpace { int16 lastSample2; }; +class Audio3DO_ADP4_Stream : public RewindableAudioStream { +public: + Audio3DO_ADP4_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace); + +protected: + const uint16 _sampleRate; + const bool _stereo; + + Common::DisposablePtr _stream; + int32 _streamBytesLeft; + + void reset(); + bool rewind(); + bool endOfData() const { return (_stream->pos() >= _stream->size()); } + bool isStereo() const { return _stereo; } + int getRate() const { return _sampleRate; } + + int readBuffer(int16 *buffer, const int numSamples); + + bool _initialRead; + audio_3DO_ADP4_PersistentSpace *_callerDecoderData; + audio_3DO_ADP4_PersistentSpace _initialDecoderData; + audio_3DO_ADP4_PersistentSpace _curDecoderData; + +private: + int16 decodeSample(byte compressedNibble); +}; + +class Audio3DO_SDX2_Stream : public RewindableAudioStream { +public: + Audio3DO_SDX2_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpacePtr); + +protected: + const uint16 _sampleRate; + const bool _stereo; + + Common::DisposablePtr _stream; + int32 _streamBytesLeft; + + void reset(); + bool rewind(); + bool endOfData() const { return (_stream->pos() >= _stream->size()); } + bool isStereo() const { return _stereo; } + int getRate() const { return _sampleRate; } + + int readBuffer(int16 *buffer, const int numSamples); + + bool _initialRead; + audio_3DO_SDX2_PersistentSpace *_callerDecoderData; + audio_3DO_SDX2_PersistentSpace _initialDecoderData; + audio_3DO_SDX2_PersistentSpace _curDecoderData; +}; /** * Try to decode 3DO ADP4 data from the given seekable stream and create a SeekableAudioStream * from that data. * - * @param stream the SeekableReadStream from which to read the 3DO ADP4 data - * @size how many bytes to read from stream + * @param stream the SeekableReadStream from which to read the 3DO SDX2 data * @sampleRate sample rate - * @audioFlags flags, that specify the type of output - * @param disposeAfterUse whether to delete the stream after use + * @stereo if it's stereo or mono + * @audioLengthMSecsPtr pointer to a uint32 variable, that is supposed to get the length of the audio in milliseconds + * @disposeAfterUse disposeAfterUse whether to delete the stream after use + * @persistentSpacePtr pointer to the persistent space structure * @return a new SeekableAudioStream, or NULL, if an error occurred */ -SeekableAudioStream *make3DO_ADP4Stream( +RewindableAudioStream *make3DO_ADP4AudioStream( Common::SeekableReadStream *stream, - uint32 size, uint16 sampleRate, - byte audioFlags, - DisposeAfterUse::Flag disposeAfterUse, - audio_3DO_ADP4_PersistentSpace *persistentSpace = NULL + bool stereo, + uint32 *audioLengthMSecsPtr = NULL, // returns the audio length in milliseconds + DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES, + audio_3DO_ADP4_PersistentSpace *persistentSpacePtr = NULL ); /** @@ -76,19 +137,20 @@ SeekableAudioStream *make3DO_ADP4Stream( * from that data. * * @param stream the SeekableReadStream from which to read the 3DO SDX2 data - * @size how many bytes to read from stream * @sampleRate sample rate - * @audioFlags flags, that specify the type of output - * @param disposeAfterUse whether to delete the stream after use + * @stereo if it's stereo or mono + * @audioLengthMSecsPtr pointer to a uint32 variable, that is supposed to get the length of the audio in milliseconds + * @disposeAfterUse disposeAfterUse whether to delete the stream after use + * @persistentSpacePtr pointer to the persistent space structure * @return a new SeekableAudioStream, or NULL, if an error occurred */ -SeekableAudioStream *make3DO_SDX2Stream( +RewindableAudioStream *make3DO_SDX2AudioStream( Common::SeekableReadStream *stream, - uint32 size, uint16 sampleRate, - byte audioFlags, - DisposeAfterUse::Flag disposeAfterUse, - audio_3DO_SDX2_PersistentSpace *persistentSpace = NULL + bool stereo, + uint32 *audioLengthMSecsPtr = NULL, // returns the audio length in milliseconds + DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES, + audio_3DO_SDX2_PersistentSpace *persistentSpacePtr = NULL ); } // End of namespace Audio diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp index 1fc811973f..3a5849f6fd 100644 --- a/audio/decoders/aiff.cpp +++ b/audio/decoders/aiff.cpp @@ -35,6 +35,7 @@ #include "audio/decoders/aiff.h" #include "audio/decoders/raw.h" +#include "audio/decoders/3do.h" namespace Audio { @@ -70,7 +71,13 @@ static const uint32 kVersionAIFC = MKTAG('A', 'I', 'F', 'C'); // Codecs static const uint32 kCodecPCM = MKTAG('N', 'O', 'N', 'E'); // very original -SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { +// temporary Wrapper +// TODO: adjust all calling code to use makeAIFFAudioStream() and dynamic_cast +SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { + return dynamic_cast(makeAIFFAudioStream(stream, disposeAfterUse)); +} + +AudioStream *makeAIFFAudioStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { if (stream->readUint32BE() != MKTAG('F', 'O', 'R', 'M')) { warning("makeAIFFStream: No 'FORM' header"); @@ -185,6 +192,8 @@ SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeA return 0; } + bool stereo = channels > 1 ? true : false; + switch (codec) { case kCodecPCM: case MKTAG('t', 'w', 'o', 's'): @@ -193,7 +202,7 @@ SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeA byte rawFlags = 0; if (bitsPerSample == 16) rawFlags |= Audio::FLAG_16BITS; - if (channels == 2) + if (stereo) rawFlags |= Audio::FLAG_STEREO; if (codec == MKTAG('s', 'o', 'w', 't')) rawFlags |= Audio::FLAG_LITTLE_ENDIAN; @@ -211,10 +220,16 @@ SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, DisposeA // (But hopefully never needed) warning("Unhandled AIFF-C QDM2 compression"); break; + case MKTAG('A', 'D', 'P', '4'): + // ADP4 on 3DO + return make3DO_ADP4AudioStream(dataStream, rate, stereo); + case MKTAG('S', 'D', 'X', '2'): + // SDX2 on 3DO + return make3DO_SDX2AudioStream(dataStream, rate, stereo); default: warning("Unhandled AIFF-C compression tag '%s'", tag2str(codec)); } - + delete dataStream; return 0; } diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h index 5f21fc9bdf..14bfd05ad9 100644 --- a/audio/decoders/aiff.h +++ b/audio/decoders/aiff.h @@ -42,6 +42,7 @@ class SeekableReadStream; namespace Audio { +class AudioStream; class SeekableAudioStream; /** @@ -56,6 +57,10 @@ SeekableAudioStream *makeAIFFStream( Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse); +AudioStream *makeAIFFAudioStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse); + } // End of namespace Audio #endif -- cgit v1.2.3