diff options
Diffstat (limited to 'audio/decoders')
| -rw-r--r-- | audio/decoders/aac.h | 6 | ||||
| -rw-r--r-- | audio/decoders/adpcm.h | 4 | ||||
| -rw-r--r-- | audio/decoders/adpcm_intern.h | 10 | ||||
| -rw-r--r-- | audio/decoders/aiff.h | 4 | ||||
| -rw-r--r-- | audio/decoders/flac.cpp | 4 | ||||
| -rw-r--r-- | audio/decoders/flac.h | 7 | ||||
| -rw-r--r-- | audio/decoders/iff_sound.cpp | 2 | ||||
| -rw-r--r-- | audio/decoders/iff_sound.h | 4 | ||||
| -rw-r--r-- | audio/decoders/mac_snd.h | 5 | ||||
| -rw-r--r-- | audio/decoders/mp3.h | 7 | ||||
| -rw-r--r-- | audio/decoders/qdm2.cpp | 8 | ||||
| -rw-r--r-- | audio/decoders/quicktime.cpp | 32 | ||||
| -rw-r--r-- | audio/decoders/raw.cpp | 174 | ||||
| -rw-r--r-- | audio/decoders/raw.h | 60 | ||||
| -rw-r--r-- | audio/decoders/voc.cpp | 677 | ||||
| -rw-r--r-- | audio/decoders/voc.h | 12 | ||||
| -rw-r--r-- | audio/decoders/vorbis.h | 7 | ||||
| -rw-r--r-- | audio/decoders/wave.cpp | 7 | ||||
| -rw-r--r-- | audio/decoders/wave.h | 4 |
19 files changed, 547 insertions, 487 deletions
diff --git a/audio/decoders/aac.h b/audio/decoders/aac.h index 68e322c844..9ad78b28a4 100644 --- a/audio/decoders/aac.h +++ b/audio/decoders/aac.h @@ -26,8 +26,8 @@ * - groovie */ -#ifndef SOUND_AAC_H -#define SOUND_AAC_H +#ifndef AUDIO_AAC_H +#define AUDIO_AAC_H #include "common/scummsys.h" #include "common/types.h" @@ -59,4 +59,4 @@ Codec *makeAACDecoder( } // End of namespace Audio #endif // #ifdef USE_FAAD -#endif // #ifndef SOUND_AAC_H +#endif // #ifndef AUDIO_AAC_H diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h index 1dd4d510df..ac8d529917 100644 --- a/audio/decoders/adpcm.h +++ b/audio/decoders/adpcm.h @@ -31,8 +31,8 @@ * - tinsel */ -#ifndef SOUND_ADPCM_H -#define SOUND_ADPCM_H +#ifndef AUDIO_ADPCM_H +#define AUDIO_ADPCM_H #include "common/scummsys.h" #include "common/types.h" diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h index 38514d7fca..31747aabaf 100644 --- a/audio/decoders/adpcm_intern.h +++ b/audio/decoders/adpcm_intern.h @@ -28,8 +28,8 @@ * ADPCM decoder implementations. */ -#ifndef SOUND_ADPCM_INTERN_H -#define SOUND_ADPCM_INTERN_H +#ifndef AUDIO_ADPCM_INTERN_H +#define AUDIO_ADPCM_INTERN_H #include "audio/audiostream.h" #include "common/endian.h" @@ -43,7 +43,7 @@ namespace Audio { class ADPCMStream : public RewindableAudioStream { protected: Common::DisposablePtr<Common::SeekableReadStream> _stream; - const int32 _startpos; + int32 _startpos; const int32 _endpos; const int _channels; const uint32 _blockAlign; @@ -97,9 +97,7 @@ protected: public: Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign) - : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) { - memset(&_status, 0, sizeof(_status)); - } + : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {} /** * This table is used by decodeIMA. diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h index 558a018f57..59664bb85a 100644 --- a/audio/decoders/aiff.h +++ b/audio/decoders/aiff.h @@ -28,8 +28,8 @@ * - sword1 */ -#ifndef SOUND_AIFF_H -#define SOUND_AIFF_H +#ifndef AUDIO_AIFF_H +#define AUDIO_AIFF_H #include "common/scummsys.h" #include "common/types.h" diff --git a/audio/decoders/flac.cpp b/audio/decoders/flac.cpp index d06a7b9c0e..bbaf5fd5ae 100644 --- a/audio/decoders/flac.cpp +++ b/audio/decoders/flac.cpp @@ -209,7 +209,7 @@ FLACStream::FLACStream(Common::SeekableReadStream *inStream, bool dispose) ::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FLACStream::callWrapWrite); ::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FLACStream::callWrapMetadata); ::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FLACStream::callWrapError); - ::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this); + ::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void *)this); success = (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK); #else @@ -223,7 +223,7 @@ FLACStream::FLACStream(Common::SeekableReadStream *inStream, bool dispose) &FLACStream::callWrapWrite, &FLACStream::callWrapMetadata, &FLACStream::callWrapError, - (void*)this + (void *)this ) == FLAC__STREAM_DECODER_INIT_STATUS_OK); #endif if (success) { diff --git a/audio/decoders/flac.h b/audio/decoders/flac.h index 3182b26425..f5e31684fe 100644 --- a/audio/decoders/flac.h +++ b/audio/decoders/flac.h @@ -26,7 +26,6 @@ * - agos * - draci * - kyra - * - m4 * - queen * - saga * - sci @@ -37,8 +36,8 @@ * - tucker */ -#ifndef SOUND_FLAC_H -#define SOUND_FLAC_H +#ifndef AUDIO_FLAC_H +#define AUDIO_FLAC_H #include "common/scummsys.h" #include "common/types.h" @@ -68,4 +67,4 @@ SeekableAudioStream *makeFLACStream( } // End of namespace Audio #endif // #ifdef USE_FLAC -#endif // #ifndef SOUND_FLAC_H +#endif // #ifndef AUDIO_FLAC_H diff --git a/audio/decoders/iff_sound.cpp b/audio/decoders/iff_sound.cpp index 4efdce0338..b0c41f0180 100644 --- a/audio/decoders/iff_sound.cpp +++ b/audio/decoders/iff_sound.cpp @@ -75,7 +75,7 @@ struct A8SVXLoader { case ID_BODY: _dataSize = chunk._size; - _data = (int8*)malloc(_dataSize); + _data = (int8 *)malloc(_dataSize); assert(_data); loadData(chunk._stream); return true; diff --git a/audio/decoders/iff_sound.h b/audio/decoders/iff_sound.h index b266e629a1..28b2c67227 100644 --- a/audio/decoders/iff_sound.h +++ b/audio/decoders/iff_sound.h @@ -26,8 +26,8 @@ * - parallaction */ -#ifndef SOUND_IFF_H -#define SOUND_IFF_H +#ifndef AUDIO_IFF_H +#define AUDIO_IFF_H namespace Common { class ReadStream; diff --git a/audio/decoders/mac_snd.h b/audio/decoders/mac_snd.h index cbbd82bbe0..4380808eae 100644 --- a/audio/decoders/mac_snd.h +++ b/audio/decoders/mac_snd.h @@ -23,11 +23,12 @@ /** * @file * Sound decoder used in engines: + * - saga * - sci */ -#ifndef SOUND_MAC_SND_H -#define SOUND_MAC_SND_H +#ifndef AUDIO_MAC_SND_H +#define AUDIO_MAC_SND_H #include "common/scummsys.h" #include "common/types.h" diff --git a/audio/decoders/mp3.h b/audio/decoders/mp3.h index 86ddc599ea..df2ee44805 100644 --- a/audio/decoders/mp3.h +++ b/audio/decoders/mp3.h @@ -26,7 +26,6 @@ * - agos * - draci * - kyra - * - m4 * - mohawk * - queen * - saga @@ -38,8 +37,8 @@ * - tucker */ -#ifndef SOUND_MP3_H -#define SOUND_MP3_H +#ifndef AUDIO_MP3_H +#define AUDIO_MP3_H #include "common/scummsys.h" #include "common/types.h" @@ -69,4 +68,4 @@ SeekableAudioStream *makeMP3Stream( } // End of namespace Audio #endif // #ifdef USE_MAD -#endif // #ifndef SOUND_MP3_H +#endif // #ifndef AUDIO_MP3_H diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp index 19b30217e9..735fb2b6a0 100644 --- a/audio/decoders/qdm2.cpp +++ b/audio/decoders/qdm2.cpp @@ -589,7 +589,7 @@ DECL_FFT(32768,16384,8192) DECL_FFT(65536,32768,16384) void fftCalc(FFTContext *s, FFTComplex *z) { - static void (* const fftDispatch[])(FFTComplex*) = { + static void (* const fftDispatch[])(FFTComplex *) = { fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, }; @@ -857,8 +857,8 @@ void rdftCalc(RDFTContext *s, float *data) { if (s->inverse) { data[0] *= k1; data[1] *= k1; - fftPermute(&s->fft, (FFTComplex*)data); - fftCalc(&s->fft, (FFTComplex*)data); + fftPermute(&s->fft, (FFTComplex *)data); + fftCalc(&s->fft, (FFTComplex *)data); } } @@ -1832,7 +1832,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *extraData, DisposeAfterUse::F _subSampling = _fftOrder - 7; _frequencyRange = 255 / (1 << (2 - _subSampling)); - switch ((_subSampling * 2 + _channels - 1)) { + switch (_subSampling * 2 + _channels - 1) { case 0: tmp = 40; break; diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 8cf0305e88..dcf80ea1c6 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -87,6 +87,9 @@ void QuickTimeAudioDecoder::init() { // Initialize the codec (if necessary) entry->initCodec(); + + if (_tracks[_audioTrackIndex]->editCount > 1) + warning("Multiple edit list entries in an audio track. Things may go awry"); } } } @@ -227,16 +230,23 @@ void QuickTimeAudioDecoder::setAudioStreamPos(const Timestamp &where) { uint32 seekSample = sample; if (!isOldDemuxing()) { - // We shouldn't have audio samples that are a different duration - // That would be quite bad! - if (_tracks[_audioTrackIndex]->timeToSampleCount != 1) { - warning("Failed seeking"); - return; - } + // For MPEG-4 style demuxing, we need to track down the sample based on the time + // The old style demuxing doesn't require this because each "sample"'s duration + // is just 1 + uint32 curSample = 0; + seekSample = 0; + + for (int32 i = 0; i < _tracks[_audioTrackIndex]->timeToSampleCount; i++) { + uint32 sampleCount = _tracks[_audioTrackIndex]->timeToSample[i].count * _tracks[_audioTrackIndex]->timeToSample[i].duration; + + if (sample < curSample + sampleCount) { + seekSample += (sample - curSample) / _tracks[_audioTrackIndex]->timeToSample[i].duration; + break; + } - // Note that duration is in terms of *one* channel - // This eases calculation a bit - seekSample /= _tracks[_audioTrackIndex]->timeToSample[0].duration; + seekSample += _tracks[_audioTrackIndex]->timeToSample[i].count; + curSample += sampleCount; + } } // Now to track down what chunk it's in @@ -414,7 +424,9 @@ public: } Timestamp getLength() const { - return Timestamp(0, _tracks[_audioTrackIndex]->duration, _tracks[_audioTrackIndex]->timeScale); + // TODO: Switch to the other one when audio edits are supported + //return Timestamp(0, _tracks[_audioTrackIndex]->duration, _timeScale); + return Timestamp(0, _tracks[_audioTrackIndex]->mediaDuration, _tracks[_audioTrackIndex]->timeScale); } }; diff --git a/audio/decoders/raw.cpp b/audio/decoders/raw.cpp index 881b8c1d6a..d24e07926e 100644 --- a/audio/decoders/raw.cpp +++ b/audio/decoders/raw.cpp @@ -45,40 +45,18 @@ namespace Audio { /** * This is a stream, which allows for playing raw PCM data from a stream. - * It also features playback of multiple blocks from a given stream. */ template<bool is16Bit, bool isUnsigned, bool isLE> class RawStream : public SeekableAudioStream { public: - RawStream(int rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, const RawStreamBlockList &blocks) - : _rate(rate), _isStereo(stereo), _playtime(0, rate), _stream(stream, disposeStream), _blocks(blocks), _curBlock(_blocks.begin()), _blockLeft(0), _buffer(0) { - - assert(_blocks.size() > 0); - + RawStream(int rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) + : _rate(rate), _isStereo(stereo), _playtime(0, rate), _stream(stream, disposeStream), _endOfData(false), _buffer(0) { // Setup our buffer for readBuffer _buffer = new byte[kSampleBufferLength * (is16Bit ? 2 : 1)]; assert(_buffer); - // Set current buffer state, playing first block - _stream->seek(_curBlock->pos, SEEK_SET); - - // In case of an error we will stop (or rather - // not start) stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len; - } - - // Add up length of all blocks in order to caluclate total play time - int32 len = 0; - for (RawStreamBlockList::const_iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - assert(i->len % (_isStereo ? 2 : 1) == 0); - len += i->len; - } - - _playtime = Timestamp(0, len / (_isStereo ? 2 : 1), rate); + // Calculate the total playtime of the stream + _playtime = Timestamp(0, _stream->size() / (_isStereo ? 2 : 1) / (is16Bit ? 2 : 1), rate); } ~RawStream() { @@ -87,8 +65,8 @@ public: int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return _isStereo; } - bool endOfData() const { return (_curBlock == _blocks.end()) && (_blockLeft == 0); } + bool isStereo() const { return _isStereo; } + bool endOfData() const { return _endOfData; } int getRate() const { return _rate; } Timestamp getLength() const { return _playtime; } @@ -99,18 +77,9 @@ private: const bool _isStereo; ///< Whether this is an stereo stream Timestamp _playtime; ///< Calculated total play time Common::DisposablePtr<Common::SeekableReadStream> _stream; ///< Stream to read data from - const RawStreamBlockList _blocks; ///< Audio block list - - RawStreamBlockList::const_iterator _curBlock; ///< Current audio block number - int32 _blockLeft; ///< How many bytes are still left in the current block - - /** - * Advance one block in the stream in case - * the current one is empty. - */ - void updateBlockIfNeeded(); + bool _endOfData; ///< Whether the stream end has been reached - byte *_buffer; ///< Buffer used in readBuffer + byte *_buffer; ///< Buffer used in readBuffer enum { /** * How many samples we can buffer at once. @@ -169,13 +138,9 @@ int RawStream<is16Bit, isUnsigned, isLE>::fillBuffer(int maxSamples) { // We will only read up to maxSamples while (maxSamples > 0 && !endOfData()) { - // Calculate how many samples we can safely read - // from the current block. - const int len = MIN<int>(maxSamples, _blockLeft); - // Try to read all the sample data and update the // destination pointer. - const int bytesRead = _stream->read(dst, len * (is16Bit ? 2 : 1)); + const int bytesRead = _stream->read(dst, maxSamples * (is16Bit ? 2 : 1)); dst += bytesRead; // Calculate how many samples we actually read. @@ -184,87 +149,31 @@ int RawStream<is16Bit, isUnsigned, isLE>::fillBuffer(int maxSamples) { // Update all status variables bufferedSamples += samplesRead; maxSamples -= samplesRead; - _blockLeft -= samplesRead; - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } - - // Advance to the next block in case the current - // one is already finished. - updateBlockIfNeeded(); + // We stop stream playback, when we reached the end of the data stream. + // We also stop playback when an error occures. + if (_stream->pos() == _stream->size() || _stream->err() || _stream->eos()) + _endOfData = true; } return bufferedSamples; } template<bool is16Bit, bool isUnsigned, bool isLE> -void RawStream<is16Bit, isUnsigned, isLE>::updateBlockIfNeeded() { - // Have we now finished this block? If so, read the next block - if (_blockLeft == 0 && _curBlock != _blocks.end()) { - // Next block - ++_curBlock; - - // Check whether we reached the end of the stream - // yet. In case we did not do this, we will just - // setup the next block as new block. - if (_curBlock != _blocks.end()) { - _stream->seek(_curBlock->pos, SEEK_SET); - - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len; - } - } - } -} - -template<bool is16Bit, bool isUnsigned, bool isLE> bool RawStream<is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) { - _blockLeft = 0; - _curBlock = _blocks.end(); + _endOfData = true; if (where > _playtime) return false; const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); - uint32 curSample = 0; - - // Search for the disk block in which the specific sample is placed - for (_curBlock = _blocks.begin(); _curBlock != _blocks.end(); ++_curBlock) { - uint32 nextBlockSample = curSample + _curBlock->len; - - if (nextBlockSample > seekSample) - break; + _stream->seek(seekSample * (is16Bit ? 2 : 1), SEEK_SET); - curSample = nextBlockSample; - } + // In case of an error we will not continue stream playback. + if (!_stream->err() && !_stream->eos() && _stream->pos() != _stream->size()) + _endOfData = false; - if (_curBlock == _blocks.end()) { - return ((seekSample - curSample) == 0); - } else { - const uint32 offset = seekSample - curSample; - - _stream->seek(_curBlock->pos + offset * (is16Bit ? 2 : 1), SEEK_SET); - - // In case of an error we will stop - // stream playback. - if (_stream->err()) { - _blockLeft = 0; - _curBlock = _blocks.end(); - } else { - _blockLeft = _curBlock->len - offset; - } - - return true; - } + return true; } #pragma mark - @@ -283,28 +192,21 @@ bool RawStream<is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) { #define MAKE_RAW_STREAM(UNSIGNED) \ if (is16Bit) { \ if (isLE) \ - return new RawStream<true, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream, blockList); \ + return new RawStream<true, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream); \ else \ - return new RawStream<true, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList); \ + return new RawStream<true, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream); \ } else \ - return new RawStream<false, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList) + return new RawStream<false, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream) SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - const RawStreamBlockList &blockList, - int rate, - byte flags, + int rate, byte flags, DisposeAfterUse::Flag disposeAfterUse) { const bool isStereo = (flags & Audio::FLAG_STEREO) != 0; const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0; const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0; const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0; - if (blockList.empty()) { - warning("Empty block list passed to makeRawStream"); - if (disposeAfterUse == DisposeAfterUse::YES) - delete stream; - return 0; - } + assert(stream->size() % ((is16Bit ? 2 : 1) * (isStereo ? 2 : 1)) == 0); if (isUnsigned) { MAKE_RAW_STREAM(true); @@ -313,38 +215,10 @@ SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, } } -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - int rate, byte flags, - DisposeAfterUse::Flag disposeAfterUse) { - RawStreamBlockList blocks; - RawStreamBlock block; - block.pos = 0; - - const bool isStereo = (flags & Audio::FLAG_STEREO) != 0; - const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0; - - assert(stream->size() % ((is16Bit ? 2 : 1) * (isStereo ? 2 : 1)) == 0); - - block.len = stream->size() / (is16Bit ? 2 : 1); - blocks.push_back(block); - - return makeRawStream(stream, blocks, rate, flags, disposeAfterUse); -} - SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size, int rate, byte flags, DisposeAfterUse::Flag disposeAfterUse) { return makeRawStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, flags, DisposeAfterUse::YES); } -SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream, RawStreamBlock *block, int numBlocks, - int rate, byte flags, DisposeAfterUse::Flag disposeStream) { - assert(numBlocks > 0); - RawStreamBlockList blocks; - for (int i = 0; i < numBlocks; ++i) - blocks.push_back(block[i]); - - return makeRawStream(stream, blocks, rate, flags, disposeStream); -} - } // End of namespace Audio diff --git a/audio/decoders/raw.h b/audio/decoders/raw.h index 5a7897b688..a06bebee10 100644 --- a/audio/decoders/raw.h +++ b/audio/decoders/raw.h @@ -20,8 +20,8 @@ * */ -#ifndef SOUND_RAW_H -#define SOUND_RAW_H +#ifndef AUDIO_RAW_H +#define AUDIO_RAW_H #include "common/scummsys.h" #include "common/types.h" @@ -60,21 +60,6 @@ enum RawFlags { FLAG_STEREO = 1 << 3 }; - -/** - * Struct used to define the audio data to be played by a RawStream. - */ -struct RawStreamBlock { - int32 pos; ///< Position in stream of the block (in bytes of course!) - int32 len; ///< Length of the block (in raw samples, not sample pairs!) -}; - -/** - * List containing all blocks of a raw stream. - * @see RawStreamBlock - */ -typedef Common::List<RawStreamBlock> RawStreamBlockList; - /** * Creates an audio stream, which plays from the given buffer. * @@ -104,47 +89,6 @@ SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, int rate, byte flags, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); -/** - * Creates an audio stream, which plays from the given stream. - * - * @param stream Stream object to play from. - * @param blockList List of blocks to play. - * @see RawDiskStreamAudioBlock - * @see RawStreamBlockList - * @param rate Rate of the sound data. - * @param flags Audio flags combination. - * @see RawFlags - * @param disposeAfterUse Whether to delete the stream after use. - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream, - const RawStreamBlockList &blockList, - int rate, - byte flags, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); - -/** - * NOTE: - * This API is considered deprecated. - * - * Creates a audio stream, which plays from given stream. - * - * @param stream Stream to play from - * @param block Pointer to an RawStreamBlock array - * @see RawStreamBlock - * @param numBlocks Number of blocks. - * @param rate The rate - * @param flags Flags combination. - * @see RawFlags - * @param disposeStream Whether the "stream" object should be destroyed after playback. - * @return The new SeekableAudioStream (or 0 on failure). - */ -SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream, - RawStreamBlock *block, int numBlocks, - int rate, byte flags, - DisposeAfterUse::Flag disposeStream); - - } // End of namespace Audio #endif diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp index f06e7f95f2..f0b5b2777d 100644 --- a/audio/decoders/voc.cpp +++ b/audio/decoders/voc.cpp @@ -25,305 +25,540 @@ #include "common/util.h" #include "common/stream.h" #include "common/textconsole.h" +#include "common/list.h" #include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "audio/decoders/voc.h" - namespace Audio { -int getSampleRateFromVOCRate(int vocSR) { - if (vocSR == 0xa5 || vocSR == 0xa6) { - return 11025; - } else if (vocSR == 0xd2 || vocSR == 0xd3) { - return 22050; - } else { - int sr = 1000000L / (256L - vocSR); - // inexact sampling rates occur e.g. in the kitchen in Monkey Island, - // very easy to reach right from the start of the game. - //warning("inexact sample rate used: %i (0x%x)", sr, vocSR); - return sr; - } -} +namespace { -byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) { +bool checkVOCHeader(Common::ReadStream &stream) { VocFileHeader fileHeader; - debug(2, "loadVOCFromStream"); - if (stream.read(&fileHeader, 8) != 8) - goto invalid; + return false; if (!memcmp(&fileHeader, "VTLK", 4)) { if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader)) - goto invalid; + return false; } else if (!memcmp(&fileHeader, "Creative", 8)) { if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8) - goto invalid; + return false; } else { - invalid:; - warning("loadVOCFromStream: Invalid header"); - return NULL; + return false; } if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0) - error("loadVOCFromStream: Invalid header"); - if (fileHeader.desc[19] != 0x1A) - debug(3, "loadVOCFromStream: Partially invalid header"); + return false; + //if (fileHeader.desc[19] != 0x1A) + // debug(3, "checkVOCHeader: Partially invalid header"); int32 offset = FROM_LE_16(fileHeader.datablock_offset); int16 version = FROM_LE_16(fileHeader.version); int16 code = FROM_LE_16(fileHeader.id); - assert(offset == sizeof(VocFileHeader)); + + if (offset != sizeof(VocFileHeader)) + return false; + // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and // French version of Simon the Sorcerer 2 (CD) - assert(version == 0x010A || version == 0x0114 || version == 0x0100); - assert(code == ~version + 0x1234); + if (version != 0x010A && version != 0x0114 && version != 0x0100) + return false; - int len; - byte *ret_sound = 0; - size = 0; + if (code != ~version + 0x1234) + return false; - while ((code = stream.readByte())) { - len = stream.readByte(); - len |= stream.readByte() << 8; - len |= stream.readByte() << 16; + return true; +} - debug(2, "Block code %d, len %d", code, len); +class VocStream : public SeekableAudioStream { +public: + VocStream(Common::SeekableReadStream *stream, bool isUnsigned, DisposeAfterUse::Flag disposeAfterUse); + ~VocStream(); + + virtual int readBuffer(int16 *buffer, const int numSamples); + + virtual bool isStereo() const { return false; } + + virtual int getRate() const { return _rate; } + + virtual bool endOfData() const { return (_curBlock == _blocks.end()) && (_blockLeft == 0); } + + virtual bool seek(const Timestamp &where); + + virtual Timestamp getLength() const { return _length; } +private: + void preProcess(); + + Common::SeekableReadStream *const _stream; + const DisposeAfterUse::Flag _disposeAfterUse; + + const bool _isUnsigned; + + int _rate; + Timestamp _length; + + struct Block { + uint8 code; + uint32 length; + + union { + struct { + uint32 offset; + int rate; + int samples; + } sampleBlock; + + struct { + int count; + } loopBlock; + }; + }; + + typedef Common::List<Block> BlockList; + BlockList _blocks; + + BlockList::const_iterator _curBlock; + uint32 _blockLeft; + + /** + * Advance one block in the stream in case + * the current one is empty. + */ + void updateBlockIfNeeded(); + + // Do some internal buffering for systems with really slow slow disk i/o + enum { + /** + * How many samples we can buffer at once. + * + * TODO: Check whether this size suffices + * for systems with slow disk I/O. + */ + kSampleBufferLength = 2048 + }; + byte _buffer[kSampleBufferLength]; + + /** + * Fill the temporary sample buffer used in readBuffer. + * + * @param maxSamples Maximum samples to read. + * @return actual count of samples read. + */ + int fillBuffer(int maxSamples); +}; + +VocStream::VocStream(Common::SeekableReadStream *stream, bool isUnsigned, DisposeAfterUse::Flag disposeAfterUse) + : _stream(stream), _disposeAfterUse(disposeAfterUse), _isUnsigned(isUnsigned), _rate(0), + _length(), _blocks(), _curBlock(_blocks.end()), _blockLeft(0), _buffer() { + preProcess(); +} - switch (code) { - case 1: - case 9: { - int packing; - if (code == 1) { - int time_constant = stream.readByte(); - packing = stream.readByte(); - len -= 2; - rate = getSampleRateFromVOCRate(time_constant); - } else { - rate = stream.readUint32LE(); - int bits = stream.readByte(); - int channels = stream.readByte(); - if (bits != 8 || channels != 1) { - warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels); - break; - } - packing = stream.readUint16LE(); - stream.readUint32LE(); - len -= 12; - } - debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len); - if (packing == 0) { - if (size) { - byte *tmp = (byte *)realloc(ret_sound, size + len); - if (!tmp) - error("Cannot reallocate memory for VOC Data Block"); - - ret_sound = tmp; - } else { - ret_sound = (byte *)malloc(len); - } - stream.read(ret_sound + size, len); - size += len; +VocStream::~VocStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _stream; +} + +int VocStream::readBuffer(int16 *buffer, const int numSamples) { + int samplesLeft = numSamples; + while (samplesLeft > 0) { + // Try to read up to "samplesLeft" samples. + int len = fillBuffer(samplesLeft); + + // In case we were not able to read any samples + // we will stop reading here. + if (!len) + break; + + // Adjust the samples left to read. + samplesLeft -= len; + + // Copy the data to the caller's buffer. + const byte *src = _buffer; + while (len-- > 0) + *buffer++ = (*src++ << 8) ^ (_isUnsigned ? 0x8000 : 0); + } + + return numSamples - samplesLeft; +} + +void VocStream::updateBlockIfNeeded() { + // Have we now finished this block? If so, read the next block + if (_blockLeft == 0 && _curBlock != _blocks.end()) { + // Find the next sample block + while (true) { + // Next block + ++_curBlock; + + // Check whether we reached the end of the stream + // yet. + if (_curBlock == _blocks.end()) + return; + + // Skip all none sample blocks for now + if (_curBlock->code != 1 && _curBlock->code != 9) + continue; + + _stream->seek(_curBlock->sampleBlock.offset, SEEK_SET); + + // In case of an error we will stop + // stream playback. + if (_stream->err()) { + _blockLeft = 0; + _curBlock = _blocks.end(); } else { - warning("VOC file packing %d unsupported", packing); + _blockLeft = _curBlock->sampleBlock.samples; } - } break; - case 3: // silence - // occur with a few Igor sounds, voc file starts with a silence block with a - // frequency different from the data block. Just ignore fow now (implementing - // it wouldn't make a big difference anyway...) - assert(len == 3); - stream.readUint16LE(); - stream.readByte(); - break; - case 6: // begin of loop - assert(len == 2); - stream.readUint16LE(); - break; - case 7: // end of loop - assert(len == 0); + + return; + } + } +} + +int VocStream::fillBuffer(int maxSamples) { + int bufferedSamples = 0; + byte *dst = _buffer; + + // We can only read up to "kSampleBufferLength" samples + // so we take this into consideration, when trying to + // read up to maxSamples. + maxSamples = MIN<int>(kSampleBufferLength, maxSamples); + + // We will only read up to maxSamples + while (maxSamples > 0 && !endOfData()) { + // Calculate how many samples we can safely read + // from the current block. + const int len = MIN<int>(maxSamples, _blockLeft); + + // Try to read all the sample data and update the + // destination pointer. + const int bytesRead = _stream->read(dst, len); + dst += bytesRead; + + // Calculate how many samples we actually read. + const int samplesRead = bytesRead; + + // Update all status variables + bufferedSamples += samplesRead; + maxSamples -= samplesRead; + _blockLeft -= samplesRead; + + // In case of an error we will stop + // stream playback. + if (_stream->err()) { + _blockLeft = 0; + _curBlock = _blocks.end(); break; - case 8: { // "Extended" - // This occures in the LoL Intro demo. - // This block overwrites the next parameters of a block 1 "Sound data". - // To assure we never get any bad data here, we will assert in case - // this tries to define a stereo sound block or tries to use something - // different than 8bit unsigned sound data. - // TODO: Actually we would need to check the frequency divisor (the - // first word) here too. It is used in the following equation: - // sampleRate = 256000000/(channels * (65536 - frequencyDivisor)) - assert(len == 4); - stream.readUint16LE(); - uint8 codec = stream.readByte(); - uint8 channels = stream.readByte() + 1; - assert(codec == 0 && channels == 1); - } break; - default: - warning("Unhandled code %d in VOC file (len %d)", code, len); - return ret_sound; } + + // Advance to the next block in case the current + // one is already finished. + updateBlockIfNeeded(); } - debug(4, "VOC Data Size : %d", size); - return ret_sound; + + return bufferedSamples; } -#ifdef STREAM_AUDIO_FROM_DISK +bool VocStream::seek(const Timestamp &where) { + // Invalidate stream + _blockLeft = 0; + _curBlock = _blocks.end(); -int parseVOCFormat(Common::SeekableReadStream& stream, RawStreamBlock* block, int &rate) { - VocFileHeader fileHeader; - int currentBlock = 0; - int size = 0; + if (where > _length) + return false; - debug(2, "parseVOCFormat"); + // Search for the block containing the requested sample + const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); + uint32 curSample = 0; - if (stream.read(&fileHeader, 8) != 8) - goto invalid; + for (_curBlock = _blocks.begin(); _curBlock != _blocks.end(); ++_curBlock) { + // Skip all none sample blocks for now + if (_curBlock->code != 1 && _curBlock->code != 9) + continue; - if (!memcmp(&fileHeader, "VTLK", 4)) { - if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader)) - goto invalid; - } else if (!memcmp(&fileHeader, "Creative", 8)) { - if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8) - goto invalid; + uint32 nextBlockSample = curSample + _curBlock->sampleBlock.samples; + + if (nextBlockSample > seekSample) + break; + + curSample = nextBlockSample; + } + + if (_curBlock == _blocks.end()) { + return ((seekSample - curSample) == 0); } else { - invalid:; - warning("loadVOCFromStream: Invalid header"); - return 0; + const uint32 offset = seekSample - curSample; + + _stream->seek(_curBlock->sampleBlock.offset + offset, SEEK_SET); + + // In case of an error we will stop + // stream playback. + if (_stream->err()) { + _blockLeft = 0; + _curBlock = _blocks.end(); + } else { + _blockLeft = _curBlock->sampleBlock.samples - offset; + } + + return true; } +} - if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0) - error("loadVOCFromStream: Invalid header"); - if (fileHeader.desc[19] != 0x1A) - debug(3, "loadVOCFromStream: Partially invalid header"); +void VocStream::preProcess() { + Block block; - int32 offset = FROM_LE_16(fileHeader.datablock_offset); - int16 version = FROM_LE_16(fileHeader.version); - int16 code = FROM_LE_16(fileHeader.id); - assert(offset == sizeof(VocFileHeader)); - // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and - // French version of Simon the Sorcerer 2 (CD) - assert(version == 0x010A || version == 0x0114 || version == 0x0100); - assert(code == ~version + 0x1234); + // Scan through the file and collect all blocks + while (true) { + block.code = _stream->readByte(); + block.length = 0; - int len; - size = 0; + // If we hit EOS here we found the end of the VOC file. + // According to http://wiki.multimedia.cx/index.php?title=Creative_Voice + // there is no need for an "Terminator" block to be present. + // In case we hit a "Terminator" block we also break here. + if (_stream->eos() || block.code == 0) + break; + // We also allow 128 as terminator, since Simon 1 Amiga CD32 uses it. + if (block.code == 128) { + debug(3, "VocStream::preProcess: Caught 128 as terminator"); + break; + } - while ((code = stream.readByte())) { - len = stream.readByte(); - len |= stream.readByte() << 8; - len |= stream.readByte() << 16; + block.length = _stream->readByte(); + block.length |= _stream->readByte() << 8; + block.length |= _stream->readByte() << 16; - debug(2, "Block code %d, len %d", code, len); + // Premature end of stream => error! + if (_stream->eos() || _stream->err()) { + warning("VocStream::preProcess: Reading failed"); + return; + } + + uint32 skip = 0; - switch (code) { + switch (block.code) { + // Sound data case 1: - case 9: { - int packing; - if (code == 1) { - int time_constant = stream.readByte(); - packing = stream.readByte(); - len -= 2; - rate = getSampleRateFromVOCRate(time_constant); + // Sound data (New format) + case 9: + if (block.code == 1) { + if (block.length < 2) { + warning("Invalid sound data block length %d in VOC file", block.length); + return; + } + + // Read header data + int freqDiv = _stream->readByte(); + // Prevent division through 0 + if (freqDiv == 256) { + warning("Invalid frequency divisor 256 in VOC file"); + return; + } + block.sampleBlock.rate = getSampleRateFromVOCRate(freqDiv); + + int codec = _stream->readByte(); + // We only support 8bit PCM + if (codec != 0) { + warning("Unhandled codec %d in VOC file", codec); + return; + } + + block.sampleBlock.samples = skip = block.length - 2; + block.sampleBlock.offset = _stream->pos(); + + // Check the last block if there is any + if (_blocks.size() > 0) { + BlockList::iterator lastBlock = _blocks.end(); + --lastBlock; + // When we have found a block 8 as predecessor + // we need to use its settings + if (lastBlock->code == 8) { + block.sampleBlock.rate = lastBlock->sampleBlock.rate; + // Remove the block since we don't need it anymore + _blocks.erase(lastBlock); + } + } } else { - rate = stream.readUint32LE(); - int bits = stream.readByte(); - int channels = stream.readByte(); - if (bits != 8 || channels != 1) { - warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels); - break; + if (block.length < 12) { + warning("Invalid sound data (wew format) block length %d in VOC file", block.length); + return; + } + + block.sampleBlock.rate = _stream->readUint32LE(); + int bitsPerSample = _stream->readByte(); + // We only support 8bit PCM + if (bitsPerSample != 8) { + warning("Unhandled bits per sample %d in VOC file", bitsPerSample); + return; + } + int channels = _stream->readByte(); + // We only support mono + if (channels != 1) { + warning("Unhandled channel count %d in VOC file", channels); + return; } - packing = stream.readUint16LE(); - stream.readUint32LE(); - len -= 12; + int codec = _stream->readUint16LE(); + // We only support 8bit PCM + if (codec != 0) { + warning("Unhandled codec %d in VOC file", codec); + return; + } + /*uint32 reserved = */_stream->readUint32LE(); + block.sampleBlock.offset = _stream->pos(); + block.sampleBlock.samples = skip = block.length - 12; } - debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len); - if (packing == 0) { - // Found a data block - so add it to the block list - block[currentBlock].pos = stream.pos(); - block[currentBlock].len = len; - currentBlock++; + // Check whether we found a new highest rate + if (_rate < block.sampleBlock.rate) + _rate = block.sampleBlock.rate; + break; - stream.seek(len, SEEK_CUR); + // Silence + case 3: { + if (block.length != 3) { + warning("Invalid silence block length %d in VOC file", block.length); + return; + } - size += len; - } else { - warning("VOC file packing %d unsupported", packing); + block.sampleBlock.offset = 0; + + block.sampleBlock.samples = _stream->readUint16LE() + 1; + int freqDiv = _stream->readByte(); + // Prevent division through 0 + if (freqDiv == 256) { + warning("Invalid frequency divisor 256 in VOC file"); + return; } + block.sampleBlock.rate = getSampleRateFromVOCRate(freqDiv); } break; - case 3: // silence - // occur with a few Igor sounds, voc file starts with a silence block with a - // frequency different from the data block. Just ignore fow now (implementing - // it wouldn't make a big difference anyway...) - assert(len == 3); - stream.readUint16LE(); - stream.readByte(); - break; - case 6: // begin of loop - assert(len == 2); - stream.readUint16LE(); - break; - case 7: // end of loop - assert(len == 0); + + // Repeat start + case 6: + if (block.length != 2) { + warning("Invalid repeat start block length %d in VOC file", block.length); + return; + } + + block.loopBlock.count = _stream->readUint16LE() + 1; break; - case 8: // "Extended" - // This occures in the LoL Intro demo. This block can usually be used to create stereo - // sound, but the LoL intro has only an empty block, thus this dummy implementation will - // work. - assert(len == 4); - stream.readUint16LE(); - stream.readByte(); - stream.readByte(); + + // Repeat end + case 7: break; + + // Extra info + case 8: { + if (block.length != 4) + return; + + int freqDiv = _stream->readUint16LE(); + // Prevent division through 0 + if (freqDiv == 65536) { + warning("Invalid frequency divisor 65536 in VOC file"); + return; + } + + int codec = _stream->readByte(); + // We only support RAW 8bit PCM. + if (codec != 0) { + warning("Unhandled codec %d in VOC file", codec); + return; + } + + int channels = _stream->readByte() + 1; + // We only support mono sound right now + if (channels != 1) { + warning("Unhandled channel count %d in VOC file", channels); + return; + } + + block.sampleBlock.offset = 0; + block.sampleBlock.samples = 0; + block.sampleBlock.rate = 256000000L / (65536L - freqDiv); + } break; + default: - warning("Unhandled code %d in VOC file (len %d)", code, len); - return 0; + warning("Unhandled code %d in VOC file (len %d)", block.code, block.length); + return; } - } - debug(4, "VOC Data Size : %d", size); - return currentBlock; -} -SeekableAudioStream *makeVOCDiskStreamNoLoop(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { - const int MAX_AUDIO_BLOCKS = 256; + // Premature end of stream => error! + if (_stream->eos() || _stream->err()) { + warning("VocStream::preProcess: Reading failed"); + return; + } - RawStreamBlock *block = new RawStreamBlock[MAX_AUDIO_BLOCKS]; - int rate; + // Skip the rest of the block + if (skip) + _stream->skip(skip); - int numBlocks = parseVOCFormat(*stream, block, rate); + _blocks.push_back(block); + } - SeekableAudioStream *audioStream = 0; + // Since we determined the sample rate we need for playback now, we will + // initialize the play length. + _length = Timestamp(0, _rate); + + // Calculate the total play time and do some more sanity checks + for (BlockList::const_iterator i = _blocks.begin(), end = _blocks.end(); i != end; ++i) { + // Check whether we found a block 8 which survived, this is not + // allowed to happen! + if (i->code == 8) { + warning("VOC file contains unused block 8"); + return; + } - // Create an audiostream from the data. Note the numBlocks may be 0, - // e.g. when invalid data is encountered. See bug #2890038. - if (numBlocks) - audioStream = makeRawDiskStream_OLD(stream, block, numBlocks, rate, flags, disposeAfterUse); + // For now only use blocks with actual samples + if (i->code != 1 && i->code != 9) + continue; - delete[] block; + // Check the sample rate + if (i->sampleBlock.rate != _rate) { + warning("VOC file contains chunks with different sample rates (%d != %d)", _rate, i->sampleBlock.rate); + return; + } - return audioStream; -} + _length = _length.addFrames(i->sampleBlock.samples); + } -#endif + // Set the current block to the first block in the stream + rewind(); +} -SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { -#ifdef STREAM_AUDIO_FROM_DISK - return makeVOCDiskStreamNoLoop(stream, flags, disposeAfterUse); -#else - int size, rate; +} // End of anonymous namespace - byte *data = loadVOCFromStream(*stream, size, rate); +int getSampleRateFromVOCRate(int vocSR) { + if (vocSR == 0xa5 || vocSR == 0xa6) { + return 11025; + } else if (vocSR == 0xd2 || vocSR == 0xd3) { + return 22050; + } else { + int sr = 1000000L / (256L - vocSR); + // inexact sampling rates occur e.g. in the kitchen in Monkey Island, + // very easy to reach right from the start of the game. + //warning("inexact sample rate used: %i (0x%x)", sr, vocSR); + return sr; + } +} - if (!data) { +SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { + if (!checkVOCHeader(*stream)) { if (disposeAfterUse == DisposeAfterUse::YES) delete stream; return 0; } - return makeRawStream(data, size, rate, flags); -#endif + SeekableAudioStream *audioStream = new VocStream(stream, (flags & Audio::FLAG_UNSIGNED) != 0, disposeAfterUse); + + if (audioStream && audioStream->endOfData()) { + delete audioStream; + return 0; + } else { + return audioStream; + } } } // End of namespace Audio diff --git a/audio/decoders/voc.h b/audio/decoders/voc.h index a920eac933..e16ffce42f 100644 --- a/audio/decoders/voc.h +++ b/audio/decoders/voc.h @@ -30,8 +30,8 @@ * - touche */ -#ifndef SOUND_VOC_H -#define SOUND_VOC_H +#ifndef AUDIO_VOC_H +#define AUDIO_VOC_H #include "common/scummsys.h" #include "common/types.h" @@ -78,14 +78,6 @@ struct VocBlockHeader { extern int getSampleRateFromVOCRate(int vocSR); /** - * Try to load a VOC from the given stream. Returns a pointer to memory - * containing the PCM sample data (allocated with malloc). It is the callers - * responsibility to dellocate that data again later on! Currently this - * function only supports uncompressed raw PCM data. - */ -extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate); - -/** * Try to load a VOC from the given seekable stream and create an AudioStream * from that data. Currently this function only supports uncompressed raw PCM * data. diff --git a/audio/decoders/vorbis.h b/audio/decoders/vorbis.h index e3d989e9b8..3a3052ed7c 100644 --- a/audio/decoders/vorbis.h +++ b/audio/decoders/vorbis.h @@ -26,7 +26,6 @@ * - agos * - draci * - kyra - * - m4 * - queen * - saga * - sci @@ -38,8 +37,8 @@ * - tucker */ -#ifndef SOUND_VORBIS_H -#define SOUND_VORBIS_H +#ifndef AUDIO_VORBIS_H +#define AUDIO_VORBIS_H #include "common/scummsys.h" #include "common/types.h" @@ -69,4 +68,4 @@ SeekableAudioStream *makeVorbisStream( } // End of namespace Audio #endif // #ifdef USE_VORBIS -#endif // #ifndef SOUND_VORBIS_H +#endif // #ifndef AUDIO_VORBIS_H diff --git a/audio/decoders/wave.cpp b/audio/decoders/wave.cpp index 3cf4566d0c..44188f84ca 100644 --- a/audio/decoders/wave.cpp +++ b/audio/decoders/wave.cpp @@ -175,6 +175,13 @@ RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, Dispose else if (type == 2) // MS ADPCM return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMS, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign); + // Raw PCM, make sure the last packet is complete + uint sampleSize = (flags & Audio::FLAG_16BITS ? 2 : 1) * (flags & Audio::FLAG_STEREO ? 2 : 1); + if (size % sampleSize != 0) { + warning("makeWAVStream: Trying to play a WAVE file with an incomplete PCM packet"); + size &= ~(sampleSize - 1); + } + // Raw PCM. Just read everything at once. // TODO: More elegant would be to wrap the stream. byte *data = (byte *)malloc(size); diff --git a/audio/decoders/wave.h b/audio/decoders/wave.h index 6a34bc175a..c8ac7fe318 100644 --- a/audio/decoders/wave.h +++ b/audio/decoders/wave.h @@ -34,8 +34,8 @@ * - tucker */ -#ifndef SOUND_WAVE_H -#define SOUND_WAVE_H +#ifndef AUDIO_WAVE_H +#define AUDIO_WAVE_H #include "common/scummsys.h" #include "common/types.h" |
