aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2010-01-10 15:20:14 +0000
committerJohannes Schickel2010-01-10 15:20:14 +0000
commit6ca0570fe3bb3f3765677ff8cd3f9e0cbf062d6b (patch)
tree732a2cc846d6f70dd2c42b0dc0cd52d45de34bb2
parentbda3fc940c3ecca011b04a32fb20970f53f49d1c (diff)
downloadscummvm-rg350-6ca0570fe3bb3f3765677ff8cd3f9e0cbf062d6b.tar.gz
scummvm-rg350-6ca0570fe3bb3f3765677ff8cd3f9e0cbf062d6b.tar.bz2
scummvm-rg350-6ca0570fe3bb3f3765677ff8cd3f9e0cbf062d6b.zip
- Add a SubLoopingAudioStream, which loops a nested part of a stream and thus features the same looping capabilites as LinearMemoryStream and LinearDiskStream.
- Remove custom looping code from LinearMemoryStream and LinearDiskStream. - Adapt various client code to the changes. svn-id: r47226
-rw-r--r--engines/kyra/sound.cpp4
-rw-r--r--engines/saga/music.cpp16
-rw-r--r--engines/sci/sound/audio.cpp7
-rw-r--r--engines/sci/sound/music.cpp3
-rw-r--r--engines/tucker/sequences.cpp2
-rw-r--r--sound/aiff.cpp2
-rw-r--r--sound/audiostream.cpp207
-rw-r--r--sound/audiostream.h46
-rw-r--r--sound/voc.cpp40
-rw-r--r--sound/voc.h7
-rw-r--r--sound/wave.cpp2
11 files changed, 243 insertions, 93 deletions
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 4049d2b456..b97d367206 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -244,9 +244,9 @@ namespace {
Audio::SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeAfterUse) {
#ifdef STREAM_AUDIO_FROM_DISK
- Audio::SeekableAudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED, 0, 0, disposeAfterUse);
+ Audio::SeekableAudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED, disposeAfterUse);
#else
- Audio::SeekableAudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED);
+ Audio::SeekableAudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED, false);
if (disposeAfterUse)
delete stream;
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index a5c28c213e..7fe8c0dbb2 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -292,7 +292,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
loopStart = 0;
// Fix ITE sunstatm/sunspot score
if (resourceId == MUSIC_SUNSPOT)
- loopStart = 4 * 18727;
+ loopStart = 18727;
// Digital music
ResourceData *resData = _digitalMusicContext->getResourceData(resourceId - 9);
@@ -311,7 +311,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
Audio::LinearDiskStreamAudioBlock audioBlocks[1];
audioBlocks[0].pos = 0;
audioBlocks[0].len = resData->size / 2; // 16-bit sound
- audioStream = Audio::makeLinearDiskStream(musicStream, audioBlocks, 1, 11025, musicFlags, false, loopStart, 0);
+ audioStream = Audio::makeLinearDiskStream(musicStream, audioBlocks, 1, 11025, musicFlags, false);
} else {
// Read compressed header to determine compression type
musicFile->seek((uint32)resData->offset, SEEK_SET);
@@ -337,8 +337,16 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
if (audioStream) {
debug(2, "Playing digitized music");
- _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
- Audio::makeLoopingAudioStream(audioStream, (flags == MUSIC_LOOP ? 0 : 1)));
+ if (loopStart) {
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
+ new Audio::SubLoopingAudioStream(audioStream,
+ (flags == MUSIC_LOOP ? 0 : 1),
+ Audio::Timestamp(0, loopStart, audioStream->getRate()),
+ audioStream->getLength()));
+ } else {
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
+ Audio::makeLoopingAudioStream(audioStream, (flags == MUSIC_LOOP ? 0 : 1)));
+ }
_digitalMusic = true;
return;
}
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 5a4f7aeafc..4011aa9fa3 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -243,10 +243,9 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
}
}
- if (data) {
- audioStream = Audio::makeLinearInputStream(data, size, _audioRate,
- flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
- }
+ if (data)
+ audioStream = Audio::makeLinearInputStream(data, size, _audioRate, flags | Audio::Mixer::FLAG_AUTOFREE);
+
if (audioStream) {
*sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
return audioStream;
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 1bb4fa883f..4b452aad56 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -303,8 +303,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
if (track->digitalChannelNr != -1) {
byte *channelData = track->channels[track->digitalChannelNr].data;
delete pSnd->pStreamAud;
- pSnd->pStreamAud = Audio::makeLinearInputStream(channelData, track->digitalSampleSize, track->digitalSampleRate,
- Audio::Mixer::FLAG_UNSIGNED, 0, 0);
+ pSnd->pStreamAud = Audio::makeLinearInputStream(channelData, track->digitalSampleSize, track->digitalSampleRate, Audio::Mixer::FLAG_UNSIGNED);
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
pSnd->soundType = Audio::Mixer::kSFXSoundType;
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index cae0f527c2..204913addf 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -598,7 +598,7 @@ Audio::RewindableAudioStream *AnimationSequencePlayer::loadSound(int index, Anim
uint8 *sampleData = (uint8 *)malloc(size);
if (sampleData) {
f.read(sampleData, size);
- stream = Audio::makeLinearInputStream(sampleData, size, rate, flags, 0, 0);
+ stream = Audio::makeLinearInputStream(sampleData, size, rate, flags);
}
}
break;
diff --git a/sound/aiff.cpp b/sound/aiff.cpp
index 69fb806420..6ac9a45372 100644
--- a/sound/aiff.cpp
+++ b/sound/aiff.cpp
@@ -174,7 +174,7 @@ SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream &stream) {
// Since we allocated our own buffer for the data, we must set the autofree flag.
flags |= Audio::Mixer::FLAG_AUTOFREE;
- return makeLinearInputStream(data, size, rate, flags, 0, 0);
+ return makeLinearInputStream(data, size, rate, flags);
}
} // End of namespace Audio
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
index 72f01b35d1..6d72b83dd1 100644
--- a/sound/audiostream.cpp
+++ b/sound/audiostream.cpp
@@ -162,6 +162,59 @@ AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start
}
#pragma mark -
+#pragma mark --- SubLoopingAudioStream ---
+#pragma mark -
+
+SubLoopingAudioStream::SubLoopingAudioStream(SeekableAudioStream *stream,
+ uint loops,
+ const Timestamp loopStart,
+ const Timestamp loopEnd,
+ bool disposeAfterUse)
+ : _parent(stream), _disposeAfterUse(disposeAfterUse), _loops(loops),
+ _pos(0, getRate() * (isStereo() ? 2 : 1)),
+ _loopStart(loopStart.convertToFramerate(getRate() * (isStereo() ? 2 : 1))),
+ _loopEnd(loopEnd.convertToFramerate(getRate() * (isStereo() ? 2 : 1))),
+ _done(false) {
+ if (!_parent->rewind())
+ _done = true;
+}
+
+SubLoopingAudioStream::~SubLoopingAudioStream() {
+ if (_disposeAfterUse)
+ delete _parent;
+}
+
+int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+ int framesLeft = MIN(_loopEnd.frameDiff(_pos), numSamples);
+ int framesRead = _parent->readBuffer(buffer, framesLeft);
+ _pos = _pos.addFrames(framesRead);
+
+ if (framesLeft < numSamples || framesRead < framesLeft) {
+ if (_loops != 0) {
+ --_loops;
+ if (!_loops) {
+ _done = true;
+ return framesRead;
+ }
+ }
+
+ if (!_parent->seek(_loopStart)) {
+ _done = true;
+ return framesRead;
+ }
+
+ _pos = _loopStart;
+ framesLeft = numSamples - framesLeft;
+ framesRead += _parent->readBuffer(buffer + framesRead, framesLeft);
+
+ if (_parent->endOfStream())
+ _done = true;
+ }
+
+ return framesRead;
+}
+
+#pragma mark -
#pragma mark --- SubSeekableAudioStream ---
#pragma mark -
@@ -226,36 +279,23 @@ class LinearMemoryStream : public SeekableAudioStream {
protected:
const byte *_ptr;
const byte *_end;
- const byte *_loopPtr;
- const byte *_loopEnd;
const int _rate;
const byte *_origPtr;
const bool _disposeAfterUse;
const Timestamp _playtime;
- uint _numLoops; ///< Number of loops to play
- uint _numPlayedLoops; ///< Number of loops which have been played
-
public:
- LinearMemoryStream(int rate, const byte *ptr, uint len, uint loopOffset, uint loopLen, bool autoFreeMemory)
- : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate), _disposeAfterUse(autoFreeMemory),
+ LinearMemoryStream(int rate, const byte *ptr, uint len, bool autoFreeMemory)
+ : _ptr(ptr), _end(ptr+len), _rate(rate), _origPtr(ptr),
+ _disposeAfterUse(autoFreeMemory),
_playtime(0, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1), rate) {
-
- if (loopLen) {
- _numLoops = 0;
- _loopPtr = _ptr + loopOffset;
- _loopEnd = _loopPtr + loopLen;
- } else {
- _numLoops = 1;
- }
- _numPlayedLoops = 0;
-
- _origPtr = ptr;
}
+
virtual ~LinearMemoryStream() {
if (_disposeAfterUse)
free(const_cast<byte *>(_origPtr));
}
+
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return stereo; }
@@ -276,14 +316,6 @@ int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buf
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
_ptr += (is16Bit ? 2 : 1);
} while (--len);
- // Loop, if looping was specified
- // TODO: Handle non-infinite loops
- if (_loopPtr && _ptr >= _end) {
- _ptr = _loopPtr;
- _end = _loopEnd;
-
- _numPlayedLoops++;
- }
}
return numSamples-samples;
}
@@ -339,17 +371,10 @@ protected:
LinearDiskStreamAudioBlock *_audioBlock; ///< Audio block list
int _audioBlockCount; ///< Number of blocks in _audioBlock
int _currentBlock; ///< Current audio block number
-
- int _beginLoop; ///< Loop start parameter
- int _endLoop; ///< Loop end parameter, currently not implemented
- bool _loop; ///< Determines if the stream should be looped when it finishes
- uint _numLoops; ///< Number of loops to play
- uint _numPlayedLoops; ///< Number of loops which have been played
-
public:
- LinearDiskStream(int rate, uint beginLoop, uint endLoop, bool disposeStream, Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, uint numBlocks, bool loop)
- : _rate(rate), _playtime(0, rate), _stream(stream), _beginLoop(beginLoop), _endLoop(endLoop), _disposeAfterUse(disposeStream),
- _audioBlockCount(numBlocks), _loop(loop), _numLoops(loop ? 0 : 1), _numPlayedLoops(0) {
+ LinearDiskStream(int rate, bool disposeStream, Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, uint numBlocks)
+ : _rate(rate), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream),
+ _audioBlockCount(numBlocks) {
assert(numBlocks > 0);
@@ -442,22 +467,12 @@ int LinearDiskStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffe
_bufferLeft = readAmount;
_diskLeft -= readAmount;
_ptr = (byte *)_buffer;
- _filePos += readAmount * (is16Bit? 2: 1);
+ _filePos += readAmount * (is16Bit ? 2 : 1);
// Set this flag now we've used the file, it restores it's
// original position.
restoreFilePosition = true;
}
-
- // Looping
- if (_diskLeft == 0 && _loop) {
- // Reset the stream
- _currentBlock = 0;
- _filePos = _audioBlock[_currentBlock].pos + _beginLoop;
- _diskLeft = _audioBlock[_currentBlock].len;
-
- _numPlayedLoops++;
- }
}
// In case calling code relies on the position of this stream staying
@@ -496,7 +511,7 @@ bool LinearDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &
} else {
const uint32 offset = seekSample - curSample;
- _filePos = _audioBlock[_currentBlock].pos + offset * (is16Bit? 2: 1);
+ _filePos = _audioBlock[_currentBlock].pos + offset * (is16Bit ? 2 : 1);
_diskLeft = _audioBlock[_currentBlock].len - offset;
return true;
@@ -519,36 +534,24 @@ bool LinearDiskStream<stereo, is16Bit, isUnsigned, isLE>::seek(const Timestamp &
#define MAKE_LINEAR(STEREO, UNSIGNED) \
if (is16Bit) { \
if (isLE) \
- return new LinearMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+ return new LinearMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, autoFree); \
else \
- return new LinearMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+ return new LinearMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, autoFree); \
} else \
- return new LinearMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree)
+ return new LinearMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, autoFree)
-SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd) {
+SeekableAudioStream *makeLinearInputStream(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 bool autoFree = (flags & Mixer::FLAG_AUTOFREE) != 0;
-
- uint loopOffset = 0, loopLen = 0;
- if (flags & Mixer::FLAG_LOOP) {
- 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((len & 3) == 0 && (loopLen & 3) == 0);
+ assert((len & 3) == 0);
} else if (is16Bit || isStereo) {
- assert((len & 1) == 0 && (loopLen & 1) == 0);
+ assert((len & 1) == 0);
}
if (isStereo) {
@@ -567,25 +570,55 @@ SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate
}
+AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate,
+ byte flags, uint loopStart, uint loopEnd) {
+ SeekableAudioStream *stream = makeLinearInputStream(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 & 3) == 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 LinearDiskStream<STEREO, true, UNSIGNED, true>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks, loop); \
+ return new LinearDiskStream<STEREO, true, UNSIGNED, true>(rate, takeOwnership, stream, block, numBlocks); \
else \
- return new LinearDiskStream<STEREO, true, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks, loop); \
+ return new LinearDiskStream<STEREO, true, UNSIGNED, false>(rate, takeOwnership, stream, block, numBlocks); \
} else \
- return new LinearDiskStream<STEREO, false, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks, loop)
+ return new LinearDiskStream<STEREO, false, UNSIGNED, false>(rate, takeOwnership, stream, block, numBlocks)
-SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd) {
+SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int numBlocks, int rate, byte flags, bool takeOwnership) {
const bool isStereo = (flags & Mixer::FLAG_STEREO) != 0;
const bool is16Bit = (flags & Mixer::FLAG_16BITS) != 0;
const bool isUnsigned = (flags & Mixer::FLAG_UNSIGNED) != 0;
const bool isLE = (flags & Mixer::FLAG_LITTLE_ENDIAN) != 0;
- const bool loop = (flags & Mixer::FLAG_LOOP) != 0;
if (isStereo) {
if (isUnsigned) {
@@ -602,7 +635,39 @@ SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, Li
}
}
+AudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block,
+ int numBlocks, int rate, byte flags, bool disposeStream, uint loopStart, uint loopEnd) {
+ SeekableAudioStream *s = makeLinearDiskStream(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 ---
diff --git a/sound/audiostream.h b/sound/audiostream.h
index 817cd36f95..003fef64f7 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -216,6 +216,42 @@ public:
AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start, Timestamp end, uint loops);
/**
+ * A looping audio stream, which features looping of a nested part of the
+ * stream.
+ *
+ * NOTE:
+ * Currently this implementation stops after the nested loop finished
+ * playback.
+ *
+ * IMPORTANT:
+ * This might be merged with SubSeekableAudioStream for playback purposes.
+ * (After extending it to accept a start time).
+ */
+class SubLoopingAudioStream : public AudioStream {
+public:
+ SubLoopingAudioStream(SeekableAudioStream *stream, uint loops,
+ const Timestamp loopStart,
+ const Timestamp loopEnd,
+ bool disposeAfterUse = true);
+ ~SubLoopingAudioStream();
+
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool endOfData() const { return _done; }
+
+ bool isStereo() const { return _parent->isStereo(); }
+ int getRate() const { return _parent->getRate(); }
+private:
+ SeekableAudioStream *_parent;
+ bool _disposeAfterUse;
+
+ uint _loops;
+ Timestamp _pos;
+ Timestamp _loopStart, _loopEnd;
+
+ bool _done;
+};
+
+/**
* A SubSeekableAudioStream provides access to a SeekableAudioStream
* just in the range [start, end).
* The same caveats apply to SubSeekableAudioStream as do to SeekableAudioStream.
@@ -259,6 +295,8 @@ private:
Timestamp _pos, _length;
};
+SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags);
+
/**
* Factory function for a raw linear AudioStream, which will simply treat all
* data in the buffer described by ptr and len as raw sample data in the
@@ -267,8 +305,8 @@ private:
* signed native endian). Optionally supports (infinite) looping of a portion
* of the data.
*/
-SeekableAudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate,
- byte flags, uint loopStart, uint loopEnd);
+AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate,
+ byte flags, uint loopStart, uint loopEnd);
/**
@@ -279,6 +317,8 @@ struct LinearDiskStreamAudioBlock {
int32 len; ///< Length of the block (in samples)
};
+SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block,
+ int numBlocks, int rate, byte flags, bool disposeStream);
/**
* Factory function for a Linear Disk Stream. This can stream linear (PCM)
@@ -286,7 +326,7 @@ struct LinearDiskStreamAudioBlock {
* LinearDiskStreamAudioBlock which defines the start position and length of
* each block of uncompressed audio in the stream.
*/
-SeekableAudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block,
+AudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block,
int numBlocks, int rate, byte flags, bool disposeStream, uint loopStart, uint loopEnd);
class QueuingAudioStream : public Audio::AudioStream {
diff --git a/sound/voc.cpp b/sound/voc.cpp
index 1c268c0260..79a64769f7 100644
--- a/sound/voc.cpp
+++ b/sound/voc.cpp
@@ -298,7 +298,7 @@ int parseVOCFormat(Common::SeekableReadStream& stream, LinearDiskStreamAudioBloc
return currentBlock;
}
-SeekableAudioStream *makeVOCDiskStream(Common::SeekableReadStream &stream, byte flags, bool takeOwnership) {
+AudioStream *makeVOCDiskStream(Common::SeekableReadStream &stream, byte flags, bool takeOwnership) {
const int MAX_AUDIO_BLOCKS = 256;
LinearDiskStreamAudioBlock *block = new LinearDiskStreamAudioBlock[MAX_AUDIO_BLOCKS];
@@ -317,11 +317,31 @@ SeekableAudioStream *makeVOCDiskStream(Common::SeekableReadStream &stream, byte
return audioStream;
}
-
+
+SeekableAudioStream *makeVOCDiskStreamNoLoop(Common::SeekableReadStream &stream, byte flags, bool takeOwnership) {
+ const int MAX_AUDIO_BLOCKS = 256;
+
+ LinearDiskStreamAudioBlock *block = new LinearDiskStreamAudioBlock[MAX_AUDIO_BLOCKS];
+ int rate, loops, begin_loop, end_loop;
+
+ int numBlocks = parseVOCFormat(stream, block, rate, loops, begin_loop, end_loop);
+
+ SeekableAudioStream *audioStream = 0;
+
+ // 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 = makeLinearDiskStream(&stream, block, numBlocks, rate, flags, takeOwnership);
+
+ delete[] block;
+
+ return audioStream;
+}
+
#endif
-SeekableAudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags, uint loopStart, uint loopEnd, bool takeOwnershipOfStream) {
+AudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags, uint loopStart, uint loopEnd, bool takeOwnershipOfStream) {
#ifdef STREAM_AUDIO_FROM_DISK
return makeVOCDiskStream(stream, flags, takeOwnershipOfStream);
#else
@@ -336,5 +356,19 @@ SeekableAudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flag
#endif
}
+SeekableAudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags, bool takeOwnershipOfStream) {
+#ifdef STREAM_AUDIO_FROM_DISK
+ return makeVOCDiskStreamNoLoop(stream, flags, takeOwnershipOfStream);
+#else
+ int size, rate;
+
+ byte *data = loadVOCFromStream(stream, size, rate);
+
+ if (!data)
+ return 0;
+
+ return makeLinearInputStream(data, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE);
+#endif
+}
} // End of namespace Audio
diff --git a/sound/voc.h b/sound/voc.h
index 44bef758f3..e16d8169f9 100644
--- a/sound/voc.h
+++ b/sound/voc.h
@@ -93,7 +93,12 @@ extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate)
*
* This function uses loadVOCFromStream() internally.
*/
-SeekableAudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags = 0, uint loopStart = 0, uint loopEnd = 0, bool takeOwnershipOfStream = false);
+AudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags = 0, uint loopStart = 0, uint loopEnd = 0, bool takeOwnershipOfStream = false);
+
+/**
+ * This does not use any of the looping features from VOC files!
+ */
+SeekableAudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags, bool takeOwnershipOfStream);
} // End of namespace Audio
diff --git a/sound/wave.cpp b/sound/wave.cpp
index a625d18d90..e1a466393f 100644
--- a/sound/wave.cpp
+++ b/sound/wave.cpp
@@ -190,7 +190,7 @@ RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, bool di
// Since we allocated our own buffer for the data, we must set the autofree flag.
flags |= Audio::Mixer::FLAG_AUTOFREE;
- return makeLinearInputStream(data, size, rate, flags, 0, 0);
+ return makeLinearInputStream(data, size, rate, flags);
}
} // End of namespace Audio