diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp index 786e3ee1d2e6..8c087025047f 100644 --- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp @@ -28,77 +28,108 @@ #include "common/textconsole.h" #include "backends/audiocd/audiocd.h" +class TownsAudio_WaveTable { +friend class TownsAudioInterfaceInternal; +friend class TownsAudio_PcmChannel; +public: + TownsAudio_WaveTable(); + ~TownsAudio_WaveTable(); + +private: + void readHeader(const uint8 *buffer); + void readData(const uint8 *buffer); + void clear(); + + char name[9]; + int32 id; + uint32 size; + uint32 loopStart; + uint32 loopLen; + uint16 rate; + uint16 rateOffs; + uint16 baseNote; + int8 *data; +}; class TownsAudio_PcmChannel { -friend class TownsAudioInterfaceInternal; public: TownsAudio_PcmChannel(); ~TownsAudio_PcmChannel(); -private: - void loadExtData(uint8 *buffer, uint32 size); - void setupLoop(uint32 start, uint32 len); void clear(); + void loadData(TownsAudio_WaveTable *w); + void loadData(uint8 *buffer, uint32 size); + + int initInstrument(uint8 ¬e, TownsAudio_WaveTable *&tables, int numTables); + void keyOn(uint8 note, uint8 velo, TownsAudio_WaveTable *w); + void keyOff(); + + void updateEnvelopeGenerator(); + + void setInstrument(uint8 *instr); + void setLevel(uint8 lvl); + void setPitch(uint32 pt); + void setBalance(uint8 blc); + + void updateOutput(); + int32 currentSampleLeft(); + int32 currentSampleRight(); + + bool _keyPressed; + bool _reserved; + bool _activeKey; + bool _activeEffect; + bool _activeOutput; + +private: + void setupLoop(uint32 loopStart, uint32 len); + void setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit = false); + void setVelo(uint8 velo); + void envAttack(); void envDecay(); void envSustain(); void envRelease(); - uint8 *curInstrument; - uint8 note; - uint8 velo; + uint8 *_curInstrument; - int8 *data; - int8 *dataEnd; + uint8 _note; - int8 *loopEnd; - uint32 loopLen; + uint8 _velo; + uint8 _level; + uint8 _tl; - uint16 stepNote; - uint16 stepPitch; - uint16 step; + uint8 _panLeft; + uint8 _panRight; - uint8 panLeft; - uint8 panRight; + int8 *_data; + int8 *_dataEnd; - uint32 pos; + int8 *_loopEnd; + uint32 _loopLen; - uint8 envTotalLevel; - uint8 envAttackRate; - uint8 envDecayRate; - uint8 envSustainLevel; - uint8 envSustainRate; - uint8 envReleaseRate; + uint16 _stepNote; + uint16 _stepPitch; + uint16 _step; - int16 envStep; - int16 envCurrentLevel; + uint32 _pos; - EnvelopeState envState; + uint8 _envTotalLevel; + uint8 _envAttackRate; + uint8 _envDecayRate; + uint8 _envSustainLevel; + uint8 _envSustainRate; + uint8 _envReleaseRate; + int16 _envStep; + int16 _envCurrentLevel; - int8 *extData; -}; + EnvelopeState _envState; -class TownsAudio_WaveTable { -friend class TownsAudioInterfaceInternal; -public: - TownsAudio_WaveTable(); - ~TownsAudio_WaveTable(); + int8 *_extData; -private: - void readHeader(const uint8 *buffer); - void readData(const uint8 *buffer); - void clear(); - - char name[9]; - int32 id; - uint32 size; - uint32 loopStart; - uint32 loopLen; - uint16 rate; - uint16 rateOffs; - uint16 baseNote; - int8 *data; + static const uint16 _pcmPhase1[]; + static const uint16 _pcmPhase2[]; }; class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { @@ -202,18 +233,8 @@ class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { int pcmLoadInstrument(int instrId, const uint8 *data); int pcmSetPitch(int chan, int pitch); int pcmSetLevel(int chan, int lvl); - void pcmUpdateEnvelopeGenerator(int chan); TownsAudio_PcmChannel *_pcmChan; - uint8 _pcmChanOut; - uint8 _pcmChanReserved; - uint8 _pcmChanKeyPressed; - uint8 _pcmChanEffectPlaying; - uint8 _pcmChanKeyPlaying; - - uint8 _pcmChanNote[8]; - uint8 _pcmChanVelo[8]; - uint8 _pcmChanLevel[8]; uint8 _numReservedChannels; uint8 *_pcmInstruments; @@ -222,8 +243,6 @@ class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { uint8 _numWaveTables; uint32 _waveTablesTotalDataSize; - void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); - void updateOutputVolume(); void updateOutputVolumeInternal(); uint8 _outputVolumeFlags; @@ -251,8 +270,6 @@ class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { static const uint16 _frequency[]; static const uint8 _carrier[]; static const uint8 _fmDefaultInstrument[]; - static const uint16 _pcmPhase1[]; - static const uint16 _pcmPhase2[]; }; TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) : @@ -260,8 +277,7 @@ TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, To _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _drvOwner(owner), _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), - _outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0), - _pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _fmChanPlaying(0), + _outputVolumeFlags(0), _fmChanPlaying(0), _numReservedChannels(0), _numWaveTables(0), _updateOutputVol(false), _ready(false) { #define INTCB(x) &TownsAudioInterfaceInternal::intf_##x @@ -377,9 +393,6 @@ TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, To memset(_fmSaveReg, 0, sizeof(_fmSaveReg)); memset(_fmChanNote, 0, sizeof(_fmChanNote)); memset(_fmChanPitch, 0, sizeof(_fmChanPitch)); - memset(_pcmChanNote, 0, sizeof(_pcmChanNote)); - memset(_pcmChanVelo, 0, sizeof(_pcmChanVelo)); - memset(_pcmChanLevel, 0, sizeof(_pcmChanLevel)); memset(_outputLevel, 0, sizeof(_outputLevel)); memset(_outputMute, 0, sizeof(_outputMute)); @@ -530,40 +543,30 @@ void TownsAudioInterfaceInternal::nextTickEx(int32 *buffer, uint32 bufferSize) { while (_timer > 0x514767) { _timer -= 0x514767; - for (int ii = 0; ii < 8; ii++) { - if ((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii])) { - TownsAudio_PcmChannel *s = &_pcmChan[ii]; - s->pos += s->step; - - if (&s->data[s->pos >> 11] >= s->loopEnd) { - if (s->loopLen) { - s->pos -= s->loopLen; - } else { - s->pos = 0; - _pcmChanEffectPlaying &= ~_chanFlags[ii]; - _pcmChanKeyPlaying &= ~_chanFlags[ii]; - } - } - } - } + for (int ii = 0; ii < 8; ii++) + _pcmChan[ii].updateOutput(); } int32 finOutL = 0; int32 finOutR = 0; for (int ii = 0; ii < 8; ii++) { - if (_pcmChanOut & _chanFlags[ii]) { - int32 o = _pcmChan[ii].data[_pcmChan[ii].pos >> 11] * _pcmChan[ii].velo; - if ((1 << ii) & (~_pcmSfxChanMask)) - o = (o * _musicVolume) / Audio::Mixer::kMaxMixerVolume; - if ((1 << ii) & _pcmSfxChanMask) - o = (o * _sfxVolume) / Audio::Mixer::kMaxMixerVolume; - if (_pcmChan[ii].panLeft) - finOutL += ((o * _pcmChan[ii].panLeft) >> 3); - if (_pcmChan[ii].panRight) - finOutR += ((o * _pcmChan[ii].panRight) >> 3); - if (!((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii]))) - _pcmChanOut &= ~_chanFlags[ii]; + if (_pcmChan[ii]._activeOutput) { + int32 oL = _pcmChan[ii].currentSampleLeft(); + int32 oR = _pcmChan[ii].currentSampleRight(); + if ((1 << ii) & (~_pcmSfxChanMask)) { + oL = (oR * _musicVolume) / Audio::Mixer::kMaxMixerVolume; + oR = (oR * _musicVolume) / Audio::Mixer::kMaxMixerVolume; + } + if ((1 << ii) & _pcmSfxChanMask) { + oL = (oL * _sfxVolume) / Audio::Mixer::kMaxMixerVolume; + oR = (oR * _sfxVolume) / Audio::Mixer::kMaxMixerVolume; + } + finOutL += oL; + finOutR += oR; + + if (!(_pcmChan[ii]._activeKey || _pcmChan[ii]._activeEffect)) + _pcmChan[ii]._activeOutput = false; } } @@ -750,22 +753,19 @@ int TownsAudioInterfaceInternal::intf_reserveEffectChannels(va_list &args) { if (numChan < _numReservedChannels) { int c = 8 - _numReservedChannels; - for (int i = numChan; i; i--) { - uint8 f = ~_chanFlags[c--]; - _pcmChanEffectPlaying &= f; - } + for (int i = numChan; i; i--) + _pcmChan[c--]._activeEffect = false; } else { int c = 7 - _numReservedChannels; for (int i = numChan - _numReservedChannels; i; i--) { - uint8 f = ~_chanFlags[c--]; - _pcmChanKeyPressed &= f; - _pcmChanKeyPlaying &= f; + _pcmChan[c]._keyPressed = false; + _pcmChan[c--]._activeKey = false; } } - static const uint8 reserveChanFlags[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; _numReservedChannels = numChan; - _pcmChanReserved = reserveChanFlags[_numReservedChannels]; + for (int i = 0; i < 8; i++) + _pcmChan[i]._reserved = i >= (8 - _numReservedChannels) ? true : false; return 0; } @@ -838,10 +838,10 @@ int TownsAudioInterfaceInternal::intf_pcmPlayEffect(va_list &args) { chan -= 0x40; - if (!(_pcmChanReserved & _chanFlags[chan])) + if (!_pcmChan[chan]._reserved) return 7; - if ((_pcmChanEffectPlaying & _chanFlags[chan])) + if (_pcmChan[chan]._activeEffect) return 2; TownsAudio_WaveTable w; @@ -855,21 +855,8 @@ int TownsAudioInterfaceInternal::intf_pcmPlayEffect(va_list &args) { TownsAudio_PcmChannel *p = &_pcmChan[chan]; - _pcmChanNote[chan] = note; - _pcmChanVelo[chan] = velo; - - p->note = note; - p->velo = velo << 1; - - p->loadExtData(data + 32, w.size); - p->setupLoop(w.loopStart, w.loopLen); - - pcmCalcPhaseStep(p, &w); - if (p->step > 2048) - p->step = 2048; - - _pcmChanEffectPlaying |= _chanFlags[chan]; - _pcmChanOut |= _chanFlags[chan]; + p->loadData(data + 32, w.size); + p->keyOn(note, velo, &w); return 0; } @@ -885,7 +872,7 @@ int TownsAudioInterfaceInternal::intf_pcmEffectPlaying(va_list &args) { if (chan < 0x40 || chan > 0x47) return 1; chan -= 0x40; - return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0; + return _pcmChan[chan]._activeEffect ? 1 : 0; } int TownsAudioInterfaceInternal::intf_fmKeyOn(va_list &args) { @@ -1044,7 +1031,7 @@ int TownsAudioInterfaceInternal::intf_getOutputMute (va_list &args) { int TownsAudioInterfaceInternal::intf_pcmUpdateEnvelopeGenerator(va_list &args) { for (int i = 0; i < 8; i++) - pcmUpdateEnvelopeGenerator(i); + _pcmChan[i].updateEnvelopeGenerator(); return 0; } @@ -1375,14 +1362,8 @@ void TownsAudioInterfaceInternal::bufferedWriteReg(uint8 part, uint8 regAddress, } void TownsAudioInterfaceInternal::pcmReset() { - _pcmChanOut = 0; - _pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0; _numReservedChannels = 0; - memset(_pcmChanNote, 0, 8); - memset(_pcmChanVelo, 0, 8); - memset(_pcmChanLevel, 0, 8); - for (int i = 0; i < 8; i++) _pcmChan[i].clear(); @@ -1410,65 +1391,19 @@ int TownsAudioInterfaceInternal::pcmKeyOn(int chan, int note, int velo) { return 3; chan -= 0x40; - - if ((_pcmChanReserved & _chanFlags[chan]) || (_pcmChanKeyPressed & _chanFlags[chan])) - return 2; - - _pcmChanNote[chan] = note; - _pcmChanVelo[chan] = velo; - + uint8 noteT = note; TownsAudio_PcmChannel *p = &_pcmChan[chan]; - p->note = note; - - uint8 *instr = _pcmChan[chan].curInstrument; - int i = 0; - for (; i < 8; i++) { - if (note <= instr[16 + 2 * i]) - break; - } - - if (i == 8) - return 8; - - int il = i << 3; - p->note += instr[il + 70]; - - p->envTotalLevel = instr[il + 64]; - p->envAttackRate = instr[il + 65]; - p->envDecayRate = instr[il + 66]; - p->envSustainLevel = instr[il + 67]; - p->envSustainRate = instr[il + 68]; - p->envReleaseRate = instr[il + 69]; - p->envStep = 0; - - int32 id = (int32)READ_LE_UINT32(&instr[i * 4 + 32]); - - for (i = 0; i < _numWaveTables; i++) { - if (id == _waveTables[i].id) - break; - } - if (i == _numWaveTables) - return 9; - - TownsAudio_WaveTable *w = &_waveTables[i]; - - p->data = w->data; - p->dataEnd = w->data + w->size; - p->setupLoop(w->loopStart, w->loopLen); - - pcmCalcPhaseStep(p, w); - - uint32 lvl = _pcmChanLevel[chan] * _pcmChanVelo[chan]; - p->envTotalLevel = ((p->envTotalLevel * lvl) >> 14) & 0xff; - p->envSustainLevel = ((p->envSustainLevel * lvl) >> 14) & 0xff; + if (p->_reserved || p->_keyPressed) + return 2; - p->envAttack(); - p->velo = (p->envCurrentLevel >> 8) << 1; + TownsAudio_WaveTable *w = _waveTables; + int res = p->initInstrument(noteT, w, _numWaveTables); + if (res) + return res; - _pcmChanKeyPressed |= _chanFlags[chan]; - _pcmChanKeyPlaying |= _chanFlags[chan]; - _pcmChanOut |= _chanFlags[chan]; + p->loadData(w); + p->keyOn(noteT, velo, w); return 0; } @@ -1478,8 +1413,7 @@ int TownsAudioInterfaceInternal::pcmKeyOff(int chan) { return 1; chan -= 0x40; - _pcmChanKeyPressed &= ~_chanFlags[chan]; - _pcmChan[chan].envRelease(); + _pcmChan[chan].keyOff(); return 0; } @@ -1488,11 +1422,7 @@ int TownsAudioInterfaceInternal::pcmChanOff(int chan) { return 1; chan -= 0x40; - - _pcmChanKeyPressed &= ~_chanFlags[chan]; - _pcmChanEffectPlaying &= ~_chanFlags[chan]; - _pcmChanKeyPlaying &= ~_chanFlags[chan]; - _pcmChanOut &= ~_chanFlags[chan]; + _pcmChan[chan]._keyPressed = _pcmChan[chan]._activeEffect = _pcmChan[chan]._activeKey = _pcmChan[chan]._activeOutput = false; return 0; } @@ -1514,8 +1444,7 @@ int TownsAudioInterfaceInternal::pcmSetPanPos(int chan, int mode) { blc = ((119 + mode) ^ (mode << 4)) & 0xff; } - _pcmChan[chan].panLeft = blc & 0x0f; - _pcmChan[chan].panRight = blc >> 4; + _pcmChan[chan].setBalance(blc); return 0; } @@ -1526,7 +1455,8 @@ int TownsAudioInterfaceInternal::pcmSetInstrument(int chan, int instrId) { if (instrId > 31) return 3; chan -= 0x40; - _pcmChan[chan].curInstrument = &_pcmInstruments[instrId * 128]; + _pcmChan[chan].setInstrument(&_pcmInstruments[instrId * 128]); + return 0; } @@ -1555,15 +1485,7 @@ int TownsAudioInterfaceInternal::pcmSetPitch(int chan, int pitch) { else if (pitch > 0) pts = (((pitch + 0x2001) << 16) / 0x2000) >> 2; - p->stepPitch = pts & 0xffff; - p->step = (p->stepNote * p->stepPitch) >> 14; - -// if (_pcmChanUnkFlag & _chanFlags[chan]) -// unk[chan] = (((p->step * 1000) << 11) / 98) / 20833; - - /*else*/ - if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048)) - p->step = 2048; + p->setPitch(pts); return 0; } @@ -1576,98 +1498,11 @@ int TownsAudioInterfaceInternal::pcmSetLevel(int chan, int lvl) { return 3; chan -= 0x40; - TownsAudio_PcmChannel *p = &_pcmChan[chan]; - - if (_pcmChanReserved & _chanFlags[chan]) { - _pcmChanVelo[chan] = lvl; - p->velo = lvl << 1; - } else { - int32 t = p->envStep * lvl; - if (_pcmChanLevel[chan]) - t /= _pcmChanLevel[chan]; - p->envStep = t; - t = p->envCurrentLevel * lvl; - if (_pcmChanLevel[chan]) - t /= _pcmChanLevel[chan]; - p->envCurrentLevel = t; - _pcmChanLevel[chan] = lvl; - p->velo = p->envCurrentLevel >> 8; - } + _pcmChan[chan].setLevel(lvl); return 0; } -void TownsAudioInterfaceInternal::pcmUpdateEnvelopeGenerator(int chan) { - TownsAudio_PcmChannel *p = &_pcmChan[chan]; - if (!p->envCurrentLevel) { - _pcmChanKeyPlaying &= ~_chanFlags[chan]; - p->envState = kEnvReady; - } - - if (!(_pcmChanKeyPlaying & _chanFlags[chan])) - return; - - switch (p->envState) { - case kEnvAttacking: - if (((p->envCurrentLevel + p->envStep) >> 8) > p->envTotalLevel) { - p->envDecay(); - return; - } else { - p->envCurrentLevel += p->envStep; - } - break; - - case kEnvDecaying: - if (((p->envCurrentLevel - p->envStep) >> 8) < p->envSustainLevel) { - p->envSustain(); - return; - } else { - p->envCurrentLevel -= p->envStep; - } - break; - - case kEnvSustaining: - case kEnvReleasing: - p->envCurrentLevel -= p->envStep; - if (p->envCurrentLevel <= 0) - p->envCurrentLevel = 0; - break; - - default: - break; - } - p->velo = (p->envCurrentLevel >> 8) << 1; -} - -void TownsAudioInterfaceInternal::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { - int8 diff = p->note - w->baseNote; - uint16 r = w->rate + w->rateOffs; - uint16 bl = 0; - uint32 s = 0; - - if (diff < 0) { - diff *= -1; - bl = diff % 12; - diff /= 12; - s = (r >> diff); - if (bl) - s = (s * _pcmPhase2[bl]) >> 16; - - } else if (diff > 0) { - bl = diff % 12; - diff /= 12; - s = (r << diff); - if (bl) - s += ((s * _pcmPhase1[bl]) >> 16); - - } else { - s = r; - } - - p->stepNote = s & 0xffff; - p->step = (s * p->stepPitch) >> 14; -} - void TownsAudioInterfaceInternal::updateOutputVolume() { // Avoid calls to g_system->getAudioCDManager() functions from the main thread // since this can cause mutex lockups. @@ -1717,16 +1552,8 @@ const uint8 TownsAudioInterfaceInternal::_fmDefaultInstrument[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const uint16 TownsAudioInterfaceInternal::_pcmPhase1[] = { - 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 -}; - -const uint16 TownsAudioInterfaceInternal::_pcmPhase2[] = { - 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC -}; - TownsAudio_PcmChannel::TownsAudio_PcmChannel() { - extData = 0; + _extData = 0; clear(); } @@ -1734,97 +1561,316 @@ TownsAudio_PcmChannel::~TownsAudio_PcmChannel() { clear(); } -void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) { - delete[] extData; - extData = new int8[size]; +void TownsAudio_PcmChannel::clear() { + _curInstrument = 0; + _note = _tl = _level = _velo = 0; + + _data = 0; + _dataEnd = 0; + _loopLen = 0; + + _pos = 0; + _loopEnd = 0; + + _step = 0; + _stepNote = 0x4000; + _stepPitch = 0x4000; + + _panLeft = _panRight = 7; + + _envTotalLevel = _envAttackRate = _envDecayRate = _envSustainLevel = _envSustainRate = _envReleaseRate = 0; + _envStep = _envCurrentLevel = 0; + + _envState = kEnvReady; + + _activeKey = _activeEffect = _activeOutput = _keyPressed = _reserved = false; + + delete[] _extData; + _extData = 0; +} + +void TownsAudio_PcmChannel::loadData(TownsAudio_WaveTable *w) { + _data = w->data; + _dataEnd = w->data + w->size; +} + +void TownsAudio_PcmChannel::loadData(uint8 *buffer, uint32 size) { + delete[] _extData; + _extData = new int8[size]; int8 *src = (int8 *)buffer; - int8 *dst = extData; + int8 *dst = _extData; for (uint32 i = 0; i < size; i++) *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; - data = extData; - dataEnd = extData + size; - pos = 0; + _data = _extData; + _dataEnd = _extData + size; + _pos = 0; } -void TownsAudio_PcmChannel::setupLoop(uint32 start, uint32 len) { - loopLen = len << 11; - loopEnd = loopLen ? &data[(start + loopLen) >> 11] : dataEnd; - pos = start; +int TownsAudio_PcmChannel::initInstrument(uint8 ¬e, TownsAudio_WaveTable *&tables, int numTables) { + int i = 0; + for (; i < 8; i++) { + if (note <= _curInstrument[16 + 2 * i]) + break; + } + + if (i == 8) + return 8; + + int il = i << 3; + note += _curInstrument[il + 70]; + + uint8 *d = &_curInstrument[il + 64]; + _envTotalLevel = d[0]; + _envAttackRate = d[1]; + _envDecayRate = d[2]; + _envSustainLevel = d[3]; + _envSustainRate = d[4]; + _envReleaseRate = d[5]; + _envStep = 0; + note += d[6]; + + int32 id = (int32)READ_LE_UINT32(&_curInstrument[i * 4 + 32]); + + for (i = 0; i < numTables; i++) { + if (id == tables[i].id) + break; + } + + if (i == numTables) + return 9; + + tables = &tables[i]; + return 0; } -void TownsAudio_PcmChannel::clear() { - curInstrument = 0; - note = 0; - velo = 0; +void TownsAudio_PcmChannel::keyOn(uint8 note, uint8 velo, TownsAudio_WaveTable *w) { + setupLoop(w->loopStart, w->loopLen); + setNote(note, w, _reserved); + setVelo(velo); - data = 0; - dataEnd = 0; - loopLen = 0; + if (_reserved) + _activeEffect = true; + else + _keyPressed = _activeKey = true; + + _activeOutput = true; +} + +void TownsAudio_PcmChannel::keyOff() { + _keyPressed = false; + envRelease(); +} + +void TownsAudio_PcmChannel::updateEnvelopeGenerator() { + if (!_envCurrentLevel) { + _activeKey = false; + _envState = kEnvReady; + } + + if (!_activeKey) + return; + + switch (_envState) { + case kEnvAttacking: + if (((_envCurrentLevel + _envStep) >> 8) > _envTotalLevel) { + envDecay(); + return; + } else { + _envCurrentLevel += _envStep; + } + break; + + case kEnvDecaying: + if (((_envCurrentLevel - _envStep) >> 8) < _envSustainLevel) { + envSustain(); + return; + } else { + _envCurrentLevel -= _envStep; + } + break; + + case kEnvSustaining: + case kEnvReleasing: + _envCurrentLevel -= _envStep; + if (_envCurrentLevel <= 0) + _envCurrentLevel = 0; + break; + + default: + break; + } + _tl = (_envCurrentLevel >> 8) << 1; +} + +void TownsAudio_PcmChannel::setInstrument(uint8 *instr) { + _curInstrument = instr; +} + +void TownsAudio_PcmChannel::setLevel(uint8 lvl) { + if (_reserved) { + _velo = lvl; + _tl = lvl << 1; + } else { + int32 t = _envStep * lvl; + if (_level) + t /= _level; + _envStep = t; + t = _envCurrentLevel * lvl; + if (_level) + t /= _level; + _envCurrentLevel = t; + _level = lvl; + _tl = _envCurrentLevel >> 8; + } +} + +void TownsAudio_PcmChannel::setPitch(uint32 pt) { + _stepPitch = pt & 0xffff; + _step = (_stepNote * _stepPitch) >> 14; + +// if (_pcmChanUnkFlag & _chanFlags[chan]) +// unk[chan] = (((p->step * 1000) << 11) / 98) / 20833; + + /*else*/ + if (_activeEffect && (_step > 2048)) + _step = 2048; +} + +void TownsAudio_PcmChannel::setBalance(uint8 blc) { + _panLeft = blc & 0x0f; + _panRight = blc >> 4; +} + +void TownsAudio_PcmChannel::updateOutput() { + if (_activeKey || _activeEffect) { + _pos += _step; + + if (&_data[_pos >> 11] >= _loopEnd) { + if (_loopLen) { + _pos -= _loopLen; + } else { + _pos = 0; + _activeKey = _activeEffect = false; + } + } + } +} - pos = 0; - loopEnd = 0; +int32 TownsAudio_PcmChannel::currentSampleLeft() { + return (_activeOutput && _panLeft) ? (((_data[_pos >> 11] * _tl) * _panLeft) >> 3) : 0; +} - step = 0; - stepNote = 0x4000; - stepPitch = 0x4000; +int32 TownsAudio_PcmChannel::currentSampleRight() { + return (_activeOutput && _panRight) ? (((_data[_pos >> 11] * _tl) * _panRight) >> 3) : 0; +} - panLeft = panRight = 7; +void TownsAudio_PcmChannel::setupLoop(uint32 loopStart, uint32 len) { + _loopLen = len << 11; + _loopEnd = _loopLen ? &_data[(loopStart + _loopLen) >> 11] : _dataEnd; + _pos = loopStart; +} - envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = envSustainRate = envReleaseRate = 0; - envStep = envCurrentLevel = 0; +void TownsAudio_PcmChannel::setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit) { + _note = note; + int8 diff = _note - w->baseNote; + uint16 r = w->rate + w->rateOffs; + uint16 bl = 0; + uint32 s = 0; - envState = kEnvReady; + if (diff < 0) { + diff *= -1; + bl = diff % 12; + diff /= 12; + s = (r >> diff); + if (bl) + s = (s * _pcmPhase2[bl]) >> 16; - delete[] extData; - extData = 0; + } else if (diff > 0) { + bl = diff % 12; + diff /= 12; + s = (r << diff); + if (bl) + s += ((s * _pcmPhase1[bl]) >> 16); + + } else { + s = r; + } + + _stepNote = s & 0xffff; + _step = (s * _stepPitch) >> 14; + + if (stepLimit && _step > 2048) + _step = 2048; +} + +void TownsAudio_PcmChannel::setVelo(uint8 velo) { + if (_reserved) { + _velo = velo; + _tl = velo << 1; + } else { + _velo = velo; + uint32 lvl = _level * _velo; + _envTotalLevel = ((_envTotalLevel * lvl) >> 14) & 0xff; + _envSustainLevel = ((_envSustainLevel * lvl) >> 14) & 0xff; + envAttack(); + _tl = (_envCurrentLevel >> 8) << 1; + } } void TownsAudio_PcmChannel::envAttack() { - envState = kEnvAttacking; - int16 t = envTotalLevel << 8; - if (envAttackRate == 127) { - envStep = 0; - } else if (envAttackRate) { - envStep = t / envAttackRate; - envCurrentLevel = 1; + _envState = kEnvAttacking; + int16 t = _envTotalLevel << 8; + if (_envAttackRate == 127) { + _envStep = 0; + } else if (_envAttackRate) { + _envStep = t / _envAttackRate; + _envCurrentLevel = 1; } else { - envCurrentLevel = t; + _envCurrentLevel = t; envDecay(); } } void TownsAudio_PcmChannel::envDecay() { - envState = kEnvDecaying; - int16 t = envTotalLevel - envSustainLevel; - if (t < 0 || envDecayRate == 127) { - envStep = 0; - } else if (envDecayRate) { - envStep = (t << 8) / envDecayRate; + _envState = kEnvDecaying; + int16 t = _envTotalLevel - _envSustainLevel; + if (t < 0 || _envDecayRate == 127) { + _envStep = 0; + } else if (_envDecayRate) { + _envStep = (t << 8) / _envDecayRate; } else { - envCurrentLevel = envSustainLevel << 8; + _envCurrentLevel = _envSustainLevel << 8; envSustain(); } } void TownsAudio_PcmChannel::envSustain() { - envState = kEnvSustaining; - if (envSustainLevel && envSustainRate) - envStep = (envSustainRate == 127) ? 0 : (envCurrentLevel / envSustainRate) >> 1; + _envState = kEnvSustaining; + if (_envSustainLevel && _envSustainRate) + _envStep = (_envSustainRate == 127) ? 0 : (_envCurrentLevel / _envSustainRate) >> 1; else - envStep = envCurrentLevel = 1; + _envStep = _envCurrentLevel = 1; } void TownsAudio_PcmChannel::envRelease() { - envState = kEnvReleasing; - if (envReleaseRate == 127) - envStep = 0; - else if (envReleaseRate) - envStep = envCurrentLevel / envReleaseRate; + _envState = kEnvReleasing; + if (_envReleaseRate == 127) + _envStep = 0; + else if (_envReleaseRate) + _envStep = _envCurrentLevel / _envReleaseRate; else - envStep = envCurrentLevel = 1; + _envStep = _envCurrentLevel = 1; } +const uint16 TownsAudio_PcmChannel::_pcmPhase1[] = { + 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 +}; + +const uint16 TownsAudio_PcmChannel::_pcmPhase2[] = { + 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC +}; + TownsAudio_WaveTable::TownsAudio_WaveTable() { data = 0; clear();