From f7a869ccc5c22212768c43f258a7fbf7dddb758f Mon Sep 17 00:00:00 2001 From: Tobias Gunkel Date: Wed, 21 Dec 2011 10:10:42 +0100 Subject: SCUMM: Optimize player_appleII sample buffer The AppleII sound player works in two phases: writing samples to the sample buffer (sample generation) or reading samples from the buffer and passing it to ScummVM's output callback. The sample buffer is read completely in the reading phase so the entries of the already read samples of the buffer can be reused again during the next write phase. --- engines/scumm/player_appleII.h | 84 +++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 34 deletions(-) (limited to 'engines/scumm') diff --git a/engines/scumm/player_appleII.h b/engines/scumm/player_appleII.h index f0b148ef86..1f53b6a8dc 100644 --- a/engines/scumm/player_appleII.h +++ b/engines/scumm/player_appleII.h @@ -35,13 +35,20 @@ namespace Scumm { class ScummEngine; -class DynamicMemoryStream { +/* + * Optimized for use with periodical read/write phases when the buffer + * is filled in a write phase and completely read in a read phase. + * The growing strategy is optimized for repeated small (e.g. 2 bytes) + * single writes resulting in large buffers + * (avg.: 4KB, max: 18KB @ 16bit/22.050kHz (MM sound21)). + */ +class SampleBuffer { public: - DynamicMemoryStream() : _data(0) { + SampleBuffer() : _data(0) { clear(); } - ~DynamicMemoryStream() { + ~SampleBuffer() { free(_data); } @@ -49,50 +56,61 @@ public: free(_data); _data = 0; _capacity = 0; - _size = 0; - _ptr = 0; - _pos = 0; + _writePos = 0; _readPos = 0; } - void ensureCapacity(uint32 new_len) { - if (new_len <= _capacity) + void ensureFree(uint32 needed) { + // if data was read completely, reset read/write pos to front + if ((_writePos != 0) && (_writePos == _readPos)) { + _writePos = 0; + _readPos = 0; + } + + // check for enough space at end of buffer + uint32 freeEndCnt = _capacity - _writePos; + if (needed <= freeEndCnt) return; - byte *old_data = _data; + uint32 avail = availableSize(); + + // check for enough space at beginning and end of buffer + if (needed <= _readPos + freeEndCnt) { + // move unread data to front of buffer + memmove(_data, _data + _readPos, avail); + _writePos = avail; + _readPos = 0; + } else { // needs a grow + byte *old_data = _data; + uint32 new_len = avail + needed; - _capacity *= 2; - if (_capacity < new_len + 2048) _capacity = new_len + 2048; - _data = (byte *)malloc(_capacity); - _ptr = _data + _pos; - - if (old_data) { - // Copy old data - memcpy(_data, old_data, _size); - free(old_data); + _data = (byte *)malloc(_capacity); + + if (old_data) { + // copy old unread data to front of new buffer + memcpy(_data, old_data + _readPos, avail); + free(old_data); + _writePos = avail; + _readPos = 0; + } } - - _size = new_len; } uint32 availableSize() const { - if (_readPos >= _size) + if (_readPos >= _writePos) return 0; - return _size - _readPos; + return _writePos - _readPos; } virtual uint32 write(const void *dataPtr, uint32 dataSize) { - ensureCapacity(_pos + dataSize); - memcpy(_ptr, dataPtr, dataSize); - _ptr += dataSize; - _pos += dataSize; - if (_pos > _size) - _size = _pos; + ensureFree(dataSize); + memcpy(_data + _writePos, dataPtr, dataSize); + _writePos += dataSize; return dataSize; } - uint32 read(byte *dataPtr, uint32 dataSize) const { + uint32 read(byte *dataPtr, uint32 dataSize) { uint32 avail = availableSize(); if (avail == 0) return 0; @@ -104,12 +122,10 @@ public: } private: - mutable uint32 _readPos; + uint32 _writePos; + uint32 _readPos; uint32 _capacity; - uint32 _size; - byte *_ptr; byte *_data; - uint32 _pos; }; // CPU_CLOCK according to AppleWin @@ -214,7 +230,7 @@ private: int _sampleCyclesSumFP; /* (fixed precision) */ int _volume; /* 0 - 256 */ static const int _maxVolume = 256; - DynamicMemoryStream _buffer; + SampleBuffer _buffer; }; class AppleII_SoundFunction; -- cgit v1.2.3