[Scummvm-git-logs] scummvm master -> b76652120b5b57a4823a0d8c6de4b04e2f9a22d3
sev-
sev at scummvm.org
Mon Aug 24 12:21:04 UTC 2020
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
b76652120b AUDIO: Separate the XA ADPCM decoder from the PSX video decoder
Commit: b76652120b5b57a4823a0d8c6de4b04e2f9a22d3
https://github.com/scummvm/scummvm/commit/b76652120b5b57a4823a0d8c6de4b04e2f9a22d3
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2020-08-24T14:21:00+02:00
Commit Message:
AUDIO: Separate the XA ADPCM decoder from the PSX video decoder
Changed paths:
audio/decoders/adpcm.cpp
audio/decoders/adpcm.h
audio/decoders/adpcm_intern.h
video/psx_decoder.cpp
video/psx_decoder.h
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp
index e87661dbbb..1f0ac3b6cf 100644
--- a/audio/decoders/adpcm.cpp
+++ b/audio/decoders/adpcm.cpp
@@ -39,6 +39,8 @@ namespace Audio {
//
// In addition, also MS IMA ADPCM is supported. See
// <http://wiki.multimedia.cx/index.php?title=Microsoft_IMA_ADPCM>.
+//
+// XA ADPCM support is based on FFmpeg/libav
ADPCMStream::ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
: _stream(stream, disposeAfterUse),
@@ -119,6 +121,106 @@ int16 Oki_ADPCMStream::decodeOKI(byte code) {
#pragma mark -
+int XA_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples;
+ byte *data = new byte[128];
+
+ for (samples = 0; samples < numSamples && !endOfData(); samples++) {
+ if (_decodedSampleCount == 0) {
+ uint32 bytesLeft = _stream->size() - _stream->pos();
+ if (bytesLeft < 128) {
+ _stream->skip(bytesLeft);
+ memset(&buffer[samples], 0, (numSamples - samples) * sizeof(uint16));
+ samples = numSamples;
+ break;
+ }
+ _stream->read(data, 128);
+ decodeXA(data);
+ _decodedSampleIndex = 0;
+ }
+
+ // _decodedSamples acts as a FIFO of depth 2 or 4;
+ buffer[samples] = _decodedSamples[_decodedSampleIndex++];
+ _decodedSampleCount--;
+ }
+
+ delete[] data;
+ return samples;
+}
+
+static const int s_xaTable[5][2] = {
+ { 0, 0 },
+ { 60, 0 },
+ { 115, -52 },
+ { 98, -55 },
+ { 122, -60 }
+};
+
+void XA_ADPCMStream::decodeXA(const byte *src) {
+ int16 *leftChannel = _decodedSamples;
+ int16 *rightChannel = _decodedSamples + 1;
+
+ for (int i = 0; i < 4; i++) {
+ int shift = 12 - (src[4 + i * 2] & 0xf);
+ int filter = src[4 + i * 2] >> 4;
+ int f0 = s_xaTable[filter][0];
+ int f1 = s_xaTable[filter][1];
+ int16 s_1 = _status.ima_ch[0].sample[0];
+ int16 s_2 = _status.ima_ch[0].sample[1];
+
+ for (int j = 0; j < 28; j++) {
+ byte d = src[16 + i + j * 4];
+ int t = (int8)(d << 4) >> 4;
+ int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
+ s_2 = s_1;
+ s_1 = CLIP<int>(s, -32768, 32767);
+ *leftChannel = s_1;
+ leftChannel += _channels;
+ _decodedSampleCount++;
+ }
+
+ if (_channels == 2) {
+ _status.ima_ch[0].sample[0] = s_1;
+ _status.ima_ch[0].sample[1] = s_2;
+ s_1 = _status.ima_ch[1].sample[0];
+ s_2 = _status.ima_ch[1].sample[1];
+ }
+
+ shift = 12 - (src[5 + i * 2] & 0xf);
+ filter = src[5 + i * 2] >> 4;
+ f0 = s_xaTable[filter][0];
+ f1 = s_xaTable[filter][1];
+
+ for (int j = 0; j < 28; j++) {
+ byte d = src[16 + i + j * 4];
+ int t = (int8)d >> 4;
+ int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
+ s_2 = s_1;
+ s_1 = CLIP<int>(s, -32768, 32767);
+
+ if (_channels == 2) {
+ *rightChannel = s_1;
+ rightChannel += 2;
+ } else {
+ *leftChannel++ = s_1;
+ }
+ _decodedSampleCount++;
+ }
+
+ if (_channels == 2) {
+ _status.ima_ch[1].sample[0] = s_1;
+ _status.ima_ch[1].sample[1] = s_2;
+ } else {
+ _status.ima_ch[0].sample[0] = s_1;
+ _status.ima_ch[0].sample[1] = s_2;
+ }
+ }
+}
+
+
+#pragma mark -
+
+
int DVI_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
int samples;
byte data;
@@ -474,6 +576,8 @@ SeekableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, Dispose
return new Apple_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
case kADPCMDK3:
return new DK3_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
+ case kADPCMXA:
+ return new XA_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
default:
error("Unsupported ADPCM encoding");
break;
@@ -501,6 +605,7 @@ PacketizedAudioStream *makePacketizedADPCMStream(ADPCMType type, int rate, int c
// Filter out types we can't support (they're not fully stateless)
switch (type) {
case kADPCMOki:
+ case kADPCMXA:
case kADPCMDVI:
return 0;
default:
diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h
index 0f0d83c3c2..4c75915ea8 100644
--- a/audio/decoders/adpcm.h
+++ b/audio/decoders/adpcm.h
@@ -59,7 +59,8 @@ enum ADPCMType {
kADPCMMS, // Microsoft ADPCM
kADPCMDVI, // Intel DVI IMA ADPCM
kADPCMApple, // Apple QuickTime IMA ADPCM
- kADPCMDK3 // Duck DK3 IMA ADPCM
+ kADPCMDK3, // Duck DK3 IMA ADPCM
+ kADPCMXA // XA ADPCM
};
/**
@@ -88,7 +89,7 @@ SeekableAudioStream *makeADPCMStream(
* packets as individual AudioStreams like returned by makeADPCMStream.
*
* Due to the ADPCM types not necessarily supporting stateless
- * streaming, OKI and DVI are not supported by this function
+ * streaming, OKI, XA and DVI are not supported by this function
* and will return NULL.
*
* @param type the compression type used
diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h
index 889b0a8118..a331cede5a 100644
--- a/audio/decoders/adpcm_intern.h
+++ b/audio/decoders/adpcm_intern.h
@@ -54,6 +54,7 @@ protected:
struct {
int32 last;
int32 stepIndex;
+ int16 sample[2];
} ima_ch[2];
} _status;
@@ -97,6 +98,24 @@ private:
int16 _decodedSamples[2];
};
+class XA_ADPCMStream : public ADPCMStream {
+public:
+ XA_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
+ : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { _decodedSampleCount = 0; }
+
+ virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
+
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+
+protected:
+ void decodeXA(const byte *src);
+
+private:
+ uint8 _decodedSampleCount;
+ uint8 _decodedSampleIndex;
+ int16 _decodedSamples[28 * 2 * 4];
+};
+
class Ima_ADPCMStream : public ADPCMStream {
protected:
int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
index ef42a72873..48de547f48 100644
--- a/video/psx_decoder.cpp
+++ b/video/psx_decoder.cpp
@@ -20,11 +20,11 @@
*
*/
-// PlayStation Stream demuxer and XA audio decoder based on FFmpeg/libav
+// PlayStation Stream demuxer based on FFmpeg/libav
// MDEC video emulation based on http://kenai.com/downloads/jpsxdec/Old/PlayStation1_STR_format1-00.txt
#include "audio/audiostream.h"
-#include "audio/decoders/raw.h"
+#include "audio/decoders/adpcm.h"
#include "common/bitstream.h"
#include "common/huffman.h"
#include "common/stream.h"
@@ -299,14 +299,6 @@ Common::SeekableReadStream *PSXStreamDecoder::readSector() {
#define AUDIO_DATA_CHUNK_SIZE 2304
#define AUDIO_DATA_SAMPLE_COUNT 4032
-static const int s_xaTable[5][2] = {
- { 0, 0 },
- { 60, 0 },
- { 115, -52 },
- { 98, -55 },
- { 122, -60 }
-};
-
PSXStreamDecoder::PSXAudioTrack::PSXAudioTrack(Common::SeekableReadStream *sector, Audio::Mixer::SoundType soundType) :
AudioTrack(soundType) {
assert(sector);
@@ -314,11 +306,9 @@ PSXStreamDecoder::PSXAudioTrack::PSXAudioTrack(Common::SeekableReadStream *secto
sector->seek(19);
byte format = sector->readByte();
- bool stereo = (format & (1 << 0)) != 0;
- uint rate = (format & (1 << 2)) ? 18900 : 37800;
- _audStream = Audio::makeQueuingAudioStream(rate, stereo);
-
- memset(&_adpcmStatus, 0, sizeof(_adpcmStatus));
+ _stereo = (format & (1 << 0)) != 0;
+ _rate = (format & (1 << 2)) ? 18900 : 37800;
+ _audStream = Audio::makeQueuingAudioStream(_rate, _stereo);
}
PSXStreamDecoder::PSXAudioTrack::~PSXAudioTrack() {
@@ -334,86 +324,16 @@ void PSXStreamDecoder::PSXAudioTrack::queueAudioFromSector(Common::SeekableReadS
sector->seek(24);
- // This XA audio is different (yet similar) from normal XA audio! Watch out!
- // TODO: It's probably similar enough to normal XA that we can merge it somehow...
- // TODO: RTZ PSX needs the same audio code in a regular AudioStream class. Probably
- // will do something similar to QuickTime and creating a base class 'ISOMode2Parser'
- // or something similar.
- byte *buf = new byte[AUDIO_DATA_CHUNK_SIZE];
- sector->read(buf, AUDIO_DATA_CHUNK_SIZE);
-
- int channels = _audStream->isStereo() ? 2 : 1;
- int16 *dst = new int16[AUDIO_DATA_SAMPLE_COUNT];
- int16 *leftChannel = dst;
- int16 *rightChannel = dst + 1;
-
- for (byte *src = buf; src < buf + AUDIO_DATA_CHUNK_SIZE; src += 128) {
- for (int i = 0; i < 4; i++) {
- int shift = 12 - (src[4 + i * 2] & 0xf);
- int filter = src[4 + i * 2] >> 4;
- int f0 = s_xaTable[filter][0];
- int f1 = s_xaTable[filter][1];
- int16 s_1 = _adpcmStatus[0].sample[0];
- int16 s_2 = _adpcmStatus[0].sample[1];
-
- for (int j = 0; j < 28; j++) {
- byte d = src[16 + i + j * 4];
- int t = (int8)(d << 4) >> 4;
- int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
- s_2 = s_1;
- s_1 = CLIP<int>(s, -32768, 32767);
- *leftChannel = s_1;
- leftChannel += channels;
- }
-
- if (channels == 2) {
- _adpcmStatus[0].sample[0] = s_1;
- _adpcmStatus[0].sample[1] = s_2;
- s_1 = _adpcmStatus[1].sample[0];
- s_2 = _adpcmStatus[1].sample[1];
- }
-
- shift = 12 - (src[5 + i * 2] & 0xf);
- filter = src[5 + i * 2] >> 4;
- f0 = s_xaTable[filter][0];
- f1 = s_xaTable[filter][1];
-
- for (int j = 0; j < 28; j++) {
- byte d = src[16 + i + j * 4];
- int t = (int8)d >> 4;
- int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
- s_2 = s_1;
- s_1 = CLIP<int>(s, -32768, 32767);
-
- if (channels == 2) {
- *rightChannel = s_1;
- rightChannel += 2;
- } else {
- *leftChannel++ = s_1;
- }
- }
+ // Read the specified sector into memory
+ Common::SeekableReadStream *compressedAudioStream = sector->readStream(AUDIO_DATA_CHUNK_SIZE);
- if (channels == 2) {
- _adpcmStatus[1].sample[0] = s_1;
- _adpcmStatus[1].sample[1] = s_2;
- } else {
- _adpcmStatus[0].sample[0] = s_1;
- _adpcmStatus[0].sample[1] = s_2;
- }
- }
+ Audio::SeekableAudioStream *audioStream = Audio::makeADPCMStream(compressedAudioStream, DisposeAfterUse::YES, AUDIO_DATA_CHUNK_SIZE, Audio::kADPCMXA, _rate, _stereo ? 2 : 1);
+ if (audioStream) {
+ _audStream->queueAudioStream(audioStream, DisposeAfterUse::YES);
+ } else {
+ // in case there was an error
+ delete compressedAudioStream;
}
-
- int flags = Audio::FLAG_16BITS;
-
- if (_audStream->isStereo())
- flags |= Audio::FLAG_STEREO;
-
-#ifdef SCUMM_LITTLE_ENDIAN
- flags |= Audio::FLAG_LITTLE_ENDIAN;
-#endif
-
- _audStream->queueBuffer((byte *)dst, AUDIO_DATA_SAMPLE_COUNT * 2, DisposeAfterUse::YES, flags);
- delete[] buf;
}
Audio::AudioStream *PSXStreamDecoder::PSXAudioTrack::getAudioStream() const {
diff --git a/video/psx_decoder.h b/video/psx_decoder.h
index 183b6da317..bf85fb11b1 100644
--- a/video/psx_decoder.h
+++ b/video/psx_decoder.h
@@ -140,11 +140,9 @@ private:
Audio::QueuingAudioStream *_audStream;
- struct ADPCMStatus {
- int16 sample[2];
- } _adpcmStatus[2];
-
bool _endOfTrack;
+ bool _stereo;
+ uint _rate;
};
CDSpeed _speed;
More information about the Scummvm-git-logs
mailing list