aboutsummaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
authorathrxx2015-11-02 20:52:49 +0100
committerathrxx2015-11-09 18:41:06 +0100
commit4ec41c291e3a1e273b0ee571acdf2942a579e3ad (patch)
tree302c307bda7c6acb845d1acb22fa916174dc510f /audio
parent82c98e98033eafa2ed04febe2607f09636e7e6a5 (diff)
downloadscummvm-rg350-4ec41c291e3a1e273b0ee571acdf2942a579e3ad.tar.gz
scummvm-rg350-4ec41c291e3a1e273b0ee571acdf2942a579e3ad.tar.bz2
scummvm-rg350-4ec41c291e3a1e273b0ee571acdf2942a579e3ad.zip
AUDIO: (FM-TOWNS) - cleanup euphony code
(rework parts of the code + improve naming of variables/functions)
Diffstat (limited to 'audio')
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_euphony.cpp1132
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_euphony.h234
2 files changed, 721 insertions, 645 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<uint8> _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