diff options
-rw-r--r-- | engines/kyra/resource.h | 1 | ||||
-rw-r--r-- | engines/kyra/sound_intern.h | 43 | ||||
-rw-r--r-- | engines/kyra/sound_towns.cpp | 4327 | ||||
-rw-r--r-- | engines/kyra/staticres.cpp | 2 | ||||
-rw-r--r-- | sound/module.mk | 4 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.cpp | 1479 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.h | 162 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 886 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_euphony.h | 178 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 1403 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_driver.h | 110 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 1461 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 171 | ||||
-rw-r--r-- | tools/create_kyradat/create_kyradat.cpp | 5 | ||||
-rw-r--r-- | tools/create_kyradat/create_kyradat.h | 2 | ||||
-rw-r--r-- | tools/create_kyradat/games.cpp | 2 | ||||
-rw-r--r-- | tools/create_kyradat/tables.cpp | 7 |
17 files changed, 6070 insertions, 4173 deletions
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 7983be9a68..d572c1ac54 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -209,6 +209,7 @@ enum KyraResources { k1CreditsStrings, + k1TownsMusicFadeTable, k1TownsSFXwdTable, k1TownsSFXbtTable, k1TownsCDATable, diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h index a229dc310d..186162a700 100644 --- a/engines/kyra/sound_intern.h +++ b/engines/kyra/sound_intern.h @@ -31,7 +31,9 @@ #include "common/mutex.h" -#include "sound/softsynth/ym2612.h" +#include "sound/softsynth/fmtowns_pc98/towns_pc98_driver.h" +#include "sound/softsynth/fmtowns_pc98/towns_euphony.h" + #include "sound/softsynth/emumidi.h" #include "sound/midiparser.h" @@ -99,10 +101,7 @@ private: Common::Mutex _mutex; }; -class Towns_EuphonyDriver; -class TownsPC98_OpnDriver; - -class SoundTowns : public MidiDriver, public Sound { +class SoundTowns : public Sound { public: SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer); ~SoundTowns(); @@ -119,43 +118,33 @@ public: void haltTrack(); void playSoundEffect(uint8); + void stopAllSoundEffects(); void beginFadeOut(); - //MidiDriver interface implementation - int open(); - void close(); - void send(uint32 b); - void metaEvent(byte type, byte *data, uint16 length) {} - - void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } - uint32 getBaseTempo(); - - //Channel allocation functions - MidiChannel *allocateChannel() { return 0; } - MidiChannel *getPercussionChannel() { return 0; } - - static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, - uint32 sampleRate, uint32 outputRate, int32 pitchWheel); - private: bool loadInstruments(); void playEuphonyTrack(uint32 offset, int loop); - static void onTimer(void *data); + void fadeOutSoundEffects(); int _lastTrack; Audio::AudioStream *_currentSFX; Audio::SoundHandle _sfxHandle; + uint8 *_musicTrackData; + uint _sfxFileIndex; uint8 *_sfxFileData; + uint8 _sfxChannel; - Towns_EuphonyDriver * _driver; - MidiParser * _parser; - + TownsEuphonyDriver *_driver; + Common::Mutex _mutex; + bool _cdaPlaying; + + const uint8 *_musicFadeTable; const uint8 *_sfxBTTable; const uint8 *_sfxWDTable; }; @@ -186,7 +175,7 @@ protected: int _lastTrack; uint8 *_musicTrackData; uint8 *_sfxTrackData; - TownsPC98_OpnDriver *_driver; + TownsPC98_AudioDriver *_driver; }; class SoundTownsPC98_v2 : public Sound { @@ -218,7 +207,7 @@ protected: uint8 *_musicTrackData; uint8 *_sfxTrackData; - TownsPC98_OpnDriver *_driver; + TownsPC98_AudioDriver *_driver; }; // PC Speaker MIDI driver diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 9b17011ecf..2ed6d972c2 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -36,3889 +36,37 @@ #include "common/util.h" -#define EUPHONY_FADEOUT_TICKS 600 - namespace Kyra { -enum EnvelopeState { s_ready, s_attacking, s_decaying, s_sustaining, s_releasing }; - -class Towns_EuphonyChannel : public MidiChannel { -public: - Towns_EuphonyChannel() {} - virtual ~Towns_EuphonyChannel() {} - - virtual void nextTick(int32 *outbuf, int buflen) = 0; - virtual void rate(uint16 r) = 0; - -protected: - uint16 _rate; -}; - -class Towns_EuphonyFmChannel : public Towns_EuphonyChannel { -public: - Towns_EuphonyFmChannel(); - virtual ~Towns_EuphonyFmChannel(); - - void nextTick(int32 *outbuf, int buflen); - void rate(uint16 r); - - // MidiChannel interface - MidiDriver *device() { return 0; } - byte getNumber() { return 0; } - void release() { } - void send(uint32) { } - void noteOff(byte note); - void noteOn(byte note, byte onVelo); - void programChange(byte) {} - void pitchBend(int16 value); - void controlChange(byte control, byte value); - void pitchBendFactor(byte) { } - void sysEx_customInstrument(uint32 unused, const byte *instr); - -protected: - Voice2612 *_voice; -}; - -class Towns_EuphonyPcmChannel : public Towns_EuphonyChannel { -public: - void nextTick(int32 *outbuf, int buflen); - void rate(uint16 r); - - Towns_EuphonyPcmChannel(); - virtual ~Towns_EuphonyPcmChannel(); - - // MidiChannel interface - MidiDriver *device() { return 0; } - byte getNumber() { return 0; } - void release() { } - void send(uint32 b) { } - void noteOff(byte note); - void noteOn(byte note, byte onVelo); - void programChange(byte program) {} - void pitchBend(int16 value); - void controlChange(byte control, byte value); - void pitchBendFactor(byte value) { } - void sysEx_customInstrument(uint32 type, const byte *instr); - -protected: - void velocity(int velo); - void panPosition(int8 pan); - void evpNextTick(); - - int _ctrl7_volume; - int16 _velocity; - int16 _note; - int32 _frequencyOffs; - float _phase; - int8 _current; - - struct Voice { - char name[9]; - uint16 split[8]; - uint32 id[8]; - struct Snd { - char name[9]; - int32 id; - int32 numSamples; - int32 loopStart; - int32 loopLength; - int32 samplingRate; - int32 keyOffset; - int32 keyNote; - const int8 *_samples; - } *_snd[8]; - struct Env { - EnvelopeState state; - int32 currentLevel; - int32 rate; - int32 tickCount; - int32 totalLevel; - int32 attackRate; - int32 decayRate; - int32 sustainLevel; - int32 sustainRate; - int32 releaseLevel; - int32 releaseRate; - int32 rootKeyOffset; - int32 size; - } *_env[8]; - } *_voice; -}; - -class Towns_EuphonyTrackQueue { -public: - Towns_EuphonyTrackQueue(Towns_EuphonyDriver *driver, Towns_EuphonyTrackQueue *last); - ~Towns_EuphonyTrackQueue() {} - - Towns_EuphonyTrackQueue *release(); - void initDriver(); - void loadDataToCurrentPosition(uint8 *trackdata, uint32 size, bool loop = 0); - void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0); - void setPlayBackStatus(bool playing); - bool isPlaying() const {return _playing; } - uint8 *trackData() {return _trackData; } - - bool _loop; - Towns_EuphonyTrackQueue *_next; - -private: - uint8 *_trackData; - uint8 *_used; - uint8 *_fchan; - uint8 *_wchan; - bool _playing; - Towns_EuphonyDriver *_driver; - Towns_EuphonyTrackQueue *_last; -}; - -class Towns_EuphonyParser : public MidiParser { -public: - Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue); - bool loadMusic (byte *data, uint32 size); - int32 calculateTempo(int16 val); - -protected: - void parseNextEvent (EventInfo &info); - void resetTracking(); - void setup(); - - byte *_enable; - byte *_mode; - byte *_channel; - byte *_adjVelo; - int8 *_adjNote; - - uint8 _firstBaseTickStep; - uint8 _nextBaseTickStep; - uint32 _initialTempo; - uint32 _baseTick; - - byte _tempo[3]; - Towns_EuphonyTrackQueue *_queue; -}; - -class Towns_EuphonyDriver : public MidiDriver_Emulated { -public: - Towns_EuphonyDriver(Audio::Mixer *mixer); - virtual ~Towns_EuphonyDriver(); - - int open(); - void close(); - void send(uint32 b); - void send(byte channel, uint32 b); - uint32 property(int prop, uint32 param) { return 0; } - - void setPitchBendRange(byte channel, uint range) { } - void loadFmInstruments(const byte *instr); - void loadWaveInstruments(const byte *instr); - - Towns_EuphonyTrackQueue *queue() { return _queue; } - - MidiChannel *allocateChannel() { return 0; } - MidiChannel *getPercussionChannel() { return 0; } - - void assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber); - void assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber); - void removeChannel(uint8 midiChannelNumber); - - void setVolume(int val = -1) { if (val >= 0) _volume = val; } - int getVolume(int val = -1) { return _volume; } - - // AudioStream API - bool isStereo() const { return true; } - int getRate() const { return _mixer->getOutputRate(); } - - void fading(bool status = true); - -protected: - void nextTick(int16 *buf1, int buflen); - void rate(uint16 r); - - void generateSamples(int16 *buf, int len); - - Towns_EuphonyFmChannel *_fChannel[6]; - Towns_EuphonyPcmChannel *_wChannel[8]; - Towns_EuphonyChannel *_channel[16]; - Towns_EuphonyTrackQueue *_queue; - - int _volume; - bool _fading; - int16 _fadestate; - - uint8 *_fmInstruments; - uint8 *_waveInstruments; - int8 * _waveSounds[10]; -}; - -Towns_EuphonyFmChannel::Towns_EuphonyFmChannel() { - _voice = new Voice2612; -} - -Towns_EuphonyFmChannel::~Towns_EuphonyFmChannel() { - delete _voice; -} - -void Towns_EuphonyFmChannel::noteOn(byte note, byte onVelo) { - _voice->noteOn(note, onVelo); -} - -void Towns_EuphonyFmChannel::noteOff(byte note) { - _voice->noteOff(note); -} - -void Towns_EuphonyFmChannel::controlChange(byte control, byte value) { - if (control == 121) { - // Reset controller - delete _voice; - _voice = new Voice2612; - } else if (control == 10) { - // pan position - } else { - _voice->setControlParameter(control, value); - } -} - -void Towns_EuphonyFmChannel::sysEx_customInstrument(uint32, const byte *fmInst) { - _voice->_rate = _rate; - _voice->setInstrument(fmInst); -} - -void Towns_EuphonyFmChannel::pitchBend(int16 value) { - _voice->pitchBend(value); -} - -void Towns_EuphonyFmChannel::nextTick(int32 *outbuf, int buflen) { - _voice->nextTick((int *)outbuf, buflen); -} - -void Towns_EuphonyFmChannel::rate(uint16 r) { - _rate = r; - _voice->_rate = r; -} - -Towns_EuphonyPcmChannel::Towns_EuphonyPcmChannel() { - _voice = new Voice; - for (uint8 i = 0; i < 8; i++) { - _voice->_env[i] = new Voice::Env; - _voice->_snd[i] = 0; - } - - _ctrl7_volume = 127; - velocity(0); - _frequencyOffs = 0x2000; - _current = -1; -} - -Towns_EuphonyPcmChannel::~Towns_EuphonyPcmChannel() { - for (uint8 i = 0; i < 8; i++) { - if (_voice->_snd[i]) - delete _voice->_snd[i]; - delete _voice->_env[i]; - } - delete _voice; -} - -void Towns_EuphonyPcmChannel::noteOn(byte note, byte onVelo) { - _note = note; - velocity(onVelo); - _phase = 0; - - for (_current = 0; _current < 7; _current++) { - if (note <= _voice->split[_current]) - break; - } - - _voice->_env[_current]->state = s_attacking; - _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->rate = _rate; - _voice->_env[_current]->tickCount = 0; -} - -void Towns_EuphonyPcmChannel::noteOff(byte note) { - if (_current == -1) - return; - if (_voice->_env[_current]->state == s_ready) - return; - - _voice->_env[_current]->state = s_releasing; - _voice->_env[_current]->releaseLevel = _voice->_env[_current]->currentLevel; - _voice->_env[_current]->tickCount = 0; -} - -void Towns_EuphonyPcmChannel::controlChange(byte control, byte value) { - switch (control) { - case 0x07: - // volume - _ctrl7_volume = value; - break; - case 0x0A: - // pan position - break; - case 0x79: - // Reset controller - for (uint8 i = 0; i < 8; i++) { - if (_voice->_snd[i]) - delete _voice->_snd[i]; - delete _voice->_env[i]; - } - delete _voice; - _voice = new Voice; - for (uint8 i = 0; i < 8; i++) { - _voice->_env[i] = new Voice::Env; - _voice->_snd[i] = 0; - } - break; - case 0x7B: - noteOff(_note); - break; - default: - break; - } -} - -void Towns_EuphonyPcmChannel::sysEx_customInstrument(uint32 type, const byte *fmInst) { - if (type == 0x80) { - for (uint8 i = 0; i < 8; i++) { - const byte * const *pos = (const byte * const *)fmInst; - for (uint8 ii = 0; ii < 10; ii++) { - if (_voice->id[i] == *(pos[ii] + 8)) { - if (!_voice->_snd[i]) - _voice->_snd[i] = new Voice::Snd; - memset(_voice->_snd[i]->name, 0, 9); - memcpy(_voice->_snd[i]->name, (const char *)pos[ii], 8); - _voice->_snd[i]->id = READ_LE_UINT32(pos[ii] + 8); - _voice->_snd[i]->numSamples = READ_LE_UINT32(pos[ii] + 12); - _voice->_snd[i]->loopStart = READ_LE_UINT32(pos[ii] + 16); - _voice->_snd[i]->loopLength = READ_LE_UINT32(pos[ii] + 20); - _voice->_snd[i]->samplingRate = READ_LE_UINT16(pos[ii] + 24); - _voice->_snd[i]->keyOffset = READ_LE_UINT16(pos[ii] + 26); - _voice->_snd[i]->keyNote = *(const uint8 *)(pos[ii] + 28); - _voice->_snd[i]->_samples = (const int8 *)(pos[ii] + 32); - } - } - } - } else { - memset(_voice->name, 0, 9); - memcpy(_voice->name, (const char *)fmInst, 8); - - for (uint8 i = 0; i < 8; i++) { - _voice->split[i] = READ_LE_UINT16(fmInst + 16 + 2 * i); - _voice->id[i] = READ_LE_UINT32(fmInst + 32 + 4 * i); - _voice->_snd[i] = 0; - _voice->_env[i]->state = s_ready; - _voice->_env[i]->currentLevel = 0; - _voice->_env[i]->totalLevel = *(fmInst + 64 + 8 * i); - _voice->_env[i]->attackRate = *(fmInst + 65 + 8 * i) * 10; - _voice->_env[i]->decayRate = *(fmInst + 66 + 8 * i) * 10; - _voice->_env[i]->sustainLevel = *(fmInst + 67 + 8 * i); - _voice->_env[i]->sustainRate = *(fmInst + 68 + 8 * i) * 20; - _voice->_env[i]->releaseRate = *(fmInst + 69 + 8 * i) * 10; - _voice->_env[i]->rootKeyOffset = *(fmInst + 70 + 8 * i); - } - } -} - -void Towns_EuphonyPcmChannel::pitchBend(int16 value) { - _frequencyOffs = value; -} - -void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) { - if (_current == -1 || !_voice->_snd[_current] || !_voice->_env[_current]->state || !_velocity) { - velocity(0); - _current = -1; - return; - } - - float phaseStep = SoundTowns::calculatePhaseStep(_note, _voice->_snd[_current]->keyNote - - _voice->_env[_current]->rootKeyOffset, _voice->_snd[_current]->samplingRate, _rate, _frequencyOffs); - - int32 looplength = _voice->_snd[_current]->loopLength; - int32 numsamples = _voice->_snd[_current]->numSamples; - const int8 * samples = _voice->_snd[_current]->_samples; - - for (int i = 0; i < buflen; i++) { - if (looplength > 0) { - while (_phase >= numsamples) - _phase -= looplength; - } else { - if (_phase >= numsamples) { - velocity(0); - _current = -1; - break; - } - } - - int32 output; - - int32 phase0 = int32(_phase); - int32 phase1 = int32(_phase + 1); - if (phase1 >= numsamples) - phase1 -= looplength; - float weight0 = _phase - phase0; - float weight1 = phase1 - _phase; - output = int32(samples[phase0] * weight0 + samples[phase1] * weight1); - - output *= _velocity; - output <<= 1; - - evpNextTick(); - output *= _voice->_env[_current]->currentLevel; - output >>= 7; - output *= _ctrl7_volume; - output >>= 7; - - output *= 185; - output >>= 8; - outbuf[i] += output; - _phase += phaseStep; - } -} - -void Towns_EuphonyPcmChannel::evpNextTick() { - switch (_voice->_env[_current]->state) { - case s_ready: - _voice->_env[_current]->currentLevel = 0; - return; - - case s_attacking: - if (_voice->_env[_current]->attackRate == 0) - _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - else if (_voice->_env[_current]->attackRate >= 1270) - _voice->_env[_current]->currentLevel = 0; - else - _voice->_env[_current]->currentLevel = (_voice->_env[_current]->totalLevel * - _voice->_env[_current]->tickCount++ * 1000) / - (_voice->_env[_current]->attackRate * _voice->_env[_current]->rate); - - if (_voice->_env[_current]->currentLevel >= _voice->_env[_current]->totalLevel) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - _voice->_env[_current]->state = s_decaying; - _voice->_env[_current]->tickCount = 0; - } - break; - - case s_decaying: - if (_voice->_env[_current]->decayRate == 0) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - } else if (_voice->_env[_current]->decayRate >= 1270) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - } else { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel; - _voice->_env[_current]->currentLevel -= ((_voice->_env[_current]->totalLevel - - _voice->_env[_current]->sustainLevel) * _voice->_env[_current]->tickCount++ * 1000) / - (_voice->_env[_current]->decayRate * _voice->_env[_current]->rate); - } - - if (_voice->_env[_current]->currentLevel <= _voice->_env[_current]->sustainLevel) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - _voice->_env[_current]->state = s_sustaining; - _voice->_env[_current]->tickCount = 0; - } - break; - - case s_sustaining: - if (_voice->_env[_current]->sustainRate == 0) { - _voice->_env[_current]->currentLevel = 0; - } else if (_voice->_env[_current]->sustainRate >= 2540) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - } else { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel; - _voice->_env[_current]->currentLevel -= (_voice->_env[_current]->sustainLevel * - _voice->_env[_current]->tickCount++ * 1000) / (_voice->_env[_current]->sustainRate * - _voice->_env[_current]->rate); - } - - if (_voice->_env[_current]->currentLevel <= 0) { - _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = s_ready; - _voice->_env[_current]->tickCount = 0; - } - break; - - case s_releasing: - if (_voice->_env[_current]->releaseRate == 0) { - _voice->_env[_current]->currentLevel = 0; - } else if (_voice->_env[_current]->releaseRate >= 1270) { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->releaseLevel; - } else { - _voice->_env[_current]->currentLevel = _voice->_env[_current]->releaseLevel; - _voice->_env[_current]->currentLevel -= (_voice->_env[_current]->releaseLevel * - _voice->_env[_current]->tickCount++ * 1000) / (_voice->_env[_current]->releaseRate * - _voice->_env[_current]->rate); - } - - if (_voice->_env[_current]->currentLevel <= 0) { - _voice->_env[_current]->currentLevel = 0; - _voice->_env[_current]->state = s_ready; - } - break; - - default: - break; - } -} - -void Towns_EuphonyPcmChannel::rate(uint16 r) { - _rate = r; -} - -void Towns_EuphonyPcmChannel::velocity(int velo) { - _velocity = velo; -} - -Towns_EuphonyDriver::Towns_EuphonyDriver(Audio::Mixer *mixer) - : MidiDriver_Emulated(mixer) { - _volume = 255; - _fadestate = EUPHONY_FADEOUT_TICKS; - _queue = 0; - - MidiDriver_YM2612::createLookupTables(); - - for (uint8 i = 0; i < 6; i++) - _channel[i] = _fChannel[i] = new Towns_EuphonyFmChannel; - for (uint8 i = 0; i < 8; i++) - _channel[i + 6] = _wChannel[i] = new Towns_EuphonyPcmChannel; - _channel[14] = _channel[15] = 0; - - _fmInstruments = _waveInstruments = 0; - memset(_waveSounds, 0, sizeof(uint8 *)* 10); - - rate(getRate()); - fading(0); - - _queue = new Towns_EuphonyTrackQueue(this, 0); -} - -Towns_EuphonyDriver::~Towns_EuphonyDriver() { - for (int i = 0; i < 6; i++) - delete _fChannel[i]; - for (int i = 0; i < 8; i++) - delete _wChannel[i]; - - MidiDriver_YM2612::removeLookupTables(); - - delete[] _fmInstruments; - _fmInstruments = 0; - - delete[] _waveInstruments; - _waveInstruments = 0; - - for (int i = 0; i < 10; i++) { - delete[] _waveSounds[i]; - _waveSounds[i] = 0; - } - - if (_queue) { - _queue->release(); - delete _queue; - _queue = 0; - } -} - -int Towns_EuphonyDriver::open() { - if (_isOpen) - return MERR_ALREADY_OPEN; - MidiDriver_Emulated::open(); - - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, - this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - - return 0; -} - -void Towns_EuphonyDriver::close() { - if (!_isOpen) - return; - _isOpen = false; - _mixer->stopHandle(_mixerSoundHandle); -} - -void Towns_EuphonyDriver::send(uint32 b) { - send(b & 0xF, b & 0xFFFFFFF0); -} - -void Towns_EuphonyDriver::send(byte chan, uint32 b) { - byte param2 = (byte) ((b >> 16) & 0xFF); - byte param1 = (byte) ((b >> 8) & 0xFF); - byte cmd = (byte) (b & 0xF0); - if (chan > ARRAYSIZE(_channel)) - return; - - switch (cmd) { - case 0x80:// Note Off - if (_channel[chan]) - _channel[chan]->noteOff(param1); - break; - case 0x90: // Note On - if (_channel[chan]) - _channel[chan]->noteOn(param1, param2); - break; - case 0xA0: // Aftertouch - break; // Not supported. - case 0xB0: // Control Change - if (param1 == 0x79) { - fading(0); - for (int i = 0; i < 15; i++) { - if (_channel[i]) { - _channel[i]->controlChange(param1, param2); - _channel[i]->programChange(0); - } - } - } else if (param1 == 0x7B) { - for (int i = 0; i < 15; i++) { - if (_channel[i]) - _channel[i]->controlChange(param1, param2); - } - } else { - if (_channel[chan]) - _channel[chan]->controlChange(param1, param2); - } - break; - case 0xC0: // Program Change - for (int i = 0; i < 6; i++) { - if (_channel[chan] == _fChannel[i]) { - _channel[chan]->sysEx_customInstrument(0, _fmInstruments + param1 * 0x30); - break; - } - } - for (int i = 0; i < 8; i++) { - if (_channel[chan] == _wChannel[i]) { - _channel[chan]->sysEx_customInstrument(0, _waveInstruments + param1 * 0x80); - _channel[chan]->sysEx_customInstrument(0x80, (const byte *)_waveSounds); - break; - } - } - break; - case 0xD0: // Channel Pressure - break; // Not supported. - case 0xE0: // Pitch Bend - if (_channel[chan]) - _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000); - break; - default: - warning("Towns_EuphonyDriver: Unknown send() command 0x%02X", cmd); - } -} - -void Towns_EuphonyDriver::loadFmInstruments(const byte *instr) { - delete[] _fmInstruments; - _fmInstruments = new uint8[0x1800]; - memcpy(_fmInstruments, instr, 0x1800); -} - -void Towns_EuphonyDriver::loadWaveInstruments(const byte *instr) { - delete[] _waveInstruments; - _waveInstruments = new uint8[0x1000]; - memcpy(_waveInstruments, instr, 0x1000); - - const uint8 *pos = (const uint8 *)(instr + 0x1000); - - for (uint8 i = 0; i < 10; i++) { - delete[] _waveSounds[i]; - uint32 numsamples = READ_LE_UINT32(pos + 0x0C); - _waveSounds[i] = new int8[numsamples + 0x20]; - memcpy(_waveSounds[i], pos, 0x20); - pos += 0x20; - for (uint32 ii = 0; ii < numsamples; ii++) { - uint8 s = *(pos + ii); - s = (s < 0x80) ? 0x80 - s : s; - _waveSounds[i][ii + 0x20] = s ^ 0x80; - } - pos += numsamples; - } -} - - -void Towns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) { - _channel[midiChannelNumber] = _fChannel[fmChannelNumber]; -} - -void Towns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) { - _channel[midiChannelNumber] = _wChannel[waveChannelNumber]; -} - -void Towns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) { - _channel[midiChannelNumber] = 0; -} - -void Towns_EuphonyDriver::generateSamples(int16 *data, int len) { - memset(data, 0, 2 * sizeof(int16) * len); - nextTick(data, len); -} - -void Towns_EuphonyDriver::nextTick(int16 *buf1, int buflen) { - int32 *buf0 = (int32 *)buf1; - - for (int i = 0; i < ARRAYSIZE(_channel); i++) { - if (_channel[i]) - _channel[i]->nextTick(buf0, buflen); - } - - for (int i = 0; i < buflen; ++i) { - int s = int( float(buf0[i] * _volume) * float((float)_fadestate / EUPHONY_FADEOUT_TICKS) ); - buf1[i*2] = buf1[i*2+1] = (s >> 9) & 0xffff; - } - - if (_fading) { - if (_fadestate) { - _fadestate--; - } else { - _fading = false; - _queue->setPlayBackStatus(false); - } - } -} - -void Towns_EuphonyDriver::rate(uint16 r) { - for (uint8 i = 0; i < 16; i++) { - if (_channel[i]) - _channel[i]->rate(r); - } -} - -void Towns_EuphonyDriver::fading(bool status) { - _fading = status; - if (!_fading) - _fadestate = EUPHONY_FADEOUT_TICKS; -} - -Towns_EuphonyParser::Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue) : MidiParser(), - _firstBaseTickStep(0x33), _nextBaseTickStep(0x33) { - _initialTempo = calculateTempo(0x5a); - _queue = queue; -} - -void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { - byte *pos = _position._play_pos; - - if (_queue->_next) { - if (info.ext.type == 0x2F) { - unloadMusic(); - memset(&info, 0, sizeof(EventInfo)); - pos = _position._play_pos = _tracks[0] = _queue->trackData() + 0x806; - } else if (_active_track == 255) { - _queue = _queue->_next; - setup(); - setTrack(0); - _queue->setPlayBackStatus(true); - return; - } else if (!_queue->isPlaying()) { - unloadMusic(); - _queue = _queue->_next; - setup(); - setTrack(0); - _queue->setPlayBackStatus(true); - return; - } - } - - bool loop = true; - while (loop) { - byte cmd = *pos; - byte evt = (cmd & 0xF0); - - if (evt == 0x90) { - byte chan = pos[1]; - - if (_enable[chan]) { - uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick; - info.start = pos + 6; - uint32 last = _position._last_event_tick; - info.delta = (tick < last) ? 0 : (tick - last); - - info.event = 0x90 | _channel[chan]; - info.length = pos[7] | (pos[8] << 4) | (pos[9] << 8) | (pos[10] << 12); - - int8 note = (int8) pos[4]; - if (_adjNote[chan]) { - note = (note & 0x7f) & _adjNote[chan]; - if (note > 0x7c) - note -= 0x0c; - else if (note < 0) - note += 0x0c; - } - info.basic.param1 = (byte) note; - - uint8 onVelo = (pos[5] & 0x7f) + _adjVelo[chan]; - if (onVelo > 0x7f) - onVelo = 0x7f; - if (onVelo < 1) - onVelo = 1; - info.basic.param2 = onVelo; - - pos += 12; - loop = false; - } else { - pos += 6; - } - } else if (evt == 0xB0 || evt == 0xC0 || evt == 0xe0) { - byte chan = pos[1]; - - if (_enable[chan]) { - info.start = pos; - uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick; - uint32 last = _position._last_event_tick; - info.delta = (tick < last) ? 0 : (tick - last); - info.event = evt | _channel[chan]; - info.length = 0; - info.basic.param1 = pos[4]; - info.basic.param2 = pos[5]; - pos += 6; - loop = false; - } else { - pos += 6; - } - } else if (cmd == 0xF2) { - static const uint16 tickTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; - _baseTick += tickTable[_nextBaseTickStep >> 4] * ((_nextBaseTickStep & 0x0f) + 1); - _nextBaseTickStep = pos[1]; - pos += 6; - } else if (cmd == 0xF8) { - int32 tempo = calculateTempo(pos[4] | (pos[5] << 7)); - info.event = 0xff; - info.length = 3; - info.ext.type = 0x51; - _tempo[0] = (tempo >> 16) & 0xff; - _tempo[1] = (tempo >> 8) & 0xff; - _tempo[2] = tempo & 0xff; - info.ext.data = (byte *)_tempo; - pos += 6; - loop = false; - } else if (cmd == 0xFD || cmd == 0xFE) { - // End of track. - if (_autoLoop) { - unloadMusic(); - _queue->setPlayBackStatus(true); - pos = info.start = _tracks[0]; - } else { - info.start = pos; - } - - uint32 last = _position._last_event_tick; - uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick; - info.delta = (tick < last) ? 0 : (tick - last); - info.event = 0xFF; - info.ext.type = 0x2F; - info.ext.data = pos; - loop = false; - } else { - warning("Unknown Euphony music event 0x%02X", (int)cmd); - memset(&info, 0, sizeof(info)); - pos = 0; - loop = false; - } - } - _position._play_pos = pos; -} - -bool Towns_EuphonyParser::loadMusic(byte *data, uint32 size) { - bool loop = _autoLoop; - - if (_queue->isPlaying() && !_queue->_loop) { - _queue->loadDataToEndOfQueue(data, size, loop); - } else { - unloadMusic(); - _queue = _queue->release(); - _queue->loadDataToCurrentPosition(data, size, loop); - setup(); - setTrack(0); - _queue->setPlayBackStatus(true); - } - return true; -} - -int32 Towns_EuphonyParser::calculateTempo(int16 val) { - int32 tempo = val; - - if (tempo < 0) - tempo = 0; - if (tempo > 0x1F4) - tempo = 0x1F4; - - tempo = 0x4C4B4 / (tempo + 0x1E); - while (tempo < 0x451) - tempo <<= 1; - tempo <<= 8; - - return tempo; -} - -void Towns_EuphonyParser::resetTracking() { - MidiParser::resetTracking(); - - _nextBaseTickStep = _firstBaseTickStep; - _baseTick = 0; - setTempo(_initialTempo); - _queue->setPlayBackStatus(false); -} - -void Towns_EuphonyParser::setup() { - uint8 *data = _queue->trackData(); - if (!data) - return; - _queue->initDriver(); - - _enable = data + 0x354; - _mode = data + 0x374; - _channel = data + 0x394; - _adjVelo = data + 0x3B4; - _adjNote = (int8 *)data + 0x3D4; - - _nextBaseTickStep = _firstBaseTickStep = data[0x804]; - _initialTempo = calculateTempo((data[0x805] > 0xfc) ? 0x5a : data[0x805]); - - property(MidiParser::mpAutoLoop, _queue->_loop); - - _num_tracks = 1; - _ppqn = 120; - _tracks[0] = data + 0x806; -} - -Towns_EuphonyTrackQueue::Towns_EuphonyTrackQueue(Towns_EuphonyDriver * driver, Towns_EuphonyTrackQueue * last) { - _trackData = 0; - _next = 0; - _driver = driver; - _last = last; - _used = _fchan = _wchan = 0; - _playing = _loop = false; -} - -void Towns_EuphonyTrackQueue::setPlayBackStatus(bool playing) { - Towns_EuphonyTrackQueue *i = this; - do { - i->_playing = playing; - i = i->_next; - } while (i); -} - -void Towns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) { - delete[] _trackData; - _trackData = new uint8[0xC58A]; - memset(_trackData, 0, 0xC58A); - Screen::decodeFrame4(trackdata, _trackData, size); - - _used = _trackData + 0x374; - _fchan = _trackData + 0x6d4; - _wchan = _trackData + 0x6dA; - _loop = loop; - _playing = false; -} - -void Towns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) { - if (!_trackData) { - loadDataToCurrentPosition(trackdata, size, loop); - return; - } - - Towns_EuphonyTrackQueue *i = this; - while (i->_next) - i = i->_next; - - i = i->_next = new Towns_EuphonyTrackQueue(_driver, i); - i->_trackData = new uint8[0xC58A]; - memset(i->_trackData, 0, 0xC58A); - Screen::decodeFrame4(trackdata, i->_trackData, size); - - i->_used = i->_trackData + 0x374; - i->_fchan = i->_trackData + 0x6d4; - i->_wchan = i->_trackData + 0x6dA; - i->_loop = loop; - i->_playing = _playing; -} - -Towns_EuphonyTrackQueue *Towns_EuphonyTrackQueue::release() { - Towns_EuphonyTrackQueue *i = this; - while (i->_next) - i = i->_next; - - Towns_EuphonyTrackQueue *res = i; - - while (i) { - i->_playing = false; - i->_used = i->_fchan = i->_wchan = 0; - delete[] i->_trackData; - i->_trackData = 0; - i = i->_last; - if (i) { - res = i; - delete i->_next; - i->_next = 0; - } - } - - delete[] res->_trackData; - res->_trackData = 0; - - return res; -} - -void Towns_EuphonyTrackQueue::initDriver() { - for (uint8 i = 0; i < 6; i++) { - if (_used[_fchan[i]]) - _driver->assignFmChannel(_fchan[i], i); - } - - for (uint8 i = 0; i < 8; i++) { - if (_used[_wchan[i]]) - _driver->assignWaveChannel(_wchan[i], i); - } - - for (uint8 i = 0; i < 16; i++) { - if (!_used[i]) - _driver->removeChannel(i); - } - _driver->send(0x79B0); -} - -class TownsPC98_OpnOperator { -public: - 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() {} - - void keyOn(); - void keyOff(); - void frequency(int freq); - void updatePhaseIncrement(); - void recalculateRates(); - void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); - - void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } - void detune(int value) { _detn = &_detnTbl[value << 5]; } - void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } - void attackRate(uint32 value) { _specifiedAttackRate = value; } - bool scaleRate(uint8 value); - void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } - void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } - void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } - void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } - void totalLevel(uint32 value) { _totalLevel = value << 3; } - void reset(); - -protected: - EnvelopeState _state; - bool _playing; - uint32 _feedbackLevel; - uint32 _multiple; - uint32 _totalLevel; - uint8 _keyScale1; - uint8 _keyScale2; - uint32 _specifiedAttackRate; - uint32 _specifiedDecayRate; - uint32 _specifiedSustainRate; - uint32 _specifiedReleaseRate; - uint32 _tickCount; - uint32 _sustainLevel; - - uint32 _frequency; - uint8 _kcode; - uint32 _phase; - uint32 _phaseIncrement; - const int32 *_detn; - - const uint8 *_rateTbl; - const uint8 *_rshiftTbl; - const uint8 *_adTbl; - const uint32 *_fTbl; - const uint32 *_sinTbl; - const int32 *_tLvlTbl; - const int32 *_detnTbl; - - const uint32 _tickLength; - uint32 _timer; - int32 _currentLevel; - - struct EvpState { - uint8 rate; - uint8 shift; - } fs_a, fs_d, fs_s, fs_r; -}; - -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(timerbase * 2), - _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), - _phase(0), _state(s_ready), _playing(false), _timer(0), _keyScale1(0), _keyScale2(0), _currentLevel(1023), - _tickCount(0) { - - fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0; - - reset(); -} - -void TownsPC98_OpnOperator::keyOn() { - if (_playing) - return; - - _playing = true; - _state = s_attacking; - _phase = 0; -} - -void TownsPC98_OpnOperator::keyOff() { - if (!_playing) - return; - - _playing = false; - if (_state != s_ready) - _state = s_releasing; -} - -void TownsPC98_OpnOperator::frequency(int freq) { - uint8 block = (freq >> 11); - uint16 pos = (freq & 0x7ff); - uint8 c = pos >> 7; - - _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); - _frequency = _fTbl[pos << 1] >> (7 - block); -} - -void TownsPC98_OpnOperator::updatePhaseIncrement() { - _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1; - uint8 keyscale = _kcode >> _keyScale1; - if (_keyScale2 != keyscale) { - _keyScale2 = keyscale; - recalculateRates(); - } -} - -void TownsPC98_OpnOperator::recalculateRates() { - int k = _keyScale2; - int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; - fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; - fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; - - r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0; - fs_d.rate = _rateTbl[r + k]; - fs_d.shift = _rshiftTbl[r + k]; - - r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0; - fs_s.rate = _rateTbl[r + k]; - fs_s.shift = _rshiftTbl[r + k]; - - r = (_specifiedReleaseRate << 2) + 0x22; - fs_r.rate = _rateTbl[r + k]; - fs_r.shift = _rshiftTbl[r + k]; -} - -void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) { - if (_state == s_ready) - return; - - _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; - ++_tickCount; - - int32 levelIncrement = 0; - uint32 targetTime = 0; - int32 targetLevel = 0; - EnvelopeState nextState = s_ready; - - switch (_state) { - case s_ready: - return; - case s_attacking: - targetLevel = 0; - nextState = s_decaying; - if ((_specifiedAttackRate << 1) + _keyScale2 < 64) { - targetTime = (1 << fs_a.shift) - 1; - levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; - break; - } else { - _currentLevel = targetLevel; - _state = nextState; - } - // Fall through - case s_decaying: - targetTime = (1 << fs_d.shift) - 1; - nextState = s_sustaining; - targetLevel = _sustainLevel; - levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; - break; - case s_sustaining: - targetTime = (1 << fs_s.shift) - 1; - nextState = s_sustaining; - targetLevel = 1023; - levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; - break; - case s_releasing: - targetTime = (1 << fs_r.shift) - 1; - nextState = s_ready; - targetLevel = 1023; - levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; - break; - } - - if (!(_tickCount & targetTime)) { - _currentLevel += levelIncrement; - if ((_state == s_attacking && _currentLevel <= targetLevel) || (_state != s_attacking && _currentLevel >= targetLevel)) { - if (_state != s_decaying) - _currentLevel = targetLevel; - _state = nextState; - } - } - } - - uint32 lvlout = _totalLevel + (uint32) _currentLevel; - - - int32 outp = 0; - int32 *i = &outp, *o = &outp; - int phaseShift = 0; - - if (feed) { - o = &feed[0]; - i = &feed[1]; - phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0; - *o = *i; - } else { - phaseShift = phasebuf << 15; - } - - if (lvlout < 832) { - uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) - + phaseShift)) >> 16) & 0x3ff]; - *i = ((index < 6656) ? _tLvlTbl[index] : 0); - } else { - *i = 0; - } - - _phase += _phaseIncrement; - out += *o; -} - -void TownsPC98_OpnOperator::reset(){ - keyOff(); - _timer = 0; - _keyScale2 = 0; - _currentLevel = 1023; - - frequency(0); - detune(0); - scaleRate(0); - multiple(0); - updatePhaseIncrement(); - attackRate(0); - decayRate(0); - releaseRate(0); - sustainRate(0); - feedbackLevel(0); - totalLevel(127); -} - -bool TownsPC98_OpnOperator::scaleRate(uint8 value) { - value = 3 - value; - if (_keyScale1 != value) { - _keyScale1 = value; - return true; - } - - int k = _keyScale2; - int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; - fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; - fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; - return false; -} - -class TownsPC98_OpnDriver; -class TownsPC98_OpnChannel { -public: - TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, - uint8 key, uint8 prt, uint8 id); - virtual ~TownsPC98_OpnChannel(); - virtual void init(); - - typedef enum channelState { - CHS_RECALCFREQ = 0x01, - CHS_KEYOFF = 0x02, - CHS_SSGOFF = 0x04, - CHS_VBROFF = 0x08, - CHS_ALLOFF = 0x0f, - CHS_PROTECT = 0x40, - CHS_EOT = 0x80 - } ChannelState; - - virtual void loadData(uint8 *data); - virtual void processEvents(); - virtual void processFrequency(); - virtual bool processControlEvent(uint8 cmd); - - virtual void keyOn(); - void keyOff(); - - void setOutputLevel(); - virtual void fadeStep(); - virtual void reset(); - - const uint8 _idFlag; - -protected: - void setupVibrato(); - bool processVibrato(); - - bool control_dummy(uint8 para); - bool control_f0_setPatch(uint8 para); - bool control_f1_presetOutputLevel(uint8 para); - bool control_f2_setKeyOffTime(uint8 para); - bool control_f3_setFreqLSB(uint8 para); - bool control_f4_setOutputLevel(uint8 para); - bool control_f5_setTempo(uint8 para); - bool control_f6_repeatSection(uint8 para); - bool control_f7_setupVibrato(uint8 para); - bool control_f8_toggleVibrato(uint8 para); - bool control_fa_writeReg(uint8 para); - virtual bool control_fb_incOutLevel(uint8 para); - virtual bool control_fc_decOutLevel(uint8 para); - bool control_fd_jump(uint8 para); - virtual bool control_ff_endOfTrack(uint8 para); - - uint8 _ticksLeft; - uint8 _algorithm; - uint8 _instr; - uint8 _totalLevel; - uint8 _frqBlockMSB; - int8 _frqLSB; - uint8 _keyOffTime; - bool _hold; - uint8 *_dataPtr; - uint8 _vbrInitDelayHi; - uint8 _vbrInitDelayLo; - int16 _vbrModInitVal; - uint8 _vbrDuration; - uint8 _vbrCurDelay; - int16 _vbrModCurVal; - uint8 _vbrDurLeft; - uint16 _frequency; - uint8 _block; - uint8 _regOffset; - uint8 _flags; - uint8 _ssgTl; - uint8 _ssgStep; - uint8 _ssgTicksLeft; - uint8 _ssgTargetLvl; - uint8 _ssgStartLvl; - - const uint8 _chanNum; - const uint8 _keyNum; - const uint8 _part; - - TownsPC98_OpnDriver *_drv; - - typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); - const ControlEventFunc *controlEvents; -}; - -class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { -public: - TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); - virtual ~TownsPC98_OpnChannelSSG() {} - void init(); - - virtual void loadData(uint8 *data); - void processEvents(); - void processFrequency(); - bool processControlEvent(uint8 cmd); - - void keyOn(); - void nextShape(); - - void protect(); - void restore(); - virtual void reset(); - - void fadeStep(); - -protected: - void setOutputLevel(uint8 lvl); - - bool control_f0_setPatch(uint8 para); - bool control_f1_setTotalLevel(uint8 para); - bool control_f4_setAlgorithm(uint8 para); - bool control_f9_loadCustomPatch(uint8 para); - bool control_fb_incOutLevel(uint8 para); - bool control_fc_decOutLevel(uint8 para); - bool control_ff_endOfTrack(uint8 para); - - typedef bool (TownsPC98_OpnChannelSSG::*ControlEventFunc)(uint8 para); - const ControlEventFunc *controlEvents; -}; - -class TownsPC98_OpnSfxChannel : public TownsPC98_OpnChannelSSG { -public: - TownsPC98_OpnSfxChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : - TownsPC98_OpnChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} - ~TownsPC98_OpnSfxChannel() {} - - void loadData(uint8 *data); - void reset(); -}; - -class TownsPC98_OpnChannelPCM : public TownsPC98_OpnChannel { -public: - TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); - ~TownsPC98_OpnChannelPCM() {} - void init(); - - void loadData(uint8 *data); - void processEvents(); - bool processControlEvent(uint8 cmd); - -private: - bool control_f1_prcStart(uint8 para); - bool control_ff_endOfTrack(uint8 para); - - typedef bool (TownsPC98_OpnChannelPCM::*ControlEventFunc)(uint8 para); - const ControlEventFunc *controlEvents; -}; - -class TownsPC98_OpnSquareSineSource { -public: - TownsPC98_OpnSquareSineSource(const uint32 timerbase); - ~TownsPC98_OpnSquareSineSource(); - - void init(const int *rsTable, const int *rseTable); - void reset(); - void writeReg(uint8 address, uint8 value, bool force = false); - - void nextTick(int32 *buffer, uint32 bufferSize); - - void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } - void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } - - uint8 chanEnable() const { return _chanEnable; } -private: - void updateRegs(); - - uint8 _updateRequestBuf[64]; - int _updateRequest; - int _rand; - - int8 _evpTimer; - uint32 _pReslt; - uint8 _attack; - - bool _evpUpdate, _cont; - - int _evpUpdateCnt; - uint8 _outN; - int _nTick; - - int32 *_tlTable; - int32 *_tleTable; - - const uint32 _tickLength; - uint32 _timer; - - struct Channel { - int tick; - uint8 smp; - uint8 out; - - uint8 frqL; - uint8 frqH; - uint8 vol; - } _channels[3]; - - uint8 _noiseGenerator; - uint8 _chanEnable; - - uint8 **_reg; - - uint16 _volumeA; - uint16 _volumeB; - int _volMaskA; - int _volMaskB; - - bool _ready; -}; - -class TownsPC98_OpnPercussionSource { -public: - TownsPC98_OpnPercussionSource(const uint32 timerbase); - ~TownsPC98_OpnPercussionSource() { delete[] _reg; } - - void init(const uint8 *instrData = 0); - void reset(); - void writeReg(uint8 address, uint8 value); - - void nextTick(int32 *buffer, uint32 bufferSize); - - void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } - void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } - -private: - struct RhtChannel { - const uint8 *data; - - const uint8 *start; - const uint8 *end; - const uint8 *pos; - uint32 size; - bool active; - uint8 level; - - int8 decState; - uint8 decStep; - - int16 samples[2]; - int out; - - uint8 startPosH; - uint8 startPosL; - uint8 endPosH; - uint8 endPosL; - }; - - void recalcOuput(RhtChannel *ins); - void advanceInput(RhtChannel *ins); - - RhtChannel _rhChan[6]; - - uint8 _totalLevel; - - const uint32 _tickLength; - uint32 _timer; - - uint8 **_reg; - - uint16 _volumeA; - uint16 _volumeB; - int _volMaskA; - int _volMaskB; - - bool _ready; -}; - -class TownsPC98_OpnCore : public Audio::AudioStream { -public: - enum OpnType { - OD_TOWNS, - OD_TYPE26, - OD_TYPE86 - }; - - TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type); - virtual ~TownsPC98_OpnCore(); - - virtual bool init(); - virtual void reset(); - - void writeReg(uint8 part, uint8 regAddress, uint8 value); - - // AudioStream interface - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _mixer->getOutputRate(); } - -protected: - void toggleRegProtection(bool prot) { _regProtectionFlag = prot; } - uint8 readSSGStatus() { return _ssg->chanEnable(); } - - virtual void timerCallbackA() = 0; - virtual void timerCallbackB() = 0; - - // The audio driver can store and apply two different audio settings - // (usually for music and sound effects). The channel mask will determine - // which channels get effected by the setting. The first bits will be - // the normal opn channels, the next bits the ssg channels and the final - // bit the rhythm channel. - void setVolumeIntern(int volA, int volB); - void setVolumeChannelMasks(int channelMaskA, int channelMaskB); - - const int _numChan; - const int _numSSG; - const bool _hasPercussion; - - Common::Mutex _mutex; -private: - void generateTables(); - void nextTick(int32 *buffer, uint32 bufferSize); - void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); - - struct ChanInternal { - ChanInternal() { - memset(this, 0, sizeof(ChanInternal)); - } - - ~ChanInternal() { - for (uint i = 0; i < ARRAYSIZE(opr); ++i) - delete opr[i]; - } - - uint16 frqTemp; - bool enableLeft; - bool enableRight; - bool updateEnvelopeParameters; - int32 feedbuf[3]; - uint8 algorithm; - TownsPC98_OpnOperator *opr[4]; - }; - - TownsPC98_OpnSquareSineSource *_ssg; - TownsPC98_OpnPercussionSource *_prc; - ChanInternal *_chanInternal; - - uint8 *_oprRates; - uint8 *_oprRateshift; - uint8 *_oprAttackDecay; - uint32 *_oprFrq; - uint32 *_oprSinTbl; - int32 *_oprLevelOut; - int32 *_oprDetune; - - bool _regProtectionFlag; - - typedef void (TownsPC98_OpnCore::*OpnTimerProc)(); - - struct OpnTimer { - bool enabled; - uint16 value; - - int32 smpTillCb; - uint32 smpTillCbRem; - int32 smpPerCb; - uint32 smpPerCbRem; - - OpnTimerProc cb; - }; - - OpnTimer _timers[2]; - - int _volMaskA, _volMaskB; - uint16 _volumeA, _volumeB; - - const float _baserate; - uint32 _timerbase; - - Audio::Mixer *_mixer; - Audio::SoundHandle _soundHandle; - - static const uint8 _percussionData[]; - static const uint32 _adtStat[]; - static const uint8 _detSrc[]; - static const int _ssgTables[]; - - bool _ready; -}; - -class TownsPC98_OpnDriver : public TownsPC98_OpnCore { -friend class TownsPC98_OpnChannel; -friend class TownsPC98_OpnChannelSSG; -friend class TownsPC98_OpnSfxChannel; -friend class TownsPC98_OpnChannelPCM; -public: - TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type); - ~TownsPC98_OpnDriver(); - - void loadMusicData(uint8 *data, bool loadPaused = false); - void loadSoundEffectData(uint8 *data, uint8 trackNum); - bool init(); - void reset(); - - void fadeStep(); - - void pause() { _musicPlaying = false; } - void cont() { _musicPlaying = true; } - - void timerCallbackB(); - void timerCallbackA(); - - bool looping() { return _looping == _updateChannelsFlag ? true : false; } - bool musicPlaying() { return _musicPlaying; } - - void setMusicVolume(int volume) { _musicVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } - void setSoundEffectVolume(int volume) { _sfxVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } - -protected: - void startSoundEffect(); - - void setMusicTempo(uint8 tempo); - void setSfxTempo(uint16 tempo); - - TownsPC98_OpnChannel **_channels; - TownsPC98_OpnChannelSSG **_ssgChannels; - TownsPC98_OpnSfxChannel **_sfxChannels; - TownsPC98_OpnChannelPCM *_rhythmChannel; - - const uint8 *_opnCarrier; - const uint8 *_opnFreqTable; - const uint8 *_opnFreqTableSSG; - const uint8 *_opnFxCmdLen; - const uint8 *_opnLvlPresets; - - uint8 *_musicBuffer; - uint8 *_sfxBuffer; - uint8 *_trackPtr; - uint8 *_patches; - uint8 *_ssgPatches; - - uint8 _updateChannelsFlag; - uint8 _updateSSGFlag; - uint8 _updateRhythmFlag; - uint8 _updateSfxFlag; - uint8 _finishedChannelsFlag; - uint8 _finishedSSGFlag; - uint8 _finishedRhythmFlag; - uint8 _finishedSfxFlag; - - bool _musicPlaying; - bool _sfxPlaying; - uint8 _fading; - uint8 _looping; - uint32 _musicTickCounter; - - int _sfxOffs; - uint8 *_sfxData; - uint16 _sfxOffsets[2]; - - uint16 _musicVolume; - uint16 _sfxVolume; - - static const uint8 _drvTables[]; - - bool _ready; -}; - -TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, - uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), - _part(prt), _idFlag(id), controlEvents(0) { - - _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0; - _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0; - _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0; - _frqLSB = 0; - _hold = false; - _dataPtr = 0; - _vbrModInitVal = _vbrModCurVal = 0; - _frequency = 0; -} - -TownsPC98_OpnChannel::~TownsPC98_OpnChannel() { -} - -void TownsPC98_OpnChannel::init() { - #define Control(x) &TownsPC98_OpnChannel::control_##x - static const ControlEventFunc ctrlEvents[] = { - Control(f0_setPatch), - Control(f1_presetOutputLevel), - Control(f2_setKeyOffTime), - Control(f3_setFreqLSB), - Control(f4_setOutputLevel), - Control(f5_setTempo), - Control(f6_repeatSection), - Control(f7_setupVibrato), - Control(f8_toggleVibrato), - Control(dummy), - Control(fa_writeReg), - Control(fb_incOutLevel), - Control(fc_decOutLevel), - Control(fd_jump), - Control(dummy), - Control(ff_endOfTrack) - }; - #undef Control - - controlEvents = ctrlEvents; -} - -void TownsPC98_OpnChannel::keyOff() { - // all operators off - uint8 value = _keyNum & 0x0f; - if (_part) - value |= 4; - uint8 regAddress = 0x28; - _drv->writeReg(0, regAddress, value); - _flags |= CHS_KEYOFF; -} - -void TownsPC98_OpnChannel::keyOn() { - // all operators on - uint8 value = _keyNum | 0xf0; - if (_part) - value |= 4; - uint8 regAddress = 0x28; - _drv->writeReg(0, regAddress, value); -} - -void TownsPC98_OpnChannel::loadData(uint8 *data) { - _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; - _ticksLeft = 1; - _dataPtr = data; - _totalLevel = 0x7F; - - uint8 *tmp = _dataPtr; - for (bool loop = true; loop; ) { - uint8 cmd = *tmp++; - if (cmd < 0xf0) { - tmp++; - } else if (cmd == 0xff) { - if (READ_LE_UINT16(tmp)) { - _drv->_looping |= _idFlag; - tmp += _drv->_opnFxCmdLen[cmd - 240]; - } else - loop = false; - } else if (cmd == 0xf6) { - // reset repeat section countdown - tmp[0] = tmp[1]; - tmp += 4; - } else { - tmp += _drv->_opnFxCmdLen[cmd - 240]; - } - } -} - -void TownsPC98_OpnChannel::processEvents() { - if (_flags & CHS_EOT) - return; - - if (!_hold && _ticksLeft == _keyOffTime) - keyOff(); - - if (--_ticksLeft) - return; - - if (!_hold) - keyOff(); - - uint8 cmd = 0; - bool loop = true; - - while (loop) { - cmd = *_dataPtr++; - if (cmd < 0xf0) - loop = false; - else if (!processControlEvent(cmd)) - return; - } - - uint8 para = *_dataPtr++; - - if (cmd == 0x80) { - keyOff(); - _hold = false; - } else { - keyOn(); - - if (_hold == false || cmd != _frqBlockMSB) - _flags |= CHS_RECALCFREQ; - - _hold = (para & 0x80) ? true : false; - _frqBlockMSB = cmd; - } - - _ticksLeft = para & 0x7f; -} - -void TownsPC98_OpnChannel::processFrequency() { - if (_flags & CHS_RECALCFREQ) { - - _frequency = (((const uint16 *)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8); - - _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); - _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); - - setupVibrato(); - } - - if (!(_flags & CHS_VBROFF)) { - if (!processVibrato()) - return; - - _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); - _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); - } -} - -void TownsPC98_OpnChannel::setupVibrato() { - _vbrCurDelay = _vbrInitDelayHi; - if (_flags & CHS_KEYOFF) { - _vbrModCurVal = _vbrModInitVal; - _vbrCurDelay += _vbrInitDelayLo; - } - _vbrDurLeft = (_vbrDuration >> 1); - _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); -} - -bool TownsPC98_OpnChannel::processVibrato() { - if (--_vbrCurDelay) - return false; - - _vbrCurDelay = _vbrInitDelayHi; - _frequency += _vbrModCurVal; - - if (!--_vbrDurLeft) { - _vbrDurLeft = _vbrDuration; - _vbrModCurVal = -_vbrModCurVal; - } - - return true; -} - -bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { - uint8 para = *_dataPtr++; - return (this->*controlEvents[cmd & 0x0f])(para); -} - -void TownsPC98_OpnChannel::setOutputLevel() { - uint8 outopr = _drv->_opnCarrier[_algorithm]; - uint8 reg = 0x40 + _regOffset; - - for (int i = 0; i < 4; i++) { - if (outopr & 1) - _drv->writeReg(_part, reg, _totalLevel); - outopr >>= 1; - reg += 4; - } -} - -void TownsPC98_OpnChannel::fadeStep() { - _totalLevel += 3; - if (_totalLevel > 0x7f) - _totalLevel = 0x7f; - setOutputLevel(); -} - -void TownsPC98_OpnChannel::reset() { - _hold = false; - _keyOffTime = 0; - _ticksLeft = 1; - - _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; - - _totalLevel = 0; - _algorithm = 0; - _flags = CHS_EOT; - _algorithm = 0; - - _block = 0; - _frequency = 0; - _frqBlockMSB = 0; - _frqLSB = 0; - - _ssgTl = 0; - _ssgStartLvl = 0; - _ssgTargetLvl = 0; - _ssgStep = 0; - _ssgTicksLeft = 0; - - _vbrInitDelayHi = 0; - _vbrInitDelayLo = 0; - _vbrModInitVal = 0; - _vbrDuration = 0; - _vbrCurDelay = 0; - _vbrModCurVal = 0; - _vbrDurLeft = 0; -} - -bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { - _instr = para; - uint8 reg = _regOffset + 0x80; - - for (int i = 0; i < 4; i++) { - // set release rate for each operator - _drv->writeReg(_part, reg, 0x0f); - reg += 4; - } - - const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5); - reg = _regOffset + 0x30; - - // write registers 0x30 to 0x8f - for (int i = 0; i < 6; i++) { - _drv->writeReg(_part, reg, tptr[0]); - reg += 4; - _drv->writeReg(_part, reg, tptr[2]); - reg += 4; - _drv->writeReg(_part, reg, tptr[1]); - reg += 4; - _drv->writeReg(_part, reg, tptr[3]); - reg += 4; - tptr += 4; - } - - reg = _regOffset + 0xB0; - _algorithm = tptr[0] & 7; - // set feedback and algorithm - _drv->writeReg(_part, reg, tptr[0]); - - setOutputLevel(); - return true; -} - -bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) { - if (_drv->_fading) - return true; - - _totalLevel = _drv->_opnLvlPresets[para]; - setOutputLevel(); - return true; -} - -bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) { - _keyOffTime = para; - return true; -} - -bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) { - _frqLSB = (int8) para; - return true; -} - -bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { - if (_drv->_fading) - return true; - - _totalLevel = para; - setOutputLevel(); - return true; -} - -bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { - _drv->setMusicTempo(para); - return true; -} - -bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { - _dataPtr--; - _dataPtr[0]--; - - if (*_dataPtr) { - // repeat section until counter has reached zero - _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2); - } else { - // reset counter, advance to next section - _dataPtr[0] = _dataPtr[1]; - _dataPtr += 4; - } - return true; -} - -bool TownsPC98_OpnChannel::control_f7_setupVibrato(uint8 para) { - _vbrInitDelayHi = _dataPtr[0]; - _vbrInitDelayLo = para; - _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); - _vbrDuration = _dataPtr[3]; - _dataPtr += 4; - _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ; - return true; -} - -bool TownsPC98_OpnChannel::control_f8_toggleVibrato(uint8 para) { - if (para == 0x10) { - if (*_dataPtr++) { - _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF; - } else { - _flags |= CHS_VBROFF; - } - } else { - /* NOT IMPLEMENTED - uint8 skipChannels = para / 36; - uint8 entry = para % 36; - TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; - - t->unnamedEntries[entry] = *_dataPtr++;*/ - } - return true; -} - -bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) { - _drv->writeReg(_part, para, *_dataPtr++); - return true; -} - -bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) { - _dataPtr--; - if (_drv->_fading) - return true; - - uint8 val = (_totalLevel + 3); - if (val > 0x7f) - val = 0x7f; - - _totalLevel = val; - setOutputLevel(); - return true; -} - -bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { - _dataPtr--; - if (_drv->_fading) - return true; - - int8 val = (int8) (_totalLevel - 3); - if (val < 0) - val = 0; - - _totalLevel = (uint8) val; - setOutputLevel(); - return true; -} - -bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { - uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1); - _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1); - return true; -} - -bool TownsPC98_OpnChannel::control_dummy(uint8 para) { - _dataPtr--; - return true; -} - -bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { - uint16 val = READ_LE_UINT16(--_dataPtr); - if (val) { - // loop - _dataPtr = _drv->_trackPtr + val; - return true; - } else { - // quit parsing for active channel - --_dataPtr; - _flags |= CHS_EOT; - _drv->_finishedChannelsFlag |= _idFlag; - keyOff(); - return false; - } -} - -TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : - TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) { -} - -void TownsPC98_OpnChannelSSG::init() { - _algorithm = 0x80; - - #define Control(x) &TownsPC98_OpnChannelSSG::control_##x - static const ControlEventFunc ctrlEventsSSG[] = { - Control(f0_setPatch), - Control(f1_setTotalLevel), - Control(f2_setKeyOffTime), - Control(f3_setFreqLSB), - Control(f4_setAlgorithm), - Control(f5_setTempo), - Control(f6_repeatSection), - Control(f7_setupVibrato), - Control(f8_toggleVibrato), - Control(f9_loadCustomPatch), - Control(fa_writeReg), - Control(fb_incOutLevel), - Control(fc_decOutLevel), - Control(fd_jump), - Control(dummy), - Control(ff_endOfTrack) - }; - #undef Control - - controlEvents = ctrlEventsSSG; -} - -void TownsPC98_OpnChannelSSG::processEvents() { - if (_flags & CHS_EOT) - return; - - _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); - - if (!_hold && _ticksLeft == _keyOffTime) - nextShape(); - - if (!--_ticksLeft) { - - uint8 cmd = 0; - bool loop = true; - - while (loop) { - cmd = *_dataPtr++; - if (cmd < 0xf0) - loop = false; - else if (!processControlEvent(cmd)) - return; - } - - uint8 para = *_dataPtr++; - - if (cmd == 0x80) { - nextShape(); - _hold = false; - } else { - if (!_hold) { - _instr &= 0xf0; - _ssgStep = _drv->_ssgPatches[_instr]; - _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; - _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; - _ssgStartLvl = _drv->_ssgPatches[_instr + 3]; - _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; - } - - keyOn(); - - if (_hold == false || cmd != _frqBlockMSB) - _flags |= CHS_RECALCFREQ; - - _hold = (para & 0x80) ? true : false; - _frqBlockMSB = cmd; - } - - _ticksLeft = para & 0x7f; - } - - if (!(_flags & CHS_SSGOFF)) { - if (--_ssgTicksLeft) { - if (!_drv->_fading) - setOutputLevel(_ssgStartLvl); - return; - } - - _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; - - if (_drv->_ssgPatches[_instr + 1] & 0x80) { - uint8 t = _ssgStartLvl - _ssgStep; - - if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { - if (!_drv->_fading) - setOutputLevel(t); - return; - } - } else { - int t = _ssgStartLvl + _ssgStep; - uint8 p = (uint8) (t & 0xff); - - if (t < 256 && _ssgTargetLvl > p) { - if (!_drv->_fading) - setOutputLevel(p); - return; - } - } - - setOutputLevel(_ssgTargetLvl); - if (_ssgStartLvl && !(_instr & 8)){ - _instr += 4; - _ssgStep = _drv->_ssgPatches[_instr]; - _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; - _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; - } else { - _flags |= CHS_SSGOFF; - setOutputLevel(0); - } - } -} - -void TownsPC98_OpnChannelSSG::processFrequency() { - if (_algorithm & 0x40) - return; - - if (_flags & CHS_RECALCFREQ) { - _block = _frqBlockMSB >> 4; - _frequency = ((const uint16 *)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; - - uint16 f = _frequency >> _block; - _drv->writeReg(_part, _regOffset << 1, f & 0xff); - _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); - - setupVibrato(); - } - - if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) { - if (!processVibrato()) - return; - - uint16 f = _frequency >> _block; - _drv->writeReg(_part, _regOffset << 1, f & 0xff); - _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); - } -} - -bool TownsPC98_OpnChannelSSG::processControlEvent(uint8 cmd) { - uint8 para = *_dataPtr++; - return (this->*controlEvents[cmd & 0x0f])(para); -} - -void TownsPC98_OpnChannelSSG::nextShape() { - _instr = (_instr & 0xf0) + 0x0c; - _ssgStep = _drv->_ssgPatches[_instr]; - _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; - _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; -} - -void TownsPC98_OpnChannelSSG::keyOn() { - uint8 c = 0x7b; - uint8 t = (_algorithm & 0xC0) << 1; - if (_algorithm & 0x80) - t |= 4; - - c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); - t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); - - if (!(_algorithm & 0x80)) - _drv->writeReg(_part, 6, _algorithm & 0x7f); - - uint8 e = (_drv->readSSGStatus() & c) | t; - _drv->writeReg(_part, 7, e); -} - -void TownsPC98_OpnChannelSSG::protect() { - _flags |= CHS_PROTECT; -} - -void TownsPC98_OpnChannelSSG::restore() { - _flags &= ~CHS_PROTECT; - keyOn(); - _drv->writeReg(_part, 8 + _regOffset, _ssgTl); - uint16 f = _frequency >> _block; - _drv->writeReg(_part, _regOffset << 1, f & 0xff); - _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); -} - -void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { - _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); - TownsPC98_OpnChannel::loadData(data); - setOutputLevel(0); - _algorithm = 0x80; -} - -void TownsPC98_OpnChannelSSG::setOutputLevel(uint8 lvl) { - _ssgStartLvl = lvl; - uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; - if (newTl == _ssgTl) - return; - _ssgTl = newTl; - _drv->writeReg(_part, 8 + _regOffset, _ssgTl); -} - -void TownsPC98_OpnChannelSSG::reset() { - TownsPC98_OpnChannel::reset(); - - // Unlike the original we restore the default patch data. This fixes a bug - // where certain sound effects would bring each other out of tune (e.g. the - // dragon's fire in Darm's house in Kyra 1 would sound different each time - // you triggered another sfx by dropping an item etc.) - uint8 i = (10 + _regOffset) << 4; - const uint8 *src = &_drv->_drvTables[156]; - _drv->_ssgPatches[i] = src[i]; - _drv->_ssgPatches[i + 3] = src[i + 3]; - _drv->_ssgPatches[i + 4] = src[i + 4]; - _drv->_ssgPatches[i + 6] = src[i + 6]; - _drv->_ssgPatches[i + 8] = src[i + 8]; - _drv->_ssgPatches[i + 12] = src[i + 12]; -} - -void TownsPC98_OpnChannelSSG::fadeStep() { - _totalLevel--; - if ((int8)_totalLevel < 0) - _totalLevel = 0; - setOutputLevel(_ssgStartLvl); -} - -bool TownsPC98_OpnChannelSSG::control_f0_setPatch(uint8 para) { - _instr = para << 4; - para = (para >> 3) & 0x1e; - if (para) - return control_f4_setAlgorithm(para | 0x40); - return true; -} - -bool TownsPC98_OpnChannelSSG::control_f1_setTotalLevel(uint8 para) { - if (!_drv->_fading) - _totalLevel = para; - return true; -} - -bool TownsPC98_OpnChannelSSG::control_f4_setAlgorithm(uint8 para) { - _algorithm = para; - return true; -} - -bool TownsPC98_OpnChannelSSG::control_f9_loadCustomPatch(uint8 para) { - _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4; - _drv->_ssgPatches[_instr] = *_dataPtr++; - _drv->_ssgPatches[_instr + 3] = para; - _drv->_ssgPatches[_instr + 4] = *_dataPtr++; - _drv->_ssgPatches[_instr + 6] = *_dataPtr++; - _drv->_ssgPatches[_instr + 8] = *_dataPtr++; - _drv->_ssgPatches[_instr + 12] = *_dataPtr++; - return true; -} - -bool TownsPC98_OpnChannelSSG::control_fb_incOutLevel(uint8 para) { - _dataPtr--; - if (_drv->_fading) - return true; - - _totalLevel--; - if ((int8)_totalLevel < 0) - _totalLevel = 0; - - return true; -} - -bool TownsPC98_OpnChannelSSG::control_fc_decOutLevel(uint8 para) { - _dataPtr--; - if (_drv->_fading) - return true; - - if (_totalLevel + 1 < 0x10) - _totalLevel++; - - return true; -} - -bool TownsPC98_OpnChannelSSG::control_ff_endOfTrack(uint8 para) { - if (!_drv->_sfxOffs) { - uint16 val = READ_LE_UINT16(--_dataPtr); - if (val) { - // loop - _dataPtr = _drv->_trackPtr + val; - return true; - } else { - // stop parsing - if (!_drv->_fading) - setOutputLevel(0); - --_dataPtr; - _flags |= CHS_EOT; - _drv->_finishedSSGFlag |= _idFlag; - } - } else { - // end of sfx track - restore ssg music channel - _flags |= CHS_EOT; - _drv->_finishedSfxFlag |= _idFlag; - _drv->_ssgChannels[_chanNum]->restore(); - } - - return false; -} - -void TownsPC98_OpnSfxChannel::loadData(uint8 *data) { - _flags = CHS_ALLOFF; - _ticksLeft = 1; - _dataPtr = data; - _ssgTl = 0xff; - _algorithm = 0x80; - - uint8 *tmp = _dataPtr; - for (bool loop = true; loop; ) { - uint8 cmd = *tmp++; - if (cmd < 0xf0) { - tmp++; - } else if (cmd == 0xff) { - loop = false; - } else if (cmd == 0xf6) { - // reset repeat section countdown - tmp[0] = tmp[1]; - tmp += 4; - } else { - tmp += _drv->_opnFxCmdLen[cmd - 240]; - } - } -} - -void TownsPC98_OpnSfxChannel::reset() { - TownsPC98_OpnChannel::reset(); - - // Unlike the original we restore the default patch data. This fixes a bug - // where certain sound effects would bring each other out of tune (e.g. the - // dragon's fire in Darm's house in Kyra 1 would sound different each time - // you triggered another sfx by dropping an item etc.) - uint8 i = (13 + _regOffset) << 4; - const uint8 *src = &_drv->_drvTables[156]; - _drv->_ssgPatches[i] = src[i]; - _drv->_ssgPatches[i + 3] = src[i + 3]; - _drv->_ssgPatches[i + 4] = src[i + 4]; - _drv->_ssgPatches[i + 6] = src[i + 6]; - _drv->_ssgPatches[i + 8] = src[i + 8]; - _drv->_ssgPatches[i + 12] = src[i + 12]; -} - -TownsPC98_OpnChannelPCM::TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : - TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) { -} - -void TownsPC98_OpnChannelPCM::init() { - _algorithm = 0x80; - - #define Control(x) &TownsPC98_OpnChannelPCM::control_##x - static const ControlEventFunc ctrlEventsPCM[] = { - Control(dummy), - Control(f1_prcStart), - Control(dummy), - Control(dummy), - Control(dummy), - Control(dummy), - Control(f6_repeatSection), - Control(dummy), - Control(dummy), - Control(dummy), - Control(fa_writeReg), - Control(dummy), - Control(dummy), - Control(dummy), - Control(dummy), - Control(ff_endOfTrack) - }; - #undef Control - - controlEvents = ctrlEventsPCM; -} - -void TownsPC98_OpnChannelPCM::loadData(uint8 *data) { - _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; - _ticksLeft = 1; - _dataPtr = data; - _totalLevel = 0x7F; -} - -void TownsPC98_OpnChannelPCM::processEvents() { - if (_flags & CHS_EOT) - return; - - if (--_ticksLeft) - return; - - uint8 cmd = 0; - bool loop = true; - - while (loop) { - cmd = *_dataPtr++; - if (cmd == 0x80) { - loop = false; - } else if (cmd < 0xf0) { - _drv->writeReg(_part, 0x10, cmd); - } else if (!processControlEvent(cmd)) { - return; - } - } - - _ticksLeft = *_dataPtr++; -} - -bool TownsPC98_OpnChannelPCM::processControlEvent(uint8 cmd) { - uint8 para = *_dataPtr++; - return (this->*controlEvents[cmd & 0x0f])(para); -} - -bool TownsPC98_OpnChannelPCM::control_f1_prcStart(uint8 para) { - _totalLevel = para; - _drv->writeReg(_part, 0x11, para); - return true; -} - -bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) { - uint16 val = READ_LE_UINT16(--_dataPtr); - if (val) { - // loop - _dataPtr = _drv->_trackPtr + val; - return true; - } else { - // quit parsing for active channel - --_dataPtr; - _flags |= CHS_EOT; - _drv->_finishedRhythmFlag |= _idFlag; - return false; - } -} - -TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : _tlTable(0), - _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1), - _nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true), - _timer(0), _noiseGenerator(0), _chanEnable(0), - _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { - - memset(_channels, 0, sizeof(_channels)); - memset(_updateRequestBuf, 0, sizeof(_updateRequestBuf)); - _reg = new uint8 *[11]; - - _reg[0] = &_channels[0].frqL; - _reg[1] = &_channels[0].frqH; - _reg[2] = &_channels[1].frqL; - _reg[3] = &_channels[1].frqH; - _reg[4] = &_channels[2].frqL; - _reg[5] = &_channels[2].frqH; - _reg[6] = &_noiseGenerator; - _reg[7] = &_chanEnable; - _reg[8] = &_channels[0].vol; - _reg[9] = &_channels[1].vol; - _reg[10] = &_channels[2].vol; - - reset(); -} - -TownsPC98_OpnSquareSineSource::~TownsPC98_OpnSquareSineSource() { - delete[] _tlTable; - delete[] _tleTable; - delete[] _reg; -} - -void TownsPC98_OpnSquareSineSource::init(const int *rsTable, const int *rseTable) { - if (_ready) { - reset(); - return; - } - - delete[] _tlTable; - delete[] _tleTable; - _tlTable = new int32[16]; - _tleTable = new int32[32]; - float a, b, d; - d = 801.0f; - - for (int i = 0; i < 16; i++) { - b = 1.0f / rsTable[i]; - a = 1.0f / d + b + 1.0f / 1000.0f; - float v = (b / a) * 32767.0f; - _tlTable[i] = (int32) v; - - b = 1.0f / rseTable[i]; - a = 1.0f / d + b + 1.0f / 1000.0f; - v = (b / a) * 32767.0f; - _tleTable[i] = (int32) v; - } - - for (int i = 16; i < 32; i++) { - b = 1.0f / rseTable[i]; - a = 1.0f / d + b + 1.0f / 1000.0f; - float v = (b / a) * 32767.0f; - _tleTable[i] = (int32) v; - } - - _ready = true; -} - -void TownsPC98_OpnSquareSineSource::reset() { - _rand = 1; - _outN = 1; - _updateRequest = -1; - _nTick = _evpUpdateCnt = 0; - _evpTimer = 0x1f; - _pReslt = 0x1f; - _attack = 0; - _cont = false; - _evpUpdate = true; - _timer = 0; - - for (int i = 0; i < 3; i++) { - _channels[i].tick = 0; - _channels[i].smp = _channels[i].out = 0; - } - - for (int i = 0; i < 14; i++) - writeReg(i, 0, true); - - writeReg(7, 0xbf, true); -} - -void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { - if (!_ready) - return; - - if (address > 10 || *_reg[address] == value) { - if ((address == 11 || address == 12 || address == 13) && value) - warning("TownsPC98_OpnSquareSineSource: unsupported reg address: %d", address); - return; - } - - if (!force) { - if (_updateRequest >= 63) { - warning("TownsPC98_OpnSquareSineSource: event buffer overflow"); - _updateRequest = -1; - } - _updateRequestBuf[++_updateRequest] = value; - _updateRequestBuf[++_updateRequest] = address; - return; - } - - *_reg[address] = value; -} - -void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { - if (!_ready) - return; - - for (uint32 i = 0; i < bufferSize; i++) { - _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; - - if (++_nTick >= (_noiseGenerator & 0x1f)) { - if ((_rand + 1) & 2) - _outN ^= 1; - - _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); - _nTick = 0; - } - - for (int ii = 0; ii < 3; ii++) { - if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) { - _channels[ii].tick = 0; - _channels[ii].smp ^= 1; - } - _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1)); - } - - if (_evpUpdate) { - if (++_evpUpdateCnt >= 0) { - _evpUpdateCnt = 0; - - if (--_evpTimer < 0) { - if (_cont) { - _evpTimer &= 0x1f; - } else { - _evpUpdate = false; - _evpTimer = 0; - } - } - } - } - _pReslt = _evpTimer ^ _attack; - updateRegs(); - } - - int32 finOut = 0; - for (int ii = 0; ii < 3; ii++) { - int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; - - if ((1 << ii) & _volMaskA) - finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume; - - if ((1 << ii) & _volMaskB) - finOutTemp = (finOutTemp * _volumeB) / Audio::Mixer::kMaxMixerVolume; - - finOut += finOutTemp; - } - - finOut /= 3; - - buffer[i << 1] += finOut; - buffer[(i << 1) + 1] += finOut; - } -} - -void TownsPC98_OpnSquareSineSource::updateRegs() { - for (int i = 0; i < _updateRequest;) { - uint8 b = _updateRequestBuf[i++]; - uint8 a = _updateRequestBuf[i++]; - writeReg(a, b, true); - } - _updateRequest = -1; -} - -TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) : - _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { - - memset(_rhChan, 0, sizeof(RhtChannel) * 6); - _reg = new uint8 *[40]; - - _reg[0] = _reg[1] = _reg[2] = _reg[3] = _reg[4] = _reg[5] = _reg[6] = _reg[7] = _reg[8] = _reg[9] = _reg[10] = _reg[11] = _reg[12] = _reg[13] = _reg[14] = _reg[15] = 0; - _reg[16] = &_rhChan[0].startPosL; - _reg[17] = &_rhChan[1].startPosL; - _reg[18] = &_rhChan[2].startPosL; - _reg[19] = &_rhChan[3].startPosL; - _reg[20] = &_rhChan[4].startPosL; - _reg[21] = &_rhChan[5].startPosL; - _reg[22] = &_rhChan[0].startPosH; - _reg[23] = &_rhChan[1].startPosH; - _reg[24] = &_rhChan[2].startPosH; - _reg[25] = &_rhChan[3].startPosH; - _reg[26] = &_rhChan[4].startPosH; - _reg[27] = &_rhChan[5].startPosH; - _reg[28] = &_rhChan[0].endPosL; - _reg[29] = &_rhChan[1].endPosL; - _reg[30] = &_rhChan[2].endPosL; - _reg[31] = &_rhChan[3].endPosL; - _reg[32] = &_rhChan[4].endPosL; - _reg[33] = &_rhChan[5].endPosL; - _reg[34] = &_rhChan[0].endPosH; - _reg[35] = &_rhChan[1].endPosH; - _reg[36] = &_rhChan[2].endPosH; - _reg[37] = &_rhChan[3].endPosH; - _reg[38] = &_rhChan[4].endPosH; - _reg[39] = &_rhChan[5].endPosH; -} - -void TownsPC98_OpnPercussionSource::init(const uint8 *instrData) { - if (_ready) { - reset(); - return; - } - - const uint8 *start = instrData; - const uint8 *pos = start; - - if (instrData) { - for (int i = 0; i < 6; i++) { - _rhChan[i].data = start + READ_BE_UINT16(pos); - pos += 2; - _rhChan[i].size = READ_BE_UINT16(pos); - pos += 2; - } - reset(); - _ready = true; - } else { - memset(_rhChan, 0, sizeof(RhtChannel) * 6); - _ready = false; - } -} - -void TownsPC98_OpnPercussionSource::reset() { - _timer = 0; - _totalLevel = 63; - - for (int i = 0; i < 6; i++) { - RhtChannel *s = &_rhChan[i]; - s->pos = s->start = s->data; - s->end = s->data + s->size; - s->active = false; - s->level = 0; - s->out = 0; - s->decStep = 1; - s->decState = 0; - s->samples[0] = s->samples[1] = 0; - s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0; - } -} - -void TownsPC98_OpnPercussionSource::writeReg(uint8 address, uint8 value) { - if (!_ready) - return; - - uint8 h = address >> 4; - uint8 l = address & 15; - - if (address > 15) - *_reg[address] = value; - - if (address == 0) { - if (value & 0x80) { - //key off - for (int i = 0; i < 6; i++) { - if ((value >> i) & 1) - _rhChan[i].active = false; - } - } else { - //key on - for (int i = 0; i < 6; i++) { - if ((value >> i) & 1) { - RhtChannel *s = &_rhChan[i]; - s->pos = s->start; - s->active = true; - s->out = 0; - s->samples[0] = s->samples[1] = 0; - s->decStep = 1; - s->decState = 0; - } - } - } - } else if (address == 1) { - // total level - _totalLevel = (value & 63) ^ 63; - for (int i = 0; i < 6; i++) - recalcOuput(&_rhChan[i]); - } else if (!h && l & 8) { - // instrument level - l &= 7; - _rhChan[l].level = (value & 0x1f) ^ 0x1f; - recalcOuput(&_rhChan[l]); - } else if (h & 3) { - l &= 7; - if (h == 1) { - // set start offset - _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8); - } else if (h == 2) { - // set end offset - _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255; - } - } -} - -void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { - if (!_ready) - return; - - for (uint32 i = 0; i < bufferSize; i++) { - _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; - - for (int ii = 0; ii < 6; ii++) { - RhtChannel *s = &_rhChan[ii]; - if (s->active) { - recalcOuput(s); - if (s->decStep) { - advanceInput(s); - if (s->pos == s->end) - s->active = false; - } - s->decStep ^= 1; - } - } - } - - int32 finOut = 0; - - for (int ii = 0; ii < 6; ii++) { - if (_rhChan[ii].active) - finOut += _rhChan[ii].out; - } - - finOut <<= 1; - - if (1 & _volMaskA) - finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; - - if (1 & _volMaskB) - finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; - - buffer[i << 1] += finOut; - buffer[(i << 1) + 1] += finOut; - } -} - -void TownsPC98_OpnPercussionSource::recalcOuput(RhtChannel *ins) { - uint32 s = _totalLevel + ins->level; - uint32 x = s > 62 ? 0 : (1 + (s >> 3)); - int32 y = s > 62 ? 0 : (15 - (s & 7)); - ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; -} - -void TownsPC98_OpnPercussionSource::advanceInput(RhtChannel *ins) { - static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; - - static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, - 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, - 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 - }; - - uint8 cur = (int8) *ins->pos++; - - for (int i = 0; i < 2; i++) { - int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; - ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); - ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48); - cur >>= 4; - } -} - -TownsPC98_OpnCore::TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type) : - _mixer(mixer), - _chanInternal(0), _ssg(0), _prc(0), - _numChan(type == OD_TYPE26 ? 3 : 6), _numSSG(type == OD_TOWNS ? 0 : 3), _hasPercussion(type == OD_TYPE86 ? true : false), - _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), - _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), - _regProtectionFlag(false), _ready(false) { - - memset(&_timers[0], 0, sizeof(OpnTimer)); - memset(&_timers[1], 0, sizeof(OpnTimer)); - _timers[0].cb = &TownsPC98_OpnCore::timerCallbackA; - _timers[1].cb = &TownsPC98_OpnCore::timerCallbackB; - _timerbase = (uint32)(_baserate * 1000000.0f); -} - -TownsPC98_OpnCore::~TownsPC98_OpnCore() { - Common::StackLock lock(_mutex); - _mixer->stopHandle(_soundHandle); - delete _ssg; - delete _prc; - delete[] _chanInternal; - - delete[] _oprRates; - delete[] _oprRateshift; - delete[] _oprFrq; - delete[] _oprAttackDecay; - delete[] _oprSinTbl; - delete[] _oprLevelOut; - delete[] _oprDetune; -} - -bool TownsPC98_OpnCore::init() { - if (_ready) { - reset(); - return true; - } - - generateTables(); - - _chanInternal = new ChanInternal[_numChan]; - for (int i = 0; i < _numChan; i++) { - memset(&_chanInternal[i], 0, sizeof(ChanInternal)); - for (int j = 0; j < 4; ++j) - _chanInternal[i].opr[j] = new TownsPC98_OpnOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); - } - - if (_numSSG) { - _ssg = new TownsPC98_OpnSquareSineSource(_timerbase); - _ssg->init(&_ssgTables[0], &_ssgTables[16]); - } - - if (_hasPercussion) { - _prc = new TownsPC98_OpnPercussionSource(_timerbase); - _prc->init(_percussionData); - } - - _mixer->playStream(Audio::Mixer::kPlainSoundType, - &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - - _ready = true; - - return true; -} - -void TownsPC98_OpnCore::reset() { - for (int i = 0; i < _numChan; i++) { - for (int ii = 0; ii < 4; ii++) - _chanInternal[i].opr[ii]->reset(); - memset(_chanInternal[i].feedbuf, 0, 3); - _chanInternal[i].algorithm = 0; - _chanInternal[i].frqTemp = 0; - _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true; - _chanInternal[i].updateEnvelopeParameters = false; - } - - writeReg(0, 0x27, 0x33); - - if (_ssg) - _ssg->reset(); - - if (_prc) - _prc->reset(); -} - -void TownsPC98_OpnCore::writeReg(uint8 part, uint8 regAddress, uint8 value) { - if (_regProtectionFlag || !_ready) - return; - - static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; - - uint8 h = regAddress & 0xf0; - uint8 l = (regAddress & 0x0f); - - ChanInternal *c = 0; - TownsPC98_OpnOperator **co = 0; - TownsPC98_OpnOperator *o = 0; - - if (regAddress > 0x2F) { - c = &_chanInternal[(l & 3) + 3 * part]; - co = c->opr; - o = c->opr[oprOrdr[(l - (l & 3)) >> 2]]; - } else if (regAddress == 0x28) { - c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)]; - co = c->opr; - } - - switch (h) { - case 0x00: - // ssg - if (_ssg) - _ssg->writeReg(l, value); - break; - case 0x10: - // pcm rhythm channel - if (_prc) - _prc->writeReg(l, value); - break; - case 0x20: - if (l == 8) { - // Key on/off - for (int i = 0; i < 4; i++) { - if ((value >> (4 + i)) & 1) - co[oprOrdr[i]]->keyOn(); - else - co[oprOrdr[i]]->keyOff(); - } - } else if (l == 4) { - // Timer A - _timers[0].value = (_timers[0].value & 0xff00) | value; - } else if (l == 5) { - // Timer A - _timers[0].value = (_timers[0].value & 0xff) | (value << 8); - } else if (l == 6) { - // Timer B - _timers[1].value = value & 0xff; - } else if (l == 7) { - _timers[0].enabled = (value & 1) ? 1 : 0; - _timers[1].enabled = (value & 2) ? 1 : 0; - - float spc = (float)(0x400 - _timers[0].value) / _baserate; - _timers[0].smpPerCb = (int32) spc; - _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); - - spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate; - _timers[1].smpPerCb = (int32) spc; - _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f); - - if (value & 10) { - _timers[0].smpTillCb = _timers[0].smpPerCb; - _timers[0].smpTillCbRem = _timers[0].smpTillCbRem; - } - - if (value & 20) { - _timers[1].smpTillCb = _timers[1].smpPerCb; - _timers[1].smpTillCbRem = _timers[1].smpTillCbRem; - } - } else if (l == 2) { - // LFO - warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); - } else if (l == 10 || l == 11) { - // DAC - warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); - } - break; - - case 0x30: - // detune, multiple - o->detune((value >> 4) & 7); - o->multiple(value & 0x0f); - c->updateEnvelopeParameters = true; - break; - - case 0x40: - // total level - o->totalLevel(value & 0x7f); - break; - - case 0x50: - // rate scaling, attack rate - o->attackRate(value & 0x1f); - if (o->scaleRate(value >> 6)) - c->updateEnvelopeParameters = true; - break; - - case 0x60: - // first decay rate, amplitude modulation - o->decayRate(value & 0x1f); - if (value & 0x80) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); - break; - - case 0x70: - // secondary decay rate - o->sustainRate(value & 0x1f); - break; - - case 0x80: - // secondary amplitude, release rate; - o->sustainLevel(value >> 4); - o->releaseRate(value & 0x0f); - break; - - case 0x90: - warning("TownsPC98_OpnDriver: TRYING TO SSG ENVELOPE SHAPES (NOT SUPPORTED)"); - break; - - case 0xa0: - // frequency - l &= ~3; - if (l == 0) { - c->frqTemp = (c->frqTemp & 0xff00) | value; - c->updateEnvelopeParameters = true; - for (int i = 0; i < 4; i++) - co[i]->frequency(c->frqTemp); - } else if (l == 4) { - c->frqTemp = (c->frqTemp & 0xff) | (value << 8); - } else if (l == 8) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } else if (l == 12) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } - break; - - case 0xb0: - l &= ~3; - if (l == 0) { - // feedback, _algorithm - co[0]->feedbackLevel((value >> 3) & 7); - c->algorithm = value & 7; - } else if (l == 4) { - // stereo, LFO sensitivity - c->enableLeft = value & 0x80 ? true : false; - c->enableRight = value & 0x40 ? true : false; - uint8 ams = (value & 0x3F) >> 3; - if (ams) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); - uint8 fms = value & 3; - if (fms) - warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); - } - break; - - default: - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress); - } -} - -int TownsPC98_OpnCore::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock lock(_mutex); - - memset(buffer, 0, sizeof(int16) * numSamples); - int32 *tmp = new int32[numSamples]; - int32 *tmpStart = tmp; - memset(tmp, 0, sizeof(int32) * numSamples); - int32 samplesLeft = numSamples >> 1; - - while (samplesLeft) { - int32 render = samplesLeft; - - for (int i = 0; i < 2; i++) { - if (_timers[i].enabled && _timers[i].cb) { - if (!_timers[i].smpTillCb) { - (this->*_timers[i].cb)(); - _timers[i].smpTillCb = _timers[i].smpPerCb; - - _timers[i].smpTillCbRem += _timers[i].smpPerCbRem; - if (_timers[i].smpTillCbRem >= _timerbase) { - _timers[i].smpTillCb++; - _timers[i].smpTillCbRem -= _timerbase; - } - } - render = MIN(render, _timers[i].smpTillCb); - } - } - - samplesLeft -= render; - - for (int i = 0; i < 2; i++) { - if (_timers[i].enabled && _timers[i].cb) { - _timers[i].smpTillCb -= render; - } - } - - nextTick(tmp, render); - - if (_ssg) - _ssg->nextTick(tmp, render); - if (_prc) - _prc->nextTick(tmp, render); - - for (int i = 0; i < render; ++i) { - int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767); - buffer[i << 1] = (int16) l; - int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767); - buffer[(i << 1) + 1] = (int16) r; - } - - buffer += (render << 1); - tmp += (render << 1); - } - - delete[] tmpStart; - return numSamples; -} - -void TownsPC98_OpnCore::setVolumeIntern(int volA, int volB) { - Common::StackLock lock(_mutex); - _volumeA = volA; - _volumeB = volB; - if (_ssg) - _ssg->setVolumeIntern(volA, volB); - if (_prc) - _prc->setVolumeIntern(volA, volB); -} - -void TownsPC98_OpnCore::setVolumeChannelMasks(int channelMaskA, int channelMaskB) { - Common::StackLock lock(_mutex); - _volMaskA = channelMaskA; - _volMaskB = channelMaskB; - if (_ssg) - _ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan); - if (_prc) - _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); -} - -void TownsPC98_OpnCore::generateTables() { - delete[] _oprRates; - _oprRates = new uint8[128]; - - WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018); - WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018); - memset(_oprRates, 0x90, 32); - memset(_oprRates + 96, 0x80, 32); - uint8 *dst = (uint8 *)_oprRates + 40; - for (int i = 0; i < 40; i += 4) - WRITE_BE_UINT32(dst + i, 0x00081018); - for (int i = 0; i < 48; i += 4) - WRITE_BE_UINT32(dst + i, 0x00081018); - dst += 40; - for (uint8 i = 0; i < 16; i ++) { - uint8 v = (i < 12) ? i : 12; - *dst++ = ((4 + v) << 3); - } - - delete[] _oprRateshift; - _oprRateshift = new uint8[128]; - memset(_oprRateshift, 0, 128); - dst = (uint8 *)_oprRateshift + 32; - for (int i = 11; i; i--) { - memset(dst, i, 4); - dst += 4; - } - - delete[] _oprFrq; - _oprFrq = new uint32[0x1000]; - for (uint32 i = 0; i < 0x1000; i++) - _oprFrq[i] = (uint32)(_baserate * (float)(i << 11)); - - delete[] _oprAttackDecay; - _oprAttackDecay = new uint8[152]; - memset(_oprAttackDecay, 0, 152); - for (int i = 0; i < 36; i++) - WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); - - delete[] _oprSinTbl; - _oprSinTbl = new uint32[1024]; - for (int i = 0; i < 1024; i++) { - double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); - double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; - int32 i_dcb = (int32)(2.0 * d_dcb); - i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); - _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); - } - - delete[] _oprLevelOut; - _oprLevelOut = new int32[0x1a00]; - for (int i = 0; i < 256; i++) { - double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); - int32 val_int = ((int32) val) >> 4; - _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; - _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; - for (int ii = 1; ii < 13; ii++) { - _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; - _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; - } - } - - uint8 *dtt = new uint8[128]; - memset(dtt, 0, 36); - memset(dtt + 36, 1, 8); - memcpy(dtt + 44, _detSrc, 84); - - delete[] _oprDetune; - _oprDetune = new int32[256]; - for (int i = 0; i < 128; i++) { - _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); - _oprDetune[i + 128] = -_oprDetune[i]; - } - - delete[] dtt; -} - -void TownsPC98_OpnCore::nextTick(int32 *buffer, uint32 bufferSize) { - if (!_ready) - return; - - for (int i = 0; i < _numChan; i++) { - TownsPC98_OpnOperator **o = _chanInternal[i].opr; - - if (_chanInternal[i].updateEnvelopeParameters) { - _chanInternal[i].updateEnvelopeParameters = false; - for (int ii = 0; ii < 4 ; ii++) - o[ii]->updatePhaseIncrement(); - } - - for (uint32 ii = 0; ii < bufferSize ; ii++) { - int32 phbuf1, phbuf2, output; - phbuf1 = phbuf2 = output = 0; - - int32 *leftSample = &buffer[ii * 2]; - int32 *rightSample = &buffer[ii * 2 + 1]; - int32 *del = &_chanInternal[i].feedbuf[2]; - int32 *feed = _chanInternal[i].feedbuf; - - switch (_chanInternal[i].algorithm) { - case 0: - o[0]->generateOutput(0, feed, phbuf1); - o[2]->generateOutput(*del, 0, phbuf2); - *del = 0; - o[1]->generateOutput(phbuf1, 0, *del); - o[3]->generateOutput(phbuf2, 0, output); - break; - case 1: - o[0]->generateOutput(0, feed, phbuf1); - o[2]->generateOutput(*del, 0, phbuf2); - o[1]->generateOutput(0, 0, phbuf1); - o[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 2: - o[0]->generateOutput(0, feed, phbuf2); - o[2]->generateOutput(*del, 0, phbuf2); - o[1]->generateOutput(0, 0, phbuf1); - o[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 3: - o[0]->generateOutput(0, feed, phbuf2); - o[2]->generateOutput(0, 0, *del); - o[1]->generateOutput(phbuf2, 0, phbuf1); - o[3]->generateOutput(*del, 0, output); - *del = phbuf1; - break; - case 4: - o[0]->generateOutput(0, feed, phbuf1); - o[2]->generateOutput(0, 0, phbuf2); - o[1]->generateOutput(phbuf1, 0, output); - o[3]->generateOutput(phbuf2, 0, output); - *del = 0; - break; - case 5: - o[0]->generateOutput(0, feed, phbuf1); - o[2]->generateOutput(*del, 0, output); - o[1]->generateOutput(phbuf1, 0, output); - o[3]->generateOutput(phbuf1, 0, output); - *del = phbuf1; - break; - case 6: - o[0]->generateOutput(0, feed, phbuf1); - o[2]->generateOutput(0, 0, output); - o[1]->generateOutput(phbuf1, 0, output); - o[3]->generateOutput(0, 0, output); - *del = 0; - break; - case 7: - o[0]->generateOutput(0, feed, output); - o[2]->generateOutput(0, 0, output); - o[1]->generateOutput(0, 0, output); - o[3]->generateOutput(0, 0, output); - *del = 0; - break; - }; - - int32 finOut = (output << 2) / ((_numChan + _numSSG - 3) / 3); - - if ((1 << i) & _volMaskA) - finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; - - if ((1 << i) & _volMaskB) - finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; - - if (_chanInternal[i].enableLeft) - *leftSample += finOut; - - if (_chanInternal[i].enableRight) - *rightSample += finOut; - } - } -} - -TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : TownsPC98_OpnCore(mixer, type), - _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0), - _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0), - _patches(0), _sfxBuffer(0), _musicBuffer(0), - - _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132), - _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 84)), - - _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), - _updateSSGFlag(type == OD_TOWNS ? 0x00 : 0x07), _finishedSSGFlag(0), - _updateRhythmFlag(type == OD_TYPE86 ? 0x01 : 0x00), _finishedRhythmFlag(0), - _updateSfxFlag(0), _finishedSfxFlag(0), - - _musicTickCounter(0), - - _musicVolume(255), _sfxVolume(255), - - _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { - - _sfxOffsets[0] = _sfxOffsets[1] = 0; -} - -TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { - reset(); - - if (_channels) { - for (int i = 0; i < _numChan; i++) - delete _channels[i]; - delete[] _channels; - } - - if (_ssgChannels) { - for (int i = 0; i < _numSSG; i++) - delete _ssgChannels[i]; - delete[] _ssgChannels; - } - - if (_sfxChannels) { - for (int i = 0; i < 2; i++) - delete _sfxChannels[i]; - delete[] _sfxChannels; - } - - delete _rhythmChannel; - - delete[] _ssgPatches; -} - -bool TownsPC98_OpnDriver::init() { - if (_ready) { - reset(); - return true; - } - - TownsPC98_OpnCore::init(); - - setVolumeChannelMasks(-1, 0); - - _channels = new TownsPC98_OpnChannel *[_numChan]; - for (int i = 0; i < _numChan; i++) { - int ii = i * 6; - _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1], - _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); - _channels[i]->init(); - } - - if (_numSSG) { - _ssgPatches = new uint8[256]; - memcpy(_ssgPatches, _drvTables + 156, 256); - - _ssgChannels = new TownsPC98_OpnChannelSSG *[_numSSG]; - for (int i = 0; i < _numSSG; i++) { - int ii = i * 6; - _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], - _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); - _ssgChannels[i]->init(); - } - - _sfxChannels = new TownsPC98_OpnSfxChannel *[2]; - for (int i = 0; i < 2; i++) { - int ii = (i + 1) * 6; - _sfxChannels[i] = new TownsPC98_OpnSfxChannel(this, _drvTables[ii], _drvTables[ii + 1], - _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); - _sfxChannels[i]->init(); - } - } - - if (_hasPercussion) { - _rhythmChannel = new TownsPC98_OpnChannelPCM(this, 0, 0, 0, 0, 0, 1); - _rhythmChannel->init(); - } - - setMusicTempo(84); - setSfxTempo(654); - - _ready = true; - - return true; -} - -void TownsPC98_OpnDriver::loadMusicData(uint8 *data, bool loadPaused) { - if (!_ready) { - warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); - return; - } - - if (!data) { - warning("TownsPC98_OpnDriver: Invalid music file data"); - return; - } - - reset(); - - Common::StackLock lock(_mutex); - uint8 *src_a = _trackPtr = _musicBuffer = data; - - for (uint8 i = 0; i < 3; i++) { - _channels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - for (int i = 0; i < _numSSG; i++) { - _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - for (uint8 i = 3; i < _numChan; i++) { - _channels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - if (_hasPercussion) { - _rhythmChannel->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - toggleRegProtection(false); - - _patches = src_a + 4; - _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0; - - _musicPlaying = (loadPaused ? false : true); -} - -void TownsPC98_OpnDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { - if (!_ready) { - warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); - return; - } - - if (!_sfxChannels) { - warning("TownsPC98_OpnDriver: Sound effects not supported by this configuration"); - return; - } - - if (!data) { - warning("TownsPC98_OpnDriver: Invalid sound effects file data"); - return; - } - - Common::StackLock lock(_mutex); - _sfxData = _sfxBuffer = data; - _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); - _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); - _sfxPlaying = true; - _finishedSfxFlag = 0; -} - -void TownsPC98_OpnDriver::reset() { - Common::StackLock lock(_mutex); - - _musicPlaying = false; - _sfxPlaying = false; - _fading = false; - _looping = 0; - _musicTickCounter = 0; - _sfxData = 0; - - TownsPC98_OpnCore::reset(); - - for (int i = 0; i < _numChan; i++) - _channels[i]->reset(); - for (int i = 0; i < _numSSG; i++) - _ssgChannels[i]->reset(); - - if (_numSSG) { - for (int i = 0; i < 2; i++) - _sfxChannels[i]->reset(); - - memcpy(_ssgPatches, _drvTables + 156, 256); - } - - if (_rhythmChannel) - _rhythmChannel->reset(); -} - -void TownsPC98_OpnDriver::fadeStep() { - if (!_musicPlaying) - return; - - Common::StackLock lock(_mutex); - for (int j = 0; j < _numChan; j++) { - if (_updateChannelsFlag & _channels[j]->_idFlag) - _channels[j]->fadeStep(); - } - - for (int j = 0; j < _numSSG; j++) { - if (_updateSSGFlag & _ssgChannels[j]->_idFlag) - _ssgChannels[j]->fadeStep(); - } - - if (!_fading) { - _fading = 19; - if (_hasPercussion) { - if (_updateRhythmFlag & _rhythmChannel->_idFlag) - _rhythmChannel->reset(); - } - } else { - if (!--_fading) - reset(); - } -} - -void TownsPC98_OpnDriver::timerCallbackB() { - _sfxOffs = 0; - - if (_musicPlaying) { - _musicTickCounter++; - - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->_idFlag) { - _channels[i]->processEvents(); - _channels[i]->processFrequency(); - } - } - - for (int i = 0; i < _numSSG; i++) { - if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { - _ssgChannels[i]->processEvents(); - _ssgChannels[i]->processFrequency(); - } - } - - if (_hasPercussion) - if (_updateRhythmFlag & _rhythmChannel->_idFlag) - _rhythmChannel->processEvents(); - } - - toggleRegProtection(false); - - if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) - _musicPlaying = false; -} - -void TownsPC98_OpnDriver::timerCallbackA() { - if (_sfxChannels && _sfxPlaying) { - if (_sfxData) - startSoundEffect(); - - _sfxOffs = 3; - _trackPtr = _sfxBuffer; - - for (int i = 0; i < 2; i++) { - if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { - _sfxChannels[i]->processEvents(); - _sfxChannels[i]->processFrequency(); - } - } - - _trackPtr = _musicBuffer; - } - - if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) { - _sfxPlaying = false; - _updateSfxFlag = 0; - setVolumeChannelMasks(-1, 0); - } -} - -void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) { - writeReg(0, 0x26, tempo); - writeReg(0, 0x27, 0x33); -} - -void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) { - writeReg(0, 0x24, tempo & 0xff); - writeReg(0, 0x25, tempo >> 8); - writeReg(0, 0x27, 0x33); -} - -void TownsPC98_OpnDriver::startSoundEffect() { - int volFlags = 0; - - for (int i = 0; i < 2; i++) { - if (_sfxOffsets[i]) { - _ssgChannels[i + 1]->protect(); - _sfxChannels[i]->reset(); - _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); - _updateSfxFlag |= _sfxChannels[i]->_idFlag; - volFlags |= (_sfxChannels[i]->_idFlag << _numChan); - } else { - _ssgChannels[i + 1]->restore(); - _updateSfxFlag &= ~_sfxChannels[i]->_idFlag; - } - } - - setVolumeChannelMasks(~volFlags, volFlags); - _sfxData = 0; -} - -const uint8 TownsPC98_OpnDriver::_drvTables[] = { - // channel presets - 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, - 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, - 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, - 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, - 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, - 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, - - // control event size - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, - 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - - // fmt level presets - 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, - 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, - 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, - - // carriers - 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, - - // pc98 level presets - 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, - 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, - 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90, - - // frequencies - 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, - 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, - 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, - - // ssg frequencies - 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C, - 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09, - 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07, - - // ssg patch data - 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, - 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, - 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, - 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, - 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, - 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, - 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, - 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00, - 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, - 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00, - 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00, - 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - - 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00, - 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00, - 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00, - 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, - 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, - 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, - 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, - 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00 -}; - SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) - : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0), - _sfxFileIndex((uint)-1), _sfxWDTable(0), _sfxBTTable(0), _parser(0) { + : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0), + _sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46) { - _driver = new Towns_EuphonyDriver(_mixer); - int ret = open(); - if (ret != MERR_ALREADY_OPEN && ret != 0) - error("couldn't open midi driver"); + _driver = new TownsEuphonyDriver(_mixer); } SoundTowns::~SoundTowns() { AudioCD.stop(); haltTrack(); + delete[] _musicTrackData; delete[] _sfxFileData; - - Common::StackLock lock(_mutex); - _driver->setTimerCallback(0, 0); - close(); - - _driver = 0; } bool SoundTowns::init() { _vm->checkCD(); int unused = 0; + _musicFadeTable = _vm->staticres()->loadRawData(k1TownsMusicFadeTable, unused); _sfxWDTable = _vm->staticres()->loadRawData(k1TownsSFXwdTable, unused); _sfxBTTable = _vm->staticres()->loadRawData(k1TownsSFXbtTable, unused); + _musicTrackData = new uint8[50570]; + + if (!_driver->init()) + return false; + + if (!loadInstruments()) + return false; - return loadInstruments(); + return true; } void SoundTowns::process() { @@ -3944,8 +92,10 @@ void SoundTowns::playTrack(uint8 track) { if (_musicEnabled == 2 && trackNum != -1) { AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); AudioCD.updateCD(); + _cdaPlaying = true; } else if (_musicEnabled) { playEuphonyTrack(READ_LE_UINT32(&tTable[tTableIndex]), loop); + _cdaPlaying = false; } _lastTrack = track; @@ -3955,15 +105,15 @@ void SoundTowns::haltTrack() { _lastTrack = -1; AudioCD.stop(); AudioCD.updateCD(); - if (_parser) { - Common::StackLock lock(_mutex); - _parser->setTrack(0); - _parser->jumpToTick(0); - _parser->unloadMusic(); - delete _parser; - _parser = 0; - } - _driver->queue()->release(); + _cdaPlaying = false; + + for (int i = 0; i < 6; i++) + _driver->chanVolume(i, 0); + for (int i = 0x40; i < 0x46; i++) + _driver->chanVolume(i, 0); + for (int i = 0; i < 32; i++) + _driver->chanEnable(i, 0); + _driver->stopParser(); } void SoundTowns::loadSoundFile(uint file) { @@ -3977,27 +127,26 @@ void SoundTowns::loadSoundFile(uint file) { void SoundTowns::playSoundEffect(uint8 track) { if (!_sfxEnabled || !_sfxFileData) return; - + if (track == 0 || track == 10) { - _mixer->stopHandle(_sfxHandle); + stopAllSoundEffects(); return; } else if (track == 1) { - // sfx fadeout - _mixer->stopHandle(_sfxHandle); + fadeOutSoundEffects(); return; } - uint8 note = 0x3c; + uint8 note = 60; if (_sfxFileIndex == 5) { - if (track == 0x10) { - note = 0x3e; - track = 0x0f; - } else if (track == 0x11) { - note = 0x40; - track = 0x0f; - } else if (track == 0x12) { - note = 0x41; - track = 0x0f; + if (track == 16) { + note = 62; + track = 15; + } else if (track == 17) { + note = 64; + track = 15; + } else if (track == 18) { + note = 65; + track = 15; } } @@ -4006,32 +155,37 @@ void SoundTowns::playSoundEffect(uint8 track) { if (offset == -1) return; - uint32 *sfxHeader = (uint32 *)(fileBody + offset); + if (!_driver->soundEffectIsPlaying(_sfxChannel ^ 1)) { + _sfxChannel ^= 1; + } else if (_driver->soundEffectIsPlaying(_sfxChannel)) { + _sfxChannel ^= 1; + _driver->stopSoundEffect(_sfxChannel); + } + uint32 *sfxHeader = (uint32 *)(fileBody + offset); uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader); - uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]); - uint32 sfxHeaderOutBufferSize = READ_LE_UINT32(&sfxHeader[3]); - uint32 sfxRootNoteOffs = READ_LE_UINT32(&sfxHeader[7]); - uint32 sfxRate = READ_LE_UINT32(&sfxHeader[6]); + uint32 playbackBufferSize = sfxHeaderID == 1 ? 30704 : READ_LE_UINT32(&sfxHeader[3]); - uint32 playbackBufferSize = (sfxHeaderID == 1) ? sfxHeaderInBufferSize : sfxHeaderOutBufferSize; + uint8 *sfxPlaybackBuffer = new uint8[playbackBufferSize + 32]; + memcpy(sfxPlaybackBuffer, fileBody + offset, 32); - uint8 *sfxPlaybackBuffer = (uint8 *)malloc(playbackBufferSize); - memset(sfxPlaybackBuffer, 0x80, playbackBufferSize); + uint8 *dst = sfxPlaybackBuffer + 32; + memset(dst, 0x80, playbackBufferSize); uint8 *sfxBody = ((uint8 *)sfxHeader) + 0x20; if (!sfxHeaderID) { - memcpy(sfxPlaybackBuffer, sfxBody, playbackBufferSize); + memcpy(dst, sfxBody, playbackBufferSize); } else if (sfxHeaderID == 1) { - Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize); + Screen::decodeFrame4(sfxBody, dst, playbackBufferSize); } else if (_sfxWDTable) { - uint8 *tgt = sfxPlaybackBuffer; + uint8 *tgt = dst; uint32 sfx_BtTable_Offset = 0; uint32 sfx_WdTable_Offset = 0; uint32 sfx_WdTable_Number = 5; + uint32 inSize = READ_LE_UINT32(&sfxHeader[1]); - for (uint32 i = 0; i < sfxHeaderInBufferSize; i++) { + for (uint32 i = 0; i < inSize; i++) { sfx_WdTable_Offset = (sfx_WdTable_Number * 3 << 9) + sfxBody[i] * 6; sfx_WdTable_Number = READ_LE_UINT16(_sfxWDTable + sfx_WdTable_Offset); @@ -4043,124 +197,161 @@ void SoundTowns::playSoundEffect(uint8 track) { } } - for (uint32 i = 0; i < playbackBufferSize; i++) { - if (sfxPlaybackBuffer[i] < 0x80) - sfxPlaybackBuffer[i] = 0x80 - sfxPlaybackBuffer[i]; - } - - playbackBufferSize -= 0x20; - - uint32 outputRate = uint32(11025 * calculatePhaseStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); + _driver->chanVolume(_sfxChannel, 127); + _driver->chanStereo(_sfxChannel, 0x40); + _driver->chanPitch(_sfxChannel, 0); + _driver->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer); +} - _currentSFX = Audio::makeRawStream(sfxPlaybackBuffer, playbackBufferSize, - outputRate, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN); - _mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX); +void SoundTowns::stopAllSoundEffects() { + _driver->chanVolume(0x46, 0); + _driver->chanVolume(0x47, 0); + _driver->stopSoundEffect(0x46); + _driver->stopSoundEffect(0x47); + _sfxChannel = 0x46; } void SoundTowns::beginFadeOut() { - _lastTrack = -1; - _driver->fading(); + if (_cdaPlaying) { + for (int i = 118; i > 103; i--) { + _driver->cdaSetVolume(1, i, i); + _vm->delay(2 * _vm->tickLength()); + } - // TODO: this should fade out too - AudioCD.stop(); - AudioCD.updateCD(); -} + for (int i = 103; i > 83; i -= 2) { + _driver->cdaSetVolume(1, i, i); + _vm->delay(2 * _vm->tickLength()); + } -int SoundTowns::open() { - if (!_driver) - return 255; + for (int i = 83; i > 58; i -= 2) { + _driver->cdaSetVolume(1, i, i); + _vm->delay(_vm->tickLength()); + } - int ret = _driver->open(); - if (ret) - return ret; + for (int i = 58; i > 0; i--) + _driver->cdaSetVolume(1, i, i); - _driver->setTimerCallback(this, &onTimer); - return 0; -} + _driver->cdaSetVolume(1, 0, 0); -void SoundTowns::close() { - if (_driver) - _driver->close(); -} + } else { + if (_lastTrack == -1) + return; -void SoundTowns::send(uint32 b) { - _driver->send(b); -} + uint32 ticks = 2; + int tickAdv = 0; + + uint16 fadeVolCur[12]; + uint16 fadeVolStep[12]; + + for (int i = 0; i < 6; i++) { + fadeVolCur[i] = READ_LE_UINT16(&_musicFadeTable[(_lastTrack * 12 + i) * 2]); + fadeVolStep[i] = fadeVolCur[i] / 50; + fadeVolCur[i + 6] = READ_LE_UINT16(&_musicFadeTable[(_lastTrack * 12 + 6 + i) * 2]); + fadeVolStep[i + 6] = fadeVolCur[i + 6] / 30; + } + + for (int i = 0; i < 12; i++) { + for (int ii = 0; ii < 6; ii++) + _driver->chanVolume(ii, fadeVolCur[ii]); + for (int ii = 0x40; ii < 0x46; ii++) + _driver->chanVolume(ii, fadeVolCur[ii - 0x3a]); + + for (int ii = 0; ii < 6; ii++) { + fadeVolCur[ii] -= fadeVolStep[ii]; + if (fadeVolCur[ii] < 10) + fadeVolCur[ii] = 0; + fadeVolCur[ii + 6] -= fadeVolStep[ii + 6]; + if (fadeVolCur[ii + 6] < 10) + fadeVolCur[ii + 6] = 0; + } + + if (++tickAdv == 3) { + tickAdv = 0; + ticks += 2; + } + _vm->delay(ticks * _vm->tickLength()); + } + } -uint32 SoundTowns::getBaseTempo() { - return _driver ? _driver->getBaseTempo() : 0; + haltTrack(); } bool SoundTowns::loadInstruments() { uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); if (!twm) return false; - _driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0); - _driver->loadFmInstruments(_driver->queue()->trackData() + 8); - _driver->queue()->loadDataToCurrentPosition(twm + 0x0CA0, 0xC58A); - _driver->loadWaveInstruments(_driver->queue()->trackData() + 8); + Common::StackLock lock(_mutex); + + Screen::decodeFrame4(twm, _musicTrackData, 50570); + for (int i = 0; i < 128; i++) + _driver->loadInstrument(0, i, &_musicTrackData[i * 48 + 8]); + + Screen::decodeFrame4(twm + 3232, _musicTrackData, 50570); + for (int i = 0; i < 32; i++) + _driver->loadInstrument(0x40, i, &_musicTrackData[i * 128 + 8]); + + _driver->unloadWaveTable(-1); + uint8 *src = &_musicTrackData[32 * 128 + 8]; + for (int i = 0; i < 10; i++) { + _driver->loadWaveTable(src); + src = src + READ_LE_UINT16(&src[12]) + 32; + } + + _driver->reserveSfxChannels(2); + delete[] twm; - _driver->queue()->release(); return true; } void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { - uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); Common::StackLock lock(_mutex); - if (!_parser) { - _parser = new Towns_EuphonyParser(_driver->queue()); - _parser->setMidiDriver(this); - _parser->setTimerRate(getBaseTempo()); - } - - _parser->property(MidiParser::mpAutoLoop, loop); - _parser->loadMusic(twm + 0x4b70 + offset, 0xC58A); - + uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0); + Screen::decodeFrame4(twm + 19312 + offset, _musicTrackData, 50570); delete[] twm; -} -void SoundTowns::onTimer(void *data) { - SoundTowns *music = (SoundTowns *)data; - Common::StackLock lock(music->_mutex); - if (music->_parser) - music->_parser->onTimer(); -} + const uint8 *src = _musicTrackData + 852; + for (int i = 0; i < 32; i++) + _driver->chanEnable(i, *src++); + for (int i = 0; i < 32; i++) + _driver->chanMode(i, *src++); + for (int i = 0; i < 32; i++) + _driver->chanOrdr(i, *src++); + for (int i = 0; i < 32; i++) + _driver->chanLevel(i, *src++); + for (int i = 0; i < 32; i++) + _driver->chanTranspose(i, *src++); + + src = _musicTrackData + 1748; + for (int i = 0; i < 6; i++) + _driver->assignChannel(i, *src++); + for (int i = 0x40; i < 0x46; i++) + _driver->assignChannel(i, *src++); -float SoundTowns::calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, - uint32 sampleRate, uint32 outputRate, int32 pitchWheel) { - if (semiTone < 0) - semiTone = 0; - if (semiTone > 119) - semiTone = 119; - if (semiTone < 0) - semiTone = 0; - if (semiTone > 119) - semiTone = 119; + uint32 trackSize = READ_LE_UINT32(_musicTrackData + 2048); + uint8 startTick = _musicTrackData[2052]; + + _driver->setMusicTempo(_musicTrackData[2053]); - static const float noteFrq[] = { - 0004.13f, 0004.40f, 0004.64f, 0004.95f, 0005.16f, 0005.50f, 0005.80f, 0006.19f, 0006.60f, 0006.86f, - 0007.43f, 0007.73f, 0008.25f, 0008.80f, 0009.28f, 0009.90f, 0010.31f, 0011.00f, 0011.60f, 0012.38f, - 0013.20f, 0013.75f, 0014.85f, 0015.47f, 0016.50f, 0017.60f, 0018.56f, 0019.80f, 0020.63f, 0022.00f, - 0023.21f, 0024.75f, 0026.40f, 0027.50f, 0029.70f, 0030.94f, 0033.00f, 0035.20f, 0037.16f, 0039.60f, - 0041.25f, 0044.00f, 0046.41f, 0049.50f, 0052.80f, 0055.00f, 0059.40f, 0061.88f, 0066.00f, 0070.40f, - 0074.25f, 0079.20f, 0082.50f, 0088.00f, 0092.83f, 0099.00f, 0105.60f, 0110.00f, 0118.80f, 0123.75f, - 0132.00f, 0140.80f, 0148.50f, 0158.40f, 0165.00f, 0176.00f, 0185.65f, 0198.00f, 0211.20f, 0220.00f, - 0237.60f, 0247.50f, 0264.00f, 0281.60f, 0297.00f, 0316.80f, 0330.00f, 0352.00f, 0371.30f, 0396.00f, - 0422.40f, 0440.00f, 0475.20f, 0495.00f, 0528.00f, 0563.20f, 0594.00f, 0633.60f, 0660.00f, 0704.00f, - 0742.60f, 0792.00f, 0844.80f, 0880.00f, 0950.40f, 0990.00f, 1056.00f, 1126.40f, 1188.00f, 1267.20f, - 1320.00f, 1408.00f, 1485.20f, 1584.00f, 1689.60f, 1760.00f, 1900.80f, 1980.00f, 2112.00f, 2252.80f, - 2376.00f, 2534.40f, 2640.00f, 2816.00f, 2970.40f, 3168.00f, 3379.20f, 3520.00f, 3801.60f, 3960.00f - }; + src = _musicTrackData + 2054; + uint32 l = READ_LE_UINT32(src + trackSize); + trackSize += (l + 4); + l = READ_LE_UINT32(src + trackSize); + trackSize += (l + 4); - float pwModifier = (pitchWheel - 0x2000) / 0x2000; - int8 d = pwModifier ? (pwModifier < 0 ? -1 : 1) : 0; - float rateshift = (noteFrq[semiTone] - ((noteFrq[semiTone] - - noteFrq[semiTone + d]) * pwModifier * d)) / noteFrq[semiToneRootkey]; + _driver->setMusicLoop(loop); + _driver->startMusicTrack(src, trackSize, startTick); +} - return (float)sampleRate * 10.0f * rateshift / outputRate; +void SoundTowns::fadeOutSoundEffects() { + for (int i = 127; i > 0; i-= 12) { + _driver->chanVolume(0x46, i); + _driver->chanVolume(0x47, i); + _vm->delay(_vm->tickLength()); + } + stopAllSoundEffects(); } SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) : @@ -4174,7 +365,7 @@ SoundPC98::~SoundPC98() { } bool SoundPC98::init() { - _driver = new TownsPC98_OpnDriver(_mixer, TownsPC98_OpnDriver::OD_TYPE26); + _driver = new TownsPC98_AudioDriver(_mixer, TownsPC98_AudioDriver::kType26); bool reslt = _driver->init(); updateVolumeSettings(); return reslt; @@ -4255,6 +446,7 @@ void SoundPC98::updateVolumeSettings() { return; bool mute = false; + _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume")); if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); @@ -4275,8 +467,8 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); + _driver = new TownsPC98_AudioDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_AudioDriver::kType86 : TownsPC98_AudioDriver::kTypeTowns); if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { _vm->checkCD(); @@ -4437,9 +629,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle, sfx[i] = cmd; } - uint32 outputRate = uint32(11025 * SoundTowns::calculatePhaseStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); - - _currentSFX = Audio::makeRawStream(sfx, outsize, outputRate, + _currentSFX = Audio::makeRawStream(sfx, outsize, 11025, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN); _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h], _currentSFX); if (handle) @@ -4461,6 +651,7 @@ void SoundTownsPC98_v2::updateVolumeSettings() { return; bool mute = false; + _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume")); if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); @@ -4468,158 +659,6 @@ void SoundTownsPC98_v2::updateVolumeSettings() { _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume"))); } -// static resources - -const uint32 TownsPC98_OpnCore::_adtStat[] = { - 0x00010001, 0x00010001, 0x00010001, 0x01010001, - 0x00010101, 0x00010101, 0x00010101, 0x01010101, - 0x01010101, 0x01010101, 0x01010102, 0x01010102, - 0x01020102, 0x01020102, 0x01020202, 0x01020202, - 0x02020202, 0x02020202, 0x02020204, 0x02020204, - 0x02040204, 0x02040204, 0x02040404, 0x02040404, - 0x04040404, 0x04040404, 0x04040408, 0x04040408, - 0x04080408, 0x04080408, 0x04080808, 0x04080808, - 0x08080808, 0x08080808, 0x10101010, 0x10101010 -}; - -const uint8 TownsPC98_OpnCore::_detSrc[] = { - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, - 0x16, 0x16, 0x16, 0x16 -}; - -const int TownsPC98_OpnCore::_ssgTables[] = { - 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, - 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, - 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, - 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, - 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, - 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB -}; - -const uint8 TownsPC98_OpnCore::_percussionData[] = { - 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57, - 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141, - 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139, - 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37, - 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137, - 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33, - 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139, - 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24, - 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144, - 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216, - 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201, - 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128, - 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33, - 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163, - 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249, - 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178, - 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148, - 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161, - 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32, - 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176, - 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140, - 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243, - 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144, - 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129, - 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56, - 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0, - 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58, - 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10, - 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8, - 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179, - 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153, - 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76, - 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193, - 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136, - 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181, - 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11, - 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184, - 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136, - 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180, - 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200, - 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10, - 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49, - 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242, - 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138, - 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171, - 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211, - 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56, - 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0, - 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61, - 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169, - 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243, - 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31, - 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160, - 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9, - 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16, - 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106, - 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144, - 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58, - 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72, - 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136, - 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161, - 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57, - 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147, - 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59, - 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25, - 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24, - 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178, - 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129, - 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63, - 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29, - 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184, - 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159, - 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153, - 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61, - 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220, - 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128, - 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145, - 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130, - 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8, - 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138, - 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176, - 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143, - 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177, - 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18, - 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59, - 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146, - 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0, - 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179, - 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122, - 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226, - 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134, - 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203, - 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151, - 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37, - 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18, - 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62, - 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231, - 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25, - 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60, - 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146, - 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119, - 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172, - 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34, - 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187, - 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21, - 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154, - 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169, - 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41, - 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83, - 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181, - 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73, - 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8 -}; - } // End of namespace Kyra #undef EUPHONY_FADEOUT_TICKS diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 9ad2f50619..274acae22c 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -42,7 +42,7 @@ namespace Kyra { -#define RESFILE_VERSION 70 +#define RESFILE_VERSION 71 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { diff --git a/sound/module.mk b/sound/module.mk index f259f9e91b..caf14be547 100644 --- a/sound/module.mk +++ b/sound/module.mk @@ -36,6 +36,10 @@ MODULE_OBJS := \ softsynth/opl/dbopl.o \ softsynth/opl/dosbox.o \ softsynth/opl/mame.o \ + softsynth/fmtowns_pc98/towns_audio.o \ + softsynth/fmtowns_pc98/towns_euphony.o \ + softsynth/fmtowns_pc98/towns_pc98_driver.o \ + softsynth/fmtowns_pc98/towns_pc98_fmsynth.o \ softsynth/ym2612.o \ softsynth/fluidsynth.o \ softsynth/mt32.o \ diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp new file mode 100644 index 0000000000..0d5a16b35f --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -0,0 +1,1479 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_audio.h" +#include "common/endian.h" + + +class TownsAudio_PcmChannel { +friend class TownsAudioInterface; +public: + TownsAudio_PcmChannel(); + ~TownsAudio_PcmChannel(); + +private: + void loadExtData(uint8 *buffer, uint32 size); + void setupLoop(uint32 start, uint32 len); + void clear(); + + void envAttack(); + void envDecay(); + void envSustain(); + void envRelease(); + + uint8 *curInstrument; + uint8 note; + uint8 velo; + + int8 *data; + int8 *dataEnd; + + int8 *loopEnd; + uint32 loopLen; + + uint16 stepNote; + uint16 stepPitch; + uint16 step; + + uint8 panLeft; + uint8 panRight; + + uint32 pos; + + uint8 envTotalLevel; + uint8 envAttackRate; + uint8 envDecayRate; + uint8 envSustainLevel; + uint8 envSustainRate; + uint8 envReleaseRate; + + int16 envStep; + int16 envCurrentLevel; + + EnvelopeState envState; + + int8 *extData; +}; + +class TownsAudio_WaveTable { +friend class TownsAudioInterface; +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; +}; + +TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), + _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _ready(false) { + +#define INTCB(x) &TownsAudioInterface::intf_##x + static const TownsAudioIntfCallback intfCb[] = { + // 0 + INTCB(reset), + INTCB(keyOn), + INTCB(keyOff), + INTCB(setPanPos), + // 4 + INTCB(setInstrument), + INTCB(loadInstrument), + INTCB(notImpl), + INTCB(setPitch), + // 8 + INTCB(setLevel), + INTCB(chanOff), + INTCB(notImpl), + INTCB(notImpl), + // 12 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 16 + INTCB(notImpl), + INTCB(writeReg), + INTCB(notImpl), + INTCB(bufferedWriteReg), + // 20 + INTCB(readRegBuffer), + INTCB(setTimerA), + INTCB(setTimerB), + INTCB(enableTimerA), + // 24 + INTCB(enableTimerB), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 28 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 32 + INTCB(notImpl), + INTCB(reserveEffectChannels), + INTCB(loadWaveTable), + INTCB(unloadWaveTable), + // 36 + INTCB(notImpl), + INTCB(pcmPlayEffect), + INTCB(notImpl), + INTCB(pcmChanOff), + // 40 + INTCB(pcmEffectPlaying), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 44 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 48 + INTCB(notImpl), + INTCB(notImpl), + INTCB(fmKeyOn), + INTCB(fmKeyOff), + // 52 + INTCB(fmSetPanPos), + INTCB(fmSetInstrument), + INTCB(fmLoadInstrument), + INTCB(notImpl), + // 56 + INTCB(fmSetPitch), + INTCB(fmSetLevel), + INTCB(fmReset), + INTCB(notImpl), + // 60 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 64 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(cdaSetVolume), + // 68 + INTCB(cdaReset), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 72 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 76 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 80 + INTCB(pcmUpdateEnvelopeGenerator), + INTCB(notImpl) + + }; +#undef INTCB + + _intfOpcodes = intfCb; + + memset(_fmSaveReg, 0, sizeof(_fmSaveReg)); + _timerBase = (uint32)(_baserate * 1000000.0f); + _tickLength = 2 * _timerBase; +} + +TownsAudioInterface::~TownsAudioInterface() { + delete[] _fmSaveReg[0]; + delete[] _fmSaveReg[1]; + delete[] _fmInstruments; + delete[] _pcmInstruments; + delete[] _waveTables; + delete[] _pcmChan; +} + +bool TownsAudioInterface::init() { + if (_ready) + return true; + + if (!_drv) + return false; + + if (!TownsPC98_FmSynth::init()) + return false; + + _fmSaveReg[0] = new uint8[256]; + _fmSaveReg[1] = new uint8[256]; + _fmInstruments = new uint8[128 * 48]; + _pcmInstruments = new uint8[32 * 128]; + _waveTables = new TownsAudio_WaveTable[128]; + _pcmChan = new TownsAudio_PcmChannel[8]; + + _timer = 0; + + callback(0); + + _ready = true; + return true; +} + +int TownsAudioInterface::callback(int command, ...) { + va_list args; + va_start(args, command); + + if (command > 81) { + va_end(args); + return 4; + } + + Common::StackLock lock(_mutex); + int res = (this->*_intfOpcodes[command])(args); + + va_end(args); + return res; +} + +void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + 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]; + } + } + } + } + } + + 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 (_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]; + } + } + + buffer[i << 1] += finOutL; + buffer[(i << 1) + 1] += finOutR; + } +} + +void TownsAudioInterface::timerCallbackA() { + Common::StackLock lock(_mutex); + if (_drv && _ready) + _drv->timerCallback(0); +} + +void TownsAudioInterface::timerCallbackB() { + Common::StackLock lock(_mutex); + if (_ready) { + if (_drv) + _drv->timerCallback(1); + for (int i = 0; i < 8; i++) + pcmUpdateEnvelopeGenerator(i); + } +} + +int TownsAudioInterface::intf_reset(va_list &args) { + Common::StackLock lock(_mutex); + fmReset(); + pcmReset(); + cdaReset(); + return 0; +} + +int TownsAudioInterface::intf_keyOn(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo); +} + +int TownsAudioInterface::intf_keyOff(va_list &args) { + int chan = va_arg(args, int); + return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan); +} + +int TownsAudioInterface::intf_setPanPos(va_list &args) { + int chan = va_arg(args, int); + int mode = va_arg(args, int); + return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode); +} + +int TownsAudioInterface::intf_setInstrument(va_list &args) { + int chan = va_arg(args, int); + int instrId = va_arg(args, int); + return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId); +} + +int TownsAudioInterface::intf_loadInstrument(va_list &args) { + int chanType = va_arg(args, int); + int instrId = va_arg(args, int); + uint8 *instrData = va_arg(args, uint8*); + return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData); +} + +int TownsAudioInterface::intf_setPitch(va_list &args) { + int chan = va_arg(args, int); + int16 pitch = (int16)(va_arg(args, int) & 0xffff); + return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch); +} + +int TownsAudioInterface::intf_setLevel(va_list &args) { + int chan = va_arg(args, int); + int lvl = va_arg(args, int); + return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl); +} + +int TownsAudioInterface::intf_chanOff(va_list &args) { + int chan = va_arg(args, int); + return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan); +} + +int TownsAudioInterface::intf_writeReg(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + int val = va_arg(args, int); + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xb6)) + return 3; + + bufferedWriteReg(part, reg, val); + return 0; +} + +int TownsAudioInterface::intf_bufferedWriteReg(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + int val = va_arg(args, int); + + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef)) + return 3; + + _fmSaveReg[part][reg] = val; + return 0; +} + +int TownsAudioInterface::intf_readRegBuffer(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + uint8 *dst = va_arg(args, uint8*); + *dst = 0; + + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef)) + return 3; + + *dst = _fmSaveReg[part][reg]; + return 0; +} + +int TownsAudioInterface::intf_setTimerA(va_list &args) { + int enable = va_arg(args, int); + int tempo = va_arg(args, int); + + if (enable) { + bufferedWriteReg(0, 0x25, tempo & 3); + bufferedWriteReg(0, 0x24, (tempo >> 2) & 0xff); + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x05); + } else { + bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xfa) | 0x10); + } + + return 0; +} + +int TownsAudioInterface::intf_setTimerB(va_list &args) { + int enable = va_arg(args, int); + int tempo = va_arg(args, int); + + if (enable) { + bufferedWriteReg(0, 0x26, tempo & 0xff); + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x0A); + } else { + bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xf5) | 0x20); + } + + return 0; +} + +int TownsAudioInterface::intf_enableTimerA(va_list &args) { + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15); + return 0; +} + +int TownsAudioInterface::intf_enableTimerB(va_list &args) { + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a); + return 0; +} + +int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { + int numChan = va_arg(args, int); + if (numChan > 8) + return 3; + if ((numChan << 13) + _waveTablesTotalDataSize > 65536) + return 5; + + if (numChan == _numReservedChannels) + return 0; + + if (numChan < _numReservedChannels) { + int c = 8 - _numReservedChannels; + for (int i = numChan; i; i--) { + uint8 f = ~_chanFlags[c--]; + _pcmChanEffectPlaying &= f; + } + } else { + int c = 7 - _numReservedChannels; + for (int i = numChan - _numReservedChannels; i; i--) { + uint8 f = ~_chanFlags[c--]; + _pcmChanKeyPressed &= f; + _pcmChanKeyPlaying &= f; + } + } + + static const uint8 reserveChanFlags[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; + _numReservedChannels = numChan; + _pcmChanReserved = reserveChanFlags[_numReservedChannels]; + + return 0; +} + +int TownsAudioInterface::intf_loadWaveTable(va_list &args) { + uint8 *data = va_arg(args, uint8*); + if (_numWaveTables > 127) + return 3; + + TownsAudio_WaveTable w; + w.readHeader(data); + if (!w.size) + return 6; + + if (_waveTablesTotalDataSize + w.size > 65504) + return 5; + + for (int i = 0; i < _numWaveTables; i++) { + if (_waveTables[i].id == w.id) + return 10; + } + + TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++]; + s->readHeader(data); + s->readData(data + 32); + + _waveTablesTotalDataSize += w.size; + + return 0; +} + +int TownsAudioInterface::intf_unloadWaveTable(va_list &args) { + int id = va_arg(args, int); + + if (id == -1) { + for (int i = 0; i < 128; i++) + _waveTables[i].clear(); + _numWaveTables = 0; + _waveTablesTotalDataSize = 0; + } else { + if (_waveTables) { + for (int i = 0; i < _numWaveTables; i++) { + if (_waveTables[i].id == id) { + _numWaveTables--; + _waveTablesTotalDataSize -= _waveTables[i].size; + _waveTables[i].clear(); + for (; i < _numWaveTables; i++) + memcpy(&_waveTables[i], &_waveTables[i + 1], sizeof(TownsAudio_WaveTable)); + return 0; + } + return 9; + } + } + } + + return 0; +} + +int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + uint8 *data = va_arg(args, uint8*); + + if (chan < 0x40 || chan > 0x47) + return 1; + + if (note & 0x80 || velo & 0x80) + return 3; + + chan -= 0x40; + + if (!(_pcmChanReserved & _chanFlags[chan])) + return 7; + + if ((_pcmChanEffectPlaying & _chanFlags[chan])) + return 2; + + TownsAudio_WaveTable w; + w.readHeader(data); + + if (!w.size < (w.loopStart + w.loopLen)) + return 13; + + if (!w.size) + return 6; + + 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]; + + return 0; +} + +int TownsAudioInterface::intf_pcmChanOff(va_list &args) { + int chan = va_arg(args, int); + pcmChanOff(chan); + return 0; +} + +int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) { + int chan = va_arg(args, int); + if (chan < 0x40 || chan > 0x47) + return 1; + chan -= 0x40; + return (_pcmChanEffectPlaying & _chanFlags[chan]) ? true : false; +} + +int TownsAudioInterface::intf_fmKeyOn(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + return fmKeyOn(chan, note, velo); +} + +int TownsAudioInterface::intf_fmKeyOff(va_list &args) { + int chan = va_arg(args, int); + return fmKeyOff(chan); +} + +int TownsAudioInterface::intf_fmSetPanPos(va_list &args) { + int chan = va_arg(args, int); + int mode = va_arg(args, int); + return fmSetPanPos(chan, mode); +} + +int TownsAudioInterface::intf_fmSetInstrument(va_list &args) { + int chan = va_arg(args, int); + int instrId = va_arg(args, int); + return fmSetInstrument(chan, instrId); +} + +int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) { + int instrId = va_arg(args, int); + uint8 *instrData = va_arg(args, uint8*); + return fmLoadInstrument(instrId, instrData); +} + +int TownsAudioInterface::intf_fmSetPitch(va_list &args) { + int chan = va_arg(args, int); + uint16 freq = va_arg(args, int) & 0xffff; + return fmSetPitch(chan, freq); +} + +int TownsAudioInterface::intf_fmSetLevel(va_list &args) { + int chan = va_arg(args, int); + int lvl = va_arg(args, int); + return fmSetLevel(chan, lvl); +} + +int TownsAudioInterface::intf_fmReset(va_list &args) { + fmReset(); + return 0; +} + +int TownsAudioInterface::intf_cdaReset(va_list &args) { + cdaReset(); + return 0; +} + +int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { + for (int i = 0; i < 8; i++) + pcmUpdateEnvelopeGenerator(i); + return 0; +} + +int TownsAudioInterface::intf_cdaSetVolume(va_list &args) { + /*int unk = va_arg(args, int); + int volume1 = va_arg(args, int); + int volume2 = va_arg(args, int);*/ + return 0; +} + +int TownsAudioInterface::intf_notImpl(va_list &args) { + return 4; +} + +void TownsAudioInterface::fmReset() { + TownsPC98_FmSynth::reset(); + + _fmChanPlaying = 0; + memset(_fmChanNote, 0, sizeof(_fmChanNote)); + memset(_fmChanPitch, 0, sizeof(_fmChanPitch)); + + memset(_fmSaveReg[0], 0, 240); + memset(&_fmSaveReg[0][240], 0x7f, 16); + memset(_fmSaveReg[1], 0, 256); + memset(&_fmSaveReg[1][240], 0x7f, 16); + _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = + _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff; + + for (int i = 0; i < 128; i++) + fmLoadInstrument(i, _fmDefaultInstrument); + + bufferedWriteReg(0, 0x21, 0); + bufferedWriteReg(0, 0x2C, 0x80); + bufferedWriteReg(0, 0x2B, 0); + bufferedWriteReg(0, 0x27, 0x30); + + for (int i = 0; i < 6; i++) { + fmKeyOff(i); + fmSetInstrument(i, 0); + fmSetLevel(i, 127); + } +} + +int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { + if (chan > 5) + return 1; + if (note < 12 || note > 107 || (velo & 0x80)) + return 3; + if (_fmChanPlaying & _chanFlags[chan]) + return 2; + + _fmChanPlaying |= _chanFlags[chan]; + note -= 12; + + _fmChanNote[chan] = note; + int16 pitch = _fmChanPitch[chan]; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + int frq = 0; + uint8 bl = 0; + + if (note) { + frq = _frequency[(note - 1) % 12]; + bl = (note - 1) / 12; + } else { + frq = 616; + } + + frq += pitch; + + if (frq < 616) { + if (!bl) { + frq = 616; + } else { + frq += 616; + --bl; + } + } else if (frq > 1232) { + if (bl == 7) { + frq = 15500; + } else { + frq -= 616; + ++bl; + } + } + + frq |= (bl << 11); + + bufferedWriteReg(part, chan + 0xa4, (frq >> 8) & 0xff); + bufferedWriteReg(part, chan + 0xa0, frq & 0xff); + + velo = (velo >> 2) + 96; + uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7]; + _fmSaveReg[part][0xe0 + chan] = velo; + + for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) { + c += c; + if (c & 0x100) { + c &= 0xff; + bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * velo) >> 7) + 1) * _fmSaveReg[part][0xd0 + chan]) >> 7) + 1) ^ 0x7f); + } + } + + uint8 v = chan; + if (part) + v |= 4; + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); + + writeReg(0, 0x28, v); + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg]); + + bufferedWriteReg(0, 0x28, v | 0xf0); + + return 0; +} + +int TownsAudioInterface::fmKeyOff(int chan) { + if (chan > 5) + return 1; + _fmChanPlaying &= ~_chanFlags[chan]; + if (chan > 2) + chan++; + bufferedWriteReg(0, 0x28, chan); + return 0; +} + +int TownsAudioInterface::fmChanOff(int chan) { + if (chan > 5) + return 1; + _fmChanPlaying &= ~_chanFlags[chan]; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); + + if (part) + chan += 4; + writeReg(0, 0x28, chan); + return 0; +} + +int TownsAudioInterface::fmSetPanPos(int chan, int value) { + if (chan > 5) + return 1; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + if (value > 0x40) + value = 0x40; + else if (value < 0x40) + value = 0x80; + else + value = 0xC0; + + bufferedWriteReg(part, 0xb4 + chan, (_fmSaveReg[part][0xb4 + chan] & 0x3f) | value); + return 0; +} + +int TownsAudioInterface::fmSetInstrument(int chan, int instrId) { + if (chan > 5) + return 1; + if (instrId > 127) + return 3; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + uint8 *src = &_fmInstruments[instrId * 48 + 8]; + + uint16 c = _carrier[src[24] & 7]; + uint8 reg = 0x30 + chan; + + for (; reg < 0x40; reg += 4) + bufferedWriteReg(part, reg, *src++); + + for (; reg < 0x50; reg += 4) { + uint8 v = *src++; + _fmSaveReg[part][0x80 + reg] = _fmSaveReg[part][reg] = v; + c += c; + if (c & 0x100) { + c &= 0xff; + v = 127; + } + writeReg(part, reg, v); + } + + for (; reg < 0x90; reg += 4) + bufferedWriteReg(part, reg, *src++); + + reg += 0x20; + bufferedWriteReg(part, reg, *src++); + + uint8 v = *src++; + reg += 4; + if (v < 64) + v |= (_fmSaveReg[part][reg] & 0xc0); + bufferedWriteReg(part, reg, v); + + return 0; +} + +int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) { + if (instrId > 127) + return 3; + assert(data); + memcpy(&_fmInstruments[instrId * 48], data, 48); + return 0; +} + +int TownsAudioInterface::fmSetPitch(int chan, int pitch) { + if (chan > 5) + return 1; + + uint8 bl = _fmChanNote[chan]; + int frq = 0; + + if (pitch < 0) { + if (bl) { + if (pitch < -8008) + pitch = -8008; + pitch *= -1; + pitch /= 13; + frq = _frequency[(bl - 1) % 12] - pitch; + bl = (bl - 1) / 12; + _fmChanPitch[chan] = -pitch; + + if (frq < 616) { + if (bl) { + frq += 616; + bl--; + } else { + frq = 616; + bl = 0; + } + } + } else { + frq = 616; + bl = 0; + } + + } else if (pitch > 0) { + if (bl < 96) { + if (pitch > 8008) + pitch = 8008; + pitch /= 13; + + if (bl) { + frq = _frequency[(bl - 1) % 12] + pitch; + bl = (bl - 1) / 12; + } else { + frq = 616; + bl = 0; + } + + _fmChanPitch[chan] = pitch; + + if (frq > 1232) { + if (bl < 7) { + frq -= 616; + bl++; + } else { + frq = 1164; + bl = 7; + } + } else { + if (bl >= 7 && frq > 1164) + frq = 1164; + } + + } else { + frq = 1164; + bl = 7; + } + } else { + _fmChanPitch[chan] = 0; + if (bl) { + frq = _frequency[(bl - 1) % 12]; + bl = (bl - 1) / 12; + } else { + frq = 616; + bl = 0; + } + } + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + frq |= (bl << 11); + + bufferedWriteReg(part, chan + 0xa4, (frq >> 8)); + bufferedWriteReg(part, chan + 0xa0, (frq & 0xff)); + + return 0; +} + +int TownsAudioInterface::fmSetLevel(int chan, int lvl) { + if (chan > 5) + return 1; + if (lvl > 127) + return 3; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7]; + _fmSaveReg[part][0xd0 + chan] = lvl; + + for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) { + c += c; + if (c & 0x100) { + c &= 0xff; + bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * lvl) >> 7) + 1) * _fmSaveReg[part][0xe0 + chan]) >> 7) + 1) ^ 0x7f); + } + } + return 0; +} + +void TownsAudioInterface::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { + _fmSaveReg[part][regAddress] = value; + writeReg(part, regAddress, value); +} + +void TownsAudioInterface::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(); + + memset(_pcmInstruments, 0, 128 * 32); + static uint8 name[] = { 0x4E, 0x6F, 0x20, 0x44, 0x61, 0x74, 0x61, 0x21 }; + for (int i = 0; i < 32; i++) + memcpy(_pcmInstruments + i * 128, name, 8); + + for (int i = 0; i < 128; i++) + _waveTables[i].clear(); + _numWaveTables = 0; + _waveTablesTotalDataSize = 0; + + for (int i = 0x40; i < 0x48; i++) { + pcmSetInstrument(i, 0); + pcmSetLevel(i, 127); + } +} + +int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { + if (chan < 0x40 || chan > 0x47) + return 1; + + if (note & 0x80 || velo & 0x80) + return 3; + + chan -= 0x40; + + if ((_pcmChanReserved & _chanFlags[chan]) || (_pcmChanKeyPressed & _chanFlags[chan])) + return 2; + + _pcmChanNote[chan] = note; + _pcmChanVelo[chan] = velo; + + 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; + + p->envAttack(); + p->velo = (p->envCurrentLevel >> 8) << 1; + + _pcmChanKeyPressed |= _chanFlags[chan]; + _pcmChanKeyPlaying |= _chanFlags[chan]; + _pcmChanOut |= _chanFlags[chan]; + + return 0; +} + +int TownsAudioInterface::pcmKeyOff(int chan) { + if (chan < 0x40 || chan > 0x47) + return 1; + + chan -= 0x40; + _pcmChanKeyPressed &= ~_chanFlags[chan]; + _pcmChan[chan].envRelease(); + return 0; +} + +int TownsAudioInterface::pcmChanOff(int chan) { + if (chan < 0x40 || chan > 0x47) + return 1; + + chan -= 0x40; + + _pcmChanKeyPressed &= ~_chanFlags[chan]; + _pcmChanEffectPlaying &= ~_chanFlags[chan]; + _pcmChanKeyPlaying &= ~_chanFlags[chan]; + _pcmChanOut &= ~_chanFlags[chan]; + + return 0; +} + +int TownsAudioInterface::pcmSetPanPos(int chan, int mode) { + if (chan > 0x47) + return 1; + if (mode & 0x80) + return 3; + + chan -= 0x40; + uint8 blc = 0x77; + + if (mode > 64) { + mode -= 64; + blc = ((blc ^ (mode >> 3)) + (mode << 4)) & 0xff; + } else if (mode < 64) { + mode = (mode >> 3) ^ 7; + blc = ((119 + mode) ^ (mode << 4)) & 0xff; + } + + _pcmChan[chan].panLeft = blc & 0x0f; + _pcmChan[chan].panRight = blc >> 4; + + return 0; +} + +int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) { + if (chan > 0x47) + return 1; + if (instrId > 31) + return 3; + chan -= 0x40; + _pcmChan[chan].curInstrument = &_pcmInstruments[instrId * 128]; + return 0; +} + +int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) { + if (instrId > 31) + return 3; + assert(data); + memcpy(&_pcmInstruments[instrId * 128], data, 128); + return 0; +} + +int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { + if (chan > 0x47) + return 1; + + if (pitch < -8192 || pitch > 8191) + return 3; + + chan -= 0x40; + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + + uint32 pts = 0x4000; + + if (pitch < 0) + pts = (0x20000000 / (-pitch + 0x2001)) >> 2; + 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; + + return 0; +} + +int TownsAudioInterface::pcmSetLevel(int chan, int lvl) { + if (chan > 0x47) + return 1; + + if (lvl & 0x80) + 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; + } + + return 0; +} + +void TownsAudioInterface::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 TownsAudioInterface::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 TownsAudioInterface::cdaReset() { + +} + +const uint8 TownsAudioInterface::_chanFlags[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 +}; + +const uint16 TownsAudioInterface::_frequency[] = { + 0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0 +}; + +const uint8 TownsAudioInterface::_carrier[] = { + 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0 +}; + +const uint8 TownsAudioInterface::_fmDefaultInstrument[] = { + 0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01, + 0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08, + 0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint16 TownsAudioInterface::_pcmPhase1[] = { + 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 +}; + +const uint16 TownsAudioInterface::_pcmPhase2[] = { + 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC +}; + +TownsAudio_PcmChannel::TownsAudio_PcmChannel() { + extData = 0; + clear(); +} + +TownsAudio_PcmChannel::~TownsAudio_PcmChannel() { + clear(); +} + +void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) { + delete[] extData; + extData = new int8[size]; + int8 *src = (int8*)buffer; + int8 *dst = extData; + for (uint32 i = 0; i < size; i++) + *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; + + 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; +} + +void TownsAudio_PcmChannel::clear() { + curInstrument = 0; + note = 0; + velo = 0; + + data = 0; + dataEnd = 0; + loopLen = 0; + + pos = 0; + loopEnd = 0; + + step = 0; + stepNote = 0x4000; + stepPitch = 0x4000; + + panLeft = panRight = 0; + + envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = + envSustainRate = envReleaseRate = 0; + envStep = envCurrentLevel = 0; + + envState = kEnvReady; + + delete[] extData; + extData = 0; +} + +void TownsAudio_PcmChannel::envAttack() { + envState = kEnvAttacking; + int16 t = envTotalLevel << 8; + if (envAttackRate == 127) { + envStep = 0; + } else if (envAttackRate) { + envStep = t / envAttackRate; + envCurrentLevel = 1; + } else { + 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; + } else { + envCurrentLevel = envSustainLevel << 8; + envSustain(); + } +} + +void TownsAudio_PcmChannel::envSustain() { + envState = kEnvSustaining; + if (envSustainLevel && envSustainRate) + envStep = (envSustainRate == 127) ? 0 : (envCurrentLevel / envSustainRate) >> 1; + else + envStep = envCurrentLevel = 1; +} + +void TownsAudio_PcmChannel::envRelease() { + envState = kEnvReleasing; + if (envReleaseRate == 127) + envStep = 0; + else if (envReleaseRate) + envStep = envCurrentLevel / envReleaseRate; + else + envStep = envCurrentLevel = 1; +} + +TownsAudio_WaveTable::TownsAudio_WaveTable() { + data = 0; + clear(); +} + +TownsAudio_WaveTable::~TownsAudio_WaveTable() { + clear(); +} + +void TownsAudio_WaveTable::readHeader(const uint8 *buffer) { + memcpy(name, buffer, 8); + name[8] = 0; + id = READ_LE_UINT32(&buffer[8]); + size = READ_LE_UINT32(&buffer[12]); + loopStart = READ_LE_UINT32(&buffer[16]); + loopLen = READ_LE_UINT32(&buffer[20]); + rate = READ_LE_UINT16(&buffer[24]); + rateOffs = READ_LE_UINT16(&buffer[26]); + baseNote = READ_LE_UINT32(&buffer[28]); +} + +void TownsAudio_WaveTable::readData(const uint8 *buffer) { + if (!size) + return; + + delete[] data; + data = new int8[size]; + + const int8 *src = (const int8*)buffer; + int8 *dst = data; + for (uint32 i = 0; i < size; i++) + *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; +} + +void TownsAudio_WaveTable::clear() { + name[0] = name[8] = 0; + id = -1; + size = 0; + loopStart = 0; + loopLen = 0; + rate = 0; + rateOffs = 0; + baseNote = 0; + delete[] data; + data = 0; +} + diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h new file mode 100644 index 0000000000..82d390d9b6 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -0,0 +1,162 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_AUDIO_H +#define TOWNS_AUDIO_H + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" + +class TownsAudioInterfacePluginDriver { +public: + virtual void timerCallback(int timerId) = 0; +}; + +class TownsAudio_PcmChannel; +class TownsAudio_WaveTable; + +class TownsAudioInterface : public TownsPC98_FmSynth { +public: + TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); + ~TownsAudioInterface(); + + bool init(); + + int callback(int command, ...); + +private: + void nextTickEx(int32 *buffer, uint32 bufferSize); + + void timerCallbackA(); + void timerCallbackB(); + + typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list&); + const TownsAudioIntfCallback *_intfOpcodes; + + int intf_reset(va_list &args); + int intf_keyOn(va_list &args); + int intf_keyOff(va_list &args); + int intf_setPanPos(va_list &args); + int intf_setInstrument(va_list &args); + int intf_loadInstrument(va_list &args); + int intf_setPitch(va_list &args); + int intf_setLevel(va_list &args); + int intf_chanOff(va_list &args); + int intf_writeReg(va_list &args); + int intf_bufferedWriteReg(va_list &args); + int intf_readRegBuffer(va_list &args); + int intf_setTimerA(va_list &args); + int intf_setTimerB(va_list &args); + int intf_enableTimerA(va_list &args); + int intf_enableTimerB(va_list &args); + int intf_reserveEffectChannels(va_list &args); + int intf_loadWaveTable(va_list &args); + int intf_unloadWaveTable(va_list &args); + int intf_pcmPlayEffect(va_list &args); + int intf_pcmChanOff(va_list &args); + int intf_pcmEffectPlaying(va_list &args); + int intf_fmKeyOn(va_list &args); + int intf_fmKeyOff(va_list &args); + int intf_fmSetPanPos(va_list &args); + int intf_fmSetInstrument(va_list &args); + int intf_fmLoadInstrument(va_list &args); + int intf_fmSetPitch(va_list &args); + int intf_fmSetLevel(va_list &args); + int intf_fmReset(va_list &args); + int intf_cdaSetVolume(va_list &args); + int intf_cdaReset(va_list &args); + int intf_pcmUpdateEnvelopeGenerator(va_list &args); + + int intf_notImpl(va_list &args); + + void fmReset(); + int fmKeyOn(int chan, int note, int velo); + int fmKeyOff(int chan); + int fmChanOff(int chan); + int fmSetPanPos(int chan, int mode); + int fmSetInstrument(int chan, int instrId); + int fmLoadInstrument(int instrId, const uint8 *data); + int fmSetPitch(int chan, int pitch); + int fmSetLevel(int chan, int lvl); + + void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value); + + uint8 _fmChanPlaying; + uint8 _fmChanNote[6]; + int16 _fmChanPitch[6]; + + uint8 *_fmSaveReg[2]; + uint8 *_fmInstruments; + + void pcmReset(); + int pcmKeyOn(int chan, int note, int velo); + int pcmKeyOff(int chan); + int pcmChanOff(int chan); + int pcmSetPanPos(int chan, int mode); + int pcmSetInstrument(int chan, int instrId); + 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; + + TownsAudio_WaveTable *_waveTables; + uint8 _numWaveTables; + uint32 _waveTablesTotalDataSize; + + void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); + + void cdaReset(); + + const float _baserate; + uint32 _timerBase; + uint32 _tickLength; + uint32 _timer; + + TownsAudioInterfacePluginDriver *_drv; + bool _ready; + + static const uint8 _chanFlags[]; + static const uint16 _frequency[]; + static const uint8 _carrier[]; + static const uint8 _fmDefaultInstrument[]; + static const uint16 _pcmPhase1[]; + static const uint16 _pcmPhase2[]; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp new file mode 100644 index 0000000000..54b5d5b1d6 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -0,0 +1,886 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_euphony.h" +#include "common/endian.h" + +TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0), + _assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0), + _tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0), + _tempoControlMode(0) { + _para[0] = _para[1] = 0; + _intf = new TownsAudioInterface(mixer, this); + resetTempo(); +} + +TownsEuphonyDriver::~TownsEuphonyDriver() { + delete[] _activeChannels; + delete[] _sustainChannels; + delete[] _assignedChannels; + + delete[] _tEnable; + delete[] _tMode; + delete[] _tOrdr; + delete[] _tLevel; + delete[] _tTranspose; + + delete _intf; +} + +bool TownsEuphonyDriver::init() { + if (!_intf->init()) + return false; + + _activeChannels = new int8[16]; + _sustainChannels = new int8[16]; + _assignedChannels = new ActiveChannel[128]; + _eventBuffer = new DlEvent[64]; + + _tEnable = new uint8[32]; + _tMode = new uint8[32]; + _tOrdr = new uint8[32]; + _tLevel = new int8[32]; + _tTranspose = new int8[32]; + + reset(); + + cdaSetVolume(1, 118, 118); + + return true; +} + +void TownsEuphonyDriver::reset() { + _intf->callback(0); + + _intf->callback(74); + _intf->callback(70); + _intf->callback(75, 3); + + setTimerA(true, 1); + setTimerA(false, 1); + setTimerB(true, 221); + + _paraCount = _command = _para[0] = _para[1] = 0; + memset(_sustainChannels, 0, 16); + memset(_activeChannels, -1, 16); + for (int i = 0; i < 128; i++) { + _assignedChannels[i].chan = _assignedChannels[i].next = -1; + _assignedChannels[i].note = _assignedChannels[i].sub = 0; + } + + int e = 0; + for (int i = 0; i < 6; i++) + assignChannel(i, e++); + for (int i = 0x40; i < 0x48; i++) + assignChannel(i, e++); + + resetTables(); + + memset(_eventBuffer, 0, 64 * sizeof(DlEvent)); + _bufferedEventsCount = 0; + + _playing = _endOfTrack = _suspendParsing = _loop = false; + _elapsedEvents = 0; + _tempoDiff = 0; + + resetTempo(); + + if (_tempoControlMode == 1) { + //if (///) + // return; + setTempoIntern(_defaultTempo); + } else { + setTempoIntern(_defaultTempo); + } + + resetControl(); +} + +void TownsEuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) { + _intf->callback(5, chanType, id, data); +} + +void TownsEuphonyDriver::loadWaveTable(const uint8 *data) { + _intf->callback(34, data); +} + +void TownsEuphonyDriver::unloadWaveTable(int id) { + _intf->callback(35, id); +} + +void TownsEuphonyDriver::reserveSfxChannels(int num) { + _intf->callback(33, num); +} + +int TownsEuphonyDriver::setMusicTempo(int tempo) { + if (tempo > 250) + return 3; + _defaultTempo = tempo; + _trackTempo = tempo; + setTempoIntern(tempo); + return 0; +} + +int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int startTick) { + if (_playing) + return 2; + + _musicPos = _musicStart = data; + _defaultBaseTickLen = _baseTickLen = startTick; + _musicTrackSize = trackSize; + _timeStampBase = _timeStampDest = 0; + _tickCounter = 0; + _playing = true; + + return 0; +} + +void TownsEuphonyDriver::setMusicLoop(bool loop) { + _loop = loop; +} + +void TownsEuphonyDriver::stopParser() { + if (_playing) { + _playing = false; + _pulseCount = 0; + _endOfTrack = false; + flushEventBuffer(); + resetControl(); + } +} + +void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) { + _intf->callback(37, chan, note, velo, data); +} + +void TownsEuphonyDriver::stopSoundEffect(int chan) { + _intf->callback(39, chan); +} + +bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) { + return _intf->callback(40, chan) ? true : false; +} + +void TownsEuphonyDriver::chanStereo(int chan, int mode) { + _intf->callback(3, chan, mode); +} + +void TownsEuphonyDriver::chanPitch(int chan, int pitch) { + _intf->callback(7, chan, pitch); +} + +void TownsEuphonyDriver::chanVolume(int chan, int vol) { + _intf->callback(8, chan, vol); +} + +void TownsEuphonyDriver::cdaSetVolume(int a, int vol1, int vol2) { + _intf->callback(67, a, vol1, vol2); +} + +int TownsEuphonyDriver::chanEnable(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + _tEnable[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanMode(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + _tMode[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val < 16) + _tOrdr[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanLevel(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val <= 40) + _tLevel[tableEntry] = (int8) (val & 0xff); + return 0; +} + +int TownsEuphonyDriver::chanTranspose(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val <= 40) + _tTranspose[tableEntry] = (int8) (val & 0xff); + return 0; +} + +int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) { + if (tableEntry > 15 || chan > 127 || chan < 0) + return 3; + + ActiveChannel *a = &_assignedChannels[chan]; + if (a->chan == tableEntry) + return 0; + + if (a->chan != -1) { + int8 *b = &_activeChannels[a->chan]; + while(*b != chan) { + b = &_assignedChannels[*b].next; + if (*b == -1 && *b != chan) + return 3; + } + + *b = a->next; + + if (a->note) + _intf->callback(2, chan); + + a->chan = a->next = -1; + a->note = 0; + } + + a->next = _activeChannels[tableEntry]; + _activeChannels[tableEntry] = chan; + a->chan = tableEntry; + a->note = a->sub = 0; + + return 0; +} + +void TownsEuphonyDriver::timerCallback(int timerId) { + switch (timerId) { + case 0: + updatePulseCount(); + while (_pulseCount > 0) { + --_pulseCount; + updateTimeStampBase(); + if (!_playing) + continue; + updateEventBuffer(); + updateParser(); + updateCheckEot(); + } + break; + default: + break; + } +} + +void TownsEuphonyDriver::resetTables() { + memset(_tEnable, 0xff, 32); + memset(_tMode, 0xff, 16); + memset(_tMode + 16, 0, 16); + for (int i = 0; i < 32; i++) + _tOrdr[i] = i & 0x0f; + memset(_tLevel, 0, 32); + memset(_tTranspose, 0, 32); +} + +void TownsEuphonyDriver::resetTempo() { + _defaultBaseTickLen = _baseTickLen = 0x33; + _pulseCount = 0; + _extraTimingControlRemainder = 0; + _extraTimingControl = 16; + _tempoModifier = 0; + _timeStampDest = 0; + _deltaTicks = 0; + _tickCounter = 0; + _defaultTempo = 90; + _trackTempo = 90; +} + +void TownsEuphonyDriver::setTempoIntern(int tempo) { + tempo = CLIP(tempo + _tempoModifier, 0, 500); + if (_tempoControlMode == 0) { + _timerSetting = 34750 / (tempo + 30); + _extraTimingControl = 16; + + while (_timerSetting < 126) { + _timerSetting <<= 1; + _extraTimingControl <<= 1; + } + + while (_timerSetting > 383) { + _timerSetting >>= 1; + _extraTimingControl >>= 1; + } + + setTimerA(true, -(_timerSetting - 2)); + + } else if (_tempoControlMode == 1) { + _timerSetting = 312500 / (tempo + 30); + _extraTimingControl = 16; + while (_timerSetting < 1105) { + _timerSetting <<= 1; + _extraTimingControl <<= 1; + } + + } else if (_tempoControlMode == 2) { + _timerSetting = 625000 / (tempo + 30); + _extraTimingControlRemainder = 0; + } +} + +void TownsEuphonyDriver::setTimerA(bool enable, int tempo) { + _intf->callback(21, enable ? 255 : 0, tempo); +} + +void TownsEuphonyDriver::setTimerB(bool enable, int tempo) { + _intf->callback(22, enable ? 255 : 0, tempo); +} + +void TownsEuphonyDriver::updatePulseCount() { + int tc = _extraTimingControl + _extraTimingControlRemainder; + _extraTimingControlRemainder = tc & 0x0f; + tc >>= 4; + _tempoDiff -= tc; + + while (_tempoDiff < 0) { + _elapsedEvents++; + _tempoDiff += 4; + } + + if (_playing && !_suspendParsing) + _pulseCount += tc; +} + +void TownsEuphonyDriver::updateTimeStampBase() { + static const uint16 table[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; + if ((uint32)(table[_baseTickLen >> 4] * ((_baseTickLen & 0x0f) + 1)) > ++_tickCounter) + return; + ++_timeStampDest; + _tickCounter = 0; + _deltaTicks = 0; +} + +void TownsEuphonyDriver::updateParser() { + for (bool loop = true; loop; ) { + uint8 cmd = _musicPos[0]; + + if (cmd == 0xff || cmd == 0xf7) { + jumpNextLoop(); + + } else if (cmd < 0x90) { + _endOfTrack = true; + flushEventBuffer(); + loop = false; + + } else if (_timeStampBase > _timeStampDest) { + loop = false; + + } else { + if (_timeStampBase == _timeStampDest) { + uint16 timeStamp = READ_LE_UINT16(&_musicPos[2]); + uint8 l = (timeStamp & 0xff) + (timeStamp & 0xff); + timeStamp = ((timeStamp & 0xff00) | l) >> 1; + if (timeStamp > _tickCounter) + loop = false; + } + + if (loop) { + if (parseNext()) + loop = false; + } + } + } +} + +void TownsEuphonyDriver::updateCheckEot() { + if (!_endOfTrack || _bufferedEventsCount) + return; + stopParser(); +} + +bool TownsEuphonyDriver::parseNext() { +#define OPC(x) &TownsEuphonyDriver::evt##x + static const EuphonyOpcode opcodes[] = { + OPC(NotImpl), + OPC(SetupNote), + OPC(PolyphonicAftertouch), + OPC(ControlPitch), + OPC(InstrumentChanAftertouch), + OPC(InstrumentChanAftertouch), + OPC(ControlPitch) + }; +#undef OPC + + uint cmd = _musicPos[0]; + if (cmd != 0xfe && cmd != 0xfd) { + if (cmd >= 0xf0 ) { + cmd &= 0x0f; + if (cmd == 0) + evtLoadInstrument(); + else if (cmd == 2) + evtAdvanceTimestampOffset(); + else if (cmd == 8) + evtTempo(); + else if (cmd == 12) + evtModeOrdrChange(); + jumpNextLoop(); + return false; + + } else if (!(this->*opcodes[(cmd - 0x80) >> 4])()) { + jumpNextLoop(); + return false; + } + } + + if (cmd == 0xfd) { + _suspendParsing = true; + return true; + } + + if (!_loop) { + _endOfTrack = true; + return true; + } + + _endOfTrack = false; + _musicPos = _musicStart; + _timeStampBase = _timeStampDest = _tickCounter = 0; + _baseTickLen = _defaultBaseTickLen; + + return false; +} + +void TownsEuphonyDriver::jumpNextLoop() { + _musicPos += 6; + if (_musicPos >= _musicStart + _musicTrackSize) + _musicPos = _musicStart; +} + +void TownsEuphonyDriver::updateEventBuffer() { + DlEvent *e = _eventBuffer; + for (int i = _bufferedEventsCount; i; e++) { + if (e->evt == 0) + continue; + if (--e->len) { + --i; + continue; + } + processBufferNote(e->mode, e->evt, e->note, e->velo); + e->evt = 0; + --i; + --_bufferedEventsCount; + } +} + +void TownsEuphonyDriver::flushEventBuffer() { + DlEvent *e = _eventBuffer; + for (int i = _bufferedEventsCount; i; e++) { + if (e->evt == 0) + continue; + processBufferNote(e->mode, e->evt, e->note, e->velo); + e->evt = 0; + --i; + --_bufferedEventsCount; + } +} + +void TownsEuphonyDriver::processBufferNote(int mode, int evt, int note, int velo) { + if (!velo) + evt &= 0x8f; + sendEvent(mode, evt); + sendEvent(mode, note); + sendEvent(mode, velo); +} + +void TownsEuphonyDriver::resetControl() { + for (int i = 0; i < 32; i++) { + if (_tOrdr[i] > 15) { + for (int ii = 0; ii < 16; ii++) + resetControlIntern(_tMode[i], ii); + } else { + resetControlIntern(_tMode[i], _tOrdr[i]); + } + } +} + +void TownsEuphonyDriver::resetControlIntern(int mode, int chan) { + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x40); + sendEvent(mode, 0); + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x7b); + sendEvent(mode, 0); + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x79); + sendEvent(mode, 0x40); +} + +uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) { + if (evt >= 0x80 && evt < 0xf0 && _tOrdr[chan] < 16) + return (evt & 0xf0) | _tOrdr[chan]; + return evt; +} + +void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { + if (mode == 0) { + warning("TownsEuphonyDriver: Mode 0 not implemented."); + + } else if (mode == 0x10) { + warning("TownsEuphonyDriver: Mode 0x10 not implemented."); + + } else if (mode == 0xff) { + if (command >= 0xf0) { + _paraCount = 1; + _command = 0; + } else if (command >= 0x80) { + _paraCount = 1; + _command = command; + } else if (_command >= 0x80) { + switch ((_command - 0x80) >> 4) { + case 0: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + sendNoteOff(); + } + break; + + case 1: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + if (command) + sendNoteOn(); + else + sendNoteOff(); + } + break; + + case 2: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + } + break; + + case 3: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + + if (_para[0] == 7) + sendChanVolume(); + else if (_para[0] == 10) + sendPanPosition(); + else if (_para[0] == 64) + sendAllNotesOff(); + } + break; + + case 4: + _paraCount = 1; + _para[0] = command; + sendSetInstrument(); + break; + + case 5: + _paraCount = 1; + _para[0] = command; + break; + + case 6: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + sendPitch(); + } + break; + } + } + } +} + +bool TownsEuphonyDriver::evtSetupNote() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) { + jumpNextLoop(); + return (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) ? true : false; + } + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + uint8 note = _musicPos[4]; + uint8 velo = _musicPos[5]; + + sendEvent(mode, evt); + sendEvent(mode, prepTranspose(note)); + sendEvent(mode, prepVelo(velo)); + + jumpNextLoop(); + if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) + return true; + + velo = _musicPos[5]; + uint16 len = ((((_musicPos[1] << 4) | (_musicPos[2] << 8)) >> 4) & 0xff) | ((((_musicPos[3] << 4) | (_musicPos[4] << 8)) >> 4) << 8); + + int i = 0; + for (; i < 64; i++) { + if (_eventBuffer[i].evt == 0) + break; + } + + if (i == 64) { + processBufferNote(mode, evt, note, velo); + } else { + _eventBuffer[i].evt = evt; + _eventBuffer[i].mode = mode; + _eventBuffer[i].note = note; + _eventBuffer[i].velo = velo; + _eventBuffer[i].len = len ? len : 1; + _bufferedEventsCount++; + } + + return false; +} + +bool TownsEuphonyDriver::evtPolyphonicAftertouch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, prepTranspose(_musicPos[4])); + sendEvent(mode, _musicPos[5]); + + return false; +} + +bool TownsEuphonyDriver::evtControlPitch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, _musicPos[4]); + sendEvent(mode, _musicPos[5]); + + return false; +} + +bool TownsEuphonyDriver::evtInstrumentChanAftertouch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, _musicPos[4]); + + return false; +} + +bool TownsEuphonyDriver::evtLoadInstrument() { + return false; +} + +bool TownsEuphonyDriver::evtAdvanceTimestampOffset() { + ++_timeStampBase; + _baseTickLen = _musicPos[1]; + return false; +} + +bool TownsEuphonyDriver::evtTempo() { + uint8 l = _musicPos[4] << 1; + _trackTempo = (l | (_musicPos[5] << 8)) >> 1; + setTempoIntern(_trackTempo); + return false; +} + +bool TownsEuphonyDriver::evtModeOrdrChange() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + if (_musicPos[4] == 1) + _tMode[_musicPos[1]] = _musicPos[5]; + else if (_musicPos[4] == 2) + _tOrdr[_musicPos[1]] = _musicPos[5]; + + return false; +} + +uint8 TownsEuphonyDriver::prepTranspose(uint8 in) { + int out = _tTranspose[_musicPos[1]]; + if (!out) + return in; + out += (in & 0x7f); + + if (out > 127) + out -= 12; + + if (out < 0) + out += 12; + + return out & 0xff; +} + +uint8 TownsEuphonyDriver::prepVelo(uint8 in) { + int out = _tLevel[_musicPos[1]]; + out += (in & 0x7f); + out = CLIP(out, 1, 127); + + return out & 0xff; +} + +void TownsEuphonyDriver::sendNoteOff() { + int8 *chan = &_activeChannels[_command & 0x0f]; + if (*chan == -1) + return; + + while (_assignedChannels[*chan].note != _para[0]) { + chan = &_assignedChannels[*chan].next; + if (*chan == -1) + return; + } + + if (_sustainChannels[_command & 0x0f]) { + _assignedChannels[*chan].note |= 0x80; + } else { + _assignedChannels[*chan].note = 0; + _intf->callback(2, *chan); + } +} + +void TownsEuphonyDriver::sendNoteOn() { + if (!_para[0]) + return; + int8 *chan = &_activeChannels[_command & 0x0f]; + if (*chan == -1) + return; + + do { + _assignedChannels[*chan].sub++; + chan = &_assignedChannels[*chan].next; + } while (*chan != -1); + + chan = &_activeChannels[_command & 0x0f]; + + int d = 0; + int c = 0; + bool found = false; + + do { + if (!_assignedChannels[*chan].note) { + found = true; + break; + } + if (d <= _assignedChannels[*chan].sub) { + c = *chan; + d = _assignedChannels[*chan].sub; + } + chan = &_assignedChannels[*chan].next; + } while (*chan != -1); + + if (found) + c = *chan; + else + _intf->callback(2, c); + + _assignedChannels[c].note = _para[0]; + _assignedChannels[c].sub = 0; + _intf->callback(1, c, _para[0], _para[1]); +} + +void TownsEuphonyDriver::sendChanVolume() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(8, *chan, _para[1] & 0x7f); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendPanPosition() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(3, *chan, _para[1] & 0x7f); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendAllNotesOff() { + if (_para[1] > 63) { + _sustainChannels[_command & 0x0f] = -1; + return; + } + + _sustainChannels[_command & 0x0f] = 0; + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + if (_assignedChannels[*chan].note & 0x80) { + _assignedChannels[*chan].note = 0; + _intf->callback(2, *chan); + } + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendSetInstrument() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(4, *chan, _para[0]); + _intf->callback(7, *chan, 0); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendPitch() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _para[0] += _para[0]; + int16 pitch = (((READ_LE_UINT16(_para)) >> 1) & 0x3fff) - 0x2000; + _intf->callback(7, *chan, pitch); + chan = &_assignedChannels[*chan].next; + }; +} diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h new file mode 100644 index 0000000000..315e4ab4f0 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -0,0 +1,178 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_EUP_H +#define TOWNS_EUP_H + +#include "sound/softsynth/fmtowns_pc98/towns_audio.h" + +class TownsEuphonyDriver : public TownsAudioInterfacePluginDriver { +public: + TownsEuphonyDriver(Audio::Mixer *mixer); + virtual ~TownsEuphonyDriver(); + + bool init(); + void reset(); + + void loadInstrument(int chanType, int id, const uint8 *data); + void loadWaveTable(const uint8 *data); + void unloadWaveTable(int id); + void reserveSfxChannels(int num); + + int setMusicTempo(int tempo); + int startMusicTrack(const uint8 *data, int trackSize, int startTick); + void setMusicLoop(bool loop); + void stopParser(); + + void playSoundEffect(int chan, int note, int velo, const uint8 *data); + void stopSoundEffect(int chan); + bool soundEffectIsPlaying(int chan); + + void chanStereo(int chan, int mode); + void chanPitch(int chan, int pitch); + void chanVolume(int chan, int vol); + + void cdaSetVolume(int a, int vol1, int vol2); + + int chanEnable(int tableEntry, int val); + int chanMode(int tableEntry, int val); + int chanOrdr(int tableEntry, int val); + int chanLevel(int tableEntry, int val); + int chanTranspose(int tableEntry, int val); + + int assignChannel(int chan, int tableEntry); + + void timerCallback(int timerId); + + TownsAudioInterface *intf() { return _intf; } + +private: + void resetTables(); + + void resetTempo(); + void setTempoIntern(int tempo); + void setTimerA(bool enable, int tempo); + void setTimerB(bool enable, int tempo); + + void updatePulseCount(); + void updateTimeStampBase(); + void updateParser(); + void updateCheckEot(); + + bool parseNext(); + void jumpNextLoop(); + + void updateEventBuffer(); + void flushEventBuffer(); + void processBufferNote(int mode, int evt, int note, int velo); + + void resetControl(); + void resetControlIntern(int mode, int chan); + uint8 appendEvent(uint8 evt, uint8 chan); + + void sendEvent(uint8 mode, uint8 command); + + typedef bool(TownsEuphonyDriver::*EuphonyOpcode)(); + bool evtSetupNote(); + bool evtPolyphonicAftertouch(); + bool evtControlPitch(); + bool evtInstrumentChanAftertouch(); + bool evtLoadInstrument(); + bool evtAdvanceTimestampOffset(); + bool evtTempo(); + bool evtModeOrdrChange(); + bool evtNotImpl() { return false; } + + uint8 prepTranspose(uint8 in); + uint8 prepVelo(uint8 in); + + void sendNoteOff(); + void sendNoteOn(); + void sendChanVolume(); + void sendPanPosition(); + void sendAllNotesOff(); + void sendSetInstrument(); + void sendPitch(); + + int8 *_activeChannels; + int8 *_sustainChannels; + + struct ActiveChannel { + int8 chan; + int8 next; + uint8 note; + uint8 sub; + } *_assignedChannels; + + uint8 *_tEnable; + uint8 *_tMode; + uint8 *_tOrdr; + int8 *_tLevel; + int8 *_tTranspose; + + struct DlEvent { + uint8 evt; + uint8 mode; + uint8 note; + uint8 velo; + uint16 len; + } *_eventBuffer; + int _bufferedEventsCount; + + uint8 _para[2]; + uint8 _paraCount; + uint8 _command; + + uint8 _defaultBaseTickLen; + uint8 _baseTickLen; + uint32 _pulseCount; + int _tempoControlMode; + int _extraTimingControlRemainder; + int _extraTimingControl; + int _timerSetting; + int8 _tempoDiff; + int _tempoModifier; + uint32 _timeStampDest; + uint32 _timeStampBase; + int8 _elapsedEvents; + uint8 _deltaTicks; + uint32 _tickCounter; + uint8 _defaultTempo; + int _trackTempo; + + bool _loop; + bool _playing; + bool _endOfTrack; + bool _suspendParsing; + + const uint8 *_musicStart; + const uint8 *_musicPos; + uint32 _musicTrackSize; + + TownsAudioInterface *_intf; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp new file mode 100644 index 0000000000..1279429e7c --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -0,0 +1,1403 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_driver.h" +#include "common/endian.h" + +class TownsPC98_MusicChannel { +public: + TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id); + virtual ~TownsPC98_MusicChannel(); + virtual void init(); + + typedef enum channelState { + CHS_RECALCFREQ = 0x01, + CHS_KEYOFF = 0x02, + CHS_SSGOFF = 0x04, + CHS_VBROFF = 0x08, + CHS_ALLOFF = 0x0f, + CHS_PROTECT = 0x40, + CHS_EOT = 0x80 + } ChannelState; + + virtual void loadData(uint8 *data); + virtual void processEvents(); + virtual void processFrequency(); + virtual bool processControlEvent(uint8 cmd); + + virtual void keyOn(); + void keyOff(); + + void setOutputLevel(); + virtual void fadeStep(); + virtual void reset(); + + const uint8 _idFlag; + +protected: + void setupVibrato(); + bool processVibrato(); + + bool control_dummy(uint8 para); + bool control_f0_setPatch(uint8 para); + bool control_f1_presetOutputLevel(uint8 para); + bool control_f2_setKeyOffTime(uint8 para); + bool control_f3_setFreqLSB(uint8 para); + bool control_f4_setOutputLevel(uint8 para); + bool control_f5_setTempo(uint8 para); + bool control_f6_repeatSection(uint8 para); + bool control_f7_setupVibrato(uint8 para); + bool control_f8_toggleVibrato(uint8 para); + bool control_fa_writeReg(uint8 para); + virtual bool control_fb_incOutLevel(uint8 para); + virtual bool control_fc_decOutLevel(uint8 para); + bool control_fd_jump(uint8 para); + virtual bool control_ff_endOfTrack(uint8 para); + + uint8 _ticksLeft; + uint8 _algorithm; + uint8 _instr; + uint8 _totalLevel; + uint8 _frqBlockMSB; + int8 _frqLSB; + uint8 _keyOffTime; + bool _hold; + uint8 *_dataPtr; + uint8 _vbrInitDelayHi; + uint8 _vbrInitDelayLo; + int16 _vbrModInitVal; + uint8 _vbrDuration; + uint8 _vbrCurDelay; + int16 _vbrModCurVal; + uint8 _vbrDurLeft; + uint16 _frequency; + uint8 _block; + uint8 _regOffset; + uint8 _flags; + uint8 _ssgTl; + uint8 _ssgStep; + uint8 _ssgTicksLeft; + uint8 _ssgTargetLvl; + uint8 _ssgStartLvl; + + const uint8 _chanNum; + const uint8 _keyNum; + const uint8 _part; + + TownsPC98_AudioDriver *_drv; + + typedef bool (TownsPC98_MusicChannel::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_MusicChannelSSG : public TownsPC98_MusicChannel { +public: + TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + virtual ~TownsPC98_MusicChannelSSG() {} + void init(); + + virtual void loadData(uint8 *data); + void processEvents(); + void processFrequency(); + bool processControlEvent(uint8 cmd); + + void keyOn(); + void nextShape(); + + void protect(); + void restore(); + virtual void reset(); + + void fadeStep(); + +protected: + void setOutputLevel(uint8 lvl); + + bool control_f0_setPatch(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_loadCustomPatch(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_MusicChannelSSG::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_SfxChannel : public TownsPC98_MusicChannelSSG { +public: + TownsPC98_SfxChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_MusicChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} + ~TownsPC98_SfxChannel() {} + + void loadData(uint8 *data); + void reset(); +}; + +class TownsPC98_MusicChannelPCM : public TownsPC98_MusicChannel { +public: + TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + ~TownsPC98_MusicChannelPCM() {} + void init(); + + void loadData(uint8 *data); + void processEvents(); + bool processControlEvent(uint8 cmd); + +private: + bool control_f1_prcStart(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_MusicChannelPCM::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +TownsPC98_MusicChannel::TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, + uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), + _part(prt), _idFlag(id), controlEvents(0) { + + _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0; + _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0; + _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0; + _frqLSB = 0; + _hold = false; + _dataPtr = 0; + _vbrModInitVal = _vbrModCurVal = 0; + _frequency = 0; +} + +TownsPC98_MusicChannel::~TownsPC98_MusicChannel() { +} + +void TownsPC98_MusicChannel::init() { + #define Control(x) &TownsPC98_MusicChannel::control_##x + static const ControlEventFunc ctrlEvents[] = { + Control(f0_setPatch), + Control(f1_presetOutputLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setOutputLevel), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupVibrato), + Control(f8_toggleVibrato), + Control(dummy), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEvents; +} + +void TownsPC98_MusicChannel::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); + _flags |= CHS_KEYOFF; +} + +void TownsPC98_MusicChannel::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); +} + +void TownsPC98_MusicChannel::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; + + uint8 *tmp = _dataPtr; + for (bool loop = true; loop; ) { + uint8 cmd = *tmp++; + if (cmd < 0xf0) { + tmp++; + } else if (cmd == 0xff) { + if (READ_LE_UINT16(tmp)) { + _drv->_looping |= _idFlag; + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } else + loop = false; + } else if (cmd == 0xf6) { + // reset repeat section countdown + tmp[0] = tmp[1]; + tmp += 4; + } else { + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } + } +} + +void TownsPC98_MusicChannel::processEvents() { + if (_flags & CHS_EOT) + return; + + if (!_hold && _ticksLeft == _keyOffTime) + keyOff(); + + if (--_ticksLeft) + return; + + if (!_hold) + keyOff(); + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + keyOff(); + _hold = false; + } else { + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; +} + +void TownsPC98_MusicChannel::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + + _frequency = (((const uint16 *)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8); + + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); + + setupVibrato(); + } + + if (!(_flags & CHS_VBROFF)) { + if (!processVibrato()) + return; + + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); + } +} + +void TownsPC98_MusicChannel::setupVibrato() { + _vbrCurDelay = _vbrInitDelayHi; + if (_flags & CHS_KEYOFF) { + _vbrModCurVal = _vbrModInitVal; + _vbrCurDelay += _vbrInitDelayLo; + } + _vbrDurLeft = (_vbrDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +} + +bool TownsPC98_MusicChannel::processVibrato() { + if (--_vbrCurDelay) + return false; + + _vbrCurDelay = _vbrInitDelayHi; + _frequency += _vbrModCurVal; + + if (!--_vbrDurLeft) { + _vbrDurLeft = _vbrDuration; + _vbrModCurVal = -_vbrModCurVal; + } + + return true; +} + +bool TownsPC98_MusicChannel::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_MusicChannel::setOutputLevel() { + uint8 outopr = _drv->_opnCarrier[_algorithm]; + uint8 reg = 0x40 + _regOffset; + + for (int i = 0; i < 4; i++) { + if (outopr & 1) + _drv->writeReg(_part, reg, _totalLevel); + outopr >>= 1; + reg += 4; + } +} + +void TownsPC98_MusicChannel::fadeStep() { + _totalLevel += 3; + if (_totalLevel > 0x7f) + _totalLevel = 0x7f; + setOutputLevel(); +} + +void TownsPC98_MusicChannel::reset() { + _hold = false; + _keyOffTime = 0; + _ticksLeft = 1; + + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + + _totalLevel = 0; + _algorithm = 0; + _flags = CHS_EOT; + _algorithm = 0; + + _block = 0; + _frequency = 0; + _frqBlockMSB = 0; + _frqLSB = 0; + + _ssgTl = 0; + _ssgStartLvl = 0; + _ssgTargetLvl = 0; + _ssgStep = 0; + _ssgTicksLeft = 0; + + _vbrInitDelayHi = 0; + _vbrInitDelayLo = 0; + _vbrModInitVal = 0; + _vbrDuration = 0; + _vbrCurDelay = 0; + _vbrModCurVal = 0; + _vbrDurLeft = 0; +} + +bool TownsPC98_MusicChannel::control_f0_setPatch(uint8 para) { + _instr = para; + uint8 reg = _regOffset + 0x80; + + for (int i = 0; i < 4; i++) { + // set release rate for each operator + _drv->writeReg(_part, reg, 0x0f); + reg += 4; + } + + const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5); + reg = _regOffset + 0x30; + + // write registers 0x30 to 0x8f + for (int i = 0; i < 6; i++) { + _drv->writeReg(_part, reg, tptr[0]); + reg += 4; + _drv->writeReg(_part, reg, tptr[2]); + reg += 4; + _drv->writeReg(_part, reg, tptr[1]); + reg += 4; + _drv->writeReg(_part, reg, tptr[3]); + reg += 4; + tptr += 4; + } + + reg = _regOffset + 0xB0; + _algorithm = tptr[0] & 7; + // set feedback and algorithm + _drv->writeReg(_part, reg, tptr[0]); + + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_f1_presetOutputLevel(uint8 para) { + if (_drv->_fading) + return true; + + _totalLevel = _drv->_opnLvlPresets[para]; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_f2_setKeyOffTime(uint8 para) { + _keyOffTime = para; + return true; +} + +bool TownsPC98_MusicChannel::control_f3_setFreqLSB(uint8 para) { + _frqLSB = (int8) para; + return true; +} + +bool TownsPC98_MusicChannel::control_f4_setOutputLevel(uint8 para) { + if (_drv->_fading) + return true; + + _totalLevel = para; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_f5_setTempo(uint8 para) { + _drv->setMusicTempo(para); + return true; +} + +bool TownsPC98_MusicChannel::control_f6_repeatSection(uint8 para) { + _dataPtr--; + _dataPtr[0]--; + + if (*_dataPtr) { + // repeat section until counter has reached zero + _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2); + } else { + // reset counter, advance to next section + _dataPtr[0] = _dataPtr[1]; + _dataPtr += 4; + } + return true; +} + +bool TownsPC98_MusicChannel::control_f7_setupVibrato(uint8 para) { + _vbrInitDelayHi = _dataPtr[0]; + _vbrInitDelayLo = para; + _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); + _vbrDuration = _dataPtr[3]; + _dataPtr += 4; + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ; + return true; +} + +bool TownsPC98_MusicChannel::control_f8_toggleVibrato(uint8 para) { + if (para == 0x10) { + if (*_dataPtr++) { + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF; + } else { + _flags |= CHS_VBROFF; + } + } else { + /* NOT IMPLEMENTED + uint8 skipChannels = para / 36; + uint8 entry = para % 36; + TownsPC98_AudioDriver::TownsPC98_MusicChannel *t = &chan[skipChannels]; + + t->unnamedEntries[entry] = *_dataPtr++;*/ + } + return true; +} + +bool TownsPC98_MusicChannel::control_fa_writeReg(uint8 para) { + _drv->writeReg(_part, para, *_dataPtr++); + return true; +} + +bool TownsPC98_MusicChannel::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + uint8 val = (_totalLevel + 3); + if (val > 0x7f) + val = 0x7f; + + _totalLevel = val; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + int8 val = (int8) (_totalLevel - 3); + if (val < 0) + val = 0; + + _totalLevel = (uint8) val; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_fd_jump(uint8 para) { + uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1); + _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1); + return true; +} + +bool TownsPC98_MusicChannel::control_dummy(uint8 para) { + _dataPtr--; + return true; +} + +bool TownsPC98_MusicChannel::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedChannelsFlag |= _idFlag; + keyOff(); + return false; + } +} + +TownsPC98_MusicChannelSSG::TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) { +} + +void TownsPC98_MusicChannelSSG::init() { + _algorithm = 0x80; + + #define Control(x) &TownsPC98_MusicChannelSSG::control_##x + static const ControlEventFunc ctrlEventsSSG[] = { + Control(f0_setPatch), + Control(f1_setTotalLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setAlgorithm), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupVibrato), + Control(f8_toggleVibrato), + Control(f9_loadCustomPatch), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEventsSSG; +} + +void TownsPC98_MusicChannelSSG::processEvents() { + if (_flags & CHS_EOT) + return; + + _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + + if (!_hold && _ticksLeft == _keyOffTime) + nextShape(); + + if (!--_ticksLeft) { + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + nextShape(); + _hold = false; + } else { + if (!_hold) { + _instr &= 0xf0; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + _ssgStartLvl = _drv->_ssgPatches[_instr + 3]; + _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; + } + + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; + } + + if (!(_flags & CHS_SSGOFF)) { + if (--_ssgTicksLeft) { + if (!_drv->_fading) + setOutputLevel(_ssgStartLvl); + return; + } + + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + + if (_drv->_ssgPatches[_instr + 1] & 0x80) { + uint8 t = _ssgStartLvl - _ssgStep; + + if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { + if (!_drv->_fading) + setOutputLevel(t); + return; + } + } else { + int t = _ssgStartLvl + _ssgStep; + uint8 p = (uint8) (t & 0xff); + + if (t < 256 && _ssgTargetLvl > p) { + if (!_drv->_fading) + setOutputLevel(p); + return; + } + } + + setOutputLevel(_ssgTargetLvl); + if (_ssgStartLvl && !(_instr & 8)){ + _instr += 4; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + } else { + _flags |= CHS_SSGOFF; + setOutputLevel(0); + } + } +} + +void TownsPC98_MusicChannelSSG::processFrequency() { + if (_algorithm & 0x40) + return; + + if (_flags & CHS_RECALCFREQ) { + _block = _frqBlockMSB >> 4; + _frequency = ((const uint16 *)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + + setupVibrato(); + } + + if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) { + if (!processVibrato()) + return; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + } +} + +bool TownsPC98_MusicChannelSSG::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_MusicChannelSSG::nextShape() { + _instr = (_instr & 0xf0) + 0x0c; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +} + +void TownsPC98_MusicChannelSSG::keyOn() { + uint8 c = 0x7b; + uint8 t = (_algorithm & 0xC0) << 1; + if (_algorithm & 0x80) + t |= 4; + + c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); + t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); + + if (!(_algorithm & 0x80)) + _drv->writeReg(_part, 6, _algorithm & 0x7f); + + uint8 e = (_drv->readSSGStatus() & c) | t; + _drv->writeReg(_part, 7, e); +} + +void TownsPC98_MusicChannelSSG::protect() { + _flags |= CHS_PROTECT; +} + +void TownsPC98_MusicChannelSSG::restore() { + _flags &= ~CHS_PROTECT; + keyOn(); + _drv->writeReg(_part, 8 + _regOffset, _ssgTl); + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); +} + +void TownsPC98_MusicChannelSSG::loadData(uint8 *data) { + _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + TownsPC98_MusicChannel::loadData(data); + setOutputLevel(0); + _algorithm = 0x80; +} + +void TownsPC98_MusicChannelSSG::setOutputLevel(uint8 lvl) { + _ssgStartLvl = lvl; + uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; + if (newTl == _ssgTl) + return; + _ssgTl = newTl; + _drv->writeReg(_part, 8 + _regOffset, _ssgTl); +} + +void TownsPC98_MusicChannelSSG::reset() { + TownsPC98_MusicChannel::reset(); + + // Unlike the original we restore the default patch data. This fixes a bug + // where certain sound effects would bring each other out of tune (e.g. the + // dragon's fire in Darm's house in Kyra 1 would sound different each time + // you triggered another sfx by dropping an item etc.) + uint8 i = (10 + _regOffset) << 4; + const uint8 *src = &_drv->_drvTables[156]; + _drv->_ssgPatches[i] = src[i]; + _drv->_ssgPatches[i + 3] = src[i + 3]; + _drv->_ssgPatches[i + 4] = src[i + 4]; + _drv->_ssgPatches[i + 6] = src[i + 6]; + _drv->_ssgPatches[i + 8] = src[i + 8]; + _drv->_ssgPatches[i + 12] = src[i + 12]; +} + +void TownsPC98_MusicChannelSSG::fadeStep() { + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + setOutputLevel(_ssgStartLvl); +} + +bool TownsPC98_MusicChannelSSG::control_f0_setPatch(uint8 para) { + _instr = para << 4; + para = (para >> 3) & 0x1e; + if (para) + return control_f4_setAlgorithm(para | 0x40); + return true; +} + +bool TownsPC98_MusicChannelSSG::control_f1_setTotalLevel(uint8 para) { + if (!_drv->_fading) + _totalLevel = para; + return true; +} + +bool TownsPC98_MusicChannelSSG::control_f4_setAlgorithm(uint8 para) { + _algorithm = para; + return true; +} + +bool TownsPC98_MusicChannelSSG::control_f9_loadCustomPatch(uint8 para) { + _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4; + _drv->_ssgPatches[_instr] = *_dataPtr++; + _drv->_ssgPatches[_instr + 3] = para; + _drv->_ssgPatches[_instr + 4] = *_dataPtr++; + _drv->_ssgPatches[_instr + 6] = *_dataPtr++; + _drv->_ssgPatches[_instr + 8] = *_dataPtr++; + _drv->_ssgPatches[_instr + 12] = *_dataPtr++; + return true; +} + +bool TownsPC98_MusicChannelSSG::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + + return true; +} + +bool TownsPC98_MusicChannelSSG::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + if (_totalLevel + 1 < 0x10) + _totalLevel++; + + return true; +} + +bool TownsPC98_MusicChannelSSG::control_ff_endOfTrack(uint8 para) { + if (!_drv->_sfxOffs) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // stop parsing + if (!_drv->_fading) + setOutputLevel(0); + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedSSGFlag |= _idFlag; + } + } else { + // end of sfx track - restore ssg music channel + _flags |= CHS_EOT; + _drv->_finishedSfxFlag |= _idFlag; + _drv->_ssgChannels[_chanNum]->restore(); + } + + return false; +} + +void TownsPC98_SfxChannel::loadData(uint8 *data) { + _flags = CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _ssgTl = 0xff; + _algorithm = 0x80; + + uint8 *tmp = _dataPtr; + for (bool loop = true; loop; ) { + uint8 cmd = *tmp++; + if (cmd < 0xf0) { + tmp++; + } else if (cmd == 0xff) { + loop = false; + } else if (cmd == 0xf6) { + // reset repeat section countdown + tmp[0] = tmp[1]; + tmp += 4; + } else { + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } + } +} + +void TownsPC98_SfxChannel::reset() { + TownsPC98_MusicChannel::reset(); + + // Unlike the original we restore the default patch data. This fixes a bug + // where certain sound effects would bring each other out of tune (e.g. the + // dragon's fire in Darm's house in Kyra 1 would sound different each time + // you triggered another sfx by dropping an item etc.) + uint8 i = (13 + _regOffset) << 4; + const uint8 *src = &_drv->_drvTables[156]; + _drv->_ssgPatches[i] = src[i]; + _drv->_ssgPatches[i + 3] = src[i + 3]; + _drv->_ssgPatches[i + 4] = src[i + 4]; + _drv->_ssgPatches[i + 6] = src[i + 6]; + _drv->_ssgPatches[i + 8] = src[i + 8]; + _drv->_ssgPatches[i + 12] = src[i + 12]; +} + +TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) { +} + +void TownsPC98_MusicChannelPCM::init() { + _algorithm = 0x80; + + #define Control(x) &TownsPC98_MusicChannelPCM::control_##x + static const ControlEventFunc ctrlEventsPCM[] = { + Control(dummy), + Control(f1_prcStart), + Control(dummy), + Control(dummy), + Control(dummy), + Control(dummy), + Control(f6_repeatSection), + Control(dummy), + Control(dummy), + Control(dummy), + Control(fa_writeReg), + Control(dummy), + Control(dummy), + Control(dummy), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEventsPCM; +} + +void TownsPC98_MusicChannelPCM::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; +} + +void TownsPC98_MusicChannelPCM::processEvents() { + if (_flags & CHS_EOT) + return; + + if (--_ticksLeft) + return; + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd == 0x80) { + loop = false; + } else if (cmd < 0xf0) { + _drv->writeReg(_part, 0x10, cmd); + } else if (!processControlEvent(cmd)) { + return; + } + } + + _ticksLeft = *_dataPtr++; +} + +bool TownsPC98_MusicChannelPCM::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +bool TownsPC98_MusicChannelPCM::control_f1_prcStart(uint8 para) { + _totalLevel = para; + _drv->writeReg(_part, 0x11, para); + return true; +} + +bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedRhythmFlag |= _idFlag; + return false; + } +} + +TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) : TownsPC98_FmSynth(mixer, type), + _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0), + _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0), + _patches(0), _sfxBuffer(0), _musicBuffer(0), + + _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132), + _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == kTypeTowns ? 52 : 84)), + + _updateChannelsFlag(type == kType26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), + _updateSSGFlag(type == kTypeTowns ? 0x00 : 0x07), _finishedSSGFlag(0), + _updateRhythmFlag(type == kType86 ? 0x01 : 0x00), _finishedRhythmFlag(0), + _updateSfxFlag(0), _finishedSfxFlag(0), + + _musicTickCounter(0), + + _musicVolume(255), _sfxVolume(255), + + _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { + + _sfxOffsets[0] = _sfxOffsets[1] = 0; +} + +TownsPC98_AudioDriver::~TownsPC98_AudioDriver() { + reset(); + + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete[] _channels; + } + + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) + delete _ssgChannels[i]; + delete[] _ssgChannels; + } + + if (_sfxChannels) { + for (int i = 0; i < 2; i++) + delete _sfxChannels[i]; + delete[] _sfxChannels; + } + + delete _rhythmChannel; + + delete[] _ssgPatches; +} + +bool TownsPC98_AudioDriver::init() { + if (_ready) { + reset(); + return true; + } + + TownsPC98_FmSynth::init(); + + setVolumeChannelMasks(-1, 0); + + _channels = new TownsPC98_MusicChannel *[_numChan]; + for (int i = 0; i < _numChan; i++) { + int ii = i * 6; + _channels[i] = new TownsPC98_MusicChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _channels[i]->init(); + } + + if (_numSSG) { + _ssgPatches = new uint8[256]; + memcpy(_ssgPatches, _drvTables + 156, 256); + + _ssgChannels = new TownsPC98_MusicChannelSSG *[_numSSG]; + for (int i = 0; i < _numSSG; i++) { + int ii = i * 6; + _ssgChannels[i] = new TownsPC98_MusicChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _ssgChannels[i]->init(); + } + + _sfxChannels = new TownsPC98_SfxChannel *[2]; + for (int i = 0; i < 2; i++) { + int ii = (i + 1) * 6; + _sfxChannels[i] = new TownsPC98_SfxChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _sfxChannels[i]->init(); + } + } + + if (_hasPercussion) { + _rhythmChannel = new TownsPC98_MusicChannelPCM(this, 0, 0, 0, 0, 0, 1); + _rhythmChannel->init(); + } + + setMusicTempo(84); + setSfxTempo(654); + + _ready = true; + + return true; +} + +void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) { + if (!_ready) { + warning("TownsPC98_AudioDriver: Driver must be initialized before loading data"); + return; + } + + if (!data) { + warning("TownsPC98_AudioDriver: Invalid music file data"); + return; + } + + reset(); + + Common::StackLock lock(_mutex); + uint8 *src_a = _trackPtr = _musicBuffer = data; + + for (uint8 i = 0; i < 3; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (uint8 i = 3; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + if (_hasPercussion) { + _rhythmChannel->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + toggleRegProtection(false); + + _patches = src_a + 4; + _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0; + + _musicPlaying = (loadPaused ? false : true); +} + +void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { + if (!_ready) { + warning("TownsPC98_AudioDriver: Driver must be initialized before loading data"); + return; + } + + if (!_sfxChannels) { + warning("TownsPC98_AudioDriver: Sound effects not supported by this configuration"); + return; + } + + if (!data) { + warning("TownsPC98_AudioDriver: Invalid sound effects file data"); + return; + } + + Common::StackLock lock(_mutex); + _sfxData = _sfxBuffer = data; + _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); + _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); + _sfxPlaying = true; + _finishedSfxFlag = 0; +} + +void TownsPC98_AudioDriver::reset() { + Common::StackLock lock(_mutex); + + _musicPlaying = false; + _sfxPlaying = false; + _fading = false; + _looping = 0; + _musicTickCounter = 0; + _sfxData = 0; + + TownsPC98_FmSynth::reset(); + + for (int i = 0; i < _numChan; i++) + _channels[i]->reset(); + for (int i = 0; i < _numSSG; i++) + _ssgChannels[i]->reset(); + + if (_numSSG) { + for (int i = 0; i < 2; i++) + _sfxChannels[i]->reset(); + + memcpy(_ssgPatches, _drvTables + 156, 256); + } + + if (_rhythmChannel) + _rhythmChannel->reset(); +} + +void TownsPC98_AudioDriver::fadeStep() { + if (!_musicPlaying) + return; + + Common::StackLock lock(_mutex); + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + + for (int j = 0; j < _numSSG; j++) { + if (_updateSSGFlag & _ssgChannels[j]->_idFlag) + _ssgChannels[j]->fadeStep(); + } + + if (!_fading) { + _fading = 19; + if (_hasPercussion) { + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->reset(); + } + } else { + if (!--_fading) + reset(); + } +} + +void TownsPC98_AudioDriver::timerCallbackB() { + _sfxOffs = 0; + + if (_musicPlaying) { + _musicTickCounter++; + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + for (int i = 0; i < _numSSG; i++) { + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + + if (_hasPercussion) + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->processEvents(); + } + + toggleRegProtection(false); + + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) + _musicPlaying = false; +} + +void TownsPC98_AudioDriver::timerCallbackA() { + if (_sfxChannels && _sfxPlaying) { + if (_sfxData) + startSoundEffect(); + + _sfxOffs = 3; + _trackPtr = _sfxBuffer; + + for (int i = 0; i < 2; i++) { + if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { + _sfxChannels[i]->processEvents(); + _sfxChannels[i]->processFrequency(); + } + } + + _trackPtr = _musicBuffer; + } + + if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) { + _sfxPlaying = false; + _updateSfxFlag = 0; + setVolumeChannelMasks(-1, 0); + } +} + +void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { + writeReg(0, 0x26, tempo); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { + writeReg(0, 0x24, tempo & 0xff); + writeReg(0, 0x25, tempo >> 8); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::startSoundEffect() { + int volFlags = 0; + + for (int i = 0; i < 2; i++) { + if (_sfxOffsets[i]) { + _ssgChannels[i + 1]->protect(); + _sfxChannels[i]->reset(); + _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); + _updateSfxFlag |= _sfxChannels[i]->_idFlag; + volFlags |= (_sfxChannels[i]->_idFlag << _numChan); + } else { + _ssgChannels[i + 1]->restore(); + _updateSfxFlag &= ~_sfxChannels[i]->_idFlag; + } + } + + setVolumeChannelMasks(~volFlags, volFlags); + _sfxData = 0; +} + +const uint8 TownsPC98_AudioDriver::_drvTables[] = { + // channel presets + 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, + 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, + 0x00, 0x80, 0x03, 0x04, 0x01, 0x08, + 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, + 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, + + // control event size + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, + 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, + + // fmt level presets + 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, + 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, + 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, + + // carriers + 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, + + // pc98 level presets + 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, + 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, + 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90, + + // frequencies + 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, + 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, + 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, + + // ssg frequencies + 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C, + 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09, + 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07, + + // ssg patch data + 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00, + 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + + 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00, + 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00 +}; + +#undef EUPHONY_FADEOUT_TICKS + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h new file mode 100644 index 0000000000..f7d09df09d --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -0,0 +1,110 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_PC98_AUDIODRIVER_H +#define TOWNS_PC98_AUDIODRIVER_H + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" + +class TownsPC98_AudioDriver : public TownsPC98_FmSynth { +friend class TownsPC98_MusicChannel; +friend class TownsPC98_MusicChannelSSG; +friend class TownsPC98_SfxChannel; +friend class TownsPC98_MusicChannelPCM; +public: + TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type); + ~TownsPC98_AudioDriver(); + + void loadMusicData(uint8 *data, bool loadPaused = false); + void loadSoundEffectData(uint8 *data, uint8 trackNum); + bool init(); + void reset(); + + void fadeStep(); + + void pause() { _musicPlaying = false; } + void cont() { _musicPlaying = true; } + + void timerCallbackB(); + void timerCallbackA(); + + bool looping() { return _looping == _updateChannelsFlag ? true : false; } + bool musicPlaying() { return _musicPlaying; } + + void setMusicVolume(int volume) { _musicVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } + void setSoundEffectVolume(int volume) { _sfxVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } + +protected: + void startSoundEffect(); + + void setMusicTempo(uint8 tempo); + void setSfxTempo(uint16 tempo); + + TownsPC98_MusicChannel **_channels; + TownsPC98_MusicChannelSSG **_ssgChannels; + TownsPC98_SfxChannel **_sfxChannels; + TownsPC98_MusicChannelPCM *_rhythmChannel; + + const uint8 *_opnCarrier; + const uint8 *_opnFreqTable; + const uint8 *_opnFreqTableSSG; + const uint8 *_opnFxCmdLen; + const uint8 *_opnLvlPresets; + + uint8 *_musicBuffer; + uint8 *_sfxBuffer; + uint8 *_trackPtr; + uint8 *_patches; + uint8 *_ssgPatches; + + uint8 _updateChannelsFlag; + uint8 _updateSSGFlag; + uint8 _updateRhythmFlag; + uint8 _updateSfxFlag; + uint8 _finishedChannelsFlag; + uint8 _finishedSSGFlag; + uint8 _finishedRhythmFlag; + uint8 _finishedSfxFlag; + + bool _musicPlaying; + bool _sfxPlaying; + uint8 _fading; + uint8 _looping; + uint32 _musicTickCounter; + + int _sfxOffs; + uint8 *_sfxData; + uint16 _sfxOffsets[2]; + + uint16 _musicVolume; + uint16 _sfxVolume; + + static const uint8 _drvTables[]; + + bool _ready; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp new file mode 100644 index 0000000000..5436c8e0c7 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -0,0 +1,1461 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +#include "common/endian.h" + +class TownsPC98_FmSynthOperator { +public: + TownsPC98_FmSynthOperator(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_FmSynthOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); + + void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } + void detune(int value) { _detn = &_detnTbl[value << 5]; } + void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } + void attackRate(uint32 value) { _specifiedAttackRate = value; } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } + void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } + void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } + void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } + void totalLevel(uint32 value) { _totalLevel = value << 3; } + void ampModulation(bool enable) { _ampMod = enable; } + void reset(); + +protected: + EnvelopeState _state; + bool _playing; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + bool _ampMod; + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + const int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const uint32 _tickLength; + uint32 _timer; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + +TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(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(timerbase * 2), + _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), + _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), + _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) { + + fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0; + + reset(); +} + +void TownsPC98_FmSynthOperator::keyOn() { + if (_playing) + return; + + _playing = true; + _state = kEnvAttacking; + _phase = 0; +} + +void TownsPC98_FmSynthOperator::keyOff() { + if (!_playing) + return; + + _playing = false; + if (_state != kEnvReady) + _state = kEnvReleasing; +} + +void TownsPC98_FmSynthOperator::frequency(int freq) { + uint8 block = (freq >> 11); + uint16 pos = (freq & 0x7ff); + uint8 c = pos >> 7; + + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); + _frequency = _fTbl[pos << 1] >> (7 - block); +} + +void TownsPC98_FmSynthOperator::updatePhaseIncrement() { + _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1; + uint8 keyscale = _kcode >> _keyScale1; + if (_keyScale2 != keyscale) { + _keyScale2 = keyscale; + recalculateRates(); + } +} + +void TownsPC98_FmSynthOperator::recalculateRates() { + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + + r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0; + fs_d.rate = _rateTbl[r + k]; + fs_d.shift = _rshiftTbl[r + k]; + + r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0; + fs_s.rate = _rateTbl[r + k]; + fs_s.shift = _rshiftTbl[r + k]; + + r = (_specifiedReleaseRate << 2) + 0x22; + fs_r.rate = _rateTbl[r + k]; + fs_r.shift = _rshiftTbl[r + k]; +} + +void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) { + if (_state == kEnvReady) + return; + + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + ++_tickCount; + + int32 levelIncrement = 0; + uint32 targetTime = 0; + int32 targetLevel = 0; + EnvelopeState nextState = kEnvReady; + + switch (_state) { + case kEnvReady: + return; + case kEnvAttacking: + targetLevel = 0; + nextState = kEnvDecaying; + if ((_specifiedAttackRate << 1) + _keyScale2 < 64) { + targetTime = (1 << fs_a.shift) - 1; + levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + break; + } else { + _currentLevel = targetLevel; + _state = nextState; + } + // Fall through + case kEnvDecaying: + targetTime = (1 << fs_d.shift) - 1; + nextState = kEnvSustaining; + targetLevel = _sustainLevel; + levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; + break; + case kEnvSustaining: + targetTime = (1 << fs_s.shift) - 1; + nextState = kEnvSustaining; + targetLevel = 1023; + levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; + break; + case kEnvReleasing: + targetTime = (1 << fs_r.shift) - 1; + nextState = kEnvReady; + targetLevel = 1023; + levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; + break; + } + + if (!(_tickCount & targetTime)) { + _currentLevel += levelIncrement; + if ((_state == kEnvAttacking && _currentLevel <= targetLevel) || (_state != kEnvAttacking && _currentLevel >= targetLevel)) { + if (_state != kEnvDecaying) + _currentLevel = targetLevel; + _state = nextState; + } + } + } + + uint32 lvlout = _totalLevel + (uint32) _currentLevel; + + + int32 outp = 0; + int32 *i = &outp, *o = &outp; + int phaseShift = 0; + + if (feed) { + o = &feed[0]; + i = &feed[1]; + phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0; + *o = *i; + } else { + phaseShift = phasebuf << 15; + } + + if (lvlout < 832) { + uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) + + phaseShift)) >> 16) & 0x3ff]; + *i = ((index < 6656) ? _tLvlTbl[index] : 0); + } else { + *i = 0; + } + + _phase += _phaseIncrement; + out += *o; +} + +void TownsPC98_FmSynthOperator::reset(){ + keyOff(); + _timer = 0; + _keyScale2 = 0; + _currentLevel = 1023; + + frequency(0); + detune(0); + scaleRate(0); + multiple(0); + updatePhaseIncrement(); + attackRate(0); + decayRate(0); + releaseRate(0); + sustainRate(0); + feedbackLevel(0); + totalLevel(127); + ampModulation(false); +} + +bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) { + value = 3 - value; + if (_keyScale1 != value) { + _keyScale1 = value; + return true; + } + + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + return false; +} + +class TownsPC98_FmSynthSquareSineSource { +public: + TownsPC98_FmSynthSquareSineSource(const uint32 timerbase); + ~TownsPC98_FmSynthSquareSineSource(); + + void init(const int *rsTable, const int *rseTable); + void reset(); + void writeReg(uint8 address, uint8 value, bool force = false); + + void nextTick(int32 *buffer, uint32 bufferSize); + + void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + + uint8 chanEnable() const { return _chanEnable; } +private: + void updateRegs(); + + uint8 _updateRequestBuf[64]; + int _updateRequest; + int _rand; + + int8 _evpTimer; + uint32 _pReslt; + uint8 _attack; + + bool _evpUpdate, _cont; + + int _evpUpdateCnt; + uint8 _outN; + int _nTick; + + int32 *_tlTable; + int32 *_tleTable; + + const uint32 _tickLength; + uint32 _timer; + + struct Channel { + int tick; + uint8 smp; + uint8 out; + + uint8 frqL; + uint8 frqH; + uint8 vol; + } _channels[3]; + + uint8 _noiseGenerator; + uint8 _chanEnable; + + uint8 **_reg; + + uint16 _volumeA; + uint16 _volumeB; + int _volMaskA; + int _volMaskB; + + bool _ready; +}; + +class TownsPC98_FmSynthPercussionSource { +public: + TownsPC98_FmSynthPercussionSource(const uint32 timerbase); + ~TownsPC98_FmSynthPercussionSource() { delete[] _reg; } + + void init(const uint8 *instrData = 0); + void reset(); + void writeReg(uint8 address, uint8 value); + + void nextTick(int32 *buffer, uint32 bufferSize); + + void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + +private: + struct RhtChannel { + const uint8 *data; + + const uint8 *start; + const uint8 *end; + const uint8 *pos; + uint32 size; + bool active; + uint8 level; + + int8 decState; + uint8 decStep; + + int16 samples[2]; + int out; + + uint8 startPosH; + uint8 startPosL; + uint8 endPosH; + uint8 endPosL; + }; + + void recalcOuput(RhtChannel *ins); + void advanceInput(RhtChannel *ins); + + RhtChannel _rhChan[6]; + + uint8 _totalLevel; + + const uint32 _tickLength; + uint32 _timer; + + uint8 **_reg; + + uint16 _volumeA; + uint16 _volumeB; + int _volMaskA; + int _volMaskB; + + bool _ready; +}; + +TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint32 timerbase) : _tlTable(0), + _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1), + _nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true), + _timer(0), _noiseGenerator(0), _chanEnable(0), + _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { + + memset(_channels, 0, sizeof(_channels)); + memset(_updateRequestBuf, 0, sizeof(_updateRequestBuf)); + _reg = new uint8 *[11]; + + _reg[0] = &_channels[0].frqL; + _reg[1] = &_channels[0].frqH; + _reg[2] = &_channels[1].frqL; + _reg[3] = &_channels[1].frqH; + _reg[4] = &_channels[2].frqL; + _reg[5] = &_channels[2].frqH; + _reg[6] = &_noiseGenerator; + _reg[7] = &_chanEnable; + _reg[8] = &_channels[0].vol; + _reg[9] = &_channels[1].vol; + _reg[10] = &_channels[2].vol; + + reset(); +} + +TownsPC98_FmSynthSquareSineSource::~TownsPC98_FmSynthSquareSineSource() { + delete[] _tlTable; + delete[] _tleTable; + delete[] _reg; +} + +void TownsPC98_FmSynthSquareSineSource::init(const int *rsTable, const int *rseTable) { + if (_ready) { + reset(); + return; + } + + delete[] _tlTable; + delete[] _tleTable; + _tlTable = new int32[16]; + _tleTable = new int32[32]; + float a, b, d; + d = 801.0f; + + for (int i = 0; i < 16; i++) { + b = 1.0f / rsTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tlTable[i] = (int32) v; + + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + + for (int i = 16; i < 32; i++) { + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + + _ready = true; +} + +void TownsPC98_FmSynthSquareSineSource::reset() { + _rand = 1; + _outN = 1; + _updateRequest = -1; + _nTick = _evpUpdateCnt = 0; + _evpTimer = 0x1f; + _pReslt = 0x1f; + _attack = 0; + _cont = false; + _evpUpdate = true; + _timer = 0; + + for (int i = 0; i < 3; i++) { + _channels[i].tick = 0; + _channels[i].smp = _channels[i].out = 0; + } + + for (int i = 0; i < 14; i++) + writeReg(i, 0, true); + + writeReg(7, 0xbf, true); +} + +void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { + if (!_ready) + return; + + if (address > 10 || *_reg[address] == value) { + if ((address == 11 || address == 12 || address == 13) && value) + warning("TownsPC98_FmSynthSquareSineSource: unsupported reg address: %d", address); + return; + } + + if (!force) { + if (_updateRequest >= 63) { + warning("TownsPC98_FmSynthSquareSineSource: event buffer overflow"); + _updateRequest = -1; + } + _updateRequestBuf[++_updateRequest] = value; + _updateRequestBuf[++_updateRequest] = address; + return; + } + + *_reg[address] = value; +} + +void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + if (++_nTick >= (_noiseGenerator & 0x1f)) { + if ((_rand + 1) & 2) + _outN ^= 1; + + _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); + _nTick = 0; + } + + for (int ii = 0; ii < 3; ii++) { + if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) { + _channels[ii].tick = 0; + _channels[ii].smp ^= 1; + } + _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1)); + } + + if (_evpUpdate) { + if (++_evpUpdateCnt >= 0) { + _evpUpdateCnt = 0; + + if (--_evpTimer < 0) { + if (_cont) { + _evpTimer &= 0x1f; + } else { + _evpUpdate = false; + _evpTimer = 0; + } + } + } + } + _pReslt = _evpTimer ^ _attack; + updateRegs(); + } + + int32 finOut = 0; + for (int ii = 0; ii < 3; ii++) { + int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; + + if ((1 << ii) & _volMaskA) + finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if ((1 << ii) & _volMaskB) + finOutTemp = (finOutTemp * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + finOut += finOutTemp; + } + + finOut /= 3; + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } +} + +void TownsPC98_FmSynthSquareSineSource::updateRegs() { + for (int i = 0; i < _updateRequest;) { + uint8 b = _updateRequestBuf[i++]; + uint8 a = _updateRequestBuf[i++]; + writeReg(a, b, true); + } + _updateRequest = -1; +} + +TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase) : + _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { + + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + _reg = new uint8 *[40]; + + _reg[0] = _reg[1] = _reg[2] = _reg[3] = _reg[4] = _reg[5] = _reg[6] = _reg[7] = _reg[8] = _reg[9] = _reg[10] = _reg[11] = _reg[12] = _reg[13] = _reg[14] = _reg[15] = 0; + _reg[16] = &_rhChan[0].startPosL; + _reg[17] = &_rhChan[1].startPosL; + _reg[18] = &_rhChan[2].startPosL; + _reg[19] = &_rhChan[3].startPosL; + _reg[20] = &_rhChan[4].startPosL; + _reg[21] = &_rhChan[5].startPosL; + _reg[22] = &_rhChan[0].startPosH; + _reg[23] = &_rhChan[1].startPosH; + _reg[24] = &_rhChan[2].startPosH; + _reg[25] = &_rhChan[3].startPosH; + _reg[26] = &_rhChan[4].startPosH; + _reg[27] = &_rhChan[5].startPosH; + _reg[28] = &_rhChan[0].endPosL; + _reg[29] = &_rhChan[1].endPosL; + _reg[30] = &_rhChan[2].endPosL; + _reg[31] = &_rhChan[3].endPosL; + _reg[32] = &_rhChan[4].endPosL; + _reg[33] = &_rhChan[5].endPosL; + _reg[34] = &_rhChan[0].endPosH; + _reg[35] = &_rhChan[1].endPosH; + _reg[36] = &_rhChan[2].endPosH; + _reg[37] = &_rhChan[3].endPosH; + _reg[38] = &_rhChan[4].endPosH; + _reg[39] = &_rhChan[5].endPosH; +} + +void TownsPC98_FmSynthPercussionSource::init(const uint8 *instrData) { + if (_ready) { + reset(); + return; + } + + const uint8 *start = instrData; + const uint8 *pos = start; + + if (instrData) { + for (int i = 0; i < 6; i++) { + _rhChan[i].data = start + READ_BE_UINT16(pos); + pos += 2; + _rhChan[i].size = READ_BE_UINT16(pos); + pos += 2; + } + reset(); + _ready = true; + } else { + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + _ready = false; + } +} + +void TownsPC98_FmSynthPercussionSource::reset() { + _timer = 0; + _totalLevel = 63; + + for (int i = 0; i < 6; i++) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start = s->data; + s->end = s->data + s->size; + s->active = false; + s->level = 0; + s->out = 0; + s->decStep = 1; + s->decState = 0; + s->samples[0] = s->samples[1] = 0; + s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0; + } +} + +void TownsPC98_FmSynthPercussionSource::writeReg(uint8 address, uint8 value) { + if (!_ready) + return; + + uint8 h = address >> 4; + uint8 l = address & 15; + + if (address > 15) + *_reg[address] = value; + + if (address == 0) { + if (value & 0x80) { + //key off + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) + _rhChan[i].active = false; + } + } else { + //key on + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start; + s->active = true; + s->out = 0; + s->samples[0] = s->samples[1] = 0; + s->decStep = 1; + s->decState = 0; + } + } + } + } else if (address == 1) { + // total level + _totalLevel = (value & 63) ^ 63; + for (int i = 0; i < 6; i++) + recalcOuput(&_rhChan[i]); + } else if (!h && l & 8) { + // instrument level + l &= 7; + _rhChan[l].level = (value & 0x1f) ^ 0x1f; + recalcOuput(&_rhChan[l]); + } else if (h & 3) { + l &= 7; + if (h == 1) { + // set start offset + _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8); + } else if (h == 2) { + // set end offset + _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255; + } + } +} + +void TownsPC98_FmSynthPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + for (int ii = 0; ii < 6; ii++) { + RhtChannel *s = &_rhChan[ii]; + if (s->active) { + recalcOuput(s); + if (s->decStep) { + advanceInput(s); + if (s->pos == s->end) + s->active = false; + } + s->decStep ^= 1; + } + } + } + + int32 finOut = 0; + + for (int ii = 0; ii < 6; ii++) { + if (_rhChan[ii].active) + finOut += _rhChan[ii].out; + } + + finOut <<= 1; + + if (1 & _volMaskA) + finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if (1 & _volMaskB) + finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } +} + +void TownsPC98_FmSynthPercussionSource::recalcOuput(RhtChannel *ins) { + uint32 s = _totalLevel + ins->level; + uint32 x = s > 62 ? 0 : (1 + (s >> 3)); + int32 y = s > 62 ? 0 : (15 - (s & 7)); + ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; +} + +void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) { + static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; + + static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, + 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 + }; + + uint8 cur = (int8) *ins->pos++; + + for (int i = 0; i < 2; i++) { + int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; + ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); + ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48); + cur >>= 4; + } +} + +TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : + _mixer(mixer), + _chanInternal(0), _ssg(0), _prc(0), + _numChan(type == kType26 ? 3 : 6), _numSSG(type == kTypeTowns ? 0 : 3), _hasPercussion(type == kType86 ? true : false), + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), + _baserate(55125.0f / (float)mixer->getOutputRate()), + _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), + _regProtectionFlag(false), _ready(false) { + + memset(&_timers[0], 0, sizeof(ChipTimer)); + memset(&_timers[1], 0, sizeof(ChipTimer)); + _timers[0].cb = &TownsPC98_FmSynth::timerCallbackA; + _timers[1].cb = &TownsPC98_FmSynth::timerCallbackB; + _timerbase = (uint32)(_baserate * 1000000.0f); +} + +TownsPC98_FmSynth::~TownsPC98_FmSynth() { + Common::StackLock lock(_mutex); + _mixer->stopHandle(_soundHandle); + delete _ssg; + delete _prc; + delete[] _chanInternal; + + delete[] _oprRates; + delete[] _oprRateshift; + delete[] _oprFrq; + delete[] _oprAttackDecay; + delete[] _oprSinTbl; + delete[] _oprLevelOut; + delete[] _oprDetune; +} + +bool TownsPC98_FmSynth::init() { + if (_ready) { + reset(); + return true; + } + + generateTables(); + + _chanInternal = new ChanInternal[_numChan]; + for (int i = 0; i < _numChan; i++) { + memset(&_chanInternal[i], 0, sizeof(ChanInternal)); + for (int j = 0; j < 4; ++j) + _chanInternal[i].opr[j] = new TownsPC98_FmSynthOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); + } + + if (_numSSG) { + _ssg = new TownsPC98_FmSynthSquareSineSource(_timerbase); + _ssg->init(&_ssgTables[0], &_ssgTables[16]); + } + + if (_hasPercussion) { + _prc = new TownsPC98_FmSynthPercussionSource(_timerbase); + _prc->init(_percussionData); + } + + _mixer->playStream(Audio::Mixer::kPlainSoundType, + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _ready = true; + + return true; +} + +void TownsPC98_FmSynth::reset() { + for (int i = 0; i < _numChan; i++) { + for (int ii = 0; ii < 4; ii++) + _chanInternal[i].opr[ii]->reset(); + memset(_chanInternal[i].feedbuf, 0, 3); + _chanInternal[i].algorithm = 0; + _chanInternal[i].frqTemp = 0; + _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true; + _chanInternal[i].updateEnvelopeParameters = false; + } + + writeReg(0, 0x27, 0x33); + + if (_ssg) + _ssg->reset(); + + if (_prc) + _prc->reset(); +} + +void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { + if (_regProtectionFlag || !_ready) + return; + + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; + + Common::StackLock lock(_mutex); + + uint8 h = regAddress & 0xf0; + uint8 l = (regAddress & 0x0f); + + ChanInternal *c = 0; + TownsPC98_FmSynthOperator **co = 0; + TownsPC98_FmSynthOperator *o = 0; + + if (regAddress > 0x2F) { + c = &_chanInternal[(l & 3) + 3 * part]; + co = c->opr; + o = c->opr[oprOrdr[(l - (l & 3)) >> 2]]; + } else if (regAddress == 0x28) { + c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)]; + co = c->opr; + } + + switch (h) { + case 0x00: + // ssg + if (_ssg) + _ssg->writeReg(l, value); + break; + case 0x10: + // pcm rhythm channel + if (_prc) + _prc->writeReg(l, value); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + co[oprOrdr[i]]->keyOn(); + else + co[oprOrdr[i]]->keyOff(); + } + } else if (l == 4) { + // Timer A + _timers[0].value = (_timers[0].value & 3) | (value << 2); + } else if (l == 5) { + // Timer A + _timers[0].value = (_timers[0].value & 0x3fc) | (value & 3); + } else if (l == 6) { + // Timer B + _timers[1].value = value & 0xff; + } else if (l == 7) { + if (value & 1) { + float spc = (float)(0x400 - _timers[0].value) / _baserate; + if (spc < 1) { + warning("TownsPC98_FmSynth: Invalid Timer A setting: %d", _timers[0].value); + spc = 1; + } + + _timers[0].smpPerCb = (int32) spc; + _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); + _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCbRem = _timers[0].smpPerCbRem; + _timers[0].enabled = true; + } else { + _timers[0].enabled = false; + } + + if (value & 2) { + float spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate; + if (spc < 1) { + warning("TownsPC98_FmSynth: Invalid Timer B setting: %d", _timers[1].value); + spc = 1; + } + + _timers[1].smpPerCb = (int32) spc; + _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f); + _timers[1].smpTillCb = _timers[1].smpPerCb; + _timers[1].smpTillCbRem = _timers[1].smpPerCbRem; + _timers[1].enabled = true; + } else { + _timers[1].enabled = false; + } + + if (value & 0x10) { + _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCbRem = _timers[0].smpTillCbRem; + } + + if (value & 0x20) { + _timers[1].smpTillCb = _timers[1].smpPerCb; + _timers[1].smpTillCbRem = _timers[1].smpTillCbRem; + } + } else if (l == 2) { + // LFO + if (value & 8) + warning("TownsPC98_FmSynth: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + if (l == 11 && (value & 0x80)) + warning("TownsPC98_FmSynth: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; + + case 0x30: + // detune, multiple + o->detune((value >> 4) & 7); + o->multiple(value & 0x0f); + c->updateEnvelopeParameters = true; + break; + + case 0x40: + // total level + o->totalLevel(value & 0x7f); + break; + + case 0x50: + // rate scaling, attack rate + o->attackRate(value & 0x1f); + if (o->scaleRate(value >> 6)) + c->updateEnvelopeParameters = true; + break; + + case 0x60: + // first decay rate, amplitude modulation + o->decayRate(value & 0x1f); + o->ampModulation(value & 0x80 ? true : false); + break; + + case 0x70: + // secondary decay rate + o->sustainRate(value & 0x1f); + break; + + case 0x80: + // secondary amplitude, release rate; + o->sustainLevel(value >> 4); + o->releaseRate(value & 0x0f); + break; + + case 0x90: + warning("TownsPC98_FmSynth: TRYING TO USE SSG ENVELOPE SHAPES (NOT SUPPORTED)"); + break; + + case 0xa0: + // frequency + l &= ~3; + if (l == 0) { + c->frqTemp = (c->frqTemp & 0xff00) | value; + c->updateEnvelopeParameters = true; + for (int i = 0; i < 4; i++) + co[i]->frequency(c->frqTemp); + } else if (l == 4) { + c->frqTemp = (c->frqTemp & 0xff) | (value << 8); + } else if (l == 8) { + // Ch 3/6 special mode frq + warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } else if (l == 12) { + // Ch 3/6 special mode frq + warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } + break; + + case 0xb0: + l &= ~3; + if (l == 0) { + // feedback, _algorithm + co[0]->feedbackLevel((value >> 3) & 7); + c->algorithm = value & 7; + } else if (l == 4) { + // stereo, LFO sensitivity + c->enableLeft = value & 0x80 ? true : false; + c->enableRight = value & 0x40 ? true : false; + c->ampModSensitivity((value & 0x30) >> 4); + c->frqModSensitivity(value & 3); + } + break; + + default: + warning("TownsPC98_FmSynth: UNKNOWN ADDRESS %d", regAddress); + } +} + +int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + + memset(buffer, 0, sizeof(int16) * numSamples); + int32 *tmp = new int32[numSamples]; + int32 *tmpStart = tmp; + memset(tmp, 0, sizeof(int32) * numSamples); + int32 samplesLeft = numSamples >> 1; + + while (samplesLeft) { + int32 render = samplesLeft; + + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + if (!_timers[i].smpTillCb) { + (this->*_timers[i].cb)(); + _timers[i].smpTillCb = _timers[i].smpPerCb; + + _timers[i].smpTillCbRem += _timers[i].smpPerCbRem; + if (_timers[i].smpTillCbRem >= _timerbase) { + _timers[i].smpTillCb++; + _timers[i].smpTillCbRem -= _timerbase; + } + } + render = MIN(render, _timers[i].smpTillCb); + } + } + + samplesLeft -= render; + + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + _timers[i].smpTillCb -= render; + } + } + + nextTick(tmp, render); + + if (_ssg) + _ssg->nextTick(tmp, render); + if (_prc) + _prc->nextTick(tmp, render); + + nextTickEx(tmp, render); + + for (int i = 0; i < render; ++i) { + int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767); + buffer[i << 1] = (int16) l; + int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767); + buffer[(i << 1) + 1] = (int16) r; + } + + buffer += (render << 1); + tmp += (render << 1); + } + + delete[] tmpStart; + return numSamples; +} + +uint8 TownsPC98_FmSynth::readSSGStatus() { + return _ssg->chanEnable(); +} + +void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) { + Common::StackLock lock(_mutex); + _volumeA = volA; + _volumeB = volB; + if (_ssg) + _ssg->setVolumeIntern(volA, volB); + if (_prc) + _prc->setVolumeIntern(volA, volB); +} + +void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) { + Common::StackLock lock(_mutex); + _volMaskA = channelMaskA; + _volMaskB = channelMaskB; + if (_ssg) + _ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan); + if (_prc) + _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); +} + +void TownsPC98_FmSynth::generateTables() { + delete[] _oprRates; + _oprRates = new uint8[128]; + + WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018); + WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018); + memset(_oprRates, 0x90, 32); + memset(_oprRates + 96, 0x80, 32); + uint8 *dst = (uint8 *)_oprRates + 40; + for (int i = 0; i < 40; i += 4) + WRITE_BE_UINT32(dst + i, 0x00081018); + for (int i = 0; i < 48; i += 4) + WRITE_BE_UINT32(dst + i, 0x00081018); + dst += 40; + for (uint8 i = 0; i < 16; i ++) { + uint8 v = (i < 12) ? i : 12; + *dst++ = ((4 + v) << 3); + } + + delete[] _oprRateshift; + _oprRateshift = new uint8[128]; + memset(_oprRateshift, 0, 128); + dst = (uint8 *)_oprRateshift + 32; + for (int i = 11; i; i--) { + memset(dst, i, 4); + dst += 4; + } + + delete[] _oprFrq; + _oprFrq = new uint32[0x1000]; + for (uint32 i = 0; i < 0x1000; i++) + _oprFrq[i] = (uint32)(_baserate * (float)(i << 11)); + + delete[] _oprAttackDecay; + _oprAttackDecay = new uint8[152]; + memset(_oprAttackDecay, 0, 152); + for (int i = 0; i < 36; i++) + WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); + + delete[] _oprSinTbl; + _oprSinTbl = new uint32[1024]; + for (int i = 0; i < 1024; i++) { + double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); + double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; + int32 i_dcb = (int32)(2.0 * d_dcb); + i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); + _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + } + + delete[] _oprLevelOut; + _oprLevelOut = new int32[0x1a00]; + for (int i = 0; i < 256; i++) { + double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); + int32 val_int = ((int32) val) >> 4; + _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; + _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; + for (int ii = 1; ii < 13; ii++) { + _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; + _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + } + } + + uint8 *dtt = new uint8[128]; + memset(dtt, 0, 36); + memset(dtt + 36, 1, 8); + memcpy(dtt + 44, _detSrc, 84); + + delete[] _oprDetune; + _oprDetune = new int32[256]; + for (int i = 0; i < 128; i++) { + _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); + _oprDetune[i + 128] = -_oprDetune[i]; + } + + delete[] dtt; +} + +void TownsPC98_FmSynth::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (int i = 0; i < _numChan; i++) { + TownsPC98_FmSynthOperator **o = _chanInternal[i].opr; + + if (_chanInternal[i].updateEnvelopeParameters) { + _chanInternal[i].updateEnvelopeParameters = false; + for (int ii = 0; ii < 4 ; ii++) + o[ii]->updatePhaseIncrement(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) { + int32 phbuf1, phbuf2, output; + phbuf1 = phbuf2 = output = 0; + + int32 *leftSample = &buffer[ii * 2]; + int32 *rightSample = &buffer[ii * 2 + 1]; + int32 *del = &_chanInternal[i].feedbuf[2]; + int32 *feed = _chanInternal[i].feedbuf; + + switch (_chanInternal[i].algorithm) { + case 0: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + o[1]->generateOutput(phbuf1, 0, *del); + o[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(0, 0, *del); + o[1]->generateOutput(phbuf2, 0, phbuf1); + o[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, phbuf2); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf1, 0, output); + *del = phbuf1; + break; + case 6: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + o[0]->generateOutput(0, feed, output); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(0, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + int32 finOut = (output << 2) / ((_numChan + _numSSG - 3) / 3); + + if ((1 << i) & _volMaskA) + finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if ((1 << i) & _volMaskB) + finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + if (_chanInternal[i].enableLeft) + *leftSample += finOut; + + if (_chanInternal[i].enableRight) + *rightSample += finOut; + } + } +} + +const uint32 TownsPC98_FmSynth::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + +const uint8 TownsPC98_FmSynth::_detSrc[] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16 +}; + +const int TownsPC98_FmSynth::_ssgTables[] = { + 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, + 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, + 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, + 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, + 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, + 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB +}; + +const uint8 TownsPC98_FmSynth::_percussionData[] = { + 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57, + 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141, + 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139, + 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37, + 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137, + 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33, + 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139, + 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24, + 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144, + 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216, + 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201, + 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128, + 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33, + 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163, + 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249, + 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178, + 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148, + 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161, + 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32, + 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176, + 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140, + 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243, + 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144, + 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129, + 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56, + 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0, + 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58, + 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10, + 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8, + 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179, + 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153, + 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76, + 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193, + 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136, + 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181, + 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11, + 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184, + 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136, + 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180, + 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200, + 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10, + 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49, + 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242, + 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138, + 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171, + 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211, + 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56, + 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0, + 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61, + 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169, + 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243, + 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31, + 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160, + 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9, + 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16, + 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106, + 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144, + 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58, + 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72, + 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136, + 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161, + 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57, + 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147, + 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59, + 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25, + 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24, + 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178, + 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129, + 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63, + 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29, + 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184, + 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159, + 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153, + 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61, + 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220, + 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128, + 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145, + 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130, + 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8, + 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138, + 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176, + 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143, + 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177, + 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18, + 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59, + 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146, + 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0, + 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179, + 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122, + 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226, + 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134, + 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203, + 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151, + 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37, + 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18, + 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62, + 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231, + 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25, + 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60, + 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146, + 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119, + 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172, + 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34, + 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187, + 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21, + 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154, + 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169, + 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41, + 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83, + 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181, + 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73, + 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8 +}; diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h new file mode 100644 index 0000000000..1f9d610d9d --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -0,0 +1,171 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_PC98_FMSYNTH_H +#define TOWNS_PC98_FMSYNTH_H + +#include "sound/audiostream.h" +#include "sound/mixer.h" +#include "common/list.h" + +class TownsPC98_FmSynthOperator; +class TownsPC98_FmSynthSquareSineSource; +class TownsPC98_FmSynthPercussionSource; + +enum EnvelopeState { + kEnvReady, + kEnvAttacking, + kEnvDecaying, + kEnvSustaining, + kEnvReleasing +}; + +class TownsPC98_FmSynth : public Audio::AudioStream { +public: + enum EmuType { + kTypeTowns, + kType26, + kType86 + }; + + TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type); + virtual ~TownsPC98_FmSynth(); + + virtual bool init(); + virtual void reset(); + + void writeReg(uint8 part, uint8 regAddress, uint8 value); + + // AudioStream interface + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + bool endOfData() const { return false; } + int getRate() const { return _mixer->getOutputRate(); } + +protected: + // Implement this in your inherited class if your driver generates + // additional output that has to be inserted into the buffer. + virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {} + + void toggleRegProtection(bool prot) { _regProtectionFlag = prot; } + uint8 readSSGStatus(); + + virtual void timerCallbackA() = 0; + virtual void timerCallbackB() = 0; + + // The audio driver can store and apply two different audio settings + // (usually for music and sound effects). The channel mask will determine + // which channels get effected by the setting. The first bits will be + // the normal fm channels, the next bits the ssg channels and the final + // bit the rhythm channel. + void setVolumeIntern(int volA, int volB); + void setVolumeChannelMasks(int channelMaskA, int channelMaskB); + + const int _numChan; + const int _numSSG; + const bool _hasPercussion; + + Common::Mutex _mutex; +private: + void generateTables(); + void nextTick(int32 *buffer, uint32 bufferSize); + void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); + + struct ChanInternal { + ChanInternal() { + memset(this, 0, sizeof(ChanInternal)); + } + + ~ChanInternal() { + for (uint i = 0; i < ARRAYSIZE(opr); ++i) + delete opr[i]; + } + + void ampModSensitivity(uint32 value) { ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1)); } + void frqModSensitivity(uint32 value) { frqModSvty = value << 5; } + + uint16 frqTemp; + bool enableLeft; + bool enableRight; + bool updateEnvelopeParameters; + int32 feedbuf[3]; + uint8 algorithm; + + uint32 ampModSvty; + uint32 frqModSvty; + + + TownsPC98_FmSynthOperator *opr[4]; + }; + + TownsPC98_FmSynthSquareSineSource *_ssg; + TownsPC98_FmSynthPercussionSource *_prc; + ChanInternal *_chanInternal; + + uint8 *_oprRates; + uint8 *_oprRateshift; + uint8 *_oprAttackDecay; + uint32 *_oprFrq; + uint32 *_oprSinTbl; + int32 *_oprLevelOut; + int32 *_oprDetune; + + bool _regProtectionFlag; + + typedef void (TownsPC98_FmSynth::*ChipTimerProc)(); + + struct ChipTimer { + bool enabled; + uint16 value; + + int32 smpTillCb; + uint32 smpTillCbRem; + int32 smpPerCb; + uint32 smpPerCbRem; + + ChipTimerProc cb; + }; + + ChipTimer _timers[2]; + + int _volMaskA, _volMaskB; + uint16 _volumeA, _volumeB; + + const float _baserate; + uint32 _timerbase; + + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle; + + static const uint8 _percussionData[]; + static const uint32 _adtStat[]; + static const uint8 _detSrc[]; + static const int _ssgTables[]; + + bool _ready; +}; + +#endif + diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index c1bcbc006c..38fc60763e 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -45,7 +45,7 @@ #include <map> enum { - kKyraDatVersion = 70 + kKyraDatVersion = 71 }; const ExtractFilename extractFilenames[] = { @@ -163,6 +163,7 @@ const ExtractFilename extractFilenames[] = { { k1CreditsStrings, kTypeRawData, true }, // FM-TOWNS specific + { k1TownsMusicFadeTable, k3TypeRaw16to8, false }, { k1TownsSFXwdTable, kTypeTownsWDSfxTable, false }, { k1TownsSFXbtTable, kTypeRawData, false }, { k1TownsCDATable, kTypeRawData, false }, @@ -898,6 +899,8 @@ const char *getIdString(const int id) { return "k1GUIStrings"; case k1ConfigStrings: return "k1ConfigStrings"; + case k1TownsMusicFadeTable: + return "k1TownsMusicFadeTable"; case k1TownsSFXwdTable: return "k1TownsSFXwdTable"; case k1TownsSFXbtTable: diff --git a/tools/create_kyradat/create_kyradat.h b/tools/create_kyradat/create_kyradat.h index 435e239381..25a950935b 100644 --- a/tools/create_kyradat/create_kyradat.h +++ b/tools/create_kyradat/create_kyradat.h @@ -138,6 +138,8 @@ enum kExtractID { k1CreditsStrings, + k1TownsMusicFadeTable, + k1TownsMusicFadeTable, k1TownsSFXwdTable, k1TownsSFXbtTable, k1TownsCDATable, diff --git a/tools/create_kyradat/games.cpp b/tools/create_kyradat/games.cpp index 9976451067..1bd7d31648 100644 --- a/tools/create_kyradat/games.cpp +++ b/tools/create_kyradat/games.cpp @@ -411,6 +411,8 @@ const int kyra1TownsNeed[] = { k1NewGameString, k1ConfigStrings, + k1TownsMusicFadeTable, + k1TownsMusicFadeTable, k1TownsSFXwdTable, k1TownsSFXbtTable, k1TownsCDATable, diff --git a/tools/create_kyradat/tables.cpp b/tools/create_kyradat/tables.cpp index a74f58e2c3..dc8163901d 100644 --- a/tools/create_kyradat/tables.cpp +++ b/tools/create_kyradat/tables.cpp @@ -968,6 +968,12 @@ const ExtractEntrySearchData k1ConfigStringsProvider[] = { EXTRACT_END_ENTRY }; +const ExtractEntrySearchData k1TownsMusicFadeTableProvider[] = { + { UNK_LANG, kPlatformFMTowns, { 0x00000B10, 0x000076DE, { { 0x9F, 0x08, 0x5B, 0xD6, 0x25, 0x7F, 0x11, 0x08, 0x87, 0x45, 0x92, 0xD3, 0xE5, 0xA8, 0x7C, 0x2F } } } }, + + EXTRACT_END_ENTRY +}; + const ExtractEntrySearchData k1TownsSFXwdTableProvider[] = { { UNK_LANG, kPlatformFMTowns, { 0x00012608, 0x006717A1, { { 0x34, 0xDD, 0x2D, 0xA5, 0x14, 0x05, 0xEE, 0x2F, 0x93, 0x7C, 0x78, 0x4D, 0xCA, 0x13, 0xED, 0x93 } } } }, @@ -1823,6 +1829,7 @@ const ExtractEntry extractProviders[] = { { k1SpecialPalette33, k1SpecialPalette33Provider }, { k1GUIStrings, k1GUIStringsProvider }, { k1ConfigStrings, k1ConfigStringsProvider }, + { k1TownsMusicFadeTable, k1TownsMusicFadeTableProvider }, { k1TownsSFXwdTable, k1TownsSFXwdTableProvider }, { k1TownsSFXbtTable, k1TownsSFXbtTableProvider }, { k1TownsCDATable, k1TownsCDATableProvider }, |