From 8987d9a889fb908b038e5615baab5403adf3073e Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Mon, 2 Jan 2017 11:13:11 -0600 Subject: SCI32: Enable playback of stereo audio --- engines/sci/sound/audio32.cpp | 10 ++---- engines/sci/sound/decoders/sol.cpp | 72 +++++++++++++++++++++++++------------ engines/sci/sound/decoders/sol.h | 4 +-- engines/sci/video/robot_decoder.cpp | 4 +-- 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp index d5a7ae14b8..ca2402c859 100644 --- a/engines/sci/sound/audio32.cpp +++ b/engines/sci/sound/audio32.cpp @@ -159,9 +159,7 @@ int Audio32::writeAudioInternal(Audio::AudioStream *const sourceStream, Audio::R // mono, in which case we need to request half // as many samples from the mono stream and let // the converter double them for stereo output - if (!sourceStream->isStereo()) { - samplesToRead >>= 1; - } + samplesToRead >>= 1; int samplesWritten = 0; @@ -182,12 +180,10 @@ int Audio32::writeAudioInternal(Audio::AudioStream *const sourceStream, Audio::R samplesToRead -= loopSamplesWritten; samplesWritten += loopSamplesWritten; - targetBuffer += loopSamplesWritten << 1; + targetBuffer += loopSamplesWritten << (sourceStream->isStereo() ? 0 : 1); } while (loop && samplesToRead > 0); - if (!sourceStream->isStereo()) { - samplesWritten <<= 1; - } + samplesWritten <<= 1; return samplesWritten; } diff --git a/engines/sci/sound/decoders/sol.cpp b/engines/sci/sound/decoders/sol.cpp index ee1ba35406..2dbe98c9e0 100644 --- a/engines/sci/sound/decoders/sol.cpp +++ b/engines/sci/sound/decoders/sol.cpp @@ -49,33 +49,43 @@ static const uint16 tableDPCM16[128] = { static const byte tableDPCM8[8] = { 0, 1, 2, 3, 6, 10, 15, 21 }; +/** + * Decompresses one channel of 16-bit DPCM compressed audio. + */ +static void deDPCM16Channel(int16 *out, int16 &sample, uint8 delta) { + if (delta & 0x80) { + sample -= tableDPCM16[delta & 0x7f]; + } else { + sample += tableDPCM16[delta]; + } + sample = CLIP(sample, -32768, 32767); + *out = TO_LE_16(sample); +} + /** * Decompresses 16-bit DPCM compressed audio. Each byte read * outputs one sample into the decompression buffer. */ -static void deDPCM16(int16 *out, Common::ReadStream &audioStream, const uint32 numBytes, int16 &sample) { +static void deDPCM16Mono(int16 *out, Common::ReadStream &audioStream, const uint32 numBytes, int16 &sample) { for (uint32 i = 0; i < numBytes; ++i) { const uint8 delta = audioStream.readByte(); - if (delta & 0x80) { - sample -= tableDPCM16[delta & 0x7f]; - } else { - sample += tableDPCM16[delta]; - } - sample = CLIP(sample, -32768, 32767); - *out++ = TO_LE_16(sample); + deDPCM16Channel(out++, sample, delta); } } -void deDPCM16(int16 *out, const byte *in, const uint32 numBytes, int16 &sample) { +// Used by Robot +void deDPCM16Mono(int16 *out, const byte *in, const uint32 numBytes, int16 &sample) { for (uint32 i = 0; i < numBytes; ++i) { const uint8 delta = *in++; - if (delta & 0x80) { - sample -= tableDPCM16[delta & 0x7f]; - } else { - sample += tableDPCM16[delta]; - } - sample = CLIP(sample, -32768, 32767); - *out++ = TO_LE_16(sample); + deDPCM16Channel(out++, sample, delta); + } +} + +static void deDPCM16Stereo(int16 *out, Common::ReadStream &audioStream, const uint32 numBytes, int16 &sampleL, int16 &sampleR) { + assert((numBytes % 2) == 0); + for (uint32 i = 0; i < numBytes / 2; ++i) { + deDPCM16Channel(out++, sampleL, audioStream.readByte()); + deDPCM16Channel(out++, sampleR, audioStream.readByte()); } } @@ -98,7 +108,7 @@ 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. */ -static void deDPCM8(int16 *out, Common::ReadStream &audioStream, uint32 numBytes, uint8 &sample) { +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); @@ -106,6 +116,14 @@ static void deDPCM8(int16 *out, Common::ReadStream &audioStream, uint32 numBytes } } +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); + } +} + # pragma mark - template @@ -120,9 +138,9 @@ SOLStream::SOLStream(Common::SeekableReadStream *stream, const D // carried values for each channel separately. See // 60900.aud from Lighthouse for an example stereo file if (S16BIT) { - _dpcmCarry16 = 0; + _dpcmCarry16.l = _dpcmCarry16.r = 0; } else { - _dpcmCarry8 = 0x80; + _dpcmCarry8.l = _dpcmCarry8.r = 0x80; } const uint8 compressionRatio = 2; @@ -143,9 +161,9 @@ bool SOLStream::seek(const Audio::Timestamp &where) { } if (S16BIT) { - _dpcmCarry16 = 0; + _dpcmCarry16.l = _dpcmCarry16.r = 0; } else { - _dpcmCarry8 = 0x80; + _dpcmCarry8.l = _dpcmCarry8.r = 0x80; } return _stream->seek(_dataOffset, SEEK_SET); @@ -171,9 +189,17 @@ int SOLStream::readBuffer(int16 *buffer, const int numSamples) { } if (S16BIT) { - deDPCM16(buffer, *_stream, bytesToRead, _dpcmCarry16); + if (STEREO) { + deDPCM16Stereo(buffer, *_stream, bytesToRead, _dpcmCarry16.l, _dpcmCarry16.r); + } else { + deDPCM16Mono(buffer, *_stream, bytesToRead, _dpcmCarry16.l); + } } else { - deDPCM8(buffer, *_stream, bytesToRead, _dpcmCarry8); + if (STEREO) { + deDPCM8Stereo(buffer, *_stream, bytesToRead, _dpcmCarry8.l, _dpcmCarry8.r); + } else { + deDPCM8Mono(buffer, *_stream, bytesToRead, _dpcmCarry8.l); + } } const int samplesRead = bytesToRead * samplesPerByte; diff --git a/engines/sci/sound/decoders/sol.h b/engines/sci/sound/decoders/sol.h index 1046d0b213..31914c0926 100644 --- a/engines/sci/sound/decoders/sol.h +++ b/engines/sci/sound/decoders/sol.h @@ -61,8 +61,8 @@ private: * The last sample from the previous DPCM decode. */ union { - int16 _dpcmCarry16; - uint8 _dpcmCarry8; + struct { int16 l; int16 r; } _dpcmCarry16; + struct { uint8 l; uint8 r; } _dpcmCarry8; }; /** diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index 446b986581..296fdf8db2 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -43,7 +43,7 @@ namespace Sci { #pragma mark RobotAudioStream -extern void deDPCM16(int16 *out, const byte *in, const uint32 numBytes, int16 &sample); +extern void deDPCM16Mono(int16 *out, const byte *in, const uint32 numBytes, int16 &sample); RobotAudioStream::RobotAudioStream(const int32 bufferSize) : _loopBuffer((byte *)malloc(bufferSize)), @@ -181,7 +181,7 @@ void RobotAudioStream::fillRobotBuffer(const RobotAudioPacket &packet, const int } int16 carry = 0; - deDPCM16((int16 *)_decompressionBuffer, packet.data, packet.dataSize, carry); + deDPCM16Mono((int16 *)_decompressionBuffer, packet.data, packet.dataSize, carry); _decompressionBufferPosition = packet.position; } -- cgit v1.2.3