aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Gunkel2011-11-20 20:52:28 +0100
committerTobias Gunkel2011-12-22 12:08:25 +0100
commit8b7ad559c18df51deb7682ad728244fde22dc70a (patch)
treee58cce62b9ec58628ff3f11f1801941b25288206
parente56d5df295de63ed991bf9682f1c78e3ab92f351 (diff)
downloadscummvm-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.cpp90
-rw-r--r--engines/scumm/player_appleII.h106
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);
};