diff options
-rw-r--r-- | engines/mohawk/video/qt_player.cpp | 47 | ||||
-rw-r--r-- | engines/mohawk/video/qt_player.h | 27 | ||||
-rw-r--r-- | sound/audiostream.cpp | 159 | ||||
-rw-r--r-- | sound/audiostream.h | 45 |
4 files changed, 188 insertions, 90 deletions
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp index 8c6e9b1a95..d9d4a68dac 100644 --- a/engines/mohawk/video/qt_player.cpp +++ b/engines/mohawk/video/qt_player.cpp @@ -51,47 +51,6 @@ namespace Mohawk { //////////////////////////////////////////// -// QueuedAudioStream -//////////////////////////////////////////// - -QueuedAudioStream::QueuedAudioStream(int rate, int channels, bool autofree) { - _rate = rate; - _channels = channels; - _autofree = autofree; - _finished = false; -} - -QueuedAudioStream::~QueuedAudioStream() { - if (_autofree) - while (!_queue.empty()) - delete _queue.pop(); - _queue.clear(); -} - -void QueuedAudioStream::queueAudioStream(Audio::AudioStream *audStream) { - if (audStream->getRate() != getRate() && audStream->isStereo() && isStereo()) - error("QueuedAudioStream::queueAudioStream: audStream has mismatched parameters"); - - _queue.push(audStream); -} - -int QueuedAudioStream::readBuffer(int16 *buffer, const int numSamples) { - int samplesDecoded = 0; - - while (samplesDecoded < numSamples && !_queue.empty()) { - samplesDecoded += _queue.front()->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); - - if (_queue.front()->endOfData()) { - Audio::AudioStream *temp = _queue.pop(); - if (_autofree) - delete temp; - } - } - - return samplesDecoded; -} - -//////////////////////////////////////////// // QTPlayer //////////////////////////////////////////// @@ -189,7 +148,7 @@ void QTPlayer::reset() { stopAudio(); if (_audioStreamIndex >= 0) { _curAudioChunk = 0; - _audStream = new QueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels); + _audStream = Audio::makeQueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2); } startAudio(); } @@ -345,7 +304,7 @@ bool QTPlayer::loadFile(Common::SeekableReadStream *stream) { } if (_audioStreamIndex >= 0 && checkAudioCodecSupport(_streams[_audioStreamIndex]->codec_tag)) { - _audStream = new QueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels); + _audStream = Audio::makeQueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2); _curAudioChunk = 0; // Make sure the bits per sample transfers to the sample size @@ -1229,7 +1188,7 @@ void QTPlayer::updateAudioBuffer() { return; // Keep two streams in buffer so that when the first ends, it goes right into the next - for (; _audStream->streamsInQueue() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) { + for (; _audStream->numQueuedStreams() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) { Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic(); _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]); diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h index 4bdf5b869b..5ff27a57c5 100644 --- a/engines/mohawk/video/qt_player.h +++ b/engines/mohawk/video/qt_player.h @@ -46,31 +46,6 @@ namespace Common { namespace Mohawk { -class QueuedAudioStream : public Audio::AudioStream { -public: - QueuedAudioStream(int rate, int channels, bool autofree = true); - ~QueuedAudioStream(); - - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return _channels == 2; } - int getRate() const { return _rate; } - bool endOfData() const { return _queue.empty(); } - bool endOfStream() const { return _finished; } - - void queueAudioStream(Audio::AudioStream *audStream); - void finish() { _finished = true; } - - uint32 streamsInQueue() { return _queue.size(); } - -private: - bool _autofree; - bool _finished; - int _rate; - int _channels; - - Common::Queue<Audio::AudioStream*> _queue; -}; - enum ScaleMode { kScaleNormal = 1, kScaleHalf = 2, @@ -271,7 +246,7 @@ protected: void resetInternal(); uint32 getFrameDuration(); - QueuedAudioStream *_audStream; + Audio::QueuedAudioStream *_audStream; int8 _videoStreamIndex; int8 _audioStreamIndex; uint _curAudioChunk; diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 98cece6dfb..16c5ff673a 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -27,6 +27,7 @@ #include "common/endian.h" #include "common/file.h" #include "common/list.h" +#include "common/queue.h" #include "common/util.h" #include "sound/audiostream.h" @@ -523,15 +524,15 @@ bool LinearDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp & return new LinearMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree) SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd) { - const bool isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::Mixer::FLAG_16BITS) != 0; - const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0; - const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; - const bool autoFree = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0; + const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0; + const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0; + const bool isUnsigned = (flags & Mixer::FLAG_UNSIGNED) != 0; + const bool isLE = (flags & Mixer::FLAG_LITTLE_ENDIAN) != 0; + const bool autoFree = (flags & Mixer::FLAG_AUTOFREE) != 0; uint loopOffset = 0, loopLen = 0; - if (flags & Audio::Mixer::FLAG_LOOP) { + if (flags & Mixer::FLAG_LOOP) { if (loopEnd == 0) loopEnd = len; assert(loopStart <= loopEnd); @@ -578,11 +579,11 @@ SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd) { - const bool isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::Mixer::FLAG_16BITS) != 0; - const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0; - const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; - const bool loop = (flags & Audio::Mixer::FLAG_LOOP) != 0; + const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0; + const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0; + const bool isUnsigned = (flags & Mixer::FLAG_UNSIGNED) != 0; + const bool isLE = (flags & Mixer::FLAG_LITTLE_ENDIAN) != 0; + const bool loop = (flags & Mixer::FLAG_LOOP) != 0; if (isStereo) { if (isUnsigned) { @@ -600,8 +601,6 @@ SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, Li } - - #pragma mark - #pragma mark --- Appendable audio stream --- #pragma mark - @@ -617,16 +616,18 @@ struct Buffer { class BaseAppendableMemoryStream : public AppendableAudioStream { protected: - // A mutex to avoid access problems (causing e.g. corruption of - // the linked list) in thread aware environments. + /** + * A mutex to avoid access problems (causing e.g. corruption of + * the linked list) in thread aware environments. + */ Common::Mutex _mutex; // List of all queued buffers Common::List<Buffer> _bufferQueue; - // Position in the front buffer, if any bool _finalized; const int _rate; + // Position in the front buffer, if any byte *_pos; inline bool eosIntern() const { return _bufferQueue.empty(); }; @@ -739,10 +740,10 @@ void BaseAppendableMemoryStream::queueBuffer(byte *data, uint32 size) { return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate) AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags) { - const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0; - const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0; - const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0; - const bool isLE = (_flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; + const bool isStereo = (_flags & Mixer::FLAG_STEREO) != 0; + const bool is16Bit = (_flags & Mixer::FLAG_16BITS) != 0; + const bool isUnsigned = (_flags & Mixer::FLAG_UNSIGNED) != 0; + const bool isLE = (_flags & Mixer::FLAG_LITTLE_ENDIAN) != 0; if (isStereo) { if (isUnsigned) { @@ -760,4 +761,122 @@ AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags) { } + + + +#pragma mark - +#pragma mark --- Appendable audio stream --- +#pragma mark - + + +class QueuedAudioStreamImpl : public QueuedAudioStream { +private: + /** + * We queue a number of (pointers to) audio stream objects. + * In addition, we need to remember for each stream whether + * to dispose it after all data has been read from it. + * Hence, we don't store pointers to stream objects directly, + * but rather StreamHolder structs. + */ + struct StreamHolder { + AudioStream *_stream; + bool _disposeAfterUse; + StreamHolder(AudioStream *stream, bool disposeAfterUse) + : _stream(stream), + _disposeAfterUse(disposeAfterUse) {} + }; + + /** + * The sampling rate of this audio stream. + */ + const int _rate; + + /** + * Whether this audio stream is mono (=false) or stereo (=true). + */ + const int _stereo; + + /** + * This flag is set by the finish() method only. See there for more details. + */ + bool _finished; + + /** + * A mutex to avoid access problems (causing e.g. corruption of + * the linked list) in thread aware environments. + */ + Common::Mutex _mutex; + + /** + * The queue of audio streams. + */ + Common::Queue<StreamHolder> _queue; + +public: + QueuedAudioStreamImpl(int rate, bool stereo) + : _rate(rate), _stereo(stereo), _finished(false) {} + ~QueuedAudioStreamImpl(); + + // Implement the AudioStream API + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return _stereo; } + virtual int getRate() const { return _rate; } + virtual bool endOfData() const { + //Common::StackLock lock(_mutex); + return _queue.empty(); + } + virtual bool endOfStream() const { return _finished; } + + // Implement the QueuedAudioStream API + virtual void queueAudioStream(AudioStream *stream, bool disposeAfterUse); + virtual void finish() { _finished = true; } + + uint32 numQueuedStreams() const { + //Common::StackLock lock(_mutex); + return _queue.size(); + } +}; + +QueuedAudioStreamImpl::~QueuedAudioStreamImpl() { + while (!_queue.empty()) { + StreamHolder tmp = _queue.pop(); + if (tmp._disposeAfterUse) + delete tmp._stream; + } +} + +void QueuedAudioStreamImpl::queueAudioStream(AudioStream *stream, bool disposeAfterUse) { + if ((stream->getRate() != getRate()) || (stream->isStereo() != isStereo())) + error("QueuedAudioStreamImpl::queueAudioStream: stream has mismatched parameters"); + + Common::StackLock lock(_mutex); + _queue.push(StreamHolder(stream, disposeAfterUse)); +} + +int QueuedAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + int samplesDecoded = 0; + + while (samplesDecoded < numSamples && !_queue.empty()) { + AudioStream *stream = _queue.front()._stream; + samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); + + if (stream->endOfData() ) { + StreamHolder tmp = _queue.pop(); + if (tmp._disposeAfterUse) + delete stream; + } + } + + return samplesDecoded; +} + + + +QueuedAudioStream *makeQueuedAudioStream(int rate, bool stereo) { + return new QueuedAudioStreamImpl(rate, stereo); +} + + + } // End of namespace Audio diff --git a/sound/audiostream.h b/sound/audiostream.h index e418c2d524..7ffbeab5cb 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -319,6 +319,51 @@ public: */ AppendableAudioStream *makeAppendableAudioStream(int rate, byte flags); + +class QueuedAudioStream : public Audio::AudioStream { +public: + + /** + * Queue an audio stream for playback. This stream will + * play all queued streams, in the order they were queued. + * If the disposeAfterUse is true, then the stream is + * deleted after all data contained in it has been played. + */ + virtual void queueAudioStream(Audio::AudioStream *audStream, + bool disposeAfterUse = true) = 0; + + /** + * Queue a block of raw audio data for playback. This stream + * will play all queued buffers, in the order they were + * queued. After all data contained in them has been played, + * the buffer will be delete[]'d (so make sure to allocate them + * with new[], not with malloc). + */ + void queueBuffer(byte *data, uint32 size, byte flags) { + AudioStream *stream = makeLinearInputStream(data, size, getRate(), flags, 0, 0); + queueAudioStream(stream, true); + } + + /** + * Mark the stream as finished, that is, signal that no further data + * will be appended to it. Only after this has been done can this + * stream ever 'end'. + */ + virtual void finish() = 0; + + /** + * Return the number of streams still queued for playback (including + * the currently playing stream). + */ + virtual uint32 numQueuedStreams() const = 0; +}; + +/** + * Factory function for an QueuedAudioStream. + */ +QueuedAudioStream *makeQueuedAudioStream(int rate, bool stereo); + + /** * Calculates the sample, which the timestamp describes in a * AudioStream with the given framerate. |