From 12afcaec49caf4dad5af9fc46af607044bd4b82f Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Fri, 16 Jun 2017 16:01:23 -0500 Subject: SCI32: Support old-format 8-bit DPCM coding for SCI2 --- engines/sci/sound/decoders/sol.cpp | 66 ++++++++++++++++++++++---------------- engines/sci/sound/decoders/sol.h | 2 +- 2 files changed, 40 insertions(+), 28 deletions(-) (limited to 'engines/sci/sound') diff --git a/engines/sci/sound/decoders/sol.cpp b/engines/sci/sound/decoders/sol.cpp index 4b366ce9f4..290898fabf 100644 --- a/engines/sci/sound/decoders/sol.cpp +++ b/engines/sci/sound/decoders/sol.cpp @@ -102,10 +102,11 @@ static void deDPCM16Stereo(int16 *out, Common::ReadStream &audioStream, const ui * Decompresses one half of an 8-bit DPCM compressed audio * byte. */ +template static void deDPCM8Nibble(int16 *out, uint8 &sample, uint8 delta) { const uint8 lastSample = sample; if (delta & 8) { - sample -= tableDPCM8[delta & 7]; + sample -= tableDPCM8[OLD ? (7 - (delta & 7)) : (delta & 7)]; } else { sample += tableDPCM8[delta & 7]; } @@ -116,26 +117,27 @@ static void deDPCM8Nibble(int16 *out, uint8 &sample, uint8 delta) { * Decompresses 8-bit DPCM compressed audio. Each byte read * outputs two samples into the decompression buffer. */ +template static void deDPCM8Mono(int16 *out, Common::ReadStream &audioStream, uint32 numBytes, uint8 &sample) { for (uint32 i = 0; i < numBytes; ++i) { const uint8 delta = audioStream.readByte(); - deDPCM8Nibble(out++, sample, delta >> 4); - deDPCM8Nibble(out++, sample, delta & 0xf); + deDPCM8Nibble(out++, sample, delta >> 4); + deDPCM8Nibble(out++, sample, delta & 0xf); } } static void deDPCM8Stereo(int16 *out, Common::ReadStream &audioStream, uint32 numBytes, uint8 &sampleL, uint8 &sampleR) { for (uint32 i = 0; i < numBytes; ++i) { const uint8 delta = audioStream.readByte(); - deDPCM8Nibble(out++, sampleL, delta >> 4); - deDPCM8Nibble(out++, sampleR, delta & 0xf); + deDPCM8Nibble(out++, sampleL, delta >> 4); + deDPCM8Nibble(out++, sampleR, delta & 0xf); } } # pragma mark - -template -SOLStream::SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const uint16 sampleRate, const int32 rawDataSize) : +template +SOLStream::SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const uint16 sampleRate, const int32 rawDataSize) : _stream(stream, disposeAfterUse), _sampleRate(sampleRate), // SSCI aligns the size of SOL data to 32 bits @@ -152,8 +154,8 @@ SOLStream::SOLStream(Common::SeekableReadStream *stream, const D _length = Audio::Timestamp((_rawDataSize * compressionRatio * 1000) / (_sampleRate * numChannels * bytesPerSample), 60); } -template -bool SOLStream::seek(const Audio::Timestamp &where) { +template +bool SOLStream::seek(const Audio::Timestamp &where) { if (where != 0) { // In order to seek in compressed SOL files, all // previous bytes must be known since it uses @@ -172,13 +174,13 @@ bool SOLStream::seek(const Audio::Timestamp &where) { return _stream->seek(0, SEEK_SET); } -template -Audio::Timestamp SOLStream::getLength() const { +template +Audio::Timestamp SOLStream::getLength() const { return _length; } -template -int SOLStream::readBuffer(int16 *buffer, const int numSamples) { +template +int SOLStream::readBuffer(int16 *buffer, const int numSamples) { // Reading an odd number of 8-bit samples will result in a loss of samples // since one byte represents two samples and we do not store the second // nibble in this case; it should never happen in reality @@ -200,8 +202,10 @@ int SOLStream::readBuffer(int16 *buffer, const int numSamples) { } else { if (STEREO) { deDPCM8Stereo(buffer, *_stream, bytesToRead, _dpcmCarry8.l, _dpcmCarry8.r); + } else if (OLDDPCM8) { + deDPCM8Mono(buffer, *_stream, bytesToRead, _dpcmCarry8.l); } else { - deDPCM8Mono(buffer, *_stream, bytesToRead, _dpcmCarry8.l); + deDPCM8Mono(buffer, *_stream, bytesToRead, _dpcmCarry8.l); } } @@ -209,23 +213,23 @@ int SOLStream::readBuffer(int16 *buffer, const int numSamples) { return samplesRead; } -template -bool SOLStream::isStereo() const { +template +bool SOLStream::isStereo() const { return STEREO; } -template -int SOLStream::getRate() const { +template +int SOLStream::getRate() const { return _sampleRate; } -template -bool SOLStream::endOfData() const { +template +bool SOLStream::endOfData() const { return _stream->eos() || _stream->pos() >= _rawDataSize; } -template -bool SOLStream::rewind() { +template +bool SOLStream::rewind() { return seek(0); } @@ -243,7 +247,7 @@ Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, Di return nullptr; } - const uint8 headerSize = header[1] + /* resource header */ 2; + const uint8 headerSize = header[1] + kResourceHeaderSize; const uint16 sampleRate = stream->readUint16LE(); const byte flags = stream->readByte(); const uint32 dataSize = stream->readUint32LE(); @@ -252,13 +256,21 @@ Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, Di if (flags & kCompressed) { if (flags & kStereo && flags & k16Bit) { - return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); } else if (flags & kStereo) { - return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + if (getSciVersion() < SCI_VERSION_2_1_EARLY) { + error("SCI2 and earlier did not support stereo SOL audio"); + } + + return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); } else if (flags & k16Bit) { - return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); } else { - return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + if (getSciVersion() < SCI_VERSION_2_1_EARLY) { + return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + } else { + return new SOLStream(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, sampleRate, dataSize); + } } } diff --git a/engines/sci/sound/decoders/sol.h b/engines/sci/sound/decoders/sol.h index 80a2181889..1141132365 100644 --- a/engines/sci/sound/decoders/sol.h +++ b/engines/sci/sound/decoders/sol.h @@ -33,7 +33,7 @@ enum SOLFlags { kStereo = 16 }; -template +template class SOLStream : public Audio::SeekableAudioStream { private: /** -- cgit v1.2.3