From 4ec41c291e3a1e273b0ee571acdf2942a579e3ad Mon Sep 17 00:00:00 2001 From: athrxx Date: Mon, 2 Nov 2015 20:52:49 +0100 Subject: AUDIO: (FM-TOWNS) - cleanup euphony code (rework parts of the code + improve naming of variables/functions) --- audio/softsynth/fmtowns_pc98/towns_euphony.cpp | 1132 ++++++++++++------------ audio/softsynth/fmtowns_pc98/towns_euphony.h | 234 +++-- 2 files changed, 721 insertions(+), 645 deletions(-) (limited to 'audio') diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp index fca3d19912..dfcbdaf45a 100644 --- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -25,283 +25,157 @@ #include "common/util.h" #include "common/textconsole.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), _timerSetting(0), _tempoDiff(0), _timeStampBase(0), _elapsedEvents(0), _loop(false), - _endOfTrack(false), _suspendParsing(false), _musicTrackSize(0) { - _para[0] = _para[1] = 0; - _intf = new TownsAudioInterface(mixer, this); +EuphonyPlayer::EuphonyPlayer(Audio::Mixer *mixer) : _partConfig_enable(0), _partConfig_type(0), _partConfig_ordr(0), _partConfig_volume(0), + _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _timedEvents(0), _timedEventsCount(0), + _tempoControlMode(0), _timerSetting(0), _tempoMode1PulseCounter(0), _parseToBar(0), _tempoMode1UpdateF8(0), _loop(false), + _endOfTrack(false), _paused(false), _musicTrackSize(0) { + _drivers[0] = _eupDriver = new EuphonyDriver(mixer, this); + _drivers[1] = new Type0Driver(this); + _drivers[2] = 0; resetTempo(); } -TownsEuphonyDriver::~TownsEuphonyDriver() { - delete _intf; - delete[] _activeChannels; - delete[] _sustainChannels; - delete[] _assignedChannels; - delete[] _eventBuffer; - delete[] _tEnable; - delete[] _tMode; - delete[] _tOrdr; - delete[] _tLevel; - delete[] _tTranspose; -} - -bool TownsEuphonyDriver::init() { - if (!_intf->init()) - return false; - - delete[] _activeChannels; - delete[] _sustainChannels; - delete[] _assignedChannels; - delete[] _eventBuffer; - delete[] _tEnable; - delete[] _tMode; - delete[] _tOrdr; - delete[] _tLevel; - delete[] _tTranspose; - - _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(); +EuphonyPlayer::~EuphonyPlayer() { + for (int i = 0; i < 3; i++) + delete _drivers[i]; - return true; + delete[] _timedEvents; + delete[] _partConfig_enable; + delete[] _partConfig_type; + delete[] _partConfig_ordr; + delete[] _partConfig_volume; + delete[] _partConfig_transpose; } -void TownsEuphonyDriver::reset() { - _intf->callback(0); - - _intf->callback(74); - _intf->callback(70, 0); - _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); +bool EuphonyPlayer::init() { + for (int i = 0; i < 3; i++) { + if (_drivers[i]) { + if (!_drivers[i]->init()) { + warning("EuphonyPlayer:: Driver initalization failed: %d", i); + delete _drivers[i]; + _drivers[i] = 0; + } + } } + + if (!_drivers[0] || !_drivers[1]) + return false; - 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::reserveSoundEffectChannels(int num) { - _intf->callback(33, num); - uint32 volMask = 0; + delete[] _timedEvents; + delete[] _partConfig_enable; + delete[] _partConfig_type; + delete[] _partConfig_ordr; + delete[] _partConfig_volume; + delete[] _partConfig_transpose; - if (num > 8) - return; + _timedEvents = new TimedEvent[64]; - for (uint32 v = 1 << 13; num; num--) { - volMask |= v; - v >>= 1; - } + _partConfig_enable = new uint8[32]; + _partConfig_type = new uint8[32]; + _partConfig_ordr = new uint8[32]; + _partConfig_volume = new int8[32]; + _partConfig_transpose = new int8[32]; - _intf->setSoundEffectChanMask(volMask); -} + reset(); -int TownsEuphonyDriver::setMusicTempo(int tempo) { - if (tempo > 250) - return 3; - _defaultTempo = tempo; - _trackTempo = tempo; - setTempoIntern(tempo); - return 0; + return true; } -int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int startTick) { +int EuphonyPlayer::startTrack(const uint8 *data, int trackSize, int barLen) { if (_playing) return 2; _musicPos = _musicStart = data; - _defaultBaseTickLen = _baseTickLen = startTick; + _defaultBarLength = _barLength = barLen; _musicTrackSize = trackSize; - _timeStampBase = _timeStampDest = 0; - _tickCounter = 0; + _parseToBar = _bar = 0; + _beat = 0; _playing = true; return 0; } -void TownsEuphonyDriver::setMusicLoop(bool loop) { - _loop = loop; -} - -void TownsEuphonyDriver::stopParser() { +void EuphonyPlayer::stop() { if (_playing) { _playing = false; - _pulseCount = 0; + _playerUpdatesLeft = 0; _endOfTrack = false; - flushEventBuffer(); - resetControl(); + clearHangingNotes(); + resetAllControls(); } } -void TownsEuphonyDriver::continueParsing() { - _suspendParsing = false; +void EuphonyPlayer::pause() { + _paused = true; + clearHangingNotes(); + allPartsOff(); } -void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) { - _intf->callback(37, chan, note, velo, data); +void EuphonyPlayer::resume() { + _paused = false; } -void TownsEuphonyDriver::stopSoundEffect(int chan) { - _intf->callback(39, chan); -} - -bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) { - return _intf->callback(40, chan) ? true : false; -} - -void TownsEuphonyDriver::chanPanPos(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); +int EuphonyPlayer::setTempo(int tempo) { + if (tempo > 250) + return 3; + _defaultTempo = tempo; + _trackTempo = tempo; + sendTempo(tempo); + return 0; } -void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) { - _intf->callback(67, mode, volLeft, volRight); +void EuphonyPlayer::setLoopStatus(bool loop) { + _loop = loop; } -int TownsEuphonyDriver::configChan_enable(int tableEntry, int val) { - if (tableEntry > 31) +int EuphonyPlayer::configPart_enable(int part, int val) { + if (part > 31) return 3; - _tEnable[tableEntry] = val; + _partConfig_enable[part] = val; return 0; } -int TownsEuphonyDriver::configChan_setMode(int tableEntry, int val) { - if (tableEntry > 31) +int EuphonyPlayer::configPart_setType(int part, int val) { + if (part > 31) return 3; - _tMode[tableEntry] = val; + _partConfig_type[part] = val; return 0; } -int TownsEuphonyDriver::configChan_remap(int tableEntry, int val) { - if (tableEntry > 31) +int EuphonyPlayer::configPart_remap(int part, int val) { + if (part > 31) return 3; if (val < 16) - _tOrdr[tableEntry] = val; + _partConfig_ordr[part] = val; return 0; } -int TownsEuphonyDriver::configChan_adjustVolume(int tableEntry, int val) { - if (tableEntry > 31) +int EuphonyPlayer::configPart_adjustVolume(int part, int val) { + if (part > 31) return 3; if (val <= 40) - _tLevel[tableEntry] = (int8)(val & 0xff); + _partConfig_volume[part] = (int8)(val & 0xff); return 0; } -int TownsEuphonyDriver::configChan_setTranspose(int tableEntry, int val) { - if (tableEntry > 31) +int EuphonyPlayer::configPart_setTranspose(int part, int val) { + if (part > 31) return 3; if (val <= 40) - _tTranspose[tableEntry] = (int8)(val & 0xff); + _partConfig_transpose[part] = (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) { +void EuphonyPlayer::timerCallback(int timerId) { switch (timerId) { case 0: - updatePulseCount(); - while (_pulseCount > 0) { - --_pulseCount; - updateTimeStampBase(); + updatePulseCounters(); + while (_playerUpdatesLeft) { + --_playerUpdatesLeft; + updateBeat(); if (!_playing) continue; - updateEventBuffer(); + updateHangingNotes(); updateParser(); updateCheckEot(); } @@ -311,175 +185,155 @@ void TownsEuphonyDriver::timerCallback(int timerId) { } } -void TownsEuphonyDriver::setMusicVolume(int volume) { - _intf->setMusicVolume(volume); -} +void EuphonyPlayer::reset() { + _eupDriver->reset(); + _eupDriver->setTimerA(true, 1); + _eupDriver->setTimerA(false, 1); + _eupDriver->setTimerB(true, 221); -void TownsEuphonyDriver::setSoundEffectVolume(int volume) { - _intf->setSoundEffectVolume(volume); -} + resetPartConfig(); -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); -} + memset(_timedEvents, 0, 64 * sizeof(TimedEvent)); + _timedEventsCount = 0; -void TownsEuphonyDriver::resetTempo() { - _defaultBaseTickLen = _baseTickLen = 0x33; - _pulseCount = 0; - _extraTimingControlRemainder = 0; - _extraTimingControl = 16; - _tempoModifier = 0; - _timeStampDest = 0; - _deltaTicks = 0; - _tickCounter = 0; - _defaultTempo = 90; - _trackTempo = 90; -} + _playing = _endOfTrack = _paused = _loop = false; + _tempoMode1UpdateF8 = 0; + _tempoMode1PulseCounter = 0; -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; - } + resetTempo(); - } else if (_tempoControlMode == 2) { - _timerSetting = 625000 / (tempo + 30); - _extraTimingControlRemainder = 0; + if (_tempoControlMode == 1) { + //if (///) + // return; + sendTempo(_defaultTempo); + } else { + sendTempo(_defaultTempo); } + + resetAllControls(); } -void TownsEuphonyDriver::setTimerA(bool enable, int tempo) { - _intf->callback(21, enable ? 255 : 0, tempo); +void EuphonyPlayer::resetPartConfig() { + memset(_partConfig_enable, 0xff, 32); + memset(_partConfig_type, 0xff, 16); + memset(_partConfig_type + 16, 0, 16); + for (int i = 0; i < 32; i++) + _partConfig_ordr[i] = i & 0x0f; + memset(_partConfig_volume, 0, 32); + memset(_partConfig_transpose, 0, 32); } -void TownsEuphonyDriver::setTimerB(bool enable, int tempo) { - _intf->callback(22, enable ? 255 : 0, tempo); +void EuphonyPlayer::resetTempo() { + _defaultBarLength = _barLength = 0x33; + _playerUpdatesLeft = 0; + _updatesPerPulseRemainder = 0; + _updatesPerPulse = 0x10; + _tempoModifier = 0; + _bar = 0; + _deltaTicks = 0; + _beat = 0; + _defaultTempo = 90; + _trackTempo = 90; } -void TownsEuphonyDriver::updatePulseCount() { - int tc = _extraTimingControl + _extraTimingControlRemainder; - _extraTimingControlRemainder = tc & 0x0f; +void EuphonyPlayer::updatePulseCounters() { + int tc = _updatesPerPulse + _updatesPerPulseRemainder; + _updatesPerPulseRemainder = tc & 0x0f; tc >>= 4; - _tempoDiff -= tc; + _tempoMode1PulseCounter -= tc; - while (_tempoDiff < 0) { - _elapsedEvents++; - _tempoDiff += 4; + while (_tempoMode1PulseCounter < 0) { + _tempoMode1UpdateF8++; + _tempoMode1PulseCounter += 4; } - if (_playing && !_suspendParsing) - _pulseCount += tc; + if (_playing && !_paused) + _playerUpdatesLeft += 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) +void EuphonyPlayer::updateBeat() { + static const uint16 beatLengthTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; + uint8 beatsPersBar = (_barLength & 0x0f) + 1; + uint8 beatNoteValue = _barLength >> 4; + + if ((uint32)(beatLengthTable[beatNoteValue] * beatsPersBar) > ++_beat) return; - ++_timeStampDest; - _tickCounter = 0; + + ++_bar; + _beat = 0; _deltaTicks = 0; } -void TownsEuphonyDriver::updateParser() { +void EuphonyPlayer::updateParser() { for (bool loop = true; loop;) { uint8 cmd = _musicPos[0]; if (cmd == 0xff || cmd == 0xf7) { - jumpNextLoop(); + proceedToNextEvent(); } else if (cmd < 0x90) { _endOfTrack = true; - flushEventBuffer(); + clearHangingNotes(); loop = false; - } else if (_timeStampBase > _timeStampDest) { + } else if (_parseToBar > _bar) { 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) + if (_parseToBar == _bar) { + uint16 parseToBeat = READ_LE_UINT16(&_musicPos[2]); + uint8 l = (parseToBeat & 0xff) + (parseToBeat & 0xff); + parseToBeat = ((parseToBeat & 0xff00) | l) >> 1; + if (parseToBeat > _beat) loop = false; } if (loop) { - if (parseNext()) + if (parseEvent()) loop = false; } } } } -void TownsEuphonyDriver::updateCheckEot() { - if (!_endOfTrack || _bufferedEventsCount) +void EuphonyPlayer::updateCheckEot() { + if (!_endOfTrack || _timedEventsCount) 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) + stop(); +} + +bool EuphonyPlayer::parseEvent() { +#define EVENT(x) &EuphonyPlayer::event_##x + static const EuphonyEvent events[] = { + EVENT(notImpl), + EVENT(noteOn), + EVENT(polyphonicAftertouch), + EVENT(controlChange_pitchWheel), + EVENT(programChange_channelAftertouch), + EVENT(programChange_channelAftertouch), + EVENT(controlChange_pitchWheel), + + EVENT(loadInstrument), + EVENT(advanceBar), + EVENT(notImpl), + EVENT(notImpl), + EVENT(setTempo), + EVENT(notImpl), + EVENT(typeOrdrChange) }; -#undef OPC +#undef EVENT 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(); + bool result = (cmd >= 0xf0) ? (this->*events[((cmd - 0xf0) >> 1) + 7])() : (this->*events[(cmd - 0x80) >> 4])(); + if (!result) { + proceedToNextEvent(); return false; } } if (cmd == 0xfd) { - _suspendParsing = true; + _paused = true; return true; } @@ -490,193 +344,95 @@ bool TownsEuphonyDriver::parseNext() { _endOfTrack = false; _musicPos = _musicStart; - _timeStampBase = _timeStampDest = _tickCounter = 0; - _baseTickLen = _defaultBaseTickLen; + _parseToBar = _bar = _beat = 0; + _barLength = _defaultBarLength; return false; } -void TownsEuphonyDriver::jumpNextLoop() { +void EuphonyPlayer::proceedToNextEvent() { _musicPos += 6; if (_musicPos >= _musicStart + _musicTrackSize) _musicPos = _musicStart; } -void TownsEuphonyDriver::updateEventBuffer() { - DlEvent *e = _eventBuffer; - for (int i = _bufferedEventsCount; i; e++) { +void EuphonyPlayer::updateHangingNotes() { + TimedEvent *e = _timedEvents; + for (int i = _timedEventsCount; i; e++) { if (e->evt == 0) continue; if (--e->len) { --i; continue; } - processBufferNote(e->mode, e->evt, e->note, e->velo); + sendNoteEvent(e->type, e->evt, e->note, e->velo); e->evt = 0; --i; - --_bufferedEventsCount; + --_timedEventsCount; } } -void TownsEuphonyDriver::flushEventBuffer() { - DlEvent *e = _eventBuffer; - for (int i = _bufferedEventsCount; i; e++) { +void EuphonyPlayer::clearHangingNotes() { + TimedEvent *e = _timedEvents; + for (int i = _timedEventsCount; i; e++) { if (e->evt == 0) continue; - processBufferNote(e->mode, e->evt, e->note, e->velo); + sendNoteEvent(e->type, e->evt, e->note, e->velo); e->evt = 0; --i; - --_bufferedEventsCount; + --_timedEventsCount; } } -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() { +void EuphonyPlayer::resetAllControls() { for (int i = 0; i < 32; i++) { - if (_tOrdr[i] > 15) { + if (_partConfig_ordr[i] > 15) { for (int ii = 0; ii < 16; ii++) - resetControlIntern(_tMode[i], ii); + sendControllerReset(_partConfig_type[i], ii); } else { - resetControlIntern(_tMode[i], _tOrdr[i]); + sendControllerReset(_partConfig_type[i], _partConfig_ordr[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); +void EuphonyPlayer::allPartsOff() { + for (int i = 0; i < 32; i++) { + if (_partConfig_ordr[i] > 15) { + for (int ii = 0; ii < 16; ii++) + sendAllNotesOff(_partConfig_type[i], ii); + } else { + sendAllNotesOff(_partConfig_type[i], _partConfig_ordr[i]); + } + } } -uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) { - if (evt >= 0x80 && evt < 0xf0 && _tOrdr[chan] < 16) - return (evt & 0xf0) | _tOrdr[chan]; +uint8 EuphonyPlayer::appendEvent(uint8 evt, uint8 chan) { + if (evt >= 0x80 && evt < 0xf0 && _partConfig_ordr[chan] < 16) + return (evt & 0xf0) | _partConfig_ordr[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 EuphonyPlayer::event_notImpl() { + return false; } -bool TownsEuphonyDriver::evtSetupNote() { +bool EuphonyPlayer::event_noteOn() { if (_musicPos[1] > 31) return false; - if (!_tEnable[_musicPos[1]]) { - jumpNextLoop(); + if (!_partConfig_enable[_musicPos[1]]) { + proceedToNextEvent(); return (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) ? true : false; } uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); - uint8 mode = _tMode[_musicPos[1]]; + uint8 type = _partConfig_type[_musicPos[1]]; uint8 note = _musicPos[4]; uint8 velo = _musicPos[5]; - sendEvent(mode, evt); - sendEvent(mode, applyTranspose(note)); - sendEvent(mode, applyVolumeAdjust(velo)); + sendEvent(type, evt); + sendEvent(type, applyTranspose(note)); + sendEvent(type, applyVolumeAdjust(velo)); - jumpNextLoop(); + proceedToNextEvent(); if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) return true; @@ -685,104 +441,104 @@ bool TownsEuphonyDriver::evtSetupNote() { int i = 0; for (; i < 64; i++) { - if (_eventBuffer[i].evt == 0) + if (_timedEvents[i].evt == 0) break; } if (i == 64) { - processBufferNote(mode, evt, note, velo); + sendNoteEvent(type, 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++; + _timedEvents[i].evt = evt; + _timedEvents[i].type = type; + _timedEvents[i].note = note; + _timedEvents[i].velo = velo; + _timedEvents[i].len = len ? len : 1; + _timedEventsCount++; } return false; } -bool TownsEuphonyDriver::evtPolyphonicAftertouch() { +bool EuphonyPlayer::event_polyphonicAftertouch() { if (_musicPos[1] > 31) return false; - if (!_tEnable[_musicPos[1]]) + if (!_partConfig_enable[_musicPos[1]]) return false; uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); - uint8 mode = _tMode[_musicPos[1]]; + uint8 type = _partConfig_type[_musicPos[1]]; - sendEvent(mode, evt); - sendEvent(mode, applyTranspose(_musicPos[4])); - sendEvent(mode, _musicPos[5]); + sendEvent(type, evt); + sendEvent(type, applyTranspose(_musicPos[4])); + sendEvent(type, _musicPos[5]); return false; } -bool TownsEuphonyDriver::evtControlPitch() { +bool EuphonyPlayer::event_controlChange_pitchWheel() { if (_musicPos[1] > 31) return false; - if (!_tEnable[_musicPos[1]]) + if (!_partConfig_enable[_musicPos[1]]) return false; uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); - uint8 mode = _tMode[_musicPos[1]]; + uint8 type = _partConfig_type[_musicPos[1]]; - sendEvent(mode, evt); - sendEvent(mode, _musicPos[4]); - sendEvent(mode, _musicPos[5]); + sendEvent(type, evt); + sendEvent(type, _musicPos[4]); + sendEvent(type, _musicPos[5]); return false; } -bool TownsEuphonyDriver::evtInstrumentChanAftertouch() { +bool EuphonyPlayer::event_programChange_channelAftertouch() { if (_musicPos[1] > 31) return false; - if (!_tEnable[_musicPos[1]]) + if (!_partConfig_enable[_musicPos[1]]) return false; uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); - uint8 mode = _tMode[_musicPos[1]]; + uint8 type = _partConfig_type[_musicPos[1]]; - sendEvent(mode, evt); - sendEvent(mode, _musicPos[4]); + sendEvent(type, evt); + sendEvent(type, _musicPos[4]); return false; } -bool TownsEuphonyDriver::evtLoadInstrument() { +bool EuphonyPlayer::event_loadInstrument() { return false; } -bool TownsEuphonyDriver::evtAdvanceTimestampOffset() { - ++_timeStampBase; - _baseTickLen = _musicPos[1]; +bool EuphonyPlayer::event_advanceBar() { + ++_parseToBar; + _barLength = _musicPos[1]; return false; } -bool TownsEuphonyDriver::evtTempo() { +bool EuphonyPlayer::event_setTempo() { uint8 l = _musicPos[4] << 1; _trackTempo = (l | (_musicPos[5] << 8)) >> 1; - setTempoIntern(_trackTempo); + sendTempo(_trackTempo); return false; } -bool TownsEuphonyDriver::evtModeOrdrChange() { +bool EuphonyPlayer::event_typeOrdrChange() { if (_musicPos[1] > 31) return false; - if (!_tEnable[_musicPos[1]]) + if (!_partConfig_enable[_musicPos[1]]) return false; if (_musicPos[4] == 1) - _tMode[_musicPos[1]] = _musicPos[5]; + _partConfig_type[_musicPos[1]] = _musicPos[5]; else if (_musicPos[4] == 2) - _tOrdr[_musicPos[1]] = _musicPos[5]; + _partConfig_ordr[_musicPos[1]] = _musicPos[5]; return false; } -uint8 TownsEuphonyDriver::applyTranspose(uint8 in) { - int out = _tTranspose[_musicPos[1]]; +uint8 EuphonyPlayer::applyTranspose(uint8 in) { + int out = _partConfig_transpose[_musicPos[1]]; if (!out) return in; out += (in & 0x7f); @@ -796,61 +552,328 @@ uint8 TownsEuphonyDriver::applyTranspose(uint8 in) { return out & 0xff; } -uint8 TownsEuphonyDriver::applyVolumeAdjust(uint8 in) { - int out = _tLevel[_musicPos[1]]; +uint8 EuphonyPlayer::applyVolumeAdjust(uint8 in) { + int out = _partConfig_volume[_musicPos[1]]; out += (in & 0x7f); out = CLIP(out, 1, 127); return out & 0xff; } -void TownsEuphonyDriver::sendNoteOff() { - int8 *chan = &_activeChannels[_command & 0x0f]; +void EuphonyPlayer::sendEvent(uint8 type, uint8 command) { + int drv = ((type >> 4) + 1) & 3; + if (_drivers[drv]) + _drivers[drv]->send(command); +} + +void EuphonyPlayer::sendNoteEvent(int type, int evt, int note, int velo) { + if (!velo) + evt &= 0x8f; + sendEvent(type, evt); + sendEvent(type, note); + sendEvent(type, velo); +} + +void EuphonyPlayer::sendControllerReset(int type, int part) { + sendEvent(type, 0xb0 | part); + sendEvent(type, 0x40); + sendEvent(type, 0); + sendEvent(type, 0xb0 | part); + sendEvent(type, 0x7b); + sendEvent(type, 0); + sendEvent(type, 0xb0 | part); + sendEvent(type, 0x79); + sendEvent(type, 0x40); +} + +void EuphonyPlayer::sendAllNotesOff(int type, int part) { + sendEvent(type, 0xb0 | part); + sendEvent(type, 0x40); + sendEvent(type, 0); +} + +void EuphonyPlayer::sendTempo(int tempo) { + tempo = CLIP(tempo + _tempoModifier, 0, 500); + if (_tempoControlMode == 0) { + _timerSetting = 34750 / (tempo + 30); + _updatesPerPulse = 0x10; + + while (_timerSetting < 126) { + _timerSetting <<= 1; + _updatesPerPulse <<= 1; + } + + while (_timerSetting > 383) { + _timerSetting >>= 1; + _updatesPerPulse >>= 1; + } + + _eupDriver->setTimerA(true, -(_timerSetting - 2)); + + } else if (_tempoControlMode == 1) { + _timerSetting = 312500 / (tempo + 30); + _updatesPerPulse = 0x10; + while (_timerSetting < 1105) { + _timerSetting <<= 1; + _updatesPerPulse <<= 1; + } + + } else if (_tempoControlMode == 2) { + _timerSetting = 625000 / (tempo + 30); + _updatesPerPulseRemainder = 0; + } +} + +EuphonyDriver::EuphonyDriver(Audio::Mixer *mixer, EuphonyPlayer *pl) : EuphonyBaseDriver(), _channels(0), _partToChanMapping(0), _sustainChannels(0) { + _intf = new TownsAudioInterface(mixer, pl); +} + +EuphonyDriver::~EuphonyDriver() { + delete _intf; + delete[] _partToChanMapping; + delete[] _sustainChannels; + delete[] _channels; +} + + +bool EuphonyDriver::init() { + if (!_intf->init()) + return false; + + delete[] _channels; + delete[] _partToChanMapping; + delete[] _sustainChannels; + + _channels = new Channel[128]; + _partToChanMapping = new int8[16]; + _sustainChannels = new int8[16]; + + return true; +} + +void EuphonyDriver::reset() { + _intf->callback(0); + _intf->callback(74); + _intf->callback(70, 0); + _intf->callback(75, 3); + + _currentEvent.clear(); + memset(_sustainChannels, 0, 16); + memset(_partToChanMapping, -1, 16); + + for (int i = 0; i < 128; i++) { + _channels[i].part = _channels[i].next = -1; + _channels[i].note = _channels[i].pri = 0; + } + + int e = 0; + for (int i = 0; i < 6; i++) + assignPartToChannel(i, e++); + for (int i = 0x40; i < 0x48; i++) + assignPartToChannel(i, e++); +} + +int EuphonyDriver::assignPartToChannel(int chan, int part) { + if (part > 15 || chan > 127 || chan < 0) + return 3; + + Channel *a = &_channels[chan]; + if (a->part == part) + return 0; + + if (a->part != -1) { + int8 *b = &_partToChanMapping[a->part]; + while (*b != chan) { + b = &_channels[*b].next; + if (*b == -1 && *b != chan) + return 3; + } + + *b = a->next; + + if (a->note) + _intf->callback(2, chan); + + a->part = a->next = -1; + a->note = 0; + } + + a->next = _partToChanMapping[part]; + _partToChanMapping[part] = chan; + a->part = part; + a->note = a->pri = 0; + + return 0; +} + +void EuphonyDriver::send(uint8 command) { + if (command >= 0x80) { + _currentEvent.clear(); + _currentEvent.push_back(command >= 0xf0 ? 0 : command); + } else if (_currentEvent[0] >= 0x80) { + uint8 cmd = (_currentEvent[0] - 0x80) >> 4; + _currentEvent.push_back(command); + + static const uint8 eventSize[] = { 3, 3, 3, 3, 2, 2, 3 }; + if (_currentEvent.size() != eventSize[cmd]) + return; + + switch (cmd) { + case 0: + noteOff(); + break; + case 1: + if (_currentEvent[2]) + noteOn(); + else + noteOff(); + break; + case 3: + if (_currentEvent[1] == 7) + controlChange_volume(); + else if (_currentEvent[1] == 10) + controlChange_panPos(); + else if (_currentEvent[1] == 64) + controlChange_allNotesOff(); + break; + case 4: + programChange(); + break; + case 6: + pitchWheel(); + break; + default: + break; + } + } +} + +void EuphonyDriver::setTimerA(bool enable, int tempo) { + _intf->callback(21, enable ? 255 : 0, tempo); +} + +void EuphonyDriver::setTimerB(bool enable, int tempo) { + _intf->callback(22, enable ? 255 : 0, tempo); +} + +void EuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) { + _intf->callback(5, chanType, id, data); +} + +void EuphonyDriver::setInstrument(int chan, int instrID) { + _intf->callback(4, chan, instrID); +} + +void EuphonyDriver::loadWaveTable(const uint8 *data) { + _intf->callback(34, data); +} + +void EuphonyDriver::unloadWaveTable(int id) { + _intf->callback(35, id); +} + +void EuphonyDriver::reserveSoundEffectChannels(int num) { + _intf->callback(33, num); + uint32 volMask = 0; + + if (num > 8) + return; + + for (uint32 v = 1 << 13; num; num--) { + volMask |= v; + v >>= 1; + } + + _intf->setSoundEffectChanMask(volMask); +} + +void EuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) { + _intf->callback(37, chan, note, velo, data); +} + +void EuphonyDriver::stopSoundEffect(int chan) { + _intf->callback(39, chan); +} + +bool EuphonyDriver::soundEffectIsPlaying(int chan) { + return _intf->callback(40, chan) ? true : false; +} + +void EuphonyDriver::channelPan(int chan, int mode) { + _intf->callback(3, chan, mode); +} + +void EuphonyDriver::channelPitch(int chan, int pitch) { + _intf->callback(7, chan, pitch); +} + +void EuphonyDriver::channelVolume(int chan, int vol) { + _intf->callback(8, chan, vol); +} + +void EuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) { + _intf->callback(67, mode, volLeft, volRight); +} + +void EuphonyDriver::cdaToggle(int a) { + _intf->callback(73, a); +} + +void EuphonyDriver::setMusicVolume(int volume) { + _intf->setMusicVolume(volume); +} + +void EuphonyDriver::setSoundEffectVolume(int volume) { + _intf->setSoundEffectVolume(volume); +} + +void EuphonyDriver::noteOff() { + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; if (*chan == -1) return; - while (_assignedChannels[*chan].note != _para[0]) { - chan = &_assignedChannels[*chan].next; + while (_channels[*chan].note != _currentEvent[1]) { + chan = &_channels[*chan].next; if (*chan == -1) return; } - if (_sustainChannels[_command & 0x0f]) { - _assignedChannels[*chan].note |= 0x80; + if (_sustainChannels[_currentEvent[0] & 0x0f]) { + _channels[*chan].note |= 0x80; } else { - _assignedChannels[*chan].note = 0; + _channels[*chan].note = 0; _intf->callback(2, *chan); } } -void TownsEuphonyDriver::sendNoteOn() { - if (!_para[0]) +void EuphonyDriver::noteOn() { + if (!_currentEvent[1]) return; - int8 *chan = &_activeChannels[_command & 0x0f]; + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; if (*chan == -1) return; do { - _assignedChannels[*chan].sub++; - chan = &_assignedChannels[*chan].next; + _channels[*chan].pri++; + chan = &_channels[*chan].next; } while (*chan != -1); - chan = &_activeChannels[_command & 0x0f]; + chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; int d = 0; int c = 0; bool found = false; do { - if (!_assignedChannels[*chan].note) { + if (!_channels[*chan].note) { found = true; break; } - if (d <= _assignedChannels[*chan].sub) { + if (d <= _channels[*chan].pri) { c = *chan; - d = _assignedChannels[*chan].sub; + d = _channels[*chan].pri; } - chan = &_assignedChannels[*chan].next; + chan = &_channels[*chan].next; } while (*chan != -1); if (found) @@ -858,59 +881,72 @@ void TownsEuphonyDriver::sendNoteOn() { else _intf->callback(2, c); - _assignedChannels[c].note = _para[0]; - _assignedChannels[c].sub = 0; - _intf->callback(1, c, _para[0], _para[1]); + _channels[c].note = _currentEvent[1]; + _channels[c].pri = 0; + _intf->callback(1, c, _currentEvent[1], _currentEvent[2]); } -void TownsEuphonyDriver::sendChanVolume() { - int8 *chan = &_activeChannels[_command & 0x0f]; +void EuphonyDriver::controlChange_volume() { + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; while (*chan != -1) { - _intf->callback(8, *chan, _para[1] & 0x7f); - chan = &_assignedChannels[*chan].next; + _intf->callback(8, *chan, _currentEvent[2] & 0x7f); + chan = &_channels[*chan].next; } } -void TownsEuphonyDriver::sendPanPosition() { - int8 *chan = &_activeChannels[_command & 0x0f]; +void EuphonyDriver::controlChange_panPos() { + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; while (*chan != -1) { - _intf->callback(3, *chan, _para[1] & 0x7f); - chan = &_assignedChannels[*chan].next; + _intf->callback(3, *chan, _currentEvent[2] & 0x7f); + chan = &_channels[*chan].next; } } -void TownsEuphonyDriver::sendAllNotesOff() { - if (_para[1] > 63) { - _sustainChannels[_command & 0x0f] = -1; +void EuphonyDriver::controlChange_allNotesOff() { + if (_currentEvent[2] > 63) { + _sustainChannels[_currentEvent[0] & 0x0f] = -1; return; } - _sustainChannels[_command & 0x0f] = 0; - int8 *chan = &_activeChannels[_command & 0x0f]; + _sustainChannels[_currentEvent[0] & 0x0f] = 0; + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; while (*chan != -1) { - if (_assignedChannels[*chan].note & 0x80) { - _assignedChannels[*chan].note = 0; + if (_channels[*chan].note & 0x80) { + _channels[*chan].note = 0; _intf->callback(2, *chan); } - chan = &_assignedChannels[*chan].next; + chan = &_channels[*chan].next; } } -void TownsEuphonyDriver::sendSetInstrument() { - int8 *chan = &_activeChannels[_command & 0x0f]; +void EuphonyDriver::programChange() { + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; while (*chan != -1) { - _intf->callback(4, *chan, _para[0]); + _intf->callback(4, *chan, _currentEvent[1]); _intf->callback(7, *chan, 0); - chan = &_assignedChannels[*chan].next; + chan = &_channels[*chan].next; } } -void TownsEuphonyDriver::sendPitch() { - int8 *chan = &_activeChannels[_command & 0x0f]; +void EuphonyDriver::pitchWheel() { + int8 *chan = &_partToChanMapping[_currentEvent[0] & 0x0f]; while (*chan != -1) { - _para[0] += _para[0]; - int16 pitch = (((READ_LE_UINT16(_para)) >> 1) & 0x3fff) - 0x2000; + _currentEvent[1] += _currentEvent[1]; + int16 pitch = ((((_currentEvent[2] << 8) | _currentEvent[1]) >> 1) & 0x3fff) - 0x2000; _intf->callback(7, *chan, pitch); - chan = &_assignedChannels[*chan].next; + chan = &_channels[*chan].next; } } + +Type0Driver::Type0Driver(EuphonyPlayer *pl) : EuphonyBaseDriver() { +} + +Type0Driver::~Type0Driver() { +} + +bool Type0Driver::init() { + return true; +} + +void Type0Driver::send(uint8 command) { +} diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h index d77217884d..2e935a3ca5 100644 --- a/audio/softsynth/fmtowns_pc98/towns_euphony.h +++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h @@ -24,160 +24,200 @@ #define TOWNS_EUP_H #include "audio/softsynth/fmtowns_pc98/towns_audio.h" +#include "common/array.h" -class TownsEuphonyDriver : public TownsAudioInterfacePluginDriver { +class EuphonyBaseDriver { public: - TownsEuphonyDriver(Audio::Mixer *mixer); - virtual ~TownsEuphonyDriver(); + EuphonyBaseDriver() {} + virtual ~EuphonyBaseDriver() {} + + virtual bool init() { return true; } + + virtual void send(uint8 command) = 0; +}; + +class EuphonyPlayer; + +class EuphonyDriver : public EuphonyBaseDriver { +public: + EuphonyDriver(Audio::Mixer *mixer, EuphonyPlayer *pl); + ~EuphonyDriver(); bool init(); void reset(); + int assignPartToChannel(int chan, int part); + + void send(uint8 command); + + void setTimerA(bool enable, int tempo); + void setTimerB(bool enable, int tempo); + void loadInstrument(int chanType, int id, const uint8 *data); + void setInstrument(int chan, int instrID); void loadWaveTable(const uint8 *data); void unloadWaveTable(int id); - void reserveSoundEffectChannels(int num); - - int setMusicTempo(int tempo); - int startMusicTrack(const uint8 *data, int trackSize, int startTick); - void setMusicLoop(bool loop); - void stopParser(); - bool parserIsPlaying() {return _playing; } - void continueParsing(); + void reserveSoundEffectChannels(int num); void playSoundEffect(int chan, int note, int velo, const uint8 *data); void stopSoundEffect(int chan); bool soundEffectIsPlaying(int chan); - void chanPanPos(int chan, int mode); - void chanPitch(int chan, int pitch); - void chanVolume(int chan, int vol); + void channelPan(int chan, int mode); + void channelPitch(int chan, int pitch); + void channelVolume(int chan, int vol); void setOutputVolume(int chanType, int volLeft, int volRight); + void cdaToggle(int a); - int configChan_enable(int tableEntry, int val); - int configChan_setMode(int tableEntry, int val); - int configChan_remap(int tableEntry, int val); - int configChan_adjustVolume(int tableEntry, int val); - int configChan_setTranspose(int tableEntry, int val); + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); - int assignChannel(int chan, int tableEntry); +private: + void noteOff(); + void noteOn(); + void controlChange_volume(); + void controlChange_panPos(); + void controlChange_allNotesOff(); + void programChange(); + void pitchWheel(); + + Common::Array _currentEvent; + int8 *_partToChanMapping; + int8 *_sustainChannels; - void timerCallback(int timerId); + struct Channel { + int8 part; + int8 next; + uint8 note; + uint8 pri; + } *_channels; - void setMusicVolume(int volume); - void setSoundEffectVolume(int volume); + TownsAudioInterface *_intf; +}; - TownsAudioInterface *intf() { - return _intf; - } +class Type0Driver : public EuphonyBaseDriver { +public: + Type0Driver(EuphonyPlayer *pl); + ~Type0Driver(); -private: - void resetTables(); + bool init(); + + void send(uint8 command); +}; + +class EuphonyPlayer : public TownsAudioInterfacePluginDriver { +public: + EuphonyPlayer(Audio::Mixer *mixer); + virtual ~EuphonyPlayer(); + + bool init(); + + int startTrack(const uint8 *data, int trackSize, int barLen); + void stop(); + void pause(); + void resume(); + + int setTempo(int tempo); + void setLoopStatus(bool loop); + + bool isPlaying() {return _playing; } + + int configPart_enable(int part, int val); + int configPart_setType(int part, int val); + int configPart_remap(int part, int val); + int configPart_adjustVolume(int part, int val); + int configPart_setTranspose(int part, int val); + + void timerCallback(int timerId); + + EuphonyDriver *driver() { return _eupDriver; } +private: + void reset(); + void resetPartConfig(); void resetTempo(); - void setTempoIntern(int tempo); - void setTimerA(bool enable, int tempo); - void setTimerB(bool enable, int tempo); - void updatePulseCount(); - void updateTimeStampBase(); + void updatePulseCounters(); + void updateBeat(); void updateParser(); void updateCheckEot(); - bool parseNext(); - void jumpNextLoop(); + bool parseEvent(); + void proceedToNextEvent(); - void updateEventBuffer(); - void flushEventBuffer(); - void processBufferNote(int mode, int evt, int note, int velo); - - void resetControl(); - void resetControlIntern(int mode, int chan); + void updateHangingNotes(); + void clearHangingNotes(); + + void resetAllControls(); + void allPartsOff(); + 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; - } + typedef bool(EuphonyPlayer::*EuphonyEvent)(); + bool event_notImpl(); + bool event_noteOn(); + bool event_polyphonicAftertouch(); + bool event_controlChange_pitchWheel(); + bool event_programChange_channelAftertouch(); + + bool event_loadInstrument(); + bool event_advanceBar(); + bool event_setTempo(); + bool event_typeOrdrChange(); uint8 applyTranspose(uint8 in); uint8 applyVolumeAdjust(uint8 in); - void sendNoteOff(); - void sendNoteOn(); - void sendChanVolume(); - void sendPanPosition(); - void sendAllNotesOff(); - void sendSetInstrument(); - void sendPitch(); + void sendEvent(uint8 type, uint8 command); + void sendNoteEvent(int type, int evt, int note, int velo); + void sendControllerReset(int type, int part); + void sendAllNotesOff(int type, int part); + void sendTempo(int tempo); - int8 *_activeChannels; - int8 *_sustainChannels; + uint8 *_partConfig_enable; + uint8 *_partConfig_type; + uint8 *_partConfig_ordr; + int8 *_partConfig_volume; + int8 *_partConfig_transpose; - struct ActiveChannel { - int8 chan; - int8 next; - uint8 note; - uint8 sub; - } *_assignedChannels; - - uint8 *_tEnable; - uint8 *_tMode; - uint8 *_tOrdr; - int8 *_tLevel; - int8 *_tTranspose; - - struct DlEvent { + struct TimedEvent { uint8 evt; - uint8 mode; + uint8 type; uint8 note; uint8 velo; uint16 len; - } *_eventBuffer; - int _bufferedEventsCount; - - uint8 _para[2]; - uint8 _paraCount; - uint8 _command; + } *_timedEvents; + int _timedEventsCount; - uint8 _defaultBaseTickLen; - uint8 _baseTickLen; - uint32 _pulseCount; + uint8 _defaultBarLength; + uint8 _barLength; + int _playerUpdatesLeft; int _tempoControlMode; - int _extraTimingControlRemainder; - int _extraTimingControl; + int _updatesPerPulseRemainder; + int _updatesPerPulse; int _timerSetting; - int8 _tempoDiff; + int8 _tempoMode1PulseCounter; int _tempoModifier; - uint32 _timeStampDest; - uint32 _timeStampBase; - int8 _elapsedEvents; + uint32 _bar; + uint32 _parseToBar; + int8 _tempoMode1UpdateF8; uint8 _deltaTicks; - uint32 _tickCounter; + uint32 _beat; uint8 _defaultTempo; int _trackTempo; bool _loop; bool _playing; bool _endOfTrack; - bool _suspendParsing; + bool _paused; const uint8 *_musicStart; const uint8 *_musicPos; uint32 _musicTrackSize; - TownsAudioInterface *_intf; + EuphonyDriver *_eupDriver; + EuphonyBaseDriver *_drivers[3]; }; #endif -- cgit v1.2.3