aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorFlorian Kagerer2008-08-21 12:04:55 +0000
committerFlorian Kagerer2008-08-21 12:04:55 +0000
commit513f5ae150ad60bd899bae7ecae2435363e1d84d (patch)
tree985d0657e69cc52cbfb13fb19e178896391860df /engines/kyra
parent99790e79151207988305d2a5344365994ad306ad (diff)
downloadscummvm-rg350-513f5ae150ad60bd899bae7ecae2435363e1d84d.tar.gz
scummvm-rg350-513f5ae150ad60bd899bae7ecae2435363e1d84d.tar.bz2
scummvm-rg350-513f5ae150ad60bd899bae7ecae2435363e1d84d.zip
KYRA: Towns/PC-98-Audio: increased precision for envelope generator timing and tempo when using "odd" output rates like 48 kHz or 8 kHz
svn-id: r34079
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/sound_towns.cpp89
1 files changed, 55 insertions, 34 deletions
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 17b3c4a626..99b23824c7 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -1085,7 +1085,7 @@ void Towns_EuphonyTrackQueue::initDriver() {
class TownsPC98_OpnOperator {
public:
- TownsPC98_OpnOperator(const float rate, const uint8 *rateTable,
+ TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,
const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable);
~TownsPC98_OpnOperator() {}
@@ -1137,8 +1137,8 @@ protected:
const int32 *_tLvlTbl;
const int32 *_detnTbl;
- const int _tickLength;
- int _tick;
+ const uint32 _tickLength;
+ uint32 _timer;
int32 _currentLevel;
struct EvpState {
@@ -1147,11 +1147,11 @@ protected:
} fs_a, fs_d, fs_s, fs_r;
};
-TownsPC98_OpnOperator::TownsPC98_OpnOperator(const float rate, const uint8 *rateTable,
+TownsPC98_OpnOperator::TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable,
const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :
_rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
- _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength((int)(rate * 65536.0f)),
+ _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
_specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
_phase(0), _state(s_ready) {
@@ -1209,9 +1209,9 @@ void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &o
if (_state == s_ready)
return;
- _tick += _tickLength;
- while (_tick > 0x30000) {
- _tick -= 0x30000;
+ _timer += _tickLength;
+ while (_timer > 0x5B8D80) {
+ _timer -= 0x5B8D80;
++_tickCount;
int32 levelIncrement = 0;
@@ -1289,7 +1289,7 @@ void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &o
void TownsPC98_OpnOperator::reset(){
keyOff();
- _tick = 0;
+ _timer = 0;
_keyScale2 = 0;
_currentLevel = 1023;
@@ -1486,7 +1486,7 @@ private:
class TownsPC98_OpnSquareSineSource {
public:
- TownsPC98_OpnSquareSineSource(const float rate);
+ TownsPC98_OpnSquareSineSource(const uint32 timerbase);
~TownsPC98_OpnSquareSineSource();
void init(const int *rsTable, const int *rseTable);
@@ -1518,9 +1518,8 @@ private:
int32 *_tlTable;
int32 *_tleTable;
- const float _rate;
- const int _tickLength;
- int _timer;
+ const uint32 _tickLength;
+ uint32 _timer;
struct Channel {
int tick;
@@ -1533,7 +1532,7 @@ private:
class TownsPC98_OpnPercussionSource {
public:
- TownsPC98_OpnPercussionSource(const float rate);
+ TownsPC98_OpnPercussionSource(const uint32 timerbase);
~TownsPC98_OpnPercussionSource() {}
void init(const uint8 *pcmData = 0);
@@ -1568,8 +1567,8 @@ private:
uint8 _totalLevel;
- const int _tickLength;
- int _timer;
+ const uint32 _tickLength;
+ uint32 _timer;
bool _ready;
};
@@ -1676,10 +1675,14 @@ protected:
uint8 *_sfxData;
uint16 _sfxOffsets[2];
- int32 _samplesTillMusicCallback;
- int32 _samplesPerMusicCallback;
- int32 _samplesTillSfxCallback;
- int32 _samplesPerSfxCallback;
+ uint32 _samplesTillMusicCallback;
+ uint32 _samplesTillMusicCallbackRemainder;
+ uint32 _samplesPerMusicCallback;
+ uint32 _samplesPerMusicCallbackRemainder;
+ uint32 _samplesTillSfxCallback;
+ uint32 _samplesTillSfxCallbackRemainder;
+ uint32 _samplesPerSfxCallback;
+ uint32 _samplesPerSfxCallbackRemainder;
const int _numChan;
const int _numSSG;
@@ -1690,6 +1693,8 @@ protected:
static const int _ssgTables[];
const float _baserate;
+ uint32 _timerbase;
+
bool _ready;
};
@@ -1721,7 +1726,7 @@ TownsPC98_OpnChannel::~TownsPC98_OpnChannel() {
void TownsPC98_OpnChannel::init() {
_opr = new TownsPC98_OpnOperator*[4];
for (int i = 0; i < 4; i++)
- _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift,
+ _opr[i] = new TownsPC98_OpnOperator(_drv->_timerbase, _drv->_oprRates, _drv->_oprRateshift,
_drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);
#define Control(x) &TownsPC98_OpnChannel::control_##x
@@ -2710,8 +2715,8 @@ bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) {
}
}
-TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const float rate) : _rate(rate), _tlTable(0),
- _tleTable(0), _regIndex(_reg), _updateRequest(-1), _tickLength((int)(rate * 32768.0f * 27.0f)), _ready(0) {
+TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : _tlTable(0),
+ _tleTable(0), _regIndex(_reg), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0) {
memset(_reg, 0, 16);
memset(_channels, 0, sizeof(Channel) * 3);
reset();
@@ -2807,8 +2812,8 @@ void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) {
for (uint32 i = 0; i < bufferSize; i++) {
_timer += _tickLength;
- while (_timer > 0x30000) {
- _timer -= 0x30000;
+ while (_timer > 0x5B8D80) {
+ _timer -= 0x5B8D80;
if (++_nTick >= (_reg[6] & 0x1f)) {
if ((_rand + 1) & 2)
@@ -2867,8 +2872,8 @@ void TownsPC98_OpnSquareSineSource::updatesRegs() {
_updateRequest = -1;
}
-TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const float rate) :
- _tickLength((int)(rate * 65536.0)), _timer(0), _ready(false) {
+TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) :
+ _tickLength(timerbase * 2), _timer(0), _ready(false) {
memset(_pcmInstr, 0, sizeof(PcmInstrument) * 6);
}
@@ -2973,8 +2978,8 @@ void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) {
for (uint32 i = 0; i < bufferSize; i++) {
_timer += _tickLength;
- while (_timer > 0x30000) {
- _timer -= 0x30000;
+ while (_timer > 0x5B8D80) {
+ _timer -= 0x5B8D80;
for (int ii = 0; ii < 6; ii++) {
PcmInstrument *s = &_pcmInstr[ii];
@@ -3052,11 +3057,13 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) :
_updateSfxFlag(type == OD_TOWNS ? 0x00 : 0x06), _finishedSfxFlag(0),
_baserate(55125.0f / (float)getRate()),
- _samplesTillMusicCallback(0), _samplesTillSfxCallback (0),
+ _samplesTillMusicCallback(0), _samplesTillSfxCallback(0),
+ _samplesTillMusicCallbackRemainder(0), _samplesTillSfxCallbackRemainder(0),
_musicTickCounter(0),
_musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) {
+ _timerbase = (uint32)(_baserate * 1000000.0f);
setMusicTempo(84);
setSfxTempo(654);
}
@@ -3138,7 +3145,7 @@ bool TownsPC98_OpnDriver::init() {
}
if (_numSSG) {
- _ssg = new TownsPC98_OpnSquareSineSource(_baserate);
+ _ssg = new TownsPC98_OpnSquareSineSource(_timerbase);
_ssg->init(&_ssgTables[0], &_ssgTables[16]);
_ssgPatches = new uint8[256];
memcpy(_ssgPatches, _drvTables + 244, 256);
@@ -3161,7 +3168,7 @@ bool TownsPC98_OpnDriver::init() {
}
if (_hasPCM) {
- _pcm = new TownsPC98_OpnPercussionSource(_baserate);
+ _pcm = new TownsPC98_OpnPercussionSource(_timerbase);
_pcm->init();
delete _pcmChannel;
@@ -3187,11 +3194,23 @@ int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples)
if (!_samplesTillMusicCallback) {
musicCallback();
_samplesTillMusicCallback = _samplesPerMusicCallback;
+
+ _samplesTillMusicCallbackRemainder += _samplesPerMusicCallbackRemainder;
+ if (_samplesTillMusicCallbackRemainder >= _timerbase) {
+ _samplesTillMusicCallback++;
+ _samplesTillMusicCallbackRemainder -= _timerbase;
+ }
}
if (!_samplesTillSfxCallback) {
sfxCallback();
_samplesTillSfxCallback = _samplesPerSfxCallback;
+
+ _samplesTillSfxCallbackRemainder += _samplesPerSfxCallbackRemainder;
+ if (_samplesTillSfxCallbackRemainder >= _timerbase) {
+ _samplesTillSfxCallback++;
+ _samplesTillSfxCallbackRemainder -= _timerbase;
+ }
}
int32 render = MIN(_samplesTillSfxCallback, _samplesTillMusicCallback);
@@ -3526,12 +3545,14 @@ void TownsPC98_OpnDriver::startSoundEffect() {
void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) {
float spc = (float)(0x100 - tempo) * 16.0f / _baserate;
- _samplesPerMusicCallback = (int32) spc;
+ _samplesPerMusicCallback = (uint32) spc;
+ _samplesPerMusicCallbackRemainder = (uint32) ((spc - (float)_samplesPerMusicCallback) * 1000000.0f);
}
void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) {
float spc = (float)(0x400 - tempo) / _baserate;
- _samplesPerSfxCallback = (int32) spc;
+ _samplesPerSfxCallback = (uint32) spc;
+ _samplesPerSfxCallbackRemainder = (uint32) ((spc - (float)_samplesPerSfxCallback) * 1000000.0f);
}
SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)