aboutsummaryrefslogtreecommitdiff
path: root/audio/decoders/qdm2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'audio/decoders/qdm2.cpp')
-rw-r--r--audio/decoders/qdm2.cpp116
1 files changed, 53 insertions, 63 deletions
diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp
index a178c363b5..19b30217e9 100644
--- a/audio/decoders/qdm2.cpp
+++ b/audio/decoders/qdm2.cpp
@@ -28,10 +28,13 @@
#ifdef AUDIO_QDM2_H
#include "audio/audiostream.h"
+#include "audio/decoders/codec.h"
#include "audio/decoders/qdm2data.h"
+#include "audio/decoders/raw.h"
#include "common/array.h"
#include "common/debug.h"
+#include "common/math.h"
#include "common/stream.h"
#include "common/textconsole.h"
@@ -150,19 +153,14 @@ struct RDFTContext {
FFTContext fft;
};
-class QDM2Stream : public AudioStream {
+class QDM2Stream : public Codec {
public:
- QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
+ QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData);
~QDM2Stream();
- bool isStereo() const { return _channels == 2; }
- bool endOfData() const { return _stream->pos() >= _stream->size() && _outputSamples.size() == 0 && _subPacket == 0; }
- int getRate() const { return _sampleRate; }
- int readBuffer(int16 *buffer, const int numSamples);
+ AudioStream *decodeFrame(Common::SeekableReadStream &stream);
private:
- Common::SeekableReadStream *_stream;
-
// Parameters from codec header, do not change during playback
uint8 _channels;
uint16 _sampleRate;
@@ -204,7 +202,6 @@ private:
// I/O data
uint8 *_compressedData;
float _outputBuffer[1024];
- Common::Array<int16> _outputSamples;
// Synthesis filter
int16 ff_mpa_synth_window[512];
@@ -285,7 +282,7 @@ private:
void qdm2_fft_tone_synthesizer(uint8 sub_packet);
void qdm2_calculate_fft(int channel);
void qdm2_synthesis_filter(uint8 index);
- int qdm2_decodeFrame(Common::SeekableReadStream *in);
+ bool qdm2_decodeFrame(Common::SeekableReadStream &in, QueuingAudioStream *audioStream);
};
// Fix compilation for non C99-compliant compilers, like MSVC
@@ -293,21 +290,6 @@ private:
typedef signed long long int int64_t;
#endif
-// Integer log2 function. This is much faster than invoking
-// double precision C99 log2 math functions or equivalent, since
-// this is only used to determine maximum number of bits needed
-// i.e. only non-fractional part is needed. Also, the double
-// version is incorrect for exact cases due to floating point
-// rounding errors.
-static inline int scummvm_log2(int n) {
- int ret = -1;
- while(n != 0) {
- n /= 2;
- ret++;
- }
- return ret;
-}
-
#define QDM2_LIST_ADD(list, size, packet) \
do { \
if (size > 0) \
@@ -1711,7 +1693,7 @@ void QDM2Stream::initVlc(void) {
}
}
-QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
+QDM2Stream::QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) {
uint32 tmp;
int32 tmp_s;
int tmp_val;
@@ -1719,7 +1701,6 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
debug(1, "QDM2Stream::QDM2Stream() Call");
- _stream = stream;
_compressedData = NULL;
_subPacket = 0;
_superBlockStart = 0;
@@ -1841,11 +1822,11 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
warning("QDM2Stream::QDM2Stream() u4 field not 0");
}
- _fftOrder = scummvm_log2(_frameSize) + 1;
+ _fftOrder = Common::intLog2(_frameSize) + 1;
_fftFrameSize = 2 * _frameSize; // complex has two floats
// something like max decodable tones
- _groupOrder = scummvm_log2(_blockSize) + 1;
+ _groupOrder = Common::intLog2(_blockSize) + 1;
_sFrameSize = _blockSize / 16; // 16 iterations per super block
_subSampling = _fftOrder - 7;
@@ -1906,11 +1887,13 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
initNoiseSamples();
_compressedData = new uint8[_packetSize];
+
+ if (disposeExtraData == DisposeAfterUse::YES)
+ delete extraData;
}
QDM2Stream::~QDM2Stream() {
delete[] _compressedData;
- delete _stream;
}
static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth) {
@@ -3158,30 +3141,30 @@ void QDM2Stream::qdm2_synthesis_filter(uint8 index)
_outputBuffer[_channels * i + ch] += (float)(samples[_channels * sub_sampling * i + ch] >> (sizeof(int16)*8-16));
}
-int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
- debug(1, "QDM2Stream::qdm2_decodeFrame in->pos(): %d in->size(): %d", in->pos(), in->size());
+bool QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream &in, QueuingAudioStream *audioStream) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame in.pos(): %d in.size(): %d", in.pos(), in.size());
int ch, i;
const int frame_size = (_sFrameSize * _channels);
// If we're in any packet but the first, seek back to the first
if (_subPacket == 0)
- _superBlockStart = in->pos();
+ _superBlockStart = in.pos();
else
- in->seek(_superBlockStart);
+ in.seek(_superBlockStart);
// select input buffer
- if (in->eos() || in->pos() >= in->size()) {
+ if (in.eos() || in.pos() >= in.size()) {
debug(1, "QDM2Stream::qdm2_decodeFrame End of Input Stream");
- return 0;
+ return false;
}
- if ((in->size() - in->pos()) < _packetSize) {
- debug(1, "QDM2Stream::qdm2_decodeFrame Insufficient Packet Data in Input Stream Found: %d Need: %d", in->size() - in->pos(), _packetSize);
- return 0;
+ if ((in.size() - in.pos()) < _packetSize) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame Insufficient Packet Data in Input Stream Found: %d Need: %d", in.size() - in.pos(), _packetSize);
+ return false;
}
- if (!in->eos()) {
- in->read(_compressedData, _packetSize);
+ if (!in.eos()) {
+ in.read(_compressedData, _packetSize);
debug(1, "QDM2Stream::qdm2_decodeFrame constructed input data");
}
@@ -3190,7 +3173,7 @@ int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
memset(&_outputBuffer[frame_size], 0, frame_size * sizeof(float));
debug(1, "QDM2Stream::qdm2_decodeFrame cleared outputBuffer");
- if (!in->eos()) {
+ if (!in.eos()) {
// decode block of QDM2 compressed data
debug(1, "QDM2Stream::qdm2_decodeFrame decode block of QDM2 compressed data");
if (_subPacket == 0) {
@@ -3218,7 +3201,7 @@ int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
if (!_hasErrors && _subPacketListC[0].packet != NULL) {
error("QDM2 : has errors, and C list is not empty");
- return 0;
+ return false;
}
}
@@ -3236,6 +3219,12 @@ int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
debug(1, "QDM2Stream::qdm2_decodeFrame clip and convert output float[] to 16bit signed samples");
}
+ if (frame_size == 0)
+ return false;
+
+ // Prepare a buffer for queuing
+ uint16 *outputBuffer = (uint16 *)malloc(frame_size * 2);
+
for (i = 0; i < frame_size; i++) {
int value = (int)_outputBuffer[i];
@@ -3244,34 +3233,35 @@ int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
else if (value < -SOFTCLIP_THRESHOLD)
value = (value < -HARDCLIP_THRESHOLD) ? -32767 : -_softclipTable[-value - SOFTCLIP_THRESHOLD];
- _outputSamples.push_back(value);
+ outputBuffer[i] = value;
}
- return frame_size;
-}
-int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
- debug(1, "QDM2Stream::readBuffer numSamples: %d", numSamples);
- int32 decodedSamples = _outputSamples.size();
- int32 i;
+ // Queue the translated buffer to our stream
+ byte flags = FLAG_16BITS;
- while (decodedSamples < numSamples) {
- i = qdm2_decodeFrame(_stream);
- if (i == 0)
- break; // Out Of Decode Frames...
- decodedSamples += i;
- }
+ if (_channels == 2)
+ flags |= FLAG_STEREO;
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ flags |= FLAG_LITTLE_ENDIAN;
+#endif
+
+ audioStream->queueBuffer((byte *)outputBuffer, frame_size * 2, DisposeAfterUse::YES, flags);
+
+ return true;
+}
- if (decodedSamples > numSamples)
- decodedSamples = numSamples;
+AudioStream *QDM2Stream::decodeFrame(Common::SeekableReadStream &stream) {
+ QueuingAudioStream *audioStream = makeQueuingAudioStream(_sampleRate, _channels == 2);
- for (i = 0; i < decodedSamples; i++)
- buffer[i] = _outputSamples.remove_at(0);
+ while (qdm2_decodeFrame(stream, audioStream))
+ ;
- return decodedSamples;
+ return audioStream;
}
-AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
- return new QDM2Stream(stream, extraData);
+Codec *makeQDM2Decoder(Common::SeekableReadStream *extraData, DisposeAfterUse::Flag disposeExtraData) {
+ return new QDM2Stream(extraData, disposeExtraData);
}
} // End of namespace Audio