aboutsummaryrefslogtreecommitdiff
path: root/audio/decoders
diff options
context:
space:
mode:
Diffstat (limited to 'audio/decoders')
-rw-r--r--audio/decoders/aac.h6
-rw-r--r--audio/decoders/adpcm.h4
-rw-r--r--audio/decoders/adpcm_intern.h10
-rw-r--r--audio/decoders/aiff.h4
-rw-r--r--audio/decoders/flac.cpp4
-rw-r--r--audio/decoders/flac.h7
-rw-r--r--audio/decoders/iff_sound.cpp2
-rw-r--r--audio/decoders/iff_sound.h4
-rw-r--r--audio/decoders/mac_snd.h5
-rw-r--r--audio/decoders/mp3.h7
-rw-r--r--audio/decoders/qdm2.cpp8
-rw-r--r--audio/decoders/quicktime.cpp32
-rw-r--r--audio/decoders/raw.cpp174
-rw-r--r--audio/decoders/raw.h60
-rw-r--r--audio/decoders/voc.cpp677
-rw-r--r--audio/decoders/voc.h12
-rw-r--r--audio/decoders/vorbis.h7
-rw-r--r--audio/decoders/wave.cpp7
-rw-r--r--audio/decoders/wave.h4
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"