aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/kyra/sound_towns.cpp1
-rw-r--r--engines/made/resource.cpp1
-rw-r--r--engines/mohawk/sound.cpp1
-rw-r--r--engines/mohawk/video/qt_player.cpp1
-rw-r--r--engines/parallaction/sound_br.cpp1
-rw-r--r--engines/parallaction/sound_ns.cpp1
-rw-r--r--engines/saga/music.cpp1
-rw-r--r--engines/sci/sound/audio.cpp1
-rw-r--r--engines/sci/sound/iterator/iterator.cpp1
-rw-r--r--engines/sci/sound/music.cpp1
-rw-r--r--engines/sci/sound/seq/instrument-map.cpp1
-rw-r--r--engines/scumm/he/cup_player_he.cpp1
-rw-r--r--engines/scumm/player_mod.cpp1
-rw-r--r--engines/scumm/player_pce.cpp1
-rw-r--r--engines/tucker/sequences.cpp1
-rw-r--r--sound/aiff.cpp1
-rw-r--r--sound/audiostream.cpp428
-rw-r--r--sound/audiostream.h70
-rw-r--r--sound/iff_sound.cpp1
-rw-r--r--sound/mixer.cpp1
-rw-r--r--sound/module.mk1
-rw-r--r--sound/raw.cpp463
-rw-r--r--sound/raw.h108
-rw-r--r--sound/shorten.cpp1
-rw-r--r--sound/voc.cpp1
-rw-r--r--sound/wave.cpp1
26 files changed, 600 insertions, 491 deletions
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 2c42e7fb2b..b4da44df6a 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -30,6 +30,7 @@
#include "sound/audiocd.h"
#include "sound/audiostream.h"
+#include "sound/raw.h"
#include "common/util.h"
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index 2913d23b27..335634598a 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -25,6 +25,7 @@
#include "common/endian.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
#include "made/resource.h"
#include "made/graphics.h"
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index db40555dc9..1c70972b0a 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -29,6 +29,7 @@
#include "sound/audiostream.h"
#include "sound/mp3.h"
+#include "sound/raw.h"
#include "sound/wave.h"
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp
index 2cb1ed364c..50928a0aac 100644
--- a/engines/mohawk/video/qt_player.cpp
+++ b/engines/mohawk/video/qt_player.cpp
@@ -40,6 +40,7 @@
// Audio codecs
#include "sound/adpcm.h"
+#include "sound/raw.h"
#include "mohawk/video/qdm2.h"
// Video codecs
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 003861d501..1441a313bc 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -31,6 +31,7 @@
#include "sound/mididrv.h"
#include "sound/midiparser.h"
#include "sound/mods/protracker.h"
+#include "sound/raw.h"
#include "parallaction/disk.h"
#include "parallaction/parallaction.h"
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 7bd9970c64..e9215cf117 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -30,6 +30,7 @@
#include "sound/mixer.h"
#include "sound/midiparser.h"
#include "sound/mods/protracker.h"
+#include "sound/raw.h"
#include "parallaction/sound.h"
#include "parallaction/parallaction.h"
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 32f2a3d1a4..bd089f1b38 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -33,6 +33,7 @@
#include "sound/audiostream.h"
#include "sound/mididrv.h"
#include "sound/midiparser.h"
+#include "sound/raw.h"
#include "common/config-manager.h"
#include "common/file.h"
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 5771debd60..e43d7d001f 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -32,6 +32,7 @@
#include "sound/audiostream.h"
#include "sound/audiocd.h"
+#include "sound/raw.h"
#include "sound/wave.h"
namespace Sci {
diff --git a/engines/sci/sound/iterator/iterator.cpp b/engines/sci/sound/iterator/iterator.cpp
index 513e74325c..232a40f121 100644
--- a/engines/sci/sound/iterator/iterator.cpp
+++ b/engines/sci/sound/iterator/iterator.cpp
@@ -36,6 +36,7 @@
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
namespace Sci {
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index bea15ca900..8a99c34076 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -24,6 +24,7 @@
*/
#include "sound/audiostream.h"
+#include "sound/raw.h"
#include "common/config-manager.h"
#include "sci/sci.h"
diff --git a/engines/sci/sound/seq/instrument-map.cpp b/engines/sci/sound/seq/instrument-map.cpp
index 2f1fdb2532..0390e86d32 100644
--- a/engines/sci/sound/seq/instrument-map.cpp
+++ b/engines/sci/sound/seq/instrument-map.cpp
@@ -24,6 +24,7 @@
*/
#include "common/scummsys.h"
+#include "common/endian.h"
#include "sci/sound/softseq/mididriver.h"
#include "sci/sound/seq/instrument-map.h"
diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp
index 25baa24bde..dc4eafe56b 100644
--- a/engines/scumm/he/cup_player_he.cpp
+++ b/engines/scumm/he/cup_player_he.cpp
@@ -28,6 +28,7 @@
#include "common/system.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
#include "scumm/scumm.h"
#include "scumm/util.h"
#include "scumm/he/intern_he.h"
diff --git a/engines/scumm/player_mod.cpp b/engines/scumm/player_mod.cpp
index 1b18b8f58f..6495da6d48 100644
--- a/engines/scumm/player_mod.cpp
+++ b/engines/scumm/player_mod.cpp
@@ -27,6 +27,7 @@
#include "scumm/player_mod.h"
#include "sound/mixer.h"
#include "sound/rate.h"
+#include "sound/raw.h"
namespace Scumm {
diff --git a/engines/scumm/player_pce.cpp b/engines/scumm/player_pce.cpp
index 5e8a0cdca5..bd0a358c3e 100644
--- a/engines/scumm/player_pce.cpp
+++ b/engines/scumm/player_pce.cpp
@@ -33,6 +33,7 @@
#include <math.h>
#include "player_pce.h"
+#include "common/endian.h"
// PCE sound engine is only used by Loom, which requires 16bit color support
#ifdef USE_RGB_COLOR
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index d991a6e3de..16dba3e346 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -26,6 +26,7 @@
#include "common/system.h"
#include "sound/audiostream.h"
+#include "sound/raw.h"
#include "sound/wave.h"
#include "tucker/tucker.h"
diff --git a/sound/aiff.cpp b/sound/aiff.cpp
index 884a2382b6..b1f00c714e 100644
--- a/sound/aiff.cpp
+++ b/sound/aiff.cpp
@@ -38,6 +38,7 @@
#include "sound/aiff.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
namespace Audio {
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
index 578a4a78c0..2f7be667b7 100644
--- a/sound/audiostream.cpp
+++ b/sound/audiostream.cpp
@@ -30,19 +30,11 @@
#include "common/util.h"
#include "sound/audiostream.h"
+#include "sound/flac.h"
#include "sound/mixer.h"
#include "sound/mp3.h"
+#include "sound/raw.h"
#include "sound/vorbis.h"
-#include "sound/flac.h"
-
-
-// This used to be an inline template function, but
-// buggy template function handling in MSVC6 forced
-// us to go with the macro approach. So far this is
-// the only template function that MSVC6 seemed to
-// compile incorrectly. Knock on wood.
-#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
- ((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
namespace Audio {
@@ -256,424 +248,16 @@ bool SubSeekableAudioStream::seek(const Timestamp &where) {
}
#pragma mark -
-#pragma mark --- RawMemoryStream ---
-#pragma mark -
-
-uint32 calculateSampleOffset(const Timestamp &where, int rate) {
- return where.convertToFramerate(rate).totalNumberOfFrames();
-}
-
-/**
- * A simple raw audio stream, purely memory based. It operates on a single
- * block of data, which is passed to it upon creation.
- * Optionally supports looping the sound.
- *
- * Design note: This code tries to be as efficient as possible (without
- * resorting to assembly, that is). To this end, it is written as a template
- * class. This way the compiler can create optimized code for each special
- * case. This results in a total of 12 versions of the code being generated.
- */
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-class RawMemoryStream : public SeekableAudioStream {
-protected:
- const byte *_ptr;
- const byte *_end;
- const int _rate;
- const byte *_origPtr;
- const DisposeAfterUse::Flag _disposeAfterUse;
- const Timestamp _playtime;
-
-public:
- RawMemoryStream(int rate, const byte *ptr, uint len, DisposeAfterUse::Flag autoFreeMemory)
- : _ptr(ptr), _end(ptr+len), _rate(rate), _origPtr(ptr),
- _disposeAfterUse(autoFreeMemory),
- _playtime(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate) {
- }
-
- virtual ~RawMemoryStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES)
- free(const_cast<byte *>(_origPtr));
- }
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return stereo; }
- bool endOfData() const { return _ptr >= _end; }
-
- int getRate() const { return _rate; }
- bool seek(const Timestamp &where);
- Timestamp getLength() const { return _playtime; }
-};
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-int RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
- int samples = numSamples;
- while (samples > 0 && _ptr < _end) {
- int len = MIN(samples, (int)(_end - _ptr) / (is16Bit ? 2 : 1));
- samples -= len;
- do {
- *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
- _ptr += (is16Bit ? 2 : 1);
- } while (--len);
- }
- return numSamples-samples;
-}
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-bool RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
- const uint8 *ptr = _origPtr + calculateSampleOffset(where, getRate()) * (is16Bit ? 2 : 1) * (stereo ? 2 : 1);
- if (ptr > _end) {
- _ptr = _end;
- return false;
- } else if (ptr == _end) {
- _ptr = _end;
- return true;
- } else {
- _ptr = ptr;
- return true;
- }
-}
-
-#pragma mark -
-#pragma mark --- RawDiskStream ---
-#pragma mark -
-
-
-
-/**
- * RawDiskStream. This can stream raw PCM audio data from disk. The
- * function takes an pointer to an array of RawDiskStreamAudioBlock which defines the
- * start position and length of each block of uncompressed audio in the stream.
- */
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-class RawDiskStream : public SeekableAudioStream {
-
-// Allow backends to override buffer size
-#ifdef CUSTOM_AUDIO_BUFFER_SIZE
- static const int32 BUFFER_SIZE = CUSTOM_AUDIO_BUFFER_SIZE;
-#else
- static const int32 BUFFER_SIZE = 16384;
-#endif
-
-protected:
- byte* _buffer; ///< Streaming buffer
- const byte *_ptr; ///< Pointer to current position in stream buffer
- const int _rate; ///< Sample rate of stream
-
- Timestamp _playtime; ///< Calculated total play time
- Common::SeekableReadStream *_stream; ///< Stream to read data from
- int32 _filePos; ///< Current position in stream
- int32 _diskLeft; ///< Samples left in stream in current block not yet read to buffer
- int32 _bufferLeft; ///< Samples left in buffer in current block
- const DisposeAfterUse::Flag _disposeAfterUse; ///< Indicates whether the stream object should be deleted when this RawDiskStream is destructed
-
- RawDiskStreamAudioBlock *_audioBlock; ///< Audio block list
- const int _audioBlockCount; ///< Number of blocks in _audioBlock
- int _currentBlock; ///< Current audio block number
-public:
- RawDiskStream(int rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, uint numBlocks)
- : _rate(rate), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream),
- _audioBlockCount(numBlocks) {
-
- assert(numBlocks > 0);
-
- // Allocate streaming buffer
- if (is16Bit) {
- _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(int16));
- } else {
- _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(byte));
- }
-
- _ptr = _buffer;
- _bufferLeft = 0;
-
- // Copy audio block data to our buffer
- // TODO: Replace this with a Common::Array or Common::List to
- // make it a little friendlier.
- _audioBlock = new RawDiskStreamAudioBlock[numBlocks];
- memcpy(_audioBlock, block, numBlocks * sizeof(RawDiskStreamAudioBlock));
-
- // Set current buffer state, playing first block
- _currentBlock = 0;
- _filePos = _audioBlock[_currentBlock].pos;
- _diskLeft = _audioBlock[_currentBlock].len;
-
- // Add up length of all blocks in order to caluclate total play time
- int len = 0;
- for (int r = 0; r < _audioBlockCount; r++) {
- len += _audioBlock[r].len;
- }
- _playtime = Timestamp(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate);
- }
-
-
- virtual ~RawDiskStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES) {
- delete _stream;
- }
-
- delete[] _audioBlock;
- free(_buffer);
- }
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return stereo; }
- bool endOfData() const { return (_currentBlock == _audioBlockCount - 1) && (_diskLeft == 0) && (_bufferLeft == 0); }
-
- int getRate() const { return _rate; }
- Timestamp getLength() const { return _playtime; }
-
- bool seek(const Timestamp &where);
-};
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-int RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
- int oldPos = _stream->pos();
- bool restoreFilePosition = false;
-
- int samples = numSamples;
-
- while (samples > 0 && ((_diskLeft > 0 || _bufferLeft > 0) || (_currentBlock != _audioBlockCount - 1)) ) {
- // Output samples in the buffer to the output
- int len = MIN<int>(samples, _bufferLeft);
- samples -= len;
- _bufferLeft -= len;
-
- while (len > 0) {
- *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
- _ptr += (is16Bit ? 2 : 1);
- len--;
- }
-
- // Have we now finished this block? If so, read the next block
- if ((_bufferLeft == 0) && (_diskLeft == 0) && (_currentBlock != _audioBlockCount - 1)) {
- // Next block
- _currentBlock++;
-
- _filePos = _audioBlock[_currentBlock].pos;
- _diskLeft = _audioBlock[_currentBlock].len;
- }
-
- // Now read more data from disk if there is more to be read
- if ((_bufferLeft == 0) && (_diskLeft > 0)) {
- int32 readAmount = MIN(_diskLeft, BUFFER_SIZE);
-
- _stream->seek(_filePos, SEEK_SET);
- _stream->read(_buffer, readAmount * (is16Bit? 2: 1));
-
- // Amount of data in buffer is now the amount read in, and
- // the amount left to read on disk is decreased by the same amount
- _bufferLeft = readAmount;
- _diskLeft -= readAmount;
- _ptr = (byte *)_buffer;
- _filePos += readAmount * (is16Bit ? 2 : 1);
-
- // Set this flag now we've used the file, it restores it's
- // original position.
- restoreFilePosition = true;
- }
- }
-
- // In case calling code relies on the position of this stream staying
- // constant, I restore the location if I've changed it. This is probably
- // not necessary.
- if (restoreFilePosition) {
- _stream->seek(oldPos, SEEK_SET);
- }
-
- return numSamples - samples;
-}
-
-template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-bool RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
- const uint32 seekSample = calculateSampleOffset(where, getRate()) * (stereo ? 2 : 1);
- uint32 curSample = 0;
-
- // Search for the disk block in which the specific sample is placed
- _currentBlock = 0;
- while (_currentBlock < _audioBlockCount) {
- uint32 nextBlockSample = curSample + _audioBlock[_currentBlock].len;
-
- if (nextBlockSample > seekSample)
- break;
-
- curSample = nextBlockSample;
- ++_currentBlock;
- }
-
- _filePos = 0;
- _diskLeft = 0;
- _bufferLeft = 0;
-
- if (_currentBlock == _audioBlockCount) {
- return ((seekSample - curSample) == (uint32)_audioBlock[_currentBlock - 1].len);
- } else {
- const uint32 offset = seekSample - curSample;
-
- _filePos = _audioBlock[_currentBlock].pos + offset * (is16Bit ? 2 : 1);
- _diskLeft = _audioBlock[_currentBlock].len - offset;
-
- return true;
- }
-}
-
-#pragma mark -
-#pragma mark --- Input stream factory ---
+#pragma mark --- Queueing audio stream ---
#pragma mark -
-/* In the following, we use preprocessor / macro tricks to simplify the code
- * which instantiates the input streams. We used to use template functions for
- * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
- * comes to this feature of C++... so as a compromise we use macros to cut down
- * on the (source) code duplication a bit.
- * So while normally macro tricks are said to make maintenance harder, in this
- * particular case it should actually help it :-)
- */
-
-#define MAKE_LINEAR(STEREO, UNSIGNED) \
- if (is16Bit) { \
- if (isLE) \
- return new RawMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, autoFree); \
- else \
- return new RawMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, autoFree); \
- } else \
- return new RawMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, autoFree)
-
-SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate, byte flags) {
- 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 DisposeAfterUse::Flag autoFree = (flags & Mixer::FLAG_AUTOFREE) != 0 ? DisposeAfterUse::YES : DisposeAfterUse::NO;
-
- // Verify the buffer sizes are sane
- if (is16Bit && isStereo) {
- assert((len & 3) == 0);
- } else if (is16Bit || isStereo) {
- assert((len & 1) == 0);
- }
- if (isStereo) {
- if (isUnsigned) {
- MAKE_LINEAR(true, true);
- } else {
- MAKE_LINEAR(true, false);
- }
- } else {
- if (isUnsigned) {
- MAKE_LINEAR(false, true);
- } else {
- MAKE_LINEAR(false, false);
- }
- }
+void QueuingAudioStream::queueBuffer(byte *data, uint32 size, byte flags) {
+ AudioStream *stream = makeRawMemoryStream(data, size, getRate(), flags, 0, 0);
+ queueAudioStream(stream, DisposeAfterUse::YES);
}
-AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate,
- byte flags, uint loopStart, uint loopEnd) {
- SeekableAudioStream *stream = makeRawMemoryStream(ptr, len, rate, flags);
-
- const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0;
- const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0;
- const bool isLooping = (flags & Mixer::FLAG_LOOP) != 0;
-
- if (isLooping) {
- uint loopOffset = 0, loopLen = 0;
- if (loopEnd == 0)
- loopEnd = len;
- assert(loopStart <= loopEnd);
- assert(loopEnd <= len);
-
- loopOffset = loopStart;
- loopLen = loopEnd - loopStart;
-
- // Verify the buffer sizes are sane
- if (is16Bit && isStereo)
- assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
- else if (is16Bit || isStereo)
- assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 1) == 0);
-
- const uint32 extRate = stream->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
-
- return new SubLoopingAudioStream(stream, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
- } else {
- return stream;
- }
-}
-
-
-
-#define MAKE_LINEAR_DISK(STEREO, UNSIGNED) \
- if (is16Bit) { \
- if (isLE) \
- return new RawDiskStream<STEREO, true, UNSIGNED, true>(rate, disposeStream, stream, block, numBlocks); \
- else \
- return new RawDiskStream<STEREO, true, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks); \
- } else \
- return new RawDiskStream<STEREO, false, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks)
-
-
-SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, int numBlocks,
- int rate, byte flags, DisposeAfterUse::Flag disposeStream) {
- 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) {
- MAKE_LINEAR_DISK(true, true);
- } else {
- MAKE_LINEAR_DISK(true, false);
- }
- } else {
- if (isUnsigned) {
- MAKE_LINEAR_DISK(false, true);
- } else {
- MAKE_LINEAR_DISK(false, false);
- }
- }
-}
-
-AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
- int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream, uint loopStart, uint loopEnd) {
- SeekableAudioStream *s = makeRawDiskStream(stream, block, numBlocks, rate, flags, disposeStream);
-
- const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0;
- const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0;
- const bool isLooping = (flags & Mixer::FLAG_LOOP) != 0;
-
- if (isLooping) {
- uint loopOffset = 0, loopLen = 0;
- const uint len = s->getLength().totalNumberOfFrames() / (is16Bit ? 2 : 1) / (isStereo ? 2 : 1);
-
- if (loopEnd == 0)
- loopEnd = len;
- assert(loopStart <= loopEnd);
- assert(loopEnd <= len);
-
- loopOffset = loopStart;
- loopLen = loopEnd - loopStart;
-
- // Verify the buffer sizes are sane
- if (is16Bit && isStereo)
- assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
- else if (is16Bit || isStereo)
- assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 3) == 0);
-
- const uint32 extRate = s->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
-
- return new SubLoopingAudioStream(s, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
- } else {
- return s;
- }
-}
-
-#pragma mark -
-#pragma mark --- Queueing audio stream ---
-#pragma mark -
-
-
class QueuingAudioStreamImpl : public QueuingAudioStream {
private:
/**
diff --git a/sound/audiostream.h b/sound/audiostream.h
index e04ed265ab..5ce026b3d7 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -28,7 +28,6 @@
#include "common/util.h"
#include "common/scummsys.h"
-#include "common/stream.h"
#include "common/types.h"
#include "sound/timestamp.h"
@@ -297,70 +296,6 @@ private:
Timestamp _pos;
};
-/**
- * Creates a audio stream, which plays the given raw data.
- *
- * @param ptr Data
- * @param len Length of the data (in bytes!)
- * @param rate The sample rate of the data.
- * @param flags Flags combination.
- * @see Mixer::RawFlags
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate, byte flags);
-
-/**
- * NOTE:
- * This API is considered deprecated.
- *
- * Factory function for a raw PCM AudioStream, which will simply treat all
- * data in the buffer described by ptr and len as raw sample data in the
- * specified format. It will then simply pass this data directly to the mixer,
- * after converting it to the sample format used by the mixer (i.e. 16 bit
- * signed native endian). Optionally supports (infinite) looping of a portion
- * of the data.
- */
-AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate,
- byte flags, uint loopStart, uint loopEnd);
-
-
-/**
- * Struct used to define the audio data to be played by a RawDiskStream.
- */
-struct RawDiskStreamAudioBlock {
- int32 pos; ///< Position in stream of the block
- int32 len; ///< Length of the block (in samples)
-};
-
-/**
- * Creates a audio stream, which plays from given stream.
- *
- * @param stream Stream to play from
- * @param block Pointer to an RawDiskStreamAudioBlock array
- * @see RawDiskStreamAudioBlock
- * @param numBlocks Number of blocks.
- * @param rate The rate
- * @param len Length of the data (in bytes!)
- * @param flags Flags combination.
- * @see Mixer::RawFlags
- * @param disposeStream Whether the "stream" object should be destroyed after playback.
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
- int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream);
-
-/**
- * NOTE:
- * This API is considered deprecated.
- *
- * Factory function for a Raw Disk Stream. This can stream raw PCM
- * audio data from disk. The function takes an pointer to an array of
- * RawDiskStreamAudioBlock which defines the start position and length of
- * each block of uncompressed audio in the stream.
- */
-AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
- int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream, uint loopStart, uint loopEnd);
-
class QueuingAudioStream : public Audio::AudioStream {
public:
@@ -380,10 +315,7 @@ public:
* 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 = makeRawMemoryStream(data, size, getRate(), flags, 0, 0);
- queueAudioStream(stream, DisposeAfterUse::YES);
- }
+ void queueBuffer(byte *data, uint32 size, byte flags);
/**
* Mark the stream as finished, that is, signal that no further data
diff --git a/sound/iff_sound.cpp b/sound/iff_sound.cpp
index d0e96fa9ee..a78fe97288 100644
--- a/sound/iff_sound.cpp
+++ b/sound/iff_sound.cpp
@@ -26,6 +26,7 @@
#include "sound/iff_sound.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
#include "common/func.h"
namespace Audio {
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index 40af73b3c5..a3aaa19e8f 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -30,6 +30,7 @@
#include "sound/rate.h"
#include "sound/audiostream.h"
#include "sound/timestamp.h"
+#include "sound/raw.h"
namespace Audio {
diff --git a/sound/module.mk b/sound/module.mk
index e994959e17..e21f242974 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -17,6 +17,7 @@ MODULE_OBJS := \
mpu401.o \
musicplugin.o \
null.o \
+ raw.o \
shorten.o \
timestamp.o \
vag.o \
diff --git a/sound/raw.cpp b/sound/raw.cpp
new file mode 100644
index 0000000000..84627d0ff0
--- /dev/null
+++ b/sound/raw.cpp
@@ -0,0 +1,463 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/endian.h"
+#include "common/stream.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/raw.h"
+
+namespace Audio {
+
+// This used to be an inline template function, but
+// buggy template function handling in MSVC6 forced
+// us to go with the macro approach. So far this is
+// the only template function that MSVC6 seemed to
+// compile incorrectly. Knock on wood.
+#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
+ ((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
+
+
+// TODO: Get rid of this
+uint32 calculateSampleOffset(const Timestamp &where, int rate) {
+ return where.convertToFramerate(rate).totalNumberOfFrames();
+}
+
+
+
+#pragma mark -
+#pragma mark --- RawMemoryStream ---
+#pragma mark -
+
+/**
+ * A simple raw audio stream, purely memory based. It operates on a single
+ * block of data, which is passed to it upon creation.
+ * Optionally supports looping the sound.
+ *
+ * Design note: This code tries to be as efficient as possible (without
+ * resorting to assembly, that is). To this end, it is written as a template
+ * class. This way the compiler can create optimized code for each special
+ * case. This results in a total of 12 versions of the code being generated.
+ */
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+class RawMemoryStream : public SeekableAudioStream {
+protected:
+ const byte *_ptr;
+ const byte *_end;
+ const int _rate;
+ const byte *_origPtr;
+ const DisposeAfterUse::Flag _disposeAfterUse;
+ const Timestamp _playtime;
+
+public:
+ RawMemoryStream(int rate, const byte *ptr, uint len, DisposeAfterUse::Flag autoFreeMemory)
+ : _ptr(ptr), _end(ptr+len), _rate(rate), _origPtr(ptr),
+ _disposeAfterUse(autoFreeMemory),
+ _playtime(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate) {
+ }
+
+ virtual ~RawMemoryStream() {
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ free(const_cast<byte *>(_origPtr));
+ }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool isStereo() const { return stereo; }
+ bool endOfData() const { return _ptr >= _end; }
+
+ int getRate() const { return _rate; }
+ bool seek(const Timestamp &where);
+ Timestamp getLength() const { return _playtime; }
+};
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+int RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
+ int samples = numSamples;
+ while (samples > 0 && _ptr < _end) {
+ int len = MIN(samples, (int)(_end - _ptr) / (is16Bit ? 2 : 1));
+ samples -= len;
+ do {
+ *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
+ _ptr += (is16Bit ? 2 : 1);
+ } while (--len);
+ }
+ return numSamples-samples;
+}
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+bool RawMemoryStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
+ const uint8 *ptr = _origPtr + calculateSampleOffset(where, getRate()) * (is16Bit ? 2 : 1) * (stereo ? 2 : 1);
+ if (ptr > _end) {
+ _ptr = _end;
+ return false;
+ } else if (ptr == _end) {
+ _ptr = _end;
+ return true;
+ } else {
+ _ptr = ptr;
+ return true;
+ }
+}
+
+#pragma mark -
+#pragma mark --- RawDiskStream ---
+#pragma mark -
+
+
+
+/**
+ * RawDiskStream. This can stream raw PCM audio data from disk. The
+ * function takes an pointer to an array of RawDiskStreamAudioBlock which defines the
+ * start position and length of each block of uncompressed audio in the stream.
+ */
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+class RawDiskStream : public SeekableAudioStream {
+
+// Allow backends to override buffer size
+#ifdef CUSTOM_AUDIO_BUFFER_SIZE
+ static const int32 BUFFER_SIZE = CUSTOM_AUDIO_BUFFER_SIZE;
+#else
+ static const int32 BUFFER_SIZE = 16384;
+#endif
+
+protected:
+ byte* _buffer; ///< Streaming buffer
+ const byte *_ptr; ///< Pointer to current position in stream buffer
+ const int _rate; ///< Sample rate of stream
+
+ Timestamp _playtime; ///< Calculated total play time
+ Common::SeekableReadStream *_stream; ///< Stream to read data from
+ int32 _filePos; ///< Current position in stream
+ int32 _diskLeft; ///< Samples left in stream in current block not yet read to buffer
+ int32 _bufferLeft; ///< Samples left in buffer in current block
+ const DisposeAfterUse::Flag _disposeAfterUse; ///< Indicates whether the stream object should be deleted when this RawDiskStream is destructed
+
+ RawDiskStreamAudioBlock *_audioBlock; ///< Audio block list
+ const int _audioBlockCount; ///< Number of blocks in _audioBlock
+ int _currentBlock; ///< Current audio block number
+public:
+ RawDiskStream(int rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, uint numBlocks)
+ : _rate(rate), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream),
+ _audioBlockCount(numBlocks) {
+
+ assert(numBlocks > 0);
+
+ // Allocate streaming buffer
+ if (is16Bit) {
+ _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(int16));
+ } else {
+ _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(byte));
+ }
+
+ _ptr = _buffer;
+ _bufferLeft = 0;
+
+ // Copy audio block data to our buffer
+ // TODO: Replace this with a Common::Array or Common::List to
+ // make it a little friendlier.
+ _audioBlock = new RawDiskStreamAudioBlock[numBlocks];
+ memcpy(_audioBlock, block, numBlocks * sizeof(RawDiskStreamAudioBlock));
+
+ // Set current buffer state, playing first block
+ _currentBlock = 0;
+ _filePos = _audioBlock[_currentBlock].pos;
+ _diskLeft = _audioBlock[_currentBlock].len;
+
+ // Add up length of all blocks in order to caluclate total play time
+ int len = 0;
+ for (int r = 0; r < _audioBlockCount; r++) {
+ len += _audioBlock[r].len;
+ }
+ _playtime = Timestamp(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate);
+ }
+
+
+ virtual ~RawDiskStream() {
+ if (_disposeAfterUse == DisposeAfterUse::YES) {
+ delete _stream;
+ }
+
+ delete[] _audioBlock;
+ free(_buffer);
+ }
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool isStereo() const { return stereo; }
+ bool endOfData() const { return (_currentBlock == _audioBlockCount - 1) && (_diskLeft == 0) && (_bufferLeft == 0); }
+
+ int getRate() const { return _rate; }
+ Timestamp getLength() const { return _playtime; }
+
+ bool seek(const Timestamp &where);
+};
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+int RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
+ int oldPos = _stream->pos();
+ bool restoreFilePosition = false;
+
+ int samples = numSamples;
+
+ while (samples > 0 && ((_diskLeft > 0 || _bufferLeft > 0) || (_currentBlock != _audioBlockCount - 1)) ) {
+ // Output samples in the buffer to the output
+ int len = MIN<int>(samples, _bufferLeft);
+ samples -= len;
+ _bufferLeft -= len;
+
+ while (len > 0) {
+ *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
+ _ptr += (is16Bit ? 2 : 1);
+ len--;
+ }
+
+ // Have we now finished this block? If so, read the next block
+ if ((_bufferLeft == 0) && (_diskLeft == 0) && (_currentBlock != _audioBlockCount - 1)) {
+ // Next block
+ _currentBlock++;
+
+ _filePos = _audioBlock[_currentBlock].pos;
+ _diskLeft = _audioBlock[_currentBlock].len;
+ }
+
+ // Now read more data from disk if there is more to be read
+ if ((_bufferLeft == 0) && (_diskLeft > 0)) {
+ int32 readAmount = MIN(_diskLeft, BUFFER_SIZE);
+
+ _stream->seek(_filePos, SEEK_SET);
+ _stream->read(_buffer, readAmount * (is16Bit? 2: 1));
+
+ // Amount of data in buffer is now the amount read in, and
+ // the amount left to read on disk is decreased by the same amount
+ _bufferLeft = readAmount;
+ _diskLeft -= readAmount;
+ _ptr = (byte *)_buffer;
+ _filePos += readAmount * (is16Bit ? 2 : 1);
+
+ // Set this flag now we've used the file, it restores it's
+ // original position.
+ restoreFilePosition = true;
+ }
+ }
+
+ // In case calling code relies on the position of this stream staying
+ // constant, I restore the location if I've changed it. This is probably
+ // not necessary.
+ if (restoreFilePosition) {
+ _stream->seek(oldPos, SEEK_SET);
+ }
+
+ return numSamples - samples;
+}
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+bool RawDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
+ const uint32 seekSample = calculateSampleOffset(where, getRate()) * (stereo ? 2 : 1);
+ uint32 curSample = 0;
+
+ // Search for the disk block in which the specific sample is placed
+ _currentBlock = 0;
+ while (_currentBlock < _audioBlockCount) {
+ uint32 nextBlockSample = curSample + _audioBlock[_currentBlock].len;
+
+ if (nextBlockSample > seekSample)
+ break;
+
+ curSample = nextBlockSample;
+ ++_currentBlock;
+ }
+
+ _filePos = 0;
+ _diskLeft = 0;
+ _bufferLeft = 0;
+
+ if (_currentBlock == _audioBlockCount) {
+ return ((seekSample - curSample) == (uint32)_audioBlock[_currentBlock - 1].len);
+ } else {
+ const uint32 offset = seekSample - curSample;
+
+ _filePos = _audioBlock[_currentBlock].pos + offset * (is16Bit ? 2 : 1);
+ _diskLeft = _audioBlock[_currentBlock].len - offset;
+
+ return true;
+ }
+}
+
+#pragma mark -
+#pragma mark --- Raw stream factories ---
+#pragma mark -
+
+/* In the following, we use preprocessor / macro tricks to simplify the code
+ * which instantiates the input streams. We used to use template functions for
+ * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
+ * comes to this feature of C++... so as a compromise we use macros to cut down
+ * on the (source) code duplication a bit.
+ * So while normally macro tricks are said to make maintenance harder, in this
+ * particular case it should actually help it :-)
+ */
+
+#define MAKE_LINEAR(STEREO, UNSIGNED) \
+ if (is16Bit) { \
+ if (isLE) \
+ return new RawMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, autoFree); \
+ else \
+ return new RawMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, autoFree); \
+ } else \
+ return new RawMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, autoFree)
+
+SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate, byte flags) {
+ 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 DisposeAfterUse::Flag autoFree = (flags & Mixer::FLAG_AUTOFREE) != 0 ? DisposeAfterUse::YES : DisposeAfterUse::NO;
+
+ // Verify the buffer sizes are sane
+ if (is16Bit && isStereo) {
+ assert((len & 3) == 0);
+ } else if (is16Bit || isStereo) {
+ assert((len & 1) == 0);
+ }
+
+ if (isStereo) {
+ if (isUnsigned) {
+ MAKE_LINEAR(true, true);
+ } else {
+ MAKE_LINEAR(true, false);
+ }
+ } else {
+ if (isUnsigned) {
+ MAKE_LINEAR(false, true);
+ } else {
+ MAKE_LINEAR(false, false);
+ }
+ }
+}
+
+
+AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate,
+ byte flags, uint loopStart, uint loopEnd) {
+ SeekableAudioStream *stream = makeRawMemoryStream(ptr, len, rate, flags);
+
+ const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0;
+ const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0;
+ const bool isLooping = (flags & Mixer::FLAG_LOOP) != 0;
+
+ if (isLooping) {
+ uint loopOffset = 0, loopLen = 0;
+ if (loopEnd == 0)
+ loopEnd = len;
+ assert(loopStart <= loopEnd);
+ assert(loopEnd <= len);
+
+ loopOffset = loopStart;
+ loopLen = loopEnd - loopStart;
+
+ // Verify the buffer sizes are sane
+ if (is16Bit && isStereo)
+ assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
+ else if (is16Bit || isStereo)
+ assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 1) == 0);
+
+ const uint32 extRate = stream->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
+
+ return new SubLoopingAudioStream(stream, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
+ } else {
+ return stream;
+ }
+}
+
+
+
+#define MAKE_LINEAR_DISK(STEREO, UNSIGNED) \
+ if (is16Bit) { \
+ if (isLE) \
+ return new RawDiskStream<STEREO, true, UNSIGNED, true>(rate, disposeStream, stream, block, numBlocks); \
+ else \
+ return new RawDiskStream<STEREO, true, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks); \
+ } else \
+ return new RawDiskStream<STEREO, false, UNSIGNED, false>(rate, disposeStream, stream, block, numBlocks)
+
+
+SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block, int numBlocks,
+ int rate, byte flags, DisposeAfterUse::Flag disposeStream) {
+ 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) {
+ MAKE_LINEAR_DISK(true, true);
+ } else {
+ MAKE_LINEAR_DISK(true, false);
+ }
+ } else {
+ if (isUnsigned) {
+ MAKE_LINEAR_DISK(false, true);
+ } else {
+ MAKE_LINEAR_DISK(false, false);
+ }
+ }
+}
+
+AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
+ int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream, uint loopStart, uint loopEnd) {
+ SeekableAudioStream *s = makeRawDiskStream(stream, block, numBlocks, rate, flags, disposeStream);
+
+ const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0;
+ const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0;
+ const bool isLooping = (flags & Mixer::FLAG_LOOP) != 0;
+
+ if (isLooping) {
+ uint loopOffset = 0, loopLen = 0;
+ const uint len = s->getLength().totalNumberOfFrames() / (is16Bit ? 2 : 1) / (isStereo ? 2 : 1);
+
+ if (loopEnd == 0)
+ loopEnd = len;
+ assert(loopStart <= loopEnd);
+ assert(loopEnd <= len);
+
+ loopOffset = loopStart;
+ loopLen = loopEnd - loopStart;
+
+ // Verify the buffer sizes are sane
+ if (is16Bit && isStereo)
+ assert((loopLen & 3) == 0 && (loopStart & 3) == 0 && (loopEnd & 3) == 0);
+ else if (is16Bit || isStereo)
+ assert((loopLen & 1) == 0 && (loopStart & 1) == 0 && (loopEnd & 3) == 0);
+
+ const uint32 extRate = s->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
+
+ return new SubLoopingAudioStream(s, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
+ } else {
+ return s;
+ }
+}
+
+
+
+} // End of namespace Audio
diff --git a/sound/raw.h b/sound/raw.h
new file mode 100644
index 0000000000..c06eea35d2
--- /dev/null
+++ b/sound/raw.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SOUND_RAW_H
+#define SOUND_RAW_H
+
+#include "common/scummsys.h"
+#include "common/types.h"
+
+
+namespace Common { class SeekableReadStream; }
+
+
+namespace Audio {
+
+class AudioStream;
+class SeekableAudioStream;
+
+/**
+ * Creates a audio stream, which plays the given raw data.
+ *
+ * @param ptr Data
+ * @param len Length of the data (in bytes!)
+ * @param rate The sample rate of the data.
+ * @param flags Flags combination.
+ * @see Mixer::RawFlags
+ * @return The new SeekableAudioStream (or 0 on failure).
+ */
+SeekableAudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate, byte flags);
+
+/**
+ * NOTE:
+ * This API is considered deprecated.
+ *
+ * Factory function for a raw PCM AudioStream, which will simply treat all
+ * data in the buffer described by ptr and len as raw sample data in the
+ * specified format. It will then simply pass this data directly to the mixer,
+ * after converting it to the sample format used by the mixer (i.e. 16 bit
+ * signed native endian). Optionally supports (infinite) looping of a portion
+ * of the data.
+ */
+AudioStream *makeRawMemoryStream(const byte *ptr, uint32 len, int rate,
+ byte flags, uint loopStart, uint loopEnd);
+
+
+/**
+ * Struct used to define the audio data to be played by a RawDiskStream.
+ */
+struct RawDiskStreamAudioBlock {
+ int32 pos; ///< Position in stream of the block
+ int32 len; ///< Length of the block (in samples)
+};
+
+/**
+ * Creates a audio stream, which plays from given stream.
+ *
+ * @param stream Stream to play from
+ * @param block Pointer to an RawDiskStreamAudioBlock array
+ * @see RawDiskStreamAudioBlock
+ * @param numBlocks Number of blocks.
+ * @param rate The rate
+ * @param len Length of the data (in bytes!)
+ * @param flags Flags combination.
+ * @see Mixer::RawFlags
+ * @param disposeStream Whether the "stream" object should be destroyed after playback.
+ * @return The new SeekableAudioStream (or 0 on failure).
+ */
+SeekableAudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
+ int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream);
+
+/**
+ * NOTE:
+ * This API is considered deprecated.
+ *
+ * Factory function for a Raw Disk Stream. This can stream raw PCM
+ * audio data from disk. The function takes an pointer to an array of
+ * RawDiskStreamAudioBlock which defines the start position and length of
+ * each block of uncompressed audio in the stream.
+ */
+AudioStream *makeRawDiskStream(Common::SeekableReadStream *stream, RawDiskStreamAudioBlock *block,
+ int numBlocks, int rate, byte flags, DisposeAfterUse::Flag disposeStream, uint loopStart, uint loopEnd);
+
+
+} // End of namespace Audio
+
+#endif
diff --git a/sound/shorten.cpp b/sound/shorten.cpp
index 5f4fcab5b4..fa62080c9c 100644
--- a/sound/shorten.cpp
+++ b/sound/shorten.cpp
@@ -38,6 +38,7 @@
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
namespace Audio {
diff --git a/sound/voc.cpp b/sound/voc.cpp
index 9eae18b5dd..7a9a5e8b1b 100644
--- a/sound/voc.cpp
+++ b/sound/voc.cpp
@@ -30,6 +30,7 @@
#include "sound/audiostream.h"
#include "sound/mixer.h"
+#include "sound/raw.h"
#include "sound/voc.h"
diff --git a/sound/wave.cpp b/sound/wave.cpp
index 673467628c..d299128762 100644
--- a/sound/wave.cpp
+++ b/sound/wave.cpp
@@ -31,6 +31,7 @@
#include "sound/mixer.h"
#include "sound/wave.h"
#include "sound/adpcm.h"
+#include "sound/raw.h"
namespace Audio {