SCUMM: Reduce sound buffer size for player_appleII

Sound generation functions are now called incrementally instead of just
once to generate the sound data. This reduces the max. buffer size
from 1.7MB to just ~100KB (piano, sound 50).
This commit is contained in:
Tobias Gunkel 2011-12-20 08:33:11 +01:00
parent 375047b729
commit ffc88c5ced
2 changed files with 177 additions and 63 deletions

View File

@ -28,11 +28,10 @@
namespace Scumm {
Player_AppleII::Player_AppleII(ScummEngine *scumm, Audio::Mixer *mixer) {
_speakerState = 0;
_soundNr = 0;
_mixer = mixer;
_vm = scumm;
resetState();
setSampleRate(_mixer->getOutputRate());
@ -70,18 +69,23 @@ void logSounds() {
void Player_AppleII::startSound(int nr) {
Common::StackLock lock(_mutex);
_soundNr = nr;
_sampleConverter.reset();
resetState();
byte *data = _vm->getResourceAddress(rtSound, nr);
assert(data);
byte *ptr1 = data + 4;
_state.type = ptr1[0];
if (_state.type == 0)
if (_state.type == 0) {
// nothing to play
resetState();
return;
}
_state.soundNr = nr;
_state.finished = false;
initFuncState();
_state.loop = ptr1[1];
assert(_state.loop > 0);
@ -89,44 +93,86 @@ void Player_AppleII::startSound(int nr) {
debug(4, "startSound %d: type %d, loop %d",
nr, _state.type, _state.loop);
do {
switch (_state.type) {
case 1: // freq up/down
soundFunc1();
break;
case 2: // symmetric wave (~)
soundFunc2();
break;
case 3: // asymmetric wave (__-)
soundFunc3();
break;
case 4: // polyphone (2 voices)
soundFunc4();
break;
case 5: // periodic noise
soundFunc5();
break;
}
}
void Player_AppleII::initFuncState() {
switch (_state.type) {
case 2: case 3:
_state.func23.pos = 1;
break;
case 4:
_state.func4.updateRemain1 = 80;
_state.func4.updateRemain2 = 10;
break;
case 5:
_state.func5.index = 0;
break;
}
}
bool Player_AppleII::updateSound() {
if (!_state.soundNr || _state.finished)
return false;
bool done = false;
switch (_state.type) {
case 1: // freq up/down
done = soundFunc1();
break;
case 2: // symmetric wave (~)
done = soundFunc2();
break;
case 3: // asymmetric wave (__-)
done = soundFunc3();
break;
case 4: // polyphone (2 voices)
done = soundFunc4();
break;
case 5: // periodic noise
done = soundFunc5();
break;
}
if (done) {
--_state.loop;
} while (_state.loop > 0);
if (_state.loop <= 0) {
_state.finished = true;
} else {
// reset function state on each loop
initFuncState();
}
}
return true;
}
void Player_AppleII::resetState() {
_state.soundNr = 0;
_state.type = 0;
_state.loop = 0;
_state.params = NULL;
_state.localParams = NULL;
_state.speakerState = 0;
_state.finished = true;
_sampleConverter.reset();
}
void Player_AppleII::stopAllSounds() {
Common::StackLock lock(_mutex);
_sampleConverter.reset();
resetState();
}
void Player_AppleII::stopSound(int nr) {
Common::StackLock lock(_mutex);
if (_soundNr == nr) {
_sampleConverter.reset();
if (_state.soundNr == nr) {
resetState();
}
}
int Player_AppleII::getSoundStatus(int nr) const {
Common::StackLock lock(_mutex);
return (_sampleConverter.availableSize() > 0 ? 1 : 0);
return (_state.soundNr == nr);
}
int Player_AppleII::getMusicTimer() {
@ -136,7 +182,22 @@ int Player_AppleII::getMusicTimer() {
int Player_AppleII::readBuffer(int16 *buffer, const int numSamples) {
Common::StackLock lock(_mutex);
return _sampleConverter.readSamples(buffer, numSamples);
if (!_state.soundNr)
return 0;
int samplesLeft = numSamples;
do {
int nSamplesRead = _sampleConverter.readSamples(buffer, samplesLeft);
samplesLeft -= nSamplesRead;
buffer += nSamplesRead;
} while ((samplesLeft > 0) && updateSound());
// reset state if sound is played completely
if (_state.finished && (_sampleConverter.availableSize() == 0))
resetState();
return numSamples - samplesLeft;
}
/************************************
@ -145,11 +206,11 @@ int Player_AppleII::readBuffer(int16 *buffer, const int numSamples) {
// toggle speaker on/off
void Player_AppleII::speakerToggle() {
_speakerState ^= 0x1;
_state.speakerState ^= 0x1;
}
void Player_AppleII::generateSamples(int cycles) {
_sampleConverter.addCycles(_speakerState, cycles);
_sampleConverter.addCycles(_state.speakerState, cycles);
}
void Player_AppleII::wait(int interval, int count /*y*/) {
@ -168,7 +229,7 @@ void Player_AppleII::_soundFunc1(int interval /*a*/, int count /*y*/) { // D076
}
}
void Player_AppleII::soundFunc1() { // D085
bool 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)
@ -186,6 +247,8 @@ void Player_AppleII::soundFunc1() { // D085
interval += delta;
} while (interval < limit);
}
return true;
}
void Player_AppleII::_soundFunc2(int interval /*a*/, int count) { // D0EF
@ -206,13 +269,18 @@ void Player_AppleII::_soundFunc2(int interval /*a*/, int count) { // D0EF
}
}
void Player_AppleII::soundFunc2() { // D0D6
for (int pos = 1; pos < 256; ++pos) {
byte interval = _state.params[pos];
bool Player_AppleII::soundFunc2() { // D0D6
// while (pos = 1; pos < 256; ++pos)
if (_state.func23.pos < 256) {
byte interval = _state.params[_state.func23.pos];
if (interval == 0xFF)
return;
return true;
_soundFunc2(interval, _state.params[0] /*, LD12F=interval*/);
}
++_state.func23.pos;
return false;
}
return true;
}
void Player_AppleII::_soundFunc3(int interval /*a*/, int count /*LD12D*/) { // D14B
@ -229,13 +297,18 @@ void Player_AppleII::_soundFunc3(int interval /*a*/, int count /*LD12D*/) { // D
}
}
void Player_AppleII::soundFunc3() { // D132
for (int pos = 1; pos < 256; ++pos) {
byte interval = _state.params[pos];
bool Player_AppleII::soundFunc3() { // D132
// while (pos = 1; pos < 256; ++pos)
if (_state.func23.pos < 256) {
byte interval = _state.params[_state.func23.pos];
if (interval == 0xFF)
return;
return true;
_soundFunc3(interval, _state.params[0]);
++_state.func23.pos;
return false;
}
return true;
}
void Player_AppleII::_soundFunc4(byte param0, byte param1, byte param2) { // D1A2
@ -258,8 +331,8 @@ void Player_AppleII::_soundFunc4(byte param0, byte param1, byte param2) { // D1A
}
byte speakerShiftReg = 0;
static byte updateRemain1 = 80;
static byte updateRemain2 = 10;
byte updateRemain1 = _state.func4.updateRemain1;
byte updateRemain2 = _state.func4.updateRemain2;
while (true) {
--updateRemain1;
@ -285,17 +358,26 @@ void Player_AppleII::_soundFunc4(byte param0, byte param1, byte param2) { // D1A
++count;
if (count == 0) {
_state.func4.updateRemain1 = updateRemain1;
_state.func4.updateRemain2 = updateRemain2;
return;
}
}
}
void Player_AppleII::soundFunc4() { // D170
const byte *params = _state.params;
while (params[0] != 0x01) {
_soundFunc4(params[0], params[1], params[2]);
params += 3;
bool Player_AppleII::soundFunc4() { // D170
if (!_state.localParams)
_state.localParams = _state.params;
// while (_state.params[0] != 0x01)
if (_state.localParams[0] != 0x01) {
_soundFunc4(_state.localParams[0], _state.localParams[1], _state.localParams[2]);
_state.localParams += 3;
return false;
}
_state.localParams = NULL;
return true;
}
void Player_AppleII::_soundFunc5(int interval /*a*/, int count) { // D270
@ -339,20 +421,27 @@ byte /*a*/ Player_AppleII::noise() { // D261
return result;
}
void Player_AppleII::soundFunc5() { // D222
bool Player_AppleII::soundFunc5() { // D222
const byte noiseMask[] = {
0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F
};
int param0 = _state.params[0];
assert(param0 > 0);
for (int i = 0; i < 10; ++i) {
// while (i = 0; i < 10; ++i)
if (_state.func5.index < 10) {
int count = param0;
do {
_soundFunc5(noise() & noiseMask[i], 1);
_soundFunc5(noise() & noiseMask[_state.func5.index], 1);
--count;
} while (count > 0);
++_state.func5.index;
return false;
}
return true;
}
} // End of namespace Scumm

View File

@ -241,10 +241,34 @@ public:
int getRate() const { return _sampleRate; }
private:
struct state_t {
struct sound_state {
// sound number
int soundNr;
// type of sound
int type;
// number of loops left
int loop;
// global sound param list
const byte *params;
// local sound param list
const byte *localParams;
// speaker toggle state (0 / 1)
byte speakerState;
// processing complete
bool finished;
// sound type specific data
union {
struct {
byte updateRemain1;
byte updateRemain2;
} func4;
struct {
int pos;
} func23;
struct {
int index;
} func5;
};
} _state;
ScummEngine *_vm;
@ -254,25 +278,26 @@ private:
Common::Mutex _mutex;
private:
byte _speakerState;
int _soundNr;
SampleConverter _sampleConverter;
private:
void resetState();
void initFuncState();
bool updateSound();
void speakerToggle();
void generateSamples(int cycles);
void wait(int interval, int count);
byte noise();
void soundFunc1();
bool soundFunc1();
void _soundFunc1(int interval, int count);
void soundFunc2();
bool soundFunc2();
void _soundFunc2(int interval, int count);
void soundFunc3();
bool soundFunc3();
void _soundFunc3(int interval, int count);
void soundFunc4();
bool soundFunc4();
void _soundFunc4(byte param0, byte param1, byte param2);
void soundFunc5();
bool soundFunc5();
void _soundFunc5(int interval, int count);
};