diff options
author | Tobias Gunkel | 2011-11-20 20:52:28 +0100 |
---|---|---|
committer | Tobias Gunkel | 2011-12-22 12:08:25 +0100 |
commit | 8b7ad559c18df51deb7682ad728244fde22dc70a (patch) | |
tree | e58cce62b9ec58628ff3f11f1801941b25288206 | |
parent | e56d5df295de63ed991bf9682f1c78e3ab92f351 (diff) | |
download | scummvm-rg350-8b7ad559c18df51deb7682ad728244fde22dc70a.tar.gz scummvm-rg350-8b7ad559c18df51deb7682ad728244fde22dc70a.tar.bz2 scummvm-rg350-8b7ad559c18df51deb7682ad728244fde22dc70a.zip |
SCUMM: Aggregate speaker states of CPU cycles in between samples
- formerly only two sample levels were possible: 32767 or -32767. Now the
speaker states (0/1) between two samples are aggregated by the new
SampleConverter class to allow more accurate sample values between -32767
and 32767.
- the player's state is moved into a separate state struct
-rw-r--r-- | engines/scumm/player_appleII.cpp | 90 | ||||
-rw-r--r-- | engines/scumm/player_appleII.h | 106 |
2 files changed, 139 insertions, 57 deletions
diff --git a/engines/scumm/player_appleII.cpp b/engines/scumm/player_appleII.cpp index b83bb22871..0c34c906a6 100644 --- a/engines/scumm/player_appleII.cpp +++ b/engines/scumm/player_appleII.cpp @@ -25,9 +25,6 @@ #include "scumm/player_appleII.h" #include "scumm/scumm.h" -// CPU_CLOCK according to AppleWin -static const double CPU_CLOCK = 1020484.5; // ~ 1.02 MHz - namespace Scumm { Player_AppleII::Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer) { @@ -35,9 +32,10 @@ Player_AppleII::Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer) { _soundNr = 0; _mixer = mixer; - _sampleRate = _mixer->getOutputRate(); _vm = scumm; + setSampleRate(_mixer->getOutputRate()); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); } @@ -73,60 +71,62 @@ void Player_AppleII::startSound(int nr) { Common::StackLock lock(_mutex); _soundNr = nr; - _buffer.clear(); + _sampleConverter.reset(); byte *data = _vm->getResourceAddress(rtSound, nr); assert(data); byte *ptr1 = data + 4; - int type = ptr1[0]; - if (type == 0) + _state.type = ptr1[0]; + if (_state.type == 0) return; - int loop = ptr1[1]; - assert(loop > 0); - ptr1 += 2; + + _state.loop = ptr1[1]; + assert(_state.loop > 0); + + _state.params = &ptr1[2]; debug(4, "startSound %d: type %d, loop %d", - nr, type, loop); + nr, _state.type, _state.loop); do { - switch (type) { + switch (_state.type) { case 1: // freq up/down - soundFunc1(ptr1); + soundFunc1(); break; case 2: // symmetric wave (~) - soundFunc2(ptr1); + soundFunc2(); break; case 3: // asymmetric wave (__-) - soundFunc3(ptr1); + soundFunc3(); break; case 4: // polyphone (2 voices) - soundFunc4(ptr1); + soundFunc4(); break; case 5: // periodic noise - soundFunc5(ptr1); + soundFunc5(); break; } - --loop; - } while (loop > 0); + --_state.loop; + } while (_state.loop > 0); } void Player_AppleII::stopAllSounds() { Common::StackLock lock(_mutex); - _buffer.clear(); + _sampleConverter.reset(); } void Player_AppleII::stopSound(int nr) { Common::StackLock lock(_mutex); if (_soundNr == nr) { - _buffer.clear(); + _sampleConverter.reset(); } } int Player_AppleII::getSoundStatus(int nr) const { Common::StackLock lock(_mutex); - return (_buffer.availableSize() > 0 ? 1 : 0); + return (_sampleConverter.availableSize() > 0 ? 1 : 0); } int Player_AppleII::getMusicTimer() { @@ -136,7 +136,7 @@ int Player_AppleII::getMusicTimer() { int Player_AppleII::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock lock(_mutex); - return _buffer.read((byte*)buffer, numSamples * 2) / 2; + return _sampleConverter.readSamples(buffer, numSamples); } /************************************ @@ -149,16 +149,7 @@ void Player_AppleII::speakerToggle() { } void Player_AppleII::generateSamples(int cycles) { - // sampleDiff is used to compensate fractional samples - static double sampleDiff = 0; - double fSamples = (double)cycles / CPU_CLOCK * _sampleRate + sampleDiff; - int samples = (int)(fSamples + 0.5); - sampleDiff = fSamples - samples; - - float vol = (float)_maxvol / 255; - int16 value = vol * (_speakerState ? 32767 : -32767); - for (int i = 0; i < samples; ++i) - _buffer.write(&value, sizeof(value)); + _sampleConverter.addCycles(_speakerState, cycles); } void Player_AppleII::wait(int interval, int count /*y*/) { @@ -177,12 +168,12 @@ void Player_AppleII::_soundFunc1(int interval /*a*/, int count /*y*/) { // D076 } } -void Player_AppleII::soundFunc1(const byte *params) { // D085 - int delta = params[0]; - int count = params[1]; - byte interval = params[2]; // must be byte ("interval < delta" possible) - int limit = params[3]; - bool decInterval = (params[4] >= 0x40); +void Player_AppleII::soundFunc1() { // D085 + const int delta = _state.params[0]; + const int count = _state.params[1]; + byte interval = _state.params[2]; // must be byte ("interval < delta" possible) + const int limit = _state.params[3]; + const bool decInterval = (_state.params[4] >= 0x40); if (decInterval) { do { @@ -215,12 +206,12 @@ void Player_AppleII::_soundFunc2(int interval /*a*/, int count) { // D0EF } } -void Player_AppleII::soundFunc2(const byte *params) { // D0D6 +void Player_AppleII::soundFunc2() { // D0D6 for (int pos = 1; pos < 256; ++pos) { - byte interval = params[pos]; + byte interval = _state.params[pos]; if (interval == 0xFF) return; - _soundFunc2(interval, params[0] /*, LD12F=interval*/); + _soundFunc2(interval, _state.params[0] /*, LD12F=interval*/); } } @@ -238,12 +229,12 @@ void Player_AppleII::_soundFunc3(int interval /*a*/, int count /*LD12D*/) { // D } } -void Player_AppleII::soundFunc3(const byte *params) { // D132 +void Player_AppleII::soundFunc3() { // D132 for (int pos = 1; pos < 256; ++pos) { - byte interval = params[pos]; + byte interval = _state.params[pos]; if (interval == 0xFF) return; - _soundFunc3(interval, params[0]); + _soundFunc3(interval, _state.params[0]); } } @@ -290,7 +281,7 @@ void Player_AppleII::_soundFunc4(byte param0, byte param1, byte param2) { // D1A if (speakerShiftReg & 0x1) speakerToggle(); speakerShiftReg >>= 1; - generateSamples(40); + generateSamples(42); /* actually 42.5 */ ++count; if (count == 0) { @@ -299,7 +290,8 @@ void Player_AppleII::_soundFunc4(byte param0, byte param1, byte param2) { // D1A } } -void Player_AppleII::soundFunc4(const byte *params) { // D170 +void Player_AppleII::soundFunc4() { // D170 + const byte *params = _state.params; while (params[0] != 0x01) { _soundFunc4(params[0], params[1], params[2]); params += 3; @@ -347,12 +339,12 @@ byte /*a*/ Player_AppleII::noise() { // D261 return result; } -void Player_AppleII::soundFunc5(const byte *params) { // D222 +void Player_AppleII::soundFunc5() { // D222 const byte noiseMask[] = { 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F }; - int param0 = params[0]; + int param0 = _state.params[0]; assert(param0 > 0); for (int i = 0; i < 10; ++i) { int count = param0; diff --git a/engines/scumm/player_appleII.h b/engines/scumm/player_appleII.h index 545e590fdd..18572200c2 100644 --- a/engines/scumm/player_appleII.h +++ b/engines/scumm/player_appleII.h @@ -112,12 +112,97 @@ private: uint32 _pos; }; +// CPU_CLOCK according to AppleWin +static const double CPU_CLOCK = 1020484.5; // ~ 1.02 MHz + +class SampleConverter { +private: + void newSample(int sample) { + int16 value = _volume * sample / 255; + _buffer.write(&value, sizeof(value)); + } + +public: + SampleConverter() : + _cyclesPerSample(0), + _missingCycles(0), + _sampleCyclesSum(0), + _volume(255) + {} + + void reset() { + _missingCycles = 0; + _sampleCyclesSum = 0; + _buffer.clear(); + } + + uint32 availableSize() const { + return _buffer.availableSize(); + } + + void setMusicVolume(int vol) { + assert(vol >= 0 && vol <= 255); + _volume = vol; + } + + void setSampleRate(int rate) { + _cyclesPerSample = CPU_CLOCK / (float)rate; + reset(); + } + + void addCycles(byte level, int cycles) { + // step 1: if cycles are left from the last call, process them first + if (_missingCycles > 0) { + int n = (_missingCycles < cycles) ? _missingCycles : cycles; + if (level) + _sampleCyclesSum += n; + cycles -= n; + _missingCycles -= n; + if (_missingCycles == 0) { + newSample(2*32767 * _sampleCyclesSum / _cyclesPerSample - 32767); + } else { + return; + } + } + + _sampleCyclesSum = 0; + + // step 2: process blocks of cycles fitting into a whole sample + while (cycles >= _cyclesPerSample) { + newSample(level ? 32767 : -32767); + cycles -= _cyclesPerSample; + } + + // step 3: remember cycles left for next call + if (cycles > 0) { + _missingCycles = _cyclesPerSample - cycles; + if (level) + _sampleCyclesSum = cycles; + } + } + + uint32 readSamples(void *buffer, int numSamples) { + return _buffer.read((byte*)buffer, numSamples * 2) / 2; + } + +private: + float _cyclesPerSample; + int _missingCycles; + int _sampleCyclesSum; + int _volume; /* 0 - 255 */ + DynamicMemoryStream _buffer; +}; + class Player_AppleII : public Audio::AudioStream, public MusicEngine { public: Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer); virtual ~Player_AppleII(); - virtual void setMusicVolume(int vol) { _maxvol = vol; } + virtual void setMusicVolume(int vol) { _sampleConverter.setMusicVolume(vol); } + void setSampleRate(int rate) { + _sampleRate = rate; + _sampleConverter.setSampleRate(rate); + } void startMusic(int songResIndex); virtual void startSound(int sound); virtual void stopSound(int sound); @@ -132,17 +217,22 @@ public: int getRate() const { return _sampleRate; } private: + struct state_t { + int type; + int loop; + const byte *params; + } _state; + ScummEngine *_vm; Audio::Mixer *_mixer; Audio::SoundHandle _soundHandle; - int _maxvol; int _sampleRate; Common::Mutex _mutex; private: byte _speakerState; - DynamicMemoryStream _buffer; int _soundNr; + SampleConverter _sampleConverter; private: void speakerToggle(); @@ -150,15 +240,15 @@ private: void wait(int interval, int count); byte noise(); - void soundFunc1(const byte *params); + void soundFunc1(); void _soundFunc1(int interval, int count); - void soundFunc2(const byte *params); + void soundFunc2(); void _soundFunc2(int interval, int count); - void soundFunc3(const byte *params); + void soundFunc3(); void _soundFunc3(int interval, int count); - void soundFunc4(const byte *params); + void soundFunc4(); void _soundFunc4(byte param0, byte param1, byte param2); - void soundFunc5(const byte *params); + void soundFunc5(); void _soundFunc5(int interval, int count); }; |