[Scummvm-cvs-logs] scummvm master -> c8a7e39e0522b32e29ab403188f56bee9cf1da27

clone2727 clone2727 at gmail.com
Mon Aug 31 03:05:28 CEST 2015


This automated email contains information about 13 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
030e4d0608 AUDIO: Make Rewindable- and SeekableAudioStream inherit virtually
52f67cba39 AUDIO: Split the seeking MP3 class from the base decoding stream
ccd8dbf4ba AUDIO: Add an AudioStream subclass for packetized audio
562234b96b AUDIO: Implement a packetized version of MP3
14e57ca76f VIDEO: Switch MPEG-PS audio code to use the packetized MP3 code
ba4469da6a ZVISION: Cleanup the AVI decoder subclass
de2f4e6982 VIDEO: Add support for MP3 in AVI
a64aff0287 AUDIO: Add a class to easily make stateless PacketizedAudioStreams
3aa9e2c581 AUDIO: Add a packetized version of the PCM stream
331d8ece21 AUDIO: Add a packetized version of ADPCM streams
72239a25f9 AUDIO: Add a NullAudioStream for streams that are dead-on-arrival
561d1a1d62 VIDEO: Switch to all packetized streams for AVI
c8a7e39e05 AUDIO: Mark the old Codec class as deprecated


Commit: 030e4d06088cb75e871f1373b662d14262fbfc93
    https://github.com/scummvm/scummvm/commit/030e4d06088cb75e871f1373b662d14262fbfc93
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
AUDIO: Make Rewindable- and SeekableAudioStream inherit virtually

Changed paths:
    audio/audiostream.h
    engines/groovie/music.cpp
    engines/lastexpress/data/snd.cpp
    engines/lastexpress/data/snd.h
    engines/mohawk/sound.cpp
    engines/mohawk/sound.h



diff --git a/audio/audiostream.h b/audio/audiostream.h
index 347a37b..840a25a 100644
--- a/audio/audiostream.h
+++ b/audio/audiostream.h
@@ -86,7 +86,7 @@ public:
  * to its initial state. Note that rewinding itself is not required to
  * be working when the stream is being played by Mixer!
  */
-class RewindableAudioStream : public AudioStream {
+class RewindableAudioStream : public virtual AudioStream {
 public:
 	/**
 	 * Rewinds the stream to its start.
@@ -153,7 +153,7 @@ AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops);
  * interface for seeking. The seeking itself is not required to be
  * working while the stream is being played by Mixer!
  */
-class SeekableAudioStream : public RewindableAudioStream {
+class SeekableAudioStream : public virtual RewindableAudioStream {
 public:
 	/**
 	 * Tries to load a file by trying all available formats.
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index c00290b..cf65e01 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -934,16 +934,18 @@ bool MusicPlayerIOS::load(uint32 fileref, bool loop) {
 	}
 
 	// Create the audio stream
-	Audio::AudioStream *audStream = Audio::SeekableAudioStream::openStreamFile(info.filename);
+	Audio::SeekableAudioStream *seekStream = Audio::SeekableAudioStream::openStreamFile(info.filename);
 
-	if (!audStream) {
+	if (!seekStream) {
 		warning("Could not play audio file '%s'", info.filename.c_str());
 		return false;
 	}
 
+	Audio::AudioStream *audStream = seekStream;
+
 	// Loop if requested
 	if (loop)
-		audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0);
+		audStream = Audio::makeLoopingAudioStream(seekStream, 0);
 
 	// MIDI player handles volume reset on load, IOS player doesn't - force update here
 	updateVolume();
diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp
index 2a221af..e310baf 100644
--- a/engines/lastexpress/data/snd.cpp
+++ b/engines/lastexpress/data/snd.cpp
@@ -442,7 +442,7 @@ void SimpleSound::loadHeader(Common::SeekableReadStream *in) {
 	_blockSize = _size / _blocks;
 }
 
-Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId) const {
+LastExpress_ADPCMStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId) const {
 	return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize, filterId);
 }
 
@@ -489,7 +489,7 @@ void StreamedSound::setFilterId(int32 filterId) {
 	if (!_as)
 		return;
 
-	((LastExpress_ADPCMStream *)_as)->setFilterId(filterId);
+	_as->setFilterId(filterId);
 }
 
 //////////////////////////////////////////////////////////////////////////
@@ -525,8 +525,8 @@ void AppendableSound::queueBuffer(Common::SeekableReadStream *bufferIn) {
 
 	// Setup the ADPCM decoder
 	uint32 sizeIn = (uint32)bufferIn->size();
-	Audio::AudioStream *adpcm = makeDecoder(bufferIn, sizeIn);
-	((LastExpress_ADPCMStream *)adpcm)->setFilterId(16);
+	LastExpress_ADPCMStream *adpcm = makeDecoder(bufferIn, sizeIn);
+	adpcm->setFilterId(16);
 
 	// Queue the stream
 	_as->queueAudioStream(adpcm);
diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h
index f489304..19e5fda 100644
--- a/engines/lastexpress/data/snd.h
+++ b/engines/lastexpress/data/snd.h
@@ -49,6 +49,8 @@ class SeekableReadStream;
 
 namespace LastExpress {
 
+class LastExpress_ADPCMStream;
+
 class SimpleSound {
 public:
 	SimpleSound();
@@ -59,7 +61,7 @@ public:
 
 protected:
 	void loadHeader(Common::SeekableReadStream *in);
-	Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId = -1) const;
+	LastExpress_ADPCMStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId = -1) const;
 	void play(Audio::AudioStream *as);
 
 	uint32 _size;   ///< data size
@@ -82,7 +84,7 @@ public:
 	void setFilterId(int32 filterId);
 
 private:
-	Audio::AudioStream *_as;
+	LastExpress_ADPCMStream *_as;
 	bool _loaded;
 };
 
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index 6f18d71..198627e 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -77,8 +77,8 @@ void Sound::initMidi() {
 	_midiParser->setTimerRate(_midiDriver->getBaseTempo());
 }
 
-Audio::AudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
-	Audio::AudioStream *audStream = NULL;
+Audio::RewindableAudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
+	Audio::RewindableAudioStream *audStream = NULL;
 
 	switch (_vm->getGameType()) {
 	case GType_MYST:
@@ -109,17 +109,18 @@ Audio::AudioStream *Sound::makeAudioStream(uint16 id, CueList *cueList) {
 Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop, CueList *cueList) {
 	debug (0, "Playing sound %d", id);
 
-	Audio::AudioStream *audStream = makeAudioStream(id, cueList);
+	Audio::RewindableAudioStream *rewindStream = makeAudioStream(id, cueList);
 
-	if (audStream) {
+	if (rewindStream) {
 		SndHandle *handle = getHandle();
 		handle->type = kUsedHandle;
 		handle->id = id;
-		handle->samplesPerSecond = audStream->getRate();
+		handle->samplesPerSecond = rewindStream->getRate();
 
 		// Set the stream to loop here if it's requested
+		Audio::AudioStream *audStream = rewindStream;
 		if (loop)
-			audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0);
+			audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
 
 		_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle->handle, audStream, -1, volume);
 		return &handle->handle;
@@ -335,11 +336,12 @@ void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16
 	sndHandle.id = id;
 	_currentSLSTSounds.push_back(sndHandle);
 
-	Audio::AudioStream *audStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
+	Audio::RewindableAudioStream *rewindStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
 
 	// Loop here if necessary
+	Audio::AudioStream *audStream = rewindStream;
 	if (loop)
-		audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0);
+		audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
 
 	// TODO: Handle fading, possibly just raise the volume of the channel in increments?
 
@@ -363,7 +365,7 @@ void Sound::resumeSLST() {
 		_vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false);
 }
 
-Audio::AudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
+Audio::RewindableAudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) {
 	uint32 tag = 0;
 	ADPCMStatus adpcmStatus;
 	DataChunk dataChunk;
@@ -507,7 +509,7 @@ Audio::AudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stre
 	return NULL;
 }
 
-Audio::AudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
+Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) {
 	uint16 header = stream->readUint16BE();
 	uint16 rate = 0;
 	uint32 size = 0;
@@ -646,15 +648,15 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) {
 	stopBackgroundMyst();
 
 	// Play new sound
-	Audio::AudioStream *audStream = makeAudioStream(id);
+	Audio::RewindableAudioStream *rewindStream = makeAudioStream(id);
 
-	if (audStream) {
+	if (rewindStream) {
 		_mystBackgroundSound.type = kUsedHandle;
 		_mystBackgroundSound.id = id;
-		_mystBackgroundSound.samplesPerSecond = audStream->getRate();
+		_mystBackgroundSound.samplesPerSecond = rewindStream->getRate();
 
 		// Set the stream to loop
-		audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0);
+		Audio::AudioStream *audStream = Audio::makeLoopingAudioStream(rewindStream, 0);
 
 		_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mystBackgroundSound.handle, audStream, -1, volume >> 8);
 		return &_mystBackgroundSound.handle;
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index 49f6751..75c9492 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -156,13 +156,13 @@ private:
 	MidiParser *_midiParser;
 	byte *_midiData;
 
-	static Audio::AudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = NULL);
-	static Audio::AudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
+	static Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = NULL);
+	static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream);
 	void initMidi();
 
 	Common::Array<SndHandle> _handles;
 	SndHandle *getHandle();
-	Audio::AudioStream *makeAudioStream(uint16 id, CueList *cueList = NULL);
+	Audio::RewindableAudioStream *makeAudioStream(uint16 id, CueList *cueList = NULL);
 	uint16 convertMystID(uint16 id);
 
 	// Myst-specific


Commit: 52f67cba39f466c41ec7e6505e7f48626642e62e
    https://github.com/scummvm/scummvm/commit/52f67cba39f466c41ec7e6505e7f48626642e62e
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
AUDIO: Split the seeking MP3 class from the base decoding stream

Changed paths:
    audio/decoders/mp3.cpp



diff --git a/audio/decoders/mp3.cpp b/audio/decoders/mp3.cpp
index feb531f..8550d91 100644
--- a/audio/decoders/mp3.cpp
+++ b/audio/decoders/mp3.cpp
@@ -27,6 +27,7 @@
 #include "common/debug.h"
 #include "common/ptr.h"
 #include "common/stream.h"
+#include "common/substream.h"
 #include "common/textconsole.h"
 #include "common/util.h"
 
@@ -45,20 +46,34 @@ namespace Audio {
 #pragma mark -
 
 
-class MP3Stream : public SeekableAudioStream {
+class BaseMP3Stream : public virtual AudioStream {
+public:
+	BaseMP3Stream();
+	virtual ~BaseMP3Stream();
+
+	bool endOfData() const		{ return _state == MP3_STATE_EOS; }
+	bool isStereo() const		{ return MAD_NCHANNELS(&_frame.header) == 2; }
+	int getRate() const			{ return _frame.header.samplerate; }
+
 protected:
+	void decodeMP3Data(Common::ReadStream &stream);
+	void readMP3Data(Common::ReadStream &stream);
+
+	void initStream(Common::ReadStream &stream);
+	void readHeader(Common::ReadStream &stream);
+	void deinitStream();
+
+	int fillBuffer(Common::ReadStream &stream, int16 *buffer, const int numSamples);
+
 	enum State {
 		MP3_STATE_INIT,	// Need to init the decoder
 		MP3_STATE_READY,	// ready for processing data
 		MP3_STATE_EOS		// end of data reached (may need to loop)
 	};
 
-	Common::DisposablePtr<Common::SeekableReadStream> _inStream;
-
 	uint _posInFrame;
 	State _state;
 
-	Timestamp _length;
 	mad_timer_t _curTime;
 
 	mad_stream _stream;
@@ -71,81 +86,54 @@ protected:
 
 	// This buffer contains a slab of input data
 	byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
+};
 
+class MP3Stream : public BaseMP3Stream, public SeekableAudioStream {
 public:
 	MP3Stream(Common::SeekableReadStream *inStream,
 	               DisposeAfterUse::Flag dispose);
-	~MP3Stream();
+	virtual ~MP3Stream() {}
 
 	int readBuffer(int16 *buffer, const int numSamples);
-
-	bool endOfData() const		{ return _state == MP3_STATE_EOS; }
-	bool isStereo() const		{ return MAD_NCHANNELS(&_frame.header) == 2; }
-	int getRate() const			{ return _frame.header.samplerate; }
-
 	bool seek(const Timestamp &where);
 	Timestamp getLength() const { return _length; }
+
 protected:
-	void decodeMP3Data();
-	void readMP3Data();
+	Common::ScopedPtr<Common::SeekableReadStream> _inStream;
 
-	void initStream();
-	void readHeader();
-	void deinitStream();
+	Timestamp _length;
+
+private:
+	static Common::SeekableReadStream *skipID3(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose);
 };
 
-MP3Stream::MP3Stream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
-	_inStream(inStream, dispose),
+
+BaseMP3Stream::BaseMP3Stream() :
 	_posInFrame(0),
 	_state(MP3_STATE_INIT),
-	_length(0, 1000),
 	_curTime(mad_timer_zero) {
 
 	// The MAD_BUFFER_GUARD must always contain zeros (the reason
 	// for this is that the Layer III Huffman decoder of libMAD
 	// may read a few bytes beyond the end of the input buffer).
 	memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
-
-	// Calculate the length of the stream
-	initStream();
-
-	while (_state != MP3_STATE_EOS)
-		readHeader();
-
-	// To rule out any invalid sample rate to be encountered here, say in case the
-	// MP3 stream is invalid, we just check the MAD error code here.
-	// We need to assure this, since else we might trigger an assertion in Timestamp
-	// (When getRate() returns 0 or a negative number to be precise).
-	// Note that we allow "MAD_ERROR_BUFLEN" as error code here, since according
-	// to mad.h it is also set on EOF.
-	if ((_stream.error == MAD_ERROR_NONE || _stream.error == MAD_ERROR_BUFLEN) && getRate() > 0)
-		_length = Timestamp(mad_timer_count(_curTime, MAD_UNITS_MILLISECONDS), getRate());
-
-	deinitStream();
-
-	// Reinit stream
-	_state = MP3_STATE_INIT;
-
-	// Decode the first chunk of data. This is necessary so that _frame
-	// is setup and isStereo() and getRate() return correct results.
-	decodeMP3Data();
 }
 
-MP3Stream::~MP3Stream() {
+BaseMP3Stream::~BaseMP3Stream() {
 	deinitStream();
 }
 
-void MP3Stream::decodeMP3Data() {
+void BaseMP3Stream::decodeMP3Data(Common::ReadStream &stream) {
 	do {
 		if (_state == MP3_STATE_INIT)
-			initStream();
+			initStream(stream);
 
 		if (_state == MP3_STATE_EOS)
 			return;
 
 		// If necessary, load more data into the stream decoder
 		if (_stream.error == MAD_ERROR_BUFLEN)
-			readMP3Data();
+			readMP3Data(stream);
 
 		while (_state == MP3_STATE_READY) {
 			_stream.error = MAD_ERROR_NONE;
@@ -179,11 +167,11 @@ void MP3Stream::decodeMP3Data() {
 		_state = MP3_STATE_EOS;
 }
 
-void MP3Stream::readMP3Data() {
+void BaseMP3Stream::readMP3Data(Common::ReadStream &stream) {
 	uint32 remaining = 0;
 
 	// Give up immediately if we already used up all data in the stream
-	if (_inStream->eos()) {
+	if (stream.eos()) {
 		_state = MP3_STATE_EOS;
 		return;
 	}
@@ -198,7 +186,7 @@ void MP3Stream::readMP3Data() {
 	}
 
 	// Try to read the next block
-	uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining);
+	uint32 size = stream.read(_buf + remaining, BUFFER_SIZE - remaining);
 	if (size <= 0) {
 		_state = MP3_STATE_EOS;
 		return;
@@ -209,31 +197,7 @@ void MP3Stream::readMP3Data() {
 	mad_stream_buffer(&_stream, _buf, size + remaining);
 }
 
-bool MP3Stream::seek(const Timestamp &where) {
-	if (where == _length) {
-		_state = MP3_STATE_EOS;
-		return true;
-	} else if (where > _length) {
-		return false;
-	}
-
-	const uint32 time = where.msecs();
-
-	mad_timer_t destination;
-	mad_timer_set(&destination, time / 1000, time % 1000, 1000);
-
-	if (_state != MP3_STATE_READY || mad_timer_compare(destination, _curTime) < 0)
-		initStream();
-
-	while (mad_timer_compare(destination, _curTime) > 0 && _state != MP3_STATE_EOS)
-		readHeader();
-
-	decodeMP3Data();
-
-	return (_state != MP3_STATE_EOS);
-}
-
-void MP3Stream::initStream() {
+void BaseMP3Stream::initStream(Common::ReadStream &stream) {
 	if (_state != MP3_STATE_INIT)
 		deinitStream();
 
@@ -243,41 +207,23 @@ void MP3Stream::initStream() {
 	mad_synth_init(&_synth);
 
 	// Reset the stream data
-	_inStream->seek(0, SEEK_SET);
 	_curTime = mad_timer_zero;
 	_posInFrame = 0;
-	
-	// Skip ID3 TAG if any
-	// ID3v1 (beginning with with 'TAG') is located at the end of files. So we can ignore those.
-	// ID3v2 can be located at the start of files and begins with a 10 bytes header, the first 3 bytes being 'ID3'.
-	// The tag size is coded on the last 4 bytes of the 10 bytes header as a 32 bit synchsafe integer.
-	// See http://id3.org/id3v2.4.0-structure for details.
-	char data[10];
-	_inStream->read(data, 10);
-	if (data[0] == 'I' && data[1] == 'D' && data[2] == '3') {
-		uint32 size = data[9] + 128 * (data[8] + 128 * (data[7] + 128 * data[6]));
-		// This size does not include an optional 10 bytes footer. Check if it is present.
-		if (data[5] & 0x10)
-			size += 10;
-		debug("Skipping ID3 TAG (%d bytes)", size + 10);
-		_inStream->seek(size, SEEK_CUR);
-	} else
-		_inStream->seek(0, SEEK_SET);
 
 	// Update state
 	_state = MP3_STATE_READY;
 
 	// Read the first few sample bytes
-	readMP3Data();
+	readMP3Data(stream);
 }
 
-void MP3Stream::readHeader() {
+void BaseMP3Stream::readHeader(Common::ReadStream &stream) {
 	if (_state != MP3_STATE_READY)
 		return;
 
 	// If necessary, load more data into the stream decoder
 	if (_stream.error == MAD_ERROR_BUFLEN)
-		readMP3Data();
+		readMP3Data(stream);
 
 	while (_state != MP3_STATE_EOS) {
 		_stream.error = MAD_ERROR_NONE;
@@ -287,7 +233,7 @@ void MP3Stream::readHeader() {
 		// be far too slow). Hence we perform this explicitly in a separate step.
 		if (mad_header_decode(&_frame.header, &_stream) == -1) {
 			if (_stream.error == MAD_ERROR_BUFLEN) {
-				readMP3Data();  // Read more data
+				readMP3Data(stream);  // Read more data
 				continue;
 			} else if (MAD_RECOVERABLE(_stream.error)) {
 				debug(6, "MP3Stream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
@@ -307,7 +253,7 @@ void MP3Stream::readHeader() {
 		_state = MP3_STATE_EOS;
 }
 
-void MP3Stream::deinitStream() {
+void BaseMP3Stream::deinitStream() {
 	if (_state == MP3_STATE_INIT)
 		return;
 
@@ -319,7 +265,7 @@ void MP3Stream::deinitStream() {
 	_state = MP3_STATE_EOS;
 }
 
-static inline int scale_sample(mad_fixed_t sample) {
+static inline int scaleSample(mad_fixed_t sample) {
 	// round
 	sample += (1L << (MAD_F_FRACBITS - 16));
 
@@ -333,28 +279,115 @@ static inline int scale_sample(mad_fixed_t sample) {
 	return sample >> (MAD_F_FRACBITS + 1 - 16);
 }
 
-int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
+int BaseMP3Stream::fillBuffer(Common::ReadStream &stream, int16 *buffer, const int numSamples) {
 	int samples = 0;
 	// Keep going as long as we have input available
 	while (samples < numSamples && _state != MP3_STATE_EOS) {
 		const int len = MIN(numSamples, samples + (int)(_synth.pcm.length - _posInFrame) * MAD_NCHANNELS(&_frame.header));
 		while (samples < len) {
-			*buffer++ = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]);
+			*buffer++ = (int16)scaleSample(_synth.pcm.samples[0][_posInFrame]);
 			samples++;
 			if (MAD_NCHANNELS(&_frame.header) == 2) {
-				*buffer++ = (int16)scale_sample(_synth.pcm.samples[1][_posInFrame]);
+				*buffer++ = (int16)scaleSample(_synth.pcm.samples[1][_posInFrame]);
 				samples++;
 			}
 			_posInFrame++;
 		}
 		if (_posInFrame >= _synth.pcm.length) {
 			// We used up all PCM data in the current frame -- read & decode more
-			decodeMP3Data();
+			decodeMP3Data(stream);
 		}
 	}
 	return samples;
 }
 
+MP3Stream::MP3Stream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
+		BaseMP3Stream(),
+		_inStream(skipID3(inStream, dispose)),
+		_length(0, 1000) {
+
+	// Initialize the stream with some data
+	decodeMP3Data(*_inStream);
+
+	// Calculate the length of the stream
+	while (_state != MP3_STATE_EOS)
+		readHeader(*_inStream);
+
+	// To rule out any invalid sample rate to be encountered here, say in case the
+	// MP3 stream is invalid, we just check the MAD error code here.
+	// We need to assure this, since else we might trigger an assertion in Timestamp
+	// (When getRate() returns 0 or a negative number to be precise).
+	// Note that we allow "MAD_ERROR_BUFLEN" as error code here, since according
+	// to mad.h it is also set on EOF.
+	if ((_stream.error == MAD_ERROR_NONE || _stream.error == MAD_ERROR_BUFLEN) && getRate() > 0)
+		_length = Timestamp(mad_timer_count(_curTime, MAD_UNITS_MILLISECONDS), getRate());
+
+	deinitStream();
+
+	// Reinit stream
+	_state = MP3_STATE_INIT;
+	_inStream->seek(0);
+
+	// Decode the first chunk of data. This is necessary so that _frame
+	// is setup and isStereo() and getRate() return correct results.
+	decodeMP3Data(*_inStream);
+}
+
+int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
+	return fillBuffer(*_inStream, buffer, numSamples);
+}
+
+bool MP3Stream::seek(const Timestamp &where) {
+	if (where == _length) {
+		_state = MP3_STATE_EOS;
+		return true;
+	} else if (where > _length) {
+		return false;
+	}
+
+	const uint32 time = where.msecs();
+
+	mad_timer_t destination;
+	mad_timer_set(&destination, time / 1000, time % 1000, 1000);
+
+	if (_state != MP3_STATE_READY || mad_timer_compare(destination, _curTime) < 0) {
+		_inStream->seek(0);
+		initStream(*_inStream);
+	}
+
+	while (mad_timer_compare(destination, _curTime) > 0 && _state != MP3_STATE_EOS)
+		readHeader(*_inStream);
+
+	decodeMP3Data(*_inStream);
+
+	return (_state != MP3_STATE_EOS);
+}
+
+Common::SeekableReadStream *MP3Stream::skipID3(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) {
+	// Skip ID3 TAG if any
+	// ID3v1 (beginning with with 'TAG') is located at the end of files. So we can ignore those.
+	// ID3v2 can be located at the start of files and begins with a 10 bytes header, the first 3 bytes being 'ID3'.
+	// The tag size is coded on the last 4 bytes of the 10 bytes header as a 32 bit synchsafe integer.
+	// See http://id3.org/id3v2.4.0-structure for details.
+	char data[10];
+	stream->read(data, sizeof(data));
+
+	uint32 offset = 0;
+	if (!stream->eos() && data[0] == 'I' && data[1] == 'D' && data[2] == '3') {
+		uint32 size = data[9] + 128 * (data[8] + 128 * (data[7] + 128 * data[6]));
+		// This size does not include an optional 10 bytes footer. Check if it is present.
+		if (data[5] & 0x10)
+			size += 10;
+
+		// Add in the 10 bytes we read in
+		size += sizeof(data);
+		debug("Skipping ID3 TAG (%d bytes)", size);
+		offset = size;
+	}
+
+	return new Common::SeekableSubReadStream(stream, offset, stream->size(), dispose);
+}
+
 
 #pragma mark -
 #pragma mark --- MP3 factory functions ---


Commit: ccd8dbf4baba33bda41d1d8aa7657ef7d1400463
    https://github.com/scummvm/scummvm/commit/ccd8dbf4baba33bda41d1d8aa7657ef7d1400463
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
AUDIO: Add an AudioStream subclass for packetized audio

Changed paths:
    audio/audiostream.h



diff --git a/audio/audiostream.h b/audio/audiostream.h
index 840a25a..c3dbdcf 100644
--- a/audio/audiostream.h
+++ b/audio/audiostream.h
@@ -30,6 +30,10 @@
 
 #include "audio/timestamp.h"
 
+namespace Common {
+class SeekableReadStream;
+}
+
 namespace Audio {
 
 /**
@@ -367,6 +371,30 @@ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo
  */
 AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
 
+/**
+ * An AudioStream designed to work in terms of packets.
+ *
+ * It is similar in concept to QueuingAudioStream, but does not
+ * necessarily rely on the data from each queued AudioStream
+ * being separate.
+ */
+class PacketizedAudioStream : public virtual AudioStream {
+public:
+	virtual ~PacketizedAudioStream() {}
+
+	/**
+	 * Queue the next packet to be decoded.
+	 */
+	virtual void queuePacket(Common::SeekableReadStream *data) = 0;
+
+	/**
+	 * Mark this stream as finished. That is, signal that no further data
+	 * will be queued to it. Only after this has been done can this
+	 * stream ever 'end'.
+	 */
+	virtual void finish() = 0;
+};
+
 } // End of namespace Audio
 
 #endif


Commit: 562234b96b37a8944b6c626354220f5d21357dee
    https://github.com/scummvm/scummvm/commit/562234b96b37a8944b6c626354220f5d21357dee
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
AUDIO: Implement a packetized version of MP3

Changed paths:
    audio/decoders/mp3.cpp
    audio/decoders/mp3.h



diff --git a/audio/decoders/mp3.cpp b/audio/decoders/mp3.cpp
index 8550d91..49d4d85 100644
--- a/audio/decoders/mp3.cpp
+++ b/audio/decoders/mp3.cpp
@@ -25,7 +25,9 @@
 #ifdef USE_MAD
 
 #include "common/debug.h"
+#include "common/mutex.h"
 #include "common/ptr.h"
+#include "common/queue.h"
 #include "common/stream.h"
 #include "common/substream.h"
 #include "common/textconsole.h"
@@ -51,9 +53,9 @@ public:
 	BaseMP3Stream();
 	virtual ~BaseMP3Stream();
 
-	bool endOfData() const		{ return _state == MP3_STATE_EOS; }
-	bool isStereo() const		{ return MAD_NCHANNELS(&_frame.header) == 2; }
-	int getRate() const			{ return _frame.header.samplerate; }
+	bool endOfData() const { return _state == MP3_STATE_EOS; }
+	bool isStereo() const { return _channels == 2; }
+	int getRate() const { return _rate; }
 
 protected:
 	void decodeMP3Data(Common::ReadStream &stream);
@@ -80,6 +82,9 @@ protected:
 	mad_frame _frame;
 	mad_synth _synth;
 
+	uint _channels;
+	uint _rate;
+
 	enum {
 		BUFFER_SIZE = 5 * 8192
 	};
@@ -88,11 +93,10 @@ protected:
 	byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
 };
 
-class MP3Stream : public BaseMP3Stream, public SeekableAudioStream {
+class MP3Stream : private BaseMP3Stream, public SeekableAudioStream {
 public:
 	MP3Stream(Common::SeekableReadStream *inStream,
 	               DisposeAfterUse::Flag dispose);
-	virtual ~MP3Stream() {}
 
 	int readBuffer(int16 *buffer, const int numSamples);
 	bool seek(const Timestamp &where);
@@ -107,6 +111,26 @@ private:
 	static Common::SeekableReadStream *skipID3(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose);
 };
 
+class PacketizedMP3Stream : private BaseMP3Stream, public PacketizedAudioStream {
+public:
+	PacketizedMP3Stream(Common::SeekableReadStream &firstPacket);
+	PacketizedMP3Stream(uint channels, uint rate);
+	~PacketizedMP3Stream();
+
+	// AudioStream API
+	int readBuffer(int16 *buffer, const int numSamples);
+	bool endOfStream() const;
+
+	// PacketizedAudioStream API
+	void queuePacket(Common::SeekableReadStream *packet);
+	void finish();
+
+private:
+	Common::Mutex _mutex;
+	Common::Queue<Common::SeekableReadStream *> _queue;
+	bool _finished;
+};
+
 
 BaseMP3Stream::BaseMP3Stream() :
 	_posInFrame(0),
@@ -329,8 +353,11 @@ MP3Stream::MP3Stream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag
 	_inStream->seek(0);
 
 	// Decode the first chunk of data. This is necessary so that _frame
-	// is setup and isStereo() and getRate() return correct results.
+	// is setup and we can retrieve channels/rate.
 	decodeMP3Data(*_inStream);
+
+	_channels = MAD_NCHANNELS(&_frame.header);
+	_rate = _frame.header.samplerate;
 }
 
 int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
@@ -388,6 +415,91 @@ Common::SeekableReadStream *MP3Stream::skipID3(Common::SeekableReadStream *strea
 	return new Common::SeekableSubReadStream(stream, offset, stream->size(), dispose);
 }
 
+PacketizedMP3Stream::PacketizedMP3Stream(Common::SeekableReadStream &firstPacket) :
+		BaseMP3Stream(),
+		_finished(false) {
+
+	// Load some data to get the channels/rate
+	_queue.push(&firstPacket);
+	decodeMP3Data(firstPacket);
+	_channels = MAD_NCHANNELS(&_frame.header);
+	_rate = _frame.header.samplerate;
+
+	// Clear everything
+	deinitStream();
+	_state = MP3_STATE_INIT;
+	_queue.clear();
+}
+
+PacketizedMP3Stream::PacketizedMP3Stream(uint channels, uint rate) :
+		BaseMP3Stream(),
+		_finished(false) {
+	_channels = channels;
+	_rate = rate;
+}
+
+PacketizedMP3Stream::~PacketizedMP3Stream() {
+	while (!_queue.empty()) {
+		delete _queue.front();
+		_queue.pop();
+	}
+}
+
+int PacketizedMP3Stream::readBuffer(int16 *buffer, const int numSamples) {
+	int samples = 0;
+
+	while (samples < numSamples) {
+		Common::StackLock lock(_mutex);
+
+		// Empty? Bail out for now
+		if (_queue.empty())
+			return samples;
+
+		Common::SeekableReadStream *packet = _queue.front();
+
+		if (_state == MP3_STATE_INIT) {
+			// Initialize everything
+			decodeMP3Data(*packet);
+		} else if (_state == MP3_STATE_EOS) {
+			// Reset the end-of-stream setting
+			_state = MP3_STATE_READY;
+		}
+
+		samples += fillBuffer(*packet, buffer + samples, numSamples - samples);
+
+		// If the stream is done, kill it
+		if (packet->pos() >= packet->size()) {
+			_queue.pop();
+			delete packet;
+		}
+	}
+
+	return samples;
+}
+
+bool PacketizedMP3Stream::endOfStream() const {
+	if (!endOfData())
+		return false;
+
+	// Lock the mutex
+	Common::StackLock lock(_mutex);
+	if (!_queue.empty())
+		return false;
+
+	return _finished;
+}
+
+void PacketizedMP3Stream::queuePacket(Common::SeekableReadStream *packet) {
+	Common::StackLock lock(_mutex);
+	assert(!_finished);
+	_queue.push(packet);
+}
+
+void PacketizedMP3Stream::finish() {
+	Common::StackLock lock(_mutex);
+	_finished = true;
+}
+
 
 #pragma mark -
 #pragma mark --- MP3 factory functions ---
@@ -416,6 +528,15 @@ SeekableAudioStream *makeMP3Stream(
 	}
 }
 
+PacketizedAudioStream *makePacketizedMP3Stream(Common::SeekableReadStream &firstPacket) {
+	return new PacketizedMP3Stream(firstPacket);
+}
+
+PacketizedAudioStream *makePacketizedMP3Stream(uint channels, uint rate) {
+	return new PacketizedMP3Stream(channels, rate);
+}
+
+
 } // End of namespace Audio
 
 #endif // #ifdef USE_MAD
diff --git a/audio/decoders/mp3.h b/audio/decoders/mp3.h
index 609181b..709aad8 100644
--- a/audio/decoders/mp3.h
+++ b/audio/decoders/mp3.h
@@ -51,6 +51,7 @@ class SeekableReadStream;
 
 namespace Audio {
 
+class PacketizedAudioStream;
 class SeekableAudioStream;
 
 /**
@@ -65,6 +66,26 @@ SeekableAudioStream *makeMP3Stream(
 	Common::SeekableReadStream *stream,
 	DisposeAfterUse::Flag disposeAfterUse);
 
+/**
+ * Create a new PacketizedAudioStream from the first packet in the given
+ * stream. It does not own the packet and must be queued again later.
+ *
+ * @param firstPacket		the SeekableReadStream from which to read the MP3 data
+ * @return	a new PacketizedAudioStream
+ */
+PacketizedAudioStream *makePacketizedMP3Stream(
+	Common::SeekableReadStream &firstPacket);
+
+/**
+ * Create a new PacketizedAudioStream for a given number of channels
+ * and sample rate.
+ *
+ * @param firstPacket		the SeekableReadStream from which to read the MP3 data
+ * @return	a new PacketizedAudioStream
+ */
+PacketizedAudioStream *makePacketizedMP3Stream(
+	uint channels, uint rate);
+
 } // End of namespace Audio
 
 #endif // #ifdef USE_MAD


Commit: 14e57ca76fc90de9f5ea454aa5bf543a8f97d898
    https://github.com/scummvm/scummvm/commit/14e57ca76fc90de9f5ea454aa5bf543a8f97d898
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
VIDEO: Switch MPEG-PS audio code to use the packetized MP3 code

Changed paths:
    video/mpegps_decoder.cpp
    video/mpegps_decoder.h



diff --git a/video/mpegps_decoder.cpp b/video/mpegps_decoder.cpp
index d8f7f5a..6942efb 100644
--- a/video/mpegps_decoder.cpp
+++ b/video/mpegps_decoder.cpp
@@ -22,6 +22,7 @@
 
 #include "audio/audiostream.h"
 #include "audio/decoders/raw.h"
+#include "audio/decoders/mp3.h"
 #include "common/debug.h"
 #include "common/endian.h"
 #include "common/stream.h"
@@ -142,7 +143,7 @@ void MPEGPSDecoder::readNextPacket() {
 			} else if (startCode >= 0x1C0 && startCode <= 0x1DF) {
 #ifdef USE_MAD
 				// MPEG Audio stream
-				MPEGAudioTrack *audioTrack = new MPEGAudioTrack(packet);
+				MPEGAudioTrack *audioTrack = new MPEGAudioTrack(*packet);
 				stream = audioTrack;
 				_streamMap[startCode] = audioTrack;
 				addTrack(audioTrack);
@@ -158,6 +159,8 @@ void MPEGPSDecoder::readNextPacket() {
 		}
 
 		if (stream) {
+			packet->seek(0);
+
 			bool done = stream->sendPacket(packet, pts, dts);
 
 			if (done && stream->getStreamType() == MPEGStream::kStreamTypeVideo)
@@ -510,54 +513,16 @@ void MPEGPSDecoder::MPEGVideoTrack::findDimensions(Common::SeekableReadStream *f
 
 // The audio code here is almost entirely based on what we do in mp3.cpp
 
-MPEGPSDecoder::MPEGAudioTrack::MPEGAudioTrack(Common::SeekableReadStream *firstPacket) {
-	// The MAD_BUFFER_GUARD must always contain zeros (the reason
-	// for this is that the Layer III Huffman decoder of libMAD
-	// may read a few bytes beyond the end of the input buffer).
-	memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
-
-	_state = MP3_STATE_INIT;
-	_audStream = 0;
-
-	// Find out our audio parameters
-	initStream(firstPacket);
-
-	while (_state != MP3_STATE_EOS)
-		readHeader(firstPacket);
-
-	_audStream = Audio::makeQueuingAudioStream(_frame.header.samplerate, MAD_NCHANNELS(&_frame.header) == 2);
-
-	deinitStream();
-
-	firstPacket->seek(0);
-	_state = MP3_STATE_INIT;
+MPEGPSDecoder::MPEGAudioTrack::MPEGAudioTrack(Common::SeekableReadStream &firstPacket) {
+	_audStream = Audio::makePacketizedMP3Stream(firstPacket);
 }
 
 MPEGPSDecoder::MPEGAudioTrack::~MPEGAudioTrack() {
-	deinitStream();
 	delete _audStream;
 }
 
-static inline int scaleSample(mad_fixed_t sample) {
-	// round
-	sample += (1L << (MAD_F_FRACBITS - 16));
-
-	// clip
-	if (sample > MAD_F_ONE - 1)
-		sample = MAD_F_ONE - 1;
-	else if (sample < -MAD_F_ONE)
-		sample = -MAD_F_ONE;
-
-	// quantize and scale to not saturate when mixing a lot of channels
-	return sample >> (MAD_F_FRACBITS + 1 - 16);
-}
-
 bool MPEGPSDecoder::MPEGAudioTrack::sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts) {
-	while (_state != MP3_STATE_EOS)
-		decodeMP3Data(packet);
-
-	_state = MP3_STATE_READY;
-	delete packet;
+	_audStream->queuePacket(packet);
 	return true;
 }
 
@@ -565,168 +530,6 @@ Audio::AudioStream *MPEGPSDecoder::MPEGAudioTrack::getAudioStream() const {
 	return _audStream;
 }
 
-void MPEGPSDecoder::MPEGAudioTrack::initStream(Common::SeekableReadStream *packet) {
-	if (_state != MP3_STATE_INIT)
-		deinitStream();
-
-	// Init MAD
-	mad_stream_init(&_stream);
-	mad_frame_init(&_frame);
-	mad_synth_init(&_synth);
-
-	// Reset the stream data
-	packet->seek(0, SEEK_SET);
-
-	// Update state
-	_state = MP3_STATE_READY;
-
-	// Read the first few sample bytes
-	readMP3Data(packet);
-}
-
-void MPEGPSDecoder::MPEGAudioTrack::deinitStream() {
-	if (_state == MP3_STATE_INIT)
-		return;
-
-	// Deinit MAD
-	mad_synth_finish(&_synth);
-	mad_frame_finish(&_frame);
-	mad_stream_finish(&_stream);
-
-	_state = MP3_STATE_EOS;
-}
-
-void MPEGPSDecoder::MPEGAudioTrack::readMP3Data(Common::SeekableReadStream *packet) {
-	uint32 remaining = 0;
-
-	// Give up immediately if we already used up all data in the stream
-	if (packet->eos()) {
-		_state = MP3_STATE_EOS;
-		return;
-	}
-
-	if (_stream.next_frame) {
-		// If there is still data in the MAD stream, we need to preserve it.
-		// Note that we use memmove, as we are reusing the same buffer,
-		// and hence the data regions we copy from and to may overlap.
-		remaining = _stream.bufend - _stream.next_frame;
-		assert(remaining < BUFFER_SIZE);	// Paranoia check
-		memmove(_buf, _stream.next_frame, remaining);
-	}
-
-	memset(_buf + remaining, 0, BUFFER_SIZE - remaining);
-
-	// Try to read the next block
-	uint32 size = packet->read(_buf + remaining, BUFFER_SIZE - remaining);
-	if (size == 0) {
-		_state = MP3_STATE_EOS;
-		return;
-	}
-
-	// Feed the data we just read into the stream decoder
-	_stream.error = MAD_ERROR_NONE;
-	mad_stream_buffer(&_stream, _buf, size + remaining);
-}
-
-void MPEGPSDecoder::MPEGAudioTrack::readHeader(Common::SeekableReadStream *packet) {
-	if (_state != MP3_STATE_READY)
-		return;
-
-	// If necessary, load more data into the stream decoder
-	if (_stream.error == MAD_ERROR_BUFLEN)
-		readMP3Data(packet);
-
-	while (_state != MP3_STATE_EOS) {
-		_stream.error = MAD_ERROR_NONE;
-
-		// Decode the next header. Note: mad_frame_decode would do this for us, too.
-		// However, for seeking we don't want to decode the full frame (else it would
-		// be far too slow). Hence we perform this explicitly in a separate step.
-		if (mad_header_decode(&_frame.header, &_stream) == -1) {
-			if (_stream.error == MAD_ERROR_BUFLEN) {
-				readMP3Data(packet);  // Read more data
-				continue;
-			} else if (MAD_RECOVERABLE(_stream.error)) {
-				debug(6, "MPEGAudioTrack::readHeader(): Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
-				continue;
-			} else {
-				warning("MPEGAudioTrack::readHeader(): Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
-				break;
-			}
-		}
-
-		break;
-	}
-
-	if (_stream.error != MAD_ERROR_NONE)
-		_state = MP3_STATE_EOS;
-}
-
-void MPEGPSDecoder::MPEGAudioTrack::decodeMP3Data(Common::SeekableReadStream *packet) {
-	if (_state == MP3_STATE_INIT)
-		initStream(packet);
-
-	if (_state == MP3_STATE_EOS)
-		return;
-
-	do {
-		// If necessary, load more data into the stream decoder
-		if (_stream.error == MAD_ERROR_BUFLEN)
-			readMP3Data(packet);
-
-		while (_state == MP3_STATE_READY) {
-			_stream.error = MAD_ERROR_NONE;
-
-			// Decode the next frame
-			if (mad_frame_decode(&_frame, &_stream) == -1) {
-				if (_stream.error == MAD_ERROR_BUFLEN) {
-					break; // Read more data
-				} else if (MAD_RECOVERABLE(_stream.error)) {
-					// Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here.
-					// These are normal and expected (caused by our frame skipping (i.e. "seeking")
-					// code above).
-					debug(6, "MPEGAudioTrack::decodeMP3Data(): Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
-					continue;
-				} else {
-					warning("MPEGAudioTrack::decodeMP3Data(): Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
-					break;
-				}
-			}
-
-			// Synthesize PCM data
-			mad_synth_frame(&_synth, &_frame);
-
-			// Output it to our queue
-			if (_synth.pcm.length != 0) {
-				byte *buffer = (byte *)malloc(_synth.pcm.length * 2 * MAD_NCHANNELS(&_frame.header));
-				int16 *ptr = (int16 *)buffer;
-
-				for (int i = 0; i < _synth.pcm.length; i++) {
-					*ptr++ = (int16)scaleSample(_synth.pcm.samples[0][i]);
-
-					if (MAD_NCHANNELS(&_frame.header) == 2)
-						*ptr++ = (int16)scaleSample(_synth.pcm.samples[1][i]);
-				}
-
-				int flags = Audio::FLAG_16BITS;
-
-				if (_audStream->isStereo())
-					flags |= Audio::FLAG_STEREO;
-
-#ifdef SCUMM_LITTLE_ENDIAN
-				flags |= Audio::FLAG_LITTLE_ENDIAN;
-#endif
-
-				_audStream->queueBuffer(buffer, _synth.pcm.length * 2 * MAD_NCHANNELS(&_frame.header), DisposeAfterUse::YES, flags);
-			}
-			break;
-		}
-	} while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
-
-	if (_stream.error != MAD_ERROR_NONE)
-		_state = MP3_STATE_EOS;
-}
-
 #endif
 
 } // End of namespace Video
diff --git a/video/mpegps_decoder.h b/video/mpegps_decoder.h
index 0184d6f..bdff879 100644
--- a/video/mpegps_decoder.h
+++ b/video/mpegps_decoder.h
@@ -27,12 +27,8 @@
 #include "graphics/surface.h"
 #include "video/video_decoder.h"
 
-#ifdef USE_MAD
-#include <mad.h>
-#endif
-
 namespace Audio {
-class QueuingAudioStream;
+class PacketizedAudioStream;
 }
 
 namespace Common {
@@ -115,10 +111,9 @@ private:
 
 #ifdef USE_MAD
 	// An MPEG audio track
-	// TODO: Merge this with the normal MP3Stream somehow
 	class MPEGAudioTrack : public AudioTrack, public MPEGStream {
 	public:
-		MPEGAudioTrack(Common::SeekableReadStream *firstPacket);
+		MPEGAudioTrack(Common::SeekableReadStream &firstPacket);
 		~MPEGAudioTrack();
 
 		bool sendPacket(Common::SeekableReadStream *packet, uint32 pts, uint32 dts);
@@ -128,32 +123,7 @@ private:
 		Audio::AudioStream *getAudioStream() const;
 
 	private:
-		Audio::QueuingAudioStream *_audStream;
-
-		enum State {
-			MP3_STATE_INIT,  // Need to init the decoder
-			MP3_STATE_READY, // ready for processing data
-			MP3_STATE_EOS    // end of data reached (may need to loop)
-		};
-
-		State _state;
-
-		mad_stream _stream;
-		mad_frame _frame;
-		mad_synth _synth;
-
-		enum {
-			BUFFER_SIZE = 5 * 8192
-		};
-
-		// This buffer contains a slab of input data
-		byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
-
-		void initStream(Common::SeekableReadStream *packet);
-		void deinitStream();
-		void readMP3Data(Common::SeekableReadStream *packet);
-		void readHeader(Common::SeekableReadStream *packet);
-		void decodeMP3Data(Common::SeekableReadStream *packet);
+		Audio::PacketizedAudioStream *_audStream;
 	};
 #endif
 


Commit: ba4469da6a111e208d40808cba50e797180a8edd
    https://github.com/scummvm/scummvm/commit/ba4469da6a111e208d40808cba50e797180a8edd
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
ZVISION: Cleanup the AVI decoder subclass

Changed paths:
    engines/zvision/video/zork_avi_decoder.cpp
    engines/zvision/video/zork_avi_decoder.h



diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index cf8505e..e69b27b 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -34,44 +34,32 @@
 namespace ZVision {
 
 Video::AVIDecoder::AVIAudioTrack *ZorkAVIDecoder::createAudioTrack(Video::AVIDecoder::AVIStreamHeader sHeader, Video::AVIDecoder::PCMWaveFormat wvInfo) {
-	ZorkAVIDecoder::ZorkAVIAudioTrack *audioTrack = new ZorkAVIDecoder::ZorkAVIAudioTrack(sHeader, wvInfo, _soundType);
-	return (Video::AVIDecoder::AVIAudioTrack *)audioTrack;
+	if (wvInfo.tag != kWaveFormatZorkPCM)
+		return new AVIAudioTrack(sHeader, wvInfo, _soundType);
+
+	assert(wvInfo.size == 8);
+	return new ZorkAVIAudioTrack(sHeader, wvInfo, _soundType);
 }
 
-void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
-	bool updateCurChunk = true;
-	if (_audStream) {
-		if (_wvInfo.tag == kWaveFormatZorkPCM) {
-			assert(_wvInfo.size == 8);
-			RawChunkStream::RawChunk chunk = decoder->readNextChunk(stream);
-			delete stream;
+void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {			
+	RawChunkStream::RawChunk chunk = _decoder.readNextChunk(stream);
+	delete stream;
 
-			if (chunk.data) {
-				byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
+	if (chunk.data) {
+		byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
 #ifdef SCUMM_LITTLE_ENDIAN
-				// RawChunkStream produces native endianness int16
-				flags |= Audio::FLAG_LITTLE_ENDIAN;
+		// RawChunkStream produces native endianness int16
+		flags |= Audio::FLAG_LITTLE_ENDIAN;
 #endif
-				_audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
-			}
-		} else {
-			updateCurChunk = false;
-			AVIAudioTrack::queueSound(stream);
-		}
-	} else {
-		delete stream;
+		_audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
 	}
 
-	// The superclass always updates _curChunk, whether or not audio has
-	// been queued, so we should do that too. Unless the superclass already
-	// has done it for us.
-	if (updateCurChunk) {
-		_curChunk++;
-	}
+	_curChunk++;
 }
 
 void ZorkAVIDecoder::ZorkAVIAudioTrack::resetStream() {
-	decoder->init();
+	AVIAudioTrack::resetStream();
+	_decoder.init();
 }
 
 } // End of namespace ZVision
diff --git a/engines/zvision/video/zork_avi_decoder.h b/engines/zvision/video/zork_avi_decoder.h
index 89c0d1e..8e7be71 100644
--- a/engines/zvision/video/zork_avi_decoder.h
+++ b/engines/zvision/video/zork_avi_decoder.h
@@ -41,20 +41,14 @@ private:
 	public:
 		ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
 			Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType),
-			decoder(NULL) {
-			if (_audStream) {
-				decoder = new RawChunkStream(_audStream->isStereo());
-			}
-		}
-		virtual ~ZorkAVIAudioTrack() {
-			if (decoder)
-				delete decoder;
+			_decoder(waveFormat.channels == 2) {
 		}
 
 		void queueSound(Common::SeekableReadStream *stream);
 		void resetStream();
+
 	private:
-		RawChunkStream *decoder;
+		RawChunkStream _decoder;
 	};
 
 	Video::AVIDecoder::AVIAudioTrack *createAudioTrack(Video::AVIDecoder::AVIStreamHeader sHeader, Video::AVIDecoder::PCMWaveFormat wvInfo);


Commit: de2f4e698270937251f0655c19555fb9099df55f
    https://github.com/scummvm/scummvm/commit/de2f4e698270937251f0655c19555fb9099df55f
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:53-04:00

Commit Message:
VIDEO: Add support for MP3 in AVI

Changed paths:
    engines/zvision/video/zork_avi_decoder.cpp
    video/avi_decoder.cpp
    video/avi_decoder.h



diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index e69b27b..53b0a9a 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -51,7 +51,7 @@ void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *s
 		// RawChunkStream produces native endianness int16
 		flags |= Audio::FLAG_LITTLE_ENDIAN;
 #endif
-		_audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
+		_queueStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
 	}
 
 	_curChunk++;
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp
index 700975d..aef5e76 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -31,6 +31,7 @@
 
 // Audio Codecs
 #include "audio/decoders/adpcm.h"
+#include "audio/decoders/mp3.h"
 #include "audio/decoders/raw.h"
 
 // Video Codecs
@@ -841,15 +842,18 @@ void AVIDecoder::AVIVideoTrack::setDither(const byte *palette) {
 
 AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType)
 		: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType), _curChunk(0) {
-	_audStream = createAudioStream();
+	createAudioStream();
 }
 
 AVIDecoder::AVIAudioTrack::~AVIAudioTrack() {
-	delete _audStream;
+	delete _queueStream;
+	delete _packetStream;
 }
 
 void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
-	if (_audStream) {
+	if (_packetStream) {
+		_packetStream->queuePacket(stream);
+	} else if (_queueStream) {
 		if (_wvInfo.tag == kWaveFormatPCM) {
 			byte flags = 0;
 			if (_audsHeader.sampleSize == 2)
@@ -860,13 +864,13 @@ void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
 			if (_wvInfo.channels == 2)
 				flags |= Audio::FLAG_STEREO;
 
-			_audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES);
+			_queueStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES);
 		} else if (_wvInfo.tag == kWaveFormatMSADPCM) {
-			_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
+			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
 		} else if (_wvInfo.tag == kWaveFormatMSIMAADPCM) {
-			_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
+			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
 		} else if (_wvInfo.tag == kWaveFormatDK3) {
-			_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
+			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
 		}
 	} else {
 		delete stream;
@@ -882,17 +886,22 @@ void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Au
 	if (skipFrames <= 0)
 		return;
 
-	if (_audStream->isStereo())
+	Audio::AudioStream *audioStream = getAudioStream();
+	if (!audioStream)
+		return;
+
+	if (audioStream->isStereo())
 		skipFrames *= 2;
 
 	int16 *tempBuffer = new int16[skipFrames];
-	_audStream->readBuffer(tempBuffer, skipFrames);
+	audioStream->readBuffer(tempBuffer, skipFrames);
 	delete[] tempBuffer;
 }
 
 void AVIDecoder::AVIAudioTrack::resetStream() {
-	delete _audStream;
-	_audStream = createAudioStream();
+	delete _queueStream;
+	delete _packetStream;
+	createAudioStream();
 	_curChunk = 0;
 }
 
@@ -902,18 +911,32 @@ bool AVIDecoder::AVIAudioTrack::rewind() {
 }
 
 Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const {
-	return _audStream;
-}
-
-Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() {
-	if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3)
-		return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
-	else if (_wvInfo.tag == kWaveFormatMP3)
-		warning("Unsupported AVI MP3 tracks");
-	else if (_wvInfo.tag != kWaveFormatNone) // No sound
+	if (_packetStream)
+		return _packetStream;
+
+	return _queueStream;
+}
+
+void AVIDecoder::AVIAudioTrack::createAudioStream() {
+	_queueStream = 0;
+	_packetStream = 0;
+
+	if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3) {
+		// For now, a QueuingAudioStream will be created
+	} else if (_wvInfo.tag == kWaveFormatMP3) {
+		// MPEG audio
+#ifdef USE_MAD
+		_packetStream = Audio::makePacketizedMP3Stream(_wvInfo.channels, _wvInfo.samplesPerSec);
+#else
+		warning("AVI MP3 stream found, but no libmad support compiled in");
+#endif
+	} else if (_wvInfo.tag != kWaveFormatNone) {
+		// No supported format
 		warning("Unsupported AVI audio format %d", _wvInfo.tag);
+	}
 
-	return 0;
+	if (!_packetStream)
+		_queueStream = Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
 }
 
 AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
diff --git a/video/avi_decoder.h b/video/avi_decoder.h
index 6c1ce1a..8b12c23 100644
--- a/video/avi_decoder.h
+++ b/video/avi_decoder.h
@@ -32,6 +32,7 @@
 #include "audio/mixer.h"
 
 namespace Audio {
+class PacketizedAudioStream;
 class QueuingAudioStream;
 }
 
@@ -241,8 +242,9 @@ protected:
 		AVIStreamHeader _audsHeader;
 		PCMWaveFormat _wvInfo;
 		Audio::Mixer::SoundType _soundType;
-		Audio::QueuingAudioStream *_audStream;
-		Audio::QueuingAudioStream *createAudioStream();
+		Audio::QueuingAudioStream *_queueStream;
+		Audio::PacketizedAudioStream *_packetStream;
+		void createAudioStream();
 		uint32 _curChunk;
 	};
 


Commit: a64aff02878eaaeda3a014cbfc71daf760000136
    https://github.com/scummvm/scummvm/commit/a64aff02878eaaeda3a014cbfc71daf760000136
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:54-04:00

Commit Message:
AUDIO: Add a class to easily make stateless PacketizedAudioStreams

Changed paths:
    audio/audiostream.h



diff --git a/audio/audiostream.h b/audio/audiostream.h
index c3dbdcf..6019aca 100644
--- a/audio/audiostream.h
+++ b/audio/audiostream.h
@@ -395,6 +395,44 @@ public:
 	virtual void finish() = 0;
 };
 
+/**
+ * A PacketizedAudioStream that works closer to a QueuingAudioStream.
+ * It queues individual packets as whole AudioStream to an internal
+ * QueuingAudioStream. This is used for writing quick wrappers against
+ * e.g. RawStream, which can be made into PacketizedAudioStreams with
+ * little effort.
+ */
+class StatelessPacketizedAudioStream : public PacketizedAudioStream {
+public:
+	StatelessPacketizedAudioStream(uint rate, uint channels) :
+		_rate(rate), _channels(channels), _stream(makeQueuingAudioStream(rate, channels == 2)) {}
+	virtual ~StatelessPacketizedAudioStream() {}
+
+	// AudioStream API
+	bool isStereo() const { return _channels == 2; }
+	int getRate() const { return _rate; }
+	int readBuffer(int16 *data, const int numSamples) { return _stream->readBuffer(data, numSamples); }
+	bool endOfData() const { return _stream->endOfData(); }
+	bool endOfStream() const { return _stream->endOfStream(); }
+
+	// PacketizedAudioStream API
+	void queuePacket(Common::SeekableReadStream *data) { _stream->queueAudioStream(makeStream(data)); }
+	void finish() { _stream->finish(); }
+
+	uint getChannels() const { return _channels; }
+
+protected:
+	/**
+	 * Make the AudioStream for a given packet
+	 */
+	virtual AudioStream *makeStream(Common::SeekableReadStream *data) = 0;
+
+private:
+	uint _rate;
+	uint _channels;
+	Common::ScopedPtr<QueuingAudioStream> _stream;
+};
+
 } // End of namespace Audio
 
 #endif


Commit: 3aa9e2c5816aad20aa18e04d3a6644a8f79a4e29
    https://github.com/scummvm/scummvm/commit/3aa9e2c5816aad20aa18e04d3a6644a8f79a4e29
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:54-04:00

Commit Message:
AUDIO: Add a packetized version of the PCM stream

Changed paths:
    audio/decoders/raw.cpp
    audio/decoders/raw.h



diff --git a/audio/decoders/raw.cpp b/audio/decoders/raw.cpp
index 9a9f790..477a8e7 100644
--- a/audio/decoders/raw.cpp
+++ b/audio/decoders/raw.cpp
@@ -221,4 +221,24 @@ SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size,
 	return makeRawStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, flags, DisposeAfterUse::YES);
 }
 
+class PacketizedRawStream : public StatelessPacketizedAudioStream {
+public:
+	PacketizedRawStream(int rate, byte flags) :
+		StatelessPacketizedAudioStream(rate, ((flags & FLAG_STEREO) != 0) ? 2 : 1), _flags(flags) {}
+
+protected:
+	AudioStream *makeStream(Common::SeekableReadStream *data);
+
+private:
+	byte _flags;
+};
+
+AudioStream *PacketizedRawStream::makeStream(Common::SeekableReadStream *data) {
+	return makeRawStream(data, getRate(), _flags);
+}
+
+PacketizedAudioStream *makePacketizedRawStream(int rate, byte flags) {
+	return new PacketizedRawStream(rate, flags);
+}
+
 } // End of namespace Audio
diff --git a/audio/decoders/raw.h b/audio/decoders/raw.h
index 14e7bd4..7ccbcda 100644
--- a/audio/decoders/raw.h
+++ b/audio/decoders/raw.h
@@ -35,6 +35,7 @@ class SeekableReadStream;
 
 namespace Audio {
 
+class PacketizedAudioStream;
 class SeekableAudioStream;
 
 /**
@@ -89,6 +90,17 @@ SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
                                    int rate, byte flags,
                                    DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
 
+/**
+ * Creates a PacketizedAudioStream that will automatically queue
+ * packets as individual AudioStreams like returned by makeRawStream.
+ *
+ * @param rate   Rate of the sound data.
+ * @param flags	 Audio flags combination.
+ * @see RawFlags
+ * @return The new PacketizedAudioStream.
+ */
+PacketizedAudioStream *makePacketizedRawStream(int rate, byte flags);
+
 } // End of namespace Audio
 
 #endif


Commit: 331d8ece21948bb07f43be512ab686bb41cf01fa
    https://github.com/scummvm/scummvm/commit/331d8ece21948bb07f43be512ab686bb41cf01fa
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T19:53:54-04:00

Commit Message:
AUDIO: Add a packetized version of ADPCM streams

Changed paths:
    audio/decoders/adpcm.cpp
    audio/decoders/adpcm.h



diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp
index 2f710f7..fe5eec5 100644
--- a/audio/decoders/adpcm.cpp
+++ b/audio/decoders/adpcm.cpp
@@ -457,4 +457,34 @@ RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, Dispo
 	}
 }
 
+class PacketizedADPCMStream : public StatelessPacketizedAudioStream {
+public:
+	PacketizedADPCMStream(ADPCMType type, int rate, int channels, uint32 blockAlign) :
+		StatelessPacketizedAudioStream(rate, channels), _type(type), _blockAlign(blockAlign) {}
+
+protected:
+	AudioStream *makeStream(Common::SeekableReadStream *data);
+
+private:
+	ADPCMType _type;
+	uint32 _blockAlign;
+};
+
+AudioStream *PacketizedADPCMStream::makeStream(Common::SeekableReadStream *data) {
+	return makeADPCMStream(data, DisposeAfterUse::YES, data->size(), _type, getRate(), getChannels(), _blockAlign);
+}
+
+PacketizedAudioStream *makePacketizedADPCMStream(ADPCMType type, int rate, int channels, uint32 blockAlign) {
+	// Filter out types we can't support (they're not fully stateless)
+	switch (type) {
+	case kADPCMOki:
+	case kADPCMDVI:
+		return 0;
+	default:
+		break;
+	}
+
+	return new PacketizedADPCMStream(type, rate, channels, blockAlign);
+}
+
 } // End of namespace Audio
diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h
index bf6e7f7..650bc34 100644
--- a/audio/decoders/adpcm.h
+++ b/audio/decoders/adpcm.h
@@ -44,6 +44,7 @@ class SeekableReadStream;
 
 namespace Audio {
 
+class PacketizedAudioStream;
 class RewindableAudioStream;
 
 // There are several types of ADPCM encoding, only some are supported here
@@ -81,6 +82,26 @@ RewindableAudioStream *makeADPCMStream(
     int channels,
     uint32 blockAlign = 0);
 
+/**
+ * Creates a PacketizedAudioStream that will automatically queue
+ * 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
+ * and will return NULL.
+ *
+ * @param type              the compression type used
+ * @param rate              the sampling rate
+ * @param channels          the number of channels
+ * @param blockAlign        block alignment ???
+ * @return The new PacketizedAudioStream or NULL, if the type isn't supported.
+ */
+PacketizedAudioStream *makePacketizedADPCMStream(
+	ADPCMType type,
+	int rate,
+	int channels,
+	uint32 blockAlign = 0);
+
 } // End of namespace Audio
 
 #endif


Commit: 72239a25f9608935024560ab07f17a47863de0d7
    https://github.com/scummvm/scummvm/commit/72239a25f9608935024560ab07f17a47863de0d7
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T21:00:54-04:00

Commit Message:
AUDIO: Add a NullAudioStream for streams that are dead-on-arrival

Changed paths:
    audio/audiostream.cpp
    audio/audiostream.h



diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp
index c413edb..88c41e8 100644
--- a/audio/audiostream.cpp
+++ b/audio/audiostream.cpp
@@ -33,6 +33,7 @@
 #include "audio/decoders/quicktime.h"
 #include "audio/decoders/raw.h"
 #include "audio/decoders/vorbis.h"
+#include "audio/mixer.h"
 
 
 namespace Audio {
@@ -465,4 +466,24 @@ AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp
 	return new LimitingAudioStream(parentStream, length, disposeAfterUse);
 }
 
+/**
+ * An AudioStream that plays nothing and immediately returns that
+ * the endOfStream() has been reached
+ */
+class NullAudioStream : public AudioStream {
+public:
+        bool isStereo() const { return false; }
+        int getRate() const;
+        int readBuffer(int16 *data, const int numSamples) { return 0; }
+        bool endOfData() const { return true; }
+};
+
+int NullAudioStream::getRate() const {
+	return g_system->getMixer()->getOutputRate();
+}
+
+AudioStream *makeNullAudioStream() {
+	return new NullAudioStream();
+}
+
 } // End of namespace Audio
diff --git a/audio/audiostream.h b/audio/audiostream.h
index 6019aca..a60d5a2 100644
--- a/audio/audiostream.h
+++ b/audio/audiostream.h
@@ -433,6 +433,12 @@ private:
 	Common::ScopedPtr<QueuingAudioStream> _stream;
 };
 
+/**
+ * Create an AudioStream that plays nothing and immediately returns that
+ * endOfStream() has been reached.
+ */
+AudioStream *makeNullAudioStream();
+
 } // End of namespace Audio
 
 #endif


Commit: 561d1a1d62b8abd3f5ff51d66e0c32ea436e68de
    https://github.com/scummvm/scummvm/commit/561d1a1d62b8abd3f5ff51d66e0c32ea436e68de
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T21:01:39-04:00

Commit Message:
VIDEO: Switch to all packetized streams for AVI

ZVision does not currently, but that's OK

Changed paths:
    engines/zvision/video/zork_avi_decoder.cpp
    engines/zvision/video/zork_avi_decoder.h
    video/avi_decoder.cpp
    video/avi_decoder.h



diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index 53b0a9a..fb6bdba 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -41,6 +41,15 @@ Video::AVIDecoder::AVIAudioTrack *ZorkAVIDecoder::createAudioTrack(Video::AVIDec
 	return new ZorkAVIAudioTrack(sHeader, wvInfo, _soundType);
 }
 
+ZorkAVIDecoder::ZorkAVIAudioTrack::ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
+		Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType), _queueStream(0), _decoder(waveFormat.channels == 2) {
+}
+
+void ZorkAVIDecoder::ZorkAVIAudioTrack::createAudioStream() {
+	_queueStream = Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
+	_audioStream = _queueStream;
+}
+
 void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {			
 	RawChunkStream::RawChunk chunk = _decoder.readNextChunk(stream);
 	delete stream;
diff --git a/engines/zvision/video/zork_avi_decoder.h b/engines/zvision/video/zork_avi_decoder.h
index 8e7be71..afcdb05 100644
--- a/engines/zvision/video/zork_avi_decoder.h
+++ b/engines/zvision/video/zork_avi_decoder.h
@@ -39,15 +39,14 @@ public:
 private:
 	class ZorkAVIAudioTrack : public Video::AVIDecoder::AVIAudioTrack {
 	public:
-		ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
-			Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType),
-			_decoder(waveFormat.channels == 2) {
-		}
+		ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType);
 
+		void createAudioStream();
 		void queueSound(Common::SeekableReadStream *stream);
 		void resetStream();
 
 	private:
+		Audio::QueuingAudioStream *_queueStream;
 		RawChunkStream _decoder;
 	};
 
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp
index aef5e76..52a55f6 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -278,7 +278,9 @@ void AVIDecoder::handleStreamHeader(uint32 size) {
 		if (wvInfo.channels == 2)
 			sHeader.sampleSize /= 2;
 
-		addTrack(createAudioTrack(sHeader, wvInfo));
+		AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo);
+		track->createAudioStream();
+		addTrack(track);
 	}
 
 	// Ensure that we're at the end of the chunk
@@ -841,40 +843,18 @@ void AVIDecoder::AVIVideoTrack::setDither(const byte *palette) {
 }
 
 AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType)
-		: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType), _curChunk(0) {
-	createAudioStream();
+		: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType), _audioStream(0), _packetStream(0), _curChunk(0) {
 }
 
 AVIDecoder::AVIAudioTrack::~AVIAudioTrack() {
-	delete _queueStream;
-	delete _packetStream;
+	delete _audioStream;
 }
 
 void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
-	if (_packetStream) {
+	if (_packetStream)
 		_packetStream->queuePacket(stream);
-	} else if (_queueStream) {
-		if (_wvInfo.tag == kWaveFormatPCM) {
-			byte flags = 0;
-			if (_audsHeader.sampleSize == 2)
-				flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
-			else
-				flags |= Audio::FLAG_UNSIGNED;
-
-			if (_wvInfo.channels == 2)
-				flags |= Audio::FLAG_STEREO;
-
-			_queueStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES);
-		} else if (_wvInfo.tag == kWaveFormatMSADPCM) {
-			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
-		} else if (_wvInfo.tag == kWaveFormatMSIMAADPCM) {
-			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
-		} else if (_wvInfo.tag == kWaveFormatDK3) {
-			_queueStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
-		}
-	} else {
+	else
 		delete stream;
-	}
 
 	_curChunk++;
 }
@@ -899,8 +879,7 @@ void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Au
 }
 
 void AVIDecoder::AVIAudioTrack::resetStream() {
-	delete _queueStream;
-	delete _packetStream;
+	delete _audioStream;
 	createAudioStream();
 	_curChunk = 0;
 }
@@ -910,33 +889,50 @@ bool AVIDecoder::AVIAudioTrack::rewind() {
 	return true;
 }
 
-Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const {
-	if (_packetStream)
-		return _packetStream;
-
-	return _queueStream;
-}
-
 void AVIDecoder::AVIAudioTrack::createAudioStream() {
-	_queueStream = 0;
 	_packetStream = 0;
 
-	if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3) {
-		// For now, a QueuingAudioStream will be created
-	} else if (_wvInfo.tag == kWaveFormatMP3) {
-		// MPEG audio
+	switch (_wvInfo.tag) {
+	case kWaveFormatPCM: {
+		byte flags = 0;
+		if (_audsHeader.sampleSize == 2)
+			flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
+		else
+			flags |= Audio::FLAG_UNSIGNED;
+
+		if (_wvInfo.channels == 2)
+			flags |= Audio::FLAG_STEREO;
+
+		_packetStream = Audio::makePacketizedRawStream(_wvInfo.samplesPerSec, flags);
+		break;
+	}
+	case kWaveFormatMSADPCM:
+		_packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
+		break;
+	case kWaveFormatMSIMAADPCM:
+		_packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
+		break;
+	case kWaveFormatDK3:
+		_packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
+		break;
+	case kWaveFormatMP3:
 #ifdef USE_MAD
 		_packetStream = Audio::makePacketizedMP3Stream(_wvInfo.channels, _wvInfo.samplesPerSec);
 #else
 		warning("AVI MP3 stream found, but no libmad support compiled in");
 #endif
-	} else if (_wvInfo.tag != kWaveFormatNone) {
-		// No supported format
+		break;
+	case kWaveFormatNone:
+		break;
+	default:
 		warning("Unsupported AVI audio format %d", _wvInfo.tag);
+		break;
 	}
 
-	if (!_packetStream)
-		_queueStream = Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
+	if (_packetStream)
+		_audioStream = _packetStream;
+	else
+		_audioStream = Audio::makeNullAudioStream();
 }
 
 AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
diff --git a/video/avi_decoder.h b/video/avi_decoder.h
index 8b12c23..96d9e82 100644
--- a/video/avi_decoder.h
+++ b/video/avi_decoder.h
@@ -32,8 +32,8 @@
 #include "audio/mixer.h"
 
 namespace Audio {
+class AudioStream;
 class PacketizedAudioStream;
-class QueuingAudioStream;
 }
 
 namespace Common {
@@ -216,6 +216,7 @@ protected:
 		AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType);
 		~AVIAudioTrack();
 
+		virtual void createAudioStream();
 		virtual void queueSound(Common::SeekableReadStream *stream);
 		Audio::Mixer::SoundType getSoundType() const { return _soundType; }
 		void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime);
@@ -227,7 +228,7 @@ protected:
 		bool rewind();
 
 	protected:
-		Audio::AudioStream *getAudioStream() const;
+		Audio::AudioStream *getAudioStream() const { return _audioStream; }
 
 		// Audio Codecs
 		enum {
@@ -242,9 +243,8 @@ protected:
 		AVIStreamHeader _audsHeader;
 		PCMWaveFormat _wvInfo;
 		Audio::Mixer::SoundType _soundType;
-		Audio::QueuingAudioStream *_queueStream;
+		Audio::AudioStream *_audioStream;
 		Audio::PacketizedAudioStream *_packetStream;
-		void createAudioStream();
 		uint32 _curChunk;
 	};
 


Commit: c8a7e39e0522b32e29ab403188f56bee9cf1da27
    https://github.com/scummvm/scummvm/commit/c8a7e39e0522b32e29ab403188f56bee9cf1da27
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2015-08-30T21:01:43-04:00

Commit Message:
AUDIO: Mark the old Codec class as deprecated

Once QuickTime audio edits are rewritten to use PacketizedAudioStream, we can remove this class.

Changed paths:
    audio/decoders/codec.h



diff --git a/audio/decoders/codec.h b/audio/decoders/codec.h
index 93b6878..75910c0 100644
--- a/audio/decoders/codec.h
+++ b/audio/decoders/codec.h
@@ -31,6 +31,13 @@ namespace Audio {
 
 class AudioStream;
 
+/**
+ * @deprecated The old method of handling audio codecs that rely
+ * on the state remaining the same between calls. This should
+ * only be used for old code.
+ *
+ * DEPRECATED; USE PacketizedAudioStream INSTEAD!
+ */
 class Codec {
 public:
 	Codec() {}






More information about the Scummvm-git-logs mailing list