aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2007-02-28 14:48:26 +0000
committerMax Horn2007-02-28 14:48:26 +0000
commit8c8abca6f80fc63b5c11fa43319cdf56b4845660 (patch)
treeec031a874e67c92d3640824c2ee9816b5b6cab90
parentdea688d0f5303e552bff8ff22798719d92ed53c1 (diff)
downloadscummvm-rg350-8c8abca6f80fc63b5c11fa43319cdf56b4845660.tar.gz
scummvm-rg350-8c8abca6f80fc63b5c11fa43319cdf56b4845660.tar.bz2
scummvm-rg350-8c8abca6f80fc63b5c11fa43319cdf56b4845660.zip
Changed the AppendableAudioStream code to use a queue of buffers, instead of a fixed size wrap-around memory buffer (this reduces memory usage in some cases by 500-700k, while actually being more flexible)
svn-id: r25909
-rw-r--r--engines/kyra/vqa.cpp33
-rw-r--r--engines/scumm/imuse_digi/dimuse.cpp9
-rw-r--r--engines/scumm/imuse_digi/dimuse_sndmgr.cpp4
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.cpp6
-rw-r--r--engines/scumm/smush/smush_mixer.cpp10
-rw-r--r--engines/scumm/smush/smush_player.cpp8
-rw-r--r--engines/sword1/sound.cpp6
-rw-r--r--sound/audiostream.cpp114
-rw-r--r--sound/audiostream.h32
9 files changed, 127 insertions, 95 deletions
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp
index 3660bcf217..603b67221b 100644
--- a/engines/kyra/vqa.cpp
+++ b/engines/kyra/vqa.cpp
@@ -268,8 +268,8 @@ bool VQAMovie::open(const char *filename) {
_numPartialCodeBooks = 0;
if (_header.flags & 1) {
- // A 2-second buffer ought to be enough
- _stream = Audio::makeAppendableAudioStream(_header.freq, Audio::Mixer::FLAG_UNSIGNED, 2 * _header.freq * _header.channels);
+ // TODO/FIXME: Shouldn't we set FLAG_STEREO if _header.channels == 2 (wonders Fingolfin)
+ _stream = Audio::makeAppendableAudioStream(_header.freq, Audio::Mixer::FLAG_UNSIGNED);
} else {
_stream = NULL;
}
@@ -399,9 +399,10 @@ void VQAMovie::displayFrame(uint frameNum) {
switch (tag) {
case MKID_BE('SND0'): // Uncompressed sound
foundSound = true;
- inbuf = (byte *)allocBuffer(0, size);
+ inbuf = new byte[size];
_file.read(inbuf, size);
- _stream->append(inbuf, size);
+ assert(_stream);
+ _stream->queueBuffer(inbuf, size);
break;
case MKID_BE('SND1'): // Compressed sound, almost like AUD
@@ -409,15 +410,18 @@ void VQAMovie::displayFrame(uint frameNum) {
outsize = _file.readUint16LE();
insize = _file.readUint16LE();
- inbuf = (byte *)allocBuffer(0, insize);
+ inbuf = new byte[insize];
_file.read(inbuf, insize);
if (insize == outsize) {
- _stream->append(inbuf, insize);
+ assert(_stream);
+ _stream->queueBuffer(inbuf, insize);
} else {
- outbuf = (byte *)allocBuffer(1, outsize);
+ outbuf = new byte[outsize];
decodeSND1(inbuf, insize, outbuf, outsize);
- _stream->append(outbuf, outsize);
+ assert(_stream);
+ _stream->queueBuffer(outbuf, outsize);
+ delete[] inbuf;
}
break;
@@ -589,24 +593,25 @@ void VQAMovie::play() {
switch (tag) {
case MKID_BE('SND0'): // Uncompressed sound
- inbuf = (byte *)allocBuffer(0, size);
+ inbuf = new byte[size];
_file.read(inbuf, size);
- _stream->append(inbuf, size);
+ _stream->queueBuffer(inbuf, size);
break;
case MKID_BE('SND1'): // Compressed sound
outsize = _file.readUint16LE();
insize = _file.readUint16LE();
- inbuf = (byte *)allocBuffer(0, insize);
+ inbuf = new byte[insize];
_file.read(inbuf, insize);
if (insize == outsize) {
- _stream->append(inbuf, insize);
+ _stream->queueBuffer(inbuf, insize);
} else {
- outbuf = (byte *)allocBuffer(1, outsize);
+ outbuf = new byte[outsize];
decodeSND1(inbuf, insize, outbuf, outsize);
- _stream->append(outbuf, outsize);
+ _stream->queueBuffer(outbuf, outsize);
+ delete[] inbuf;
}
break;
diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp
index 7e70268b12..c249dd57a9 100644
--- a/engines/scumm/imuse_digi/dimuse.cpp
+++ b/engines/scumm/imuse_digi/dimuse.cpp
@@ -188,9 +188,8 @@ void IMuseDigital::saveOrLoad(Serializer *ser) {
track->mixerFlags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
#endif
- int32 streamBufferSize = track->iteration;
track->stream2 = NULL;
- track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
+ track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags);
const int pan = (track->pan != 64) ? 2 * track->pan - 127 : 0;
const int vol = track->vol / 1000;
@@ -324,10 +323,10 @@ void IMuseDigital::callback() {
if (_mixer->isReady()) {
_mixer->setChannelVolume(track->handle, vol);
_mixer->setChannelBalance(track->handle, pan);
- track->stream->append(data, result);
+ track->stream->queueBuffer(data, result);
track->regionOffset += result;
- }
- free(data);
+ } else
+ delete[] data;
if (_sound->isEndOfRegion(track->soundHandle, track->curRegion)) {
switchToNextRegion(track);
diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
index 2b88f37b17..5c7fa5b613 100644
--- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
+++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
@@ -583,11 +583,11 @@ int32 ImuseDigiSndMgr::getDataFromRegion(soundStruct *soundHandle, int region, b
if ((soundHandle->bundle) && (!soundHandle->compressed)) {
size = soundHandle->bundle->decompressSampleByCurIndex(start + offset, size, buf, header_size, header_outside);
} else if (soundHandle->resPtr) {
- *buf = (byte *)malloc(size);
+ *buf = new byte[size];
assert(*buf);
memcpy(*buf, soundHandle->resPtr + start + offset + header_size, size);
} else if ((soundHandle->bundle) && (soundHandle->compressed)) {
- *buf = (byte *)malloc(size);
+ *buf = new byte[size];
assert(*buf);
char fileName[24];
sprintf(fileName, "%s_reg%03d", soundHandle->name, region);
diff --git a/engines/scumm/imuse_digi/dimuse_track.cpp b/engines/scumm/imuse_digi/dimuse_track.cpp
index 37ae22f47f..6acb2a0318 100644
--- a/engines/scumm/imuse_digi/dimuse_track.cpp
+++ b/engines/scumm/imuse_digi/dimuse_track.cpp
@@ -176,9 +176,8 @@ void IMuseDigital::startSound(int soundId, const char *soundName, int soundType,
type = Audio::Mixer::kMusicSoundType;
// setup 1 second stream wrapped buffer
- int32 streamBufferSize = track->iteration;
track->stream2 = NULL;
- track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags, streamBufferSize);
+ track->stream = Audio::makeAppendableAudioStream(freq, track->mixerFlags);
_mixer->playInputStream(type, &track->handle, track->stream, -1, vol, pan, false);
track->started = true;
}
@@ -356,8 +355,7 @@ IMuseDigital::Track *IMuseDigital::cloneToFadeOutTrack(Track *track, int fadeDel
type = Audio::Mixer::kMusicSoundType;
// setup 1 second stream wrapped buffer
- int32 streamBufferSize = fadeTrack->iteration;
- fadeTrack->stream = Audio::makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundHandle), fadeTrack->mixerFlags, streamBufferSize);
+ fadeTrack->stream = Audio::makeAppendableAudioStream(_sound->getFreq(fadeTrack->soundHandle), fadeTrack->mixerFlags);
_mixer->playInputStream(type, &fadeTrack->handle, fadeTrack->stream, -1, fadeTrack->vol / 1000, fadeTrack->pan, false);
fadeTrack->started = true;
fadeTrack->used = true;
diff --git a/engines/scumm/smush/smush_mixer.cpp b/engines/scumm/smush/smush_mixer.cpp
index 9e6631a365..e29a921224 100644
--- a/engines/scumm/smush/smush_mixer.cpp
+++ b/engines/scumm/smush/smush_mixer.cpp
@@ -105,6 +105,7 @@ bool SmushMixer::handleFrame() {
_channels[i].chan->getParameters(stereo, is_16bit, vol, pan);
+ // Grab the audio data from the channel
int32 size = _channels[i].chan->getAvailableSoundDataSize();
byte *data = _channels[i].chan->getSoundData();
@@ -116,15 +117,16 @@ bool SmushMixer::handleFrame() {
}
if (_mixer->isReady()) {
+ // Stream the data
if (!_channels[i].stream) {
- _channels[i].stream = Audio::makeAppendableAudioStream(_channels[i].chan->getRate(), flags, 500000);
+ _channels[i].stream = Audio::makeAppendableAudioStream(_channels[i].chan->getRate(), flags);
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_channels[i].handle, _channels[i].stream);
}
_mixer->setChannelVolume(_channels[i].handle, vol);
_mixer->setChannelBalance(_channels[i].handle, pan);
- _channels[i].stream->append(data, size);
- }
- delete[] data;
+ _channels[i].stream->queueBuffer(data, size); // The stream will free the buffer for us
+ } else
+ delete[] data;
}
}
}
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index d4b3352be4..3310415f30 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -462,7 +462,7 @@ void SmushPlayer::handleIACT(Chunk &b) {
c->checkParameters(index, nbframes, size, track_flags, unknown);
c->appendData(b, bsize);
} else {
- byte output_data[4096];
+ // TODO: Move this code into another SmushChannel subclass?
byte *src = (byte *)malloc(bsize);
b.read(src, bsize);
byte *d_src = src;
@@ -477,6 +477,8 @@ void SmushPlayer::handleIACT(Chunk &b) {
_IACTpos += bsize;
bsize = 0;
} else {
+ byte *output_data = new byte[4096];
+
memcpy(_IACToutput + _IACTpos, d_src, len);
byte *dst = output_data;
byte *d_src2 = _IACToutput;
@@ -507,10 +509,10 @@ void SmushPlayer::handleIACT(Chunk &b) {
} while (--count);
if (!_IACTstream) {
- _IACTstream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_16BITS, 900000);
+ _IACTstream = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_STEREO | Audio::Mixer::FLAG_16BITS);
_vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_IACTchannel, _IACTstream);
}
- _IACTstream->append(output_data, 0x1000);
+ _IACTstream->queueBuffer(output_data, 0x1000);
bsize -= len;
d_src += len;
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index fd0a37003e..6c255cb4ce 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -382,10 +382,8 @@ void Sound::initCowSystem(void) {
}
void Sound::closeCowSystem(void) {
- if (_cowFile.isOpen())
- _cowFile.close();
- if (_cowHeader)
- free(_cowHeader);
+ _cowFile.close();
+ free(_cowHeader);
_cowHeader = NULL;
_currentCowFile = 0;
}
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
index d3c0e2e745..54b0221199 100644
--- a/sound/audiostream.cpp
+++ b/sound/audiostream.cpp
@@ -23,6 +23,7 @@
#include "common/stdafx.h"
#include "common/endian.h"
#include "common/file.h"
+#include "common/list.h"
#include "common/util.h"
#include "sound/audiostream.h"
@@ -128,7 +129,6 @@ protected:
const int _rate;
const byte *_origPtr;
- inline bool eosIntern() const { return _ptr >= _end; };
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) {
@@ -154,7 +154,7 @@ public:
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return stereo; }
- bool endOfData() const { return eosIntern(); }
+ bool endOfData() const { return _ptr >= _end; }
int getRate() const { return _rate; }
};
@@ -162,7 +162,7 @@ public:
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
- while (samples < numSamples && !eosIntern()) {
+ while (samples < numSamples && _ptr < _end) {
const int len = MIN(numSamples, samples + (int)(_end - _ptr) / (is16Bit ? 2 : 1));
while (samples < len) {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
@@ -170,7 +170,7 @@ int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buf
samples++;
}
// Loop, if looping was specified
- if (_loopPtr && eosIntern()) {
+ if (_loopPtr && _ptr >= _end) {
_ptr = _loopPtr;
_end = _loopEnd;
}
@@ -228,6 +228,10 @@ AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32
#pragma mark --- Appendable audio stream ---
#pragma mark -
+struct Buffer {
+ byte *start;
+ byte *end;
+};
/**
* Wrapped memory stream.
@@ -235,18 +239,22 @@ AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
class AppendableMemoryStream : public AppendableAudioStream {
protected:
+
+ // A mutex to avoid access problems (causing e.g. corruption of
+ // the linked list) in thread aware environments.
Common::Mutex _mutex;
- byte *_bufferStart;
- byte *_bufferEnd;
- byte *_pos;
- byte *_end;
+ // List of all queueud buffers
+ Common::List<Buffer> _bufferQueue;
+
+ // Position in the front buffer, if any
bool _finalized;
const int _rate;
+ byte *_pos;
- inline bool eosIntern() const { return _end == _pos; };
+ inline bool eosIntern() const { return _bufferQueue.empty(); };
public:
- AppendableMemoryStream(int rate, uint bufferSize);
+ AppendableMemoryStream(int rate);
~AppendableMemoryStream();
int readBuffer(int16 *buffer, const int numSamples);
@@ -256,30 +264,22 @@ public:
int getRate() const { return _rate; }
- void append(const byte *data, uint32 len);
+ void queueBuffer(byte *data, uint32 size);
void finish() { _finalized = true; }
};
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate, uint bufferSize)
- : _finalized(false), _rate(rate) {
-
- // Verify the buffer size is sane
- if (is16Bit && stereo)
- assert((bufferSize & 3) == 0);
- else if (is16Bit || stereo)
- assert((bufferSize & 1) == 0);
-
- _bufferStart = (byte *)malloc(bufferSize);
- assert(_bufferStart != NULL);
+AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::AppendableMemoryStream(int rate)
+ : _finalized(false), _rate(rate), _pos(0) {
- _pos = _end = _bufferStart;
- _bufferEnd = _bufferStart + bufferSize;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::~AppendableMemoryStream() {
- free(_bufferStart);
+ // Clear the queue
+ Common::List<Buffer>::iterator iter;
+ for (iter = _bufferQueue.begin(); iter != _bufferQueue.end(); ++iter)
+ delete[] iter->start;
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
@@ -288,12 +288,19 @@ int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16
int samples = 0;
while (samples < numSamples && !eosIntern()) {
- // Wrap around?
- if (_pos >= _bufferEnd)
- _pos = _pos - (_bufferEnd - _bufferStart);
+ Buffer buf = *_bufferQueue.begin();
+ if (_pos == 0)
+ _pos = buf.start;
+
+ assert(buf.start <= _pos && _pos <= buf.end);
+ const int samplesLeftInCurBuffer = buf.end - _pos;
+ if (samplesLeftInCurBuffer == 0) {
+ _bufferQueue.erase(_bufferQueue.begin());
+ _pos = 0;
+ continue;
+ }
- const byte *endMarker = (_pos > _end) ? _bufferEnd : _end;
- const int len = MIN(numSamples, samples + (int)(endMarker - _pos) / (is16Bit ? 2 : 1));
+ const int len = MIN(numSamples, samples + samplesLeftInCurBuffer / (is16Bit ? 2 : 1));
while (samples < len) {
*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _pos, isLE);
_pos += (is16Bit ? 2 : 1);
@@ -305,50 +312,45 @@ int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16
}
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
-void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::append(const byte *data, uint32 len) {
+void AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::queueBuffer(byte *data, uint32 size) {
Common::StackLock lock(_mutex);
// Verify the buffer size is sane
if (is16Bit && stereo)
- assert((len & 3) == 0);
+ assert((size & 3) == 0);
else if (is16Bit || stereo)
- assert((len & 1) == 0);
+ assert((size & 1) == 0);
// Verify that the stream has not yet been finalized (by a call to finish())
assert(!_finalized);
- if (_end + len > _bufferEnd) {
- // Wrap-around case
- uint32 size_to_end_of_buffer = _bufferEnd - _end;
- len -= size_to_end_of_buffer;
- if ((_end < _pos) || (_bufferStart + len >= _pos)) {
- debug(2, "AppendableMemoryStream: buffer overflow (A)");
- return;
- }
- memcpy(_end, data, size_to_end_of_buffer);
- memcpy(_bufferStart, data + size_to_end_of_buffer, len);
- _end = _bufferStart + len;
- } else {
- if ((_end < _pos) && (_end + len >= _pos)) {
- debug(2, "AppendableMemoryStream: buffer overflow (B)");
- return;
- }
- memcpy(_end, data, len);
- _end += len;
- }
+ // Queue the buffer
+ Buffer buf = {data, data+size};
+ _bufferQueue.push_back(buf);
+
+
+#if 0
+ // Output some stats
+ uint totalSize = 0;
+ Common::List<Buffer>::iterator iter;
+ for (iter = _bufferQueue.begin(); iter != _bufferQueue.end(); ++iter)
+ totalSize += iter->end - iter->start;
+ printf("AppendableMemoryStream::queueBuffer: added a %d byte buf, a total of %d bytes are queued\n",
+ size, totalSize);
+#endif
}
#define MAKE_WRAPPED(STEREO, UNSIGNED) \
if (is16Bit) { \
if (isLE) \
- return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate, len); \
+ return new AppendableMemoryStream<STEREO, true, UNSIGNED, true>(rate); \
else \
- return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate, len); \
+ return new AppendableMemoryStream<STEREO, true, UNSIGNED, false>(rate); \
} else \
- return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate, len)
+ return new AppendableMemoryStream<STEREO, false, UNSIGNED, false>(rate)
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len) {
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags) {
const bool isStereo = (_flags & Audio::Mixer::FLAG_STEREO) != 0;
const bool is16Bit = (_flags & Audio::Mixer::FLAG_16BITS) != 0;
const bool isUnsigned = (_flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
diff --git a/sound/audiostream.h b/sound/audiostream.h
index b76f2f9cd2..499fb782ab 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -31,7 +31,8 @@
namespace Audio {
/**
- * Generic input stream for the resampling code.
+ * Generic audio input stream. Subclasses of this are used to feed arbitrary
+ * sampled audio data into ScummVM's audio mixer.
*/
class AudioStream {
public:
@@ -89,6 +90,13 @@ public:
static AudioStream* openStreamFile(const char *filename);
};
+/**
+ * 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 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 *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
/**
@@ -97,11 +105,29 @@ AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32
*/
class AppendableAudioStream : public Audio::AudioStream {
public:
- virtual void append(const byte *data, uint32 len) = 0;
+
+ /**
+ * Queue another audio data buffer for playback. The stream
+ * will playback all queued buffers, in the order they were
+ * queued. After all data contained in them has been played,
+ * the buffer will be delete[]'d (so make sure to allocate them
+ * with new[], not with malloc).
+ */
+ virtual void queueBuffer(byte *data, uint32 size) = 0;
+
+ /**
+ * Mark the stream as finished, that is, signal that no further data
+ * will be appended to it. Only after this has been done can the
+ * AppendableAudioStream ever 'end' (
+ */
virtual void finish() = 0;
};
-AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len);
+/**
+ * Factory function for an AppendableAudioStream. The rate and flags
+ * parameters are analog to those used in makeLinearInputStream.
+ */
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte flags);
} // End of namespace Audio