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 +++-- engines/kyra/sound_intern.h | 2 +- engines/kyra/sound_towns.cpp | 100 +-- engines/scumm/players/player_towns.cpp | 61 +- engines/scumm/players/player_towns.h | 4 +- 6 files changed, 804 insertions(+), 729 deletions(-) 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 diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h index 007ca3d3f5..4b77bf1351 100644 --- a/engines/kyra/sound_intern.h +++ b/engines/kyra/sound_intern.h @@ -151,7 +151,7 @@ private: uint8 *_sfxFileData; uint8 _sfxChannel; - TownsEuphonyDriver *_driver; + EuphonyPlayer *_player; bool _cdaPlaying; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 725dedae3f..65ab4f31ef 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -37,13 +37,13 @@ SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _lastTrack(-1), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0), _sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46), _currentResourceSet(0) { memset(&_resInfo, 0, sizeof(_resInfo)); - _driver = new TownsEuphonyDriver(_mixer); + _player = new EuphonyPlayer(_mixer); } SoundTowns::~SoundTowns() { g_system->getAudioCDManager()->stop(); haltTrack(); - delete _driver; + delete _player; delete[] _musicTrackData; delete[] _sfxFileData; for (int i = 0; i < 3; i++) @@ -58,15 +58,15 @@ bool SoundTowns::init() { _sfxBTTable = _vm->staticres()->loadRawData(k1TownsSFXbtTable, unused); _musicTrackData = new uint8[50570]; - if (!_driver->init()) + if (!_player->init()) return false; if (!loadInstruments()) return false; - _driver->intf()->callback(68); - _driver->intf()->callback(70, 0x33); - _driver->setOutputVolume(1, 118, 118); + /*_player->driver()->intf()->callback(68); + _player->driver()->intf()->callback(70, 0x33);*/ + _player->driver()->setOutputVolume(1, 118, 118); return true; } @@ -93,7 +93,7 @@ void SoundTowns::playTrack(uint8 track) { beginFadeOut(); if (_musicEnabled == 2 && trackNum != -1) { - _driver->setOutputVolume(1, 118, 118); + _player->driver()->setOutputVolume(1, 118, 118); g_system->getAudioCDManager()->play(trackNum + 1, loop ? -1 : 1, 0, 0); g_system->getAudioCDManager()->updateCD(); _cdaPlaying = true; @@ -112,12 +112,12 @@ void SoundTowns::haltTrack() { _cdaPlaying = false; for (int i = 0; i < 6; i++) - _driver->chanVolume(i, 0); + _player->driver()->channelVolume(i, 0); for (int i = 0x40; i < 0x46; i++) - _driver->chanVolume(i, 0); + _player->driver()->channelVolume(i, 0); for (int i = 0; i < 32; i++) - _driver->configChan_enable(i, 0); - _driver->stopParser(); + _player->configPart_enable(i, 0); + _player->stop(); } void SoundTowns::initAudioResourceInfo(int set, void *info) { @@ -179,11 +179,11 @@ void SoundTowns::playSoundEffect(uint8 track, uint8) { if (offset == -1) return; - if (!_driver->soundEffectIsPlaying(_sfxChannel ^ 1)) { + if (!_player->driver()->soundEffectIsPlaying(_sfxChannel ^ 1)) { _sfxChannel ^= 1; - } else if (_driver->soundEffectIsPlaying(_sfxChannel)) { + } else if (_player->driver()->soundEffectIsPlaying(_sfxChannel)) { _sfxChannel ^= 1; - _driver->stopSoundEffect(_sfxChannel); + _player->driver()->stopSoundEffect(_sfxChannel); } uint32 *sfxHeader = (uint32 *)(fileBody + offset); @@ -221,57 +221,57 @@ void SoundTowns::playSoundEffect(uint8 track, uint8) { } } - _driver->chanVolume(_sfxChannel, 127); - _driver->chanPanPos(_sfxChannel, 0x40); - _driver->chanPitch(_sfxChannel, 0); - _driver->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer); + _player->driver()->channelVolume(_sfxChannel, 127); + _player->driver()->channelPan(_sfxChannel, 0x40); + _player->driver()->channelPitch(_sfxChannel, 0); + _player->driver()->playSoundEffect(_sfxChannel, note, 127, sfxPlaybackBuffer); delete[] sfxPlaybackBuffer; } void SoundTowns::updateVolumeSettings() { - if (!_driver) + if (!_player) return; bool mute = false; - _driver->setSoundEffectVolume(ConfMan.getInt("sfx_volume")); + _player->driver()->setSoundEffectVolume(ConfMan.getInt("sfx_volume")); if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); - _driver->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume"))); - _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume"))); + _player->driver()->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume"))); + _player->driver()->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume"))); } void SoundTowns::stopAllSoundEffects() { - _driver->chanVolume(0x46, 0); - _driver->chanVolume(0x47, 0); - _driver->stopSoundEffect(0x46); - _driver->stopSoundEffect(0x47); + _player->driver()->channelVolume(0x46, 0); + _player->driver()->channelVolume(0x47, 0); + _player->driver()->stopSoundEffect(0x46); + _player->driver()->stopSoundEffect(0x47); _sfxChannel = 0x46; } void SoundTowns::beginFadeOut() { if (_cdaPlaying) { for (int i = 118; i > 103; i--) { - _driver->setOutputVolume(1, i, i); + _player->driver()->setOutputVolume(1, i, i); _vm->delay(2 * _vm->tickLength()); } for (int i = 103; i > 83; i -= 2) { - _driver->setOutputVolume(1, i, i); + _player->driver()->setOutputVolume(1, i, i); _vm->delay(2 * _vm->tickLength()); } for (int i = 83; i > 58; i -= 2) { - _driver->setOutputVolume(1, i, i); + _player->driver()->setOutputVolume(1, i, i); _vm->delay(_vm->tickLength()); } for (int i = 58; i > 0; i--) { - _driver->setOutputVolume(1, i, i); + _player->driver()->setOutputVolume(1, i, i); _vm->delay(1); } - _driver->setOutputVolume(1, 0, 0); + _player->driver()->setOutputVolume(1, 0, 0); } else { if (_lastTrack == -1) @@ -292,9 +292,9 @@ void SoundTowns::beginFadeOut() { for (int i = 0; i < 12; i++) { for (int ii = 0; ii < 6; ii++) - _driver->chanVolume(ii, fadeVolCur[ii]); + _player->driver()->channelVolume(ii, fadeVolCur[ii]); for (int ii = 0x40; ii < 0x46; ii++) - _driver->chanVolume(ii, fadeVolCur[ii - 0x3A]); + _player->driver()->channelVolume(ii, fadeVolCur[ii - 0x3A]); for (int ii = 0; ii < 6; ii++) { fadeVolCur[ii] -= fadeVolStep[ii]; @@ -323,20 +323,20 @@ bool SoundTowns::loadInstruments() { Screen::decodeFrame4(twm, _musicTrackData, 50570); for (int i = 0; i < 128; i++) - _driver->loadInstrument(0, i, &_musicTrackData[i * 48 + 8]); + _player->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]); + _player->driver()->loadInstrument(0x40, i, &_musicTrackData[i * 128 + 8]); - _driver->unloadWaveTable(-1); + _player->driver()->unloadWaveTable(-1); uint8 *src = &_musicTrackData[32 * 128 + 8]; for (int i = 0; i < 10; i++) { - _driver->loadWaveTable(src); + _player->driver()->loadWaveTable(src); src = src + READ_LE_UINT16(&src[12]) + 32; } - _driver->reserveSoundEffectChannels(2); + _player->driver()->reserveSoundEffectChannels(2); delete[] twm; @@ -350,26 +350,26 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { const uint8 *src = _musicTrackData + 852; for (int i = 0; i < 32; i++) - _driver->configChan_enable(i, *src++); + _player->configPart_enable(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_setMode(i, *src++); + _player->configPart_setType(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_remap(i, *src++); + _player->configPart_remap(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_adjustVolume(i, *src++); + _player->configPart_adjustVolume(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_setTranspose(i, *src++); + _player->configPart_setTranspose(i, *src++); src = _musicTrackData + 1748; for (int i = 0; i < 6; i++) - _driver->assignChannel(i, *src++); + _player->driver()->assignPartToChannel(i, *src++); for (int i = 0x40; i < 0x46; i++) - _driver->assignChannel(i, *src++); + _player->driver()->assignPartToChannel(i, *src++); uint32 trackSize = READ_LE_UINT32(_musicTrackData + 2048); uint8 startTick = _musicTrackData[2052]; - _driver->setMusicTempo(_musicTrackData[2053]); + _player->setTempo(_musicTrackData[2053]); src = _musicTrackData + 2054; uint32 l = READ_LE_UINT32(src + trackSize); @@ -377,14 +377,14 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { l = READ_LE_UINT32(src + trackSize); trackSize += (l + 4); - _driver->setMusicLoop(loop); - _driver->startMusicTrack(src, trackSize, startTick); + _player->setLoopStatus(loop); + _player->startTrack(src, trackSize, startTick); } void SoundTowns::fadeOutSoundEffects() { for (int i = 127; i > 0; i-= 12) { - _driver->chanVolume(0x46, i); - _driver->chanVolume(0x47, i); + _player->driver()->channelVolume(0x46, i); + _player->driver()->channelVolume(0x47, i); _vm->delay(_vm->tickLength()); } stopAllSoundEffects(); diff --git a/engines/scumm/players/player_towns.cpp b/engines/scumm/players/player_towns.cpp index 5b8ca04021..67993888aa 100644 --- a/engines/scumm/players/player_towns.cpp +++ b/engines/scumm/players/player_towns.cpp @@ -202,23 +202,24 @@ Player_Towns_v1::Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer) : Player_ memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters)); } - _driver = new TownsEuphonyDriver(mixer); + _player = new EuphonyPlayer(mixer); + _intf = new TownsAudioInterface(mixer, 0); } Player_Towns_v1::~Player_Towns_v1() { - delete _driver; + delete _intf; + delete _player; delete[] _soundOverride; } bool Player_Towns_v1::init() { - if (!_driver) + if (!_player) return false; - if (!_driver->init()) + if (!_player->init()) return false; - _driver->reserveSoundEffectChannels(8); - _intf = _driver->intf(); + _player->driver()->reserveSoundEffectChannels(8); // Treat all 6 fm channels and all 8 pcm channels as sound effect channels // since music seems to exist as CD audio only in the games which use this @@ -231,7 +232,7 @@ bool Player_Towns_v1::init() { } void Player_Towns_v1::setMusicVolume(int vol) { - _driver->setMusicVolume(vol); + _player->driver()->setMusicVolume(vol); } void Player_Towns_v1::startSound(int sound) { @@ -275,7 +276,7 @@ void Player_Towns_v1::stopSound(int sound) { if (sound != 0 && sound == _eupCurrentSound) { _eupCurrentSound = 0; _eupLooping = false; - _driver->stopParser(); + _player->stop(); } stopPcmTrack(sound); @@ -288,7 +289,7 @@ void Player_Towns_v1::stopAllSounds() { _eupCurrentSound = 0; _eupLooping = false; - _driver->stopParser(); + _player->stop(); stopPcmTrack(0); } @@ -297,7 +298,7 @@ int Player_Towns_v1::getSoundStatus(int sound) const { if (sound == _cdaCurrentSound) return _vm->_sound->pollCD(); if (sound == _eupCurrentSound) - return _driver->parserIsPlaying() ? 1 : 0; + return _player->isPlaying() ? 1 : 0; return Player_Towns::getSoundStatus(sound); } @@ -306,7 +307,7 @@ int32 Player_Towns_v1::doCommand(int numargs, int args[]) { switch (args[0]) { case 2: - _driver->intf()->callback(73, 0); + _player->driver()->cdaToggle(0); break; case 3: @@ -344,7 +345,7 @@ int32 Player_Towns_v1::doCommand(int numargs, int args[]) { void Player_Towns_v1::setVolumeCD(int left, int right) { _cdaVolLeft = left & 0xff; _cdaVolRight = right & 0xff; - _driver->setOutputVolume(1, left >> 1, right >> 1); + _player->driver()->setOutputVolume(1, left >> 1, right >> 1); } void Player_Towns_v1::setSoundVolume(int sound, int left, int right) { @@ -373,7 +374,7 @@ void Player_Towns_v1::saveLoadWithSerializer(Serializer *ser) { ser->saveLoadEntries(this, cdEntries); - if (!_eupLooping && !_driver->parserIsPlaying()) + if (!_eupLooping && !_player->isPlaying()) _eupCurrentSound = 0; static const SaveLoadEntry eupEntries[] = { @@ -439,10 +440,10 @@ void Player_Towns_v1::restartLoopingSounds() { c++; } - _driver->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr); + _player->driver()->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr); } - _driver->intf()->callback(73, 1); + _player->driver()->cdaToggle(1); } void Player_Towns_v1::startSoundEx(int sound, int velo, int pan, int note) { @@ -492,9 +493,9 @@ void Player_Towns_v1::stopSoundSuspendLooping(int sound) { } else { for (int i = 1; i < 9; i++) { if (sound == _pcmCurrentSound[i].index) { - if (!_driver->soundEffectIsPlaying(i + 0x3f)) + if (!_player->driver()->soundEffectIsPlaying(i + 0x3f)) continue; - _driver->stopSoundEffect(i + 0x3f); + _player->driver()->stopSoundEffect(i + 0x3f); if (_pcmCurrentSound[i].looping) _pcmCurrentSound[i].paused = 1; else @@ -510,23 +511,23 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) { const uint8 *trackData = src + 150; for (int i = 0; i < 32; i++) - _driver->configChan_enable(i, *src++); + _player->configPart_enable(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_setMode(i, 0xff); + _player->configPart_setType(i, 0xff); for (int i = 0; i < 32; i++) - _driver->configChan_remap(i, *src++); + _player->configPart_remap(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_adjustVolume(i, *src++); + _player->configPart_adjustVolume(i, *src++); for (int i = 0; i < 32; i++) - _driver->configChan_setTranspose(i, *src++); + _player->configPart_setTranspose(i, *src++); src += 8; for (int i = 0; i < 6; i++) - _driver->assignChannel(i, *src++); + _player->driver()->assignPartToChannel(i, *src++); for (int i = 0; i < data[14]; i++) { - _driver->loadInstrument(i, i, pos + i * 48); - _driver->intf()->callback(4, i, i); + _player->driver()->loadInstrument(i, i, pos + i * 48); + _player->driver()->setInstrument(i, i); } _eupVolLeft = _soundOverride[sound].vLeft; @@ -537,18 +538,18 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) { lvl >>= 2; for (int i = 0; i < 6; i++) - _driver->chanVolume(i, lvl); + _player->driver()->channelVolume(i, lvl); uint32 trackSize = READ_LE_UINT32(src); src += 4; uint8 startTick = *src++; - _driver->setMusicTempo(*src++); - _driver->startMusicTrack(trackData, trackSize, startTick); + _player->setTempo(*src++); + _player->startTrack(trackData, trackSize, startTick); _eupLooping = (*src != 1) ? 1 : 0; - _driver->setMusicLoop(_eupLooping != 0); - _driver->continueParsing(); + _player->setLoopStatus(_eupLooping != 0); + _player->resume(); _eupCurrentSound = sound; } diff --git a/engines/scumm/players/player_towns.h b/engines/scumm/players/player_towns.h index 3736524ee2..576d17e392 100644 --- a/engines/scumm/players/player_towns.h +++ b/engines/scumm/players/player_towns.h @@ -104,8 +104,6 @@ public: void saveLoadWithSerializer(Serializer *ser); void restoreAfterLoad(); - TownsEuphonyDriver *driver() { return _driver; } - private: void restartLoopingSounds(); void startSoundEx(int sound, int velo, int pan, int note); @@ -137,7 +135,7 @@ private: uint8 _cdaCurrentSoundTemp; uint8 _cdaNumLoopsTemp; - TownsEuphonyDriver *_driver; + EuphonyPlayer *_player; }; class Player_Towns_v2 : public Player_Towns { -- cgit v1.2.3