diff options
author | Matthew Hoops | 2011-07-10 15:46:35 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-07-10 15:50:47 -0400 |
commit | 46aabed3f5bdb3549e3c804793b5198de4b1702c (patch) | |
tree | d59803c4d48e42edacb28aa62ec7d31390a0c03d /audio | |
parent | c46aa548d6d8a1eabb968bfd0152215490bf746c (diff) | |
download | scummvm-rg350-46aabed3f5bdb3549e3c804793b5198de4b1702c.tar.gz scummvm-rg350-46aabed3f5bdb3549e3c804793b5198de4b1702c.tar.bz2 scummvm-rg350-46aabed3f5bdb3549e3c804793b5198de4b1702c.zip |
AUDIO: Fix QDM2 sound in QuickTime files
Diffstat (limited to 'audio')
-rw-r--r-- | audio/decoders/qdm2.cpp | 96 | ||||
-rw-r--r-- | audio/decoders/qdm2.h | 15 | ||||
-rw-r--r-- | audio/decoders/quicktime.cpp | 10 |
3 files changed, 64 insertions, 57 deletions
diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp index a178c363b5..ec2911ef20 100644 --- a/audio/decoders/qdm2.cpp +++ b/audio/decoders/qdm2.cpp @@ -28,7 +28,9 @@ #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" @@ -150,19 +152,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 +201,6 @@ private: // I/O data uint8 *_compressedData; float _outputBuffer[1024]; - Common::Array<int16> _outputSamples; // Synthesis filter int16 ff_mpa_synth_window[512]; @@ -285,7 +281,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 @@ -1711,7 +1707,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 +1715,6 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS debug(1, "QDM2Stream::QDM2Stream() Call"); - _stream = stream; _compressedData = NULL; _subPacket = 0; _superBlockStart = 0; @@ -1906,11 +1901,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 +3155,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 +3187,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 +3215,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 +3233,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 +3247,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 diff --git a/audio/decoders/qdm2.h b/audio/decoders/qdm2.h index c0ec647bfd..f0793e3c1e 100644 --- a/audio/decoders/qdm2.h +++ b/audio/decoders/qdm2.h @@ -26,22 +26,25 @@ #ifndef AUDIO_QDM2_H #define AUDIO_QDM2_H +#include "common/types.h" + namespace Common { class SeekableReadStream; } namespace Audio { -class AudioStream; +class Codec; /** - * Create a new AudioStream from the QDM2 data in the given stream. + * Create a new Codec from the QDM2 data in the given stream. * - * @param stream the SeekableReadStream from which to read the FLAC data - * @param extraData the QuickTime extra data stream - * @return a new AudioStream, or NULL, if an error occurred + * @param extraData the QuickTime extra data stream + * @param disposeExtraData the QuickTime extra data stream + * @return a new Codec, or NULL, if an error occurred */ -AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData); +Codec *makeQDM2Decoder(Common::SeekableReadStream *extraData, + DisposeAfterUse::Flag disposeExtraData = DisposeAfterUse::NO); } // End of namespace Audio diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 4531ccee19..a39fedc1d6 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -347,11 +347,6 @@ AudioStream *QuickTimeAudioDecoder::AudioSampleDesc::createAudioStream(Common::S } else if (_codecTag == MKTAG('i', 'm', 'a', '4')) { // Riven uses this codec (as do some Myst ME videos) return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, _sampleRate, _channels, 34); -#ifdef AUDIO_QDM2_H - } else if (_codecTag == MKTAG('Q', 'D', 'M', '2')) { - // Myst ME uses this codec for many videos - return makeQDM2Stream(stream, _parentTrack->extraData); -#endif } error("Unsupported audio codec"); @@ -362,6 +357,11 @@ void QuickTimeAudioDecoder::AudioSampleDesc::initCodec() { delete _codec; _codec = 0; switch (_codecTag) { + case MKTAG('Q', 'D', 'M', '2'): +#ifdef AUDIO_QDM2_H + _codec = makeQDM2Decoder(_parentTrack->extraData); +#endif + break; case MKTAG('m', 'p', '4', 'a'): #ifdef USE_FAAD if (_parentTrack->objectTypeMP4 == 0x40) |