[Scummvm-cvs-logs] scummvm master -> 8c046f4826be1d2d85d04b1e3f83dcc62ac55e5c

athrxx athrxx at scummvm.org
Mon Nov 9 19:25:37 CET 2015


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
4ec41c291e AUDIO: (FM-TOWNS) - cleanup euphony code
160f1a074d AUDIO: (FM-TOWNS) - fix looping pcm sounds
924b582ced AUDIO: fix bug #6885 (INDY3: FMTOWNS: Music is distorted (regression))
8c046f4826 AUDIO: (FM-TOWNS) - replace fixed hanging notes buffer with a dynamic chain


Commit: 4ec41c291e3a1e273b0ee571acdf2942a579e3ad
    https://github.com/scummvm/scummvm/commit/4ec41c291e3a1e273b0ee571acdf2942a579e3ad
Author: athrxx (athrxx at scummvm.org)
Date: 2015-11-09T18:41:06+01:00

Commit Message:
AUDIO: (FM-TOWNS) - cleanup euphony code

(rework parts of the code + improve naming of variables/functions)

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.h
    engines/kyra/sound_intern.h
    engines/kyra/sound_towns.cpp
    engines/scumm/players/player_towns.cpp
    engines/scumm/players/player_towns.h



diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index fca3d19..dfcbdaf 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 d772178..2e935a3 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
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index 007ca3d..4b77bf1 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 725deda..65ab4f3 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 5b8ca04..6799388 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 3736524..576d17e 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 {


Commit: 160f1a074d4e97a9e67773d2a33ad13950a4bfc3
    https://github.com/scummvm/scummvm/commit/160f1a074d4e97a9e67773d2a33ad13950a4bfc3
Author: athrxx (athrxx at scummvm.org)
Date: 2015-11-09T18:41:07+01:00

Commit Message:
AUDIO: (FM-TOWNS) - fix looping pcm sounds

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_audio.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 7fa55ef..9db45bd 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -83,7 +83,7 @@ public:
 	bool _activeOutput;
 
 private:
-	void setupLoop(uint32 loopStart, uint32 len);
+	void setupLoop(uint32 loopStart, uint32 loopLen);
 	void setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit = false);
 	void setVelo(uint8 velo);
 
@@ -104,10 +104,10 @@ private:
 	uint8 _panRight;
 
 	int8 *_data;
-	int8 *_dataEnd;
 
-	int8 *_loopEnd;
+	uint32 _loopStart;
 	uint32 _loopLen;
+	uint32 _dataEnd;
 
 	uint16 _stepNote;
 	uint16 _stepPitch;
@@ -1571,7 +1571,7 @@ void TownsAudio_PcmChannel::clear() {
 	_loopLen = 0;
 
 	_pos = 0;
-	_loopEnd = 0;
+	_loopStart = 0;
 
 	_step = 0;
 	_stepNote = 0x4000;
@@ -1592,7 +1592,8 @@ void TownsAudio_PcmChannel::clear() {
 
 void TownsAudio_PcmChannel::loadData(TownsAudio_WaveTable *w) {
 	_data = w->data;
-	_dataEnd = w->data + w->size;
+	_dataEnd = w->size << 11;
+	_pos = 0;
 }
 
 void TownsAudio_PcmChannel::loadData(uint8 *buffer, uint32 size) {
@@ -1604,7 +1605,7 @@ void TownsAudio_PcmChannel::loadData(uint8 *buffer, uint32 size) {
 		*dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
 
 	_data = _extData;
-	_dataEnd = _extData + size;
+	_dataEnd = size << 11;
 	_pos = 0;
 }
 
@@ -1643,7 +1644,7 @@ int TownsAudio_PcmChannel::initInstrument(uint8 &note, TownsAudio_WaveTable *&ta
 }
 
 void TownsAudio_PcmChannel::keyOn(uint8 note, uint8 velo, TownsAudio_WaveTable *w) {
-	setupLoop(w->loopStart, w->loopLen);
+	setupLoop(w->loopLen ? w->loopStart : w->size, w->loopLen);
 	setNote(note, w, _reserved);
 	setVelo(velo);
 
@@ -1744,9 +1745,10 @@ void TownsAudio_PcmChannel::updateOutput() {
 	if (_activeKey || _activeEffect) {
 		_pos += _step;
 
-		if (&_data[_pos >> 11] >= _loopEnd) {
-			if (_loopLen) {
-				_pos -= _loopLen;
+		if (_pos >= _dataEnd) {
+			if (_loopStart != _dataEnd) {
+				_pos = _loopStart;
+				_dataEnd = _loopLen;
 			} else {
 				_pos = 0;
 				_activeKey = _activeEffect = false;
@@ -1763,10 +1765,9 @@ int32 TownsAudio_PcmChannel::currentSampleRight() {
 	return (_activeOutput && _panRight) ? (((_data[_pos >> 11] * _tl) * _panRight) >> 3) : 0;
 }
 
-void TownsAudio_PcmChannel::setupLoop(uint32 loopStart, uint32 len) {
-	_loopLen = len << 11;
-	_loopEnd = _loopLen ? &_data[(loopStart + _loopLen) >> 11] : _dataEnd;
-	_pos = loopStart;
+void TownsAudio_PcmChannel::setupLoop(uint32 loopStart, uint32 loopLen) {
+	_loopStart = loopStart << 11;
+	_loopLen = loopLen << 11;
 }
 
 void TownsAudio_PcmChannel::setNote(uint8 note, TownsAudio_WaveTable *w, bool stepLimit) {


Commit: 924b582ced24139b2e78a0a06d6ba5049089c8a5
    https://github.com/scummvm/scummvm/commit/924b582ced24139b2e78a0a06d6ba5049089c8a5
Author: athrxx (athrxx at scummvm.org)
Date: 2015-11-09T18:41:09+01:00

Commit Message:
AUDIO: fix bug #6885 (INDY3: FMTOWNS: Music is distorted (regression))

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.h



diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index dfcbdaf..79df54d 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -51,7 +51,7 @@ bool EuphonyPlayer::init() {
 	for (int i = 0; i < 3; i++) {
 		if (_drivers[i]) {
 			if (!_drivers[i]->init()) {
-				warning("EuphonyPlayer:: Driver initalization failed: %d", i);
+				warning("EuphonyPlayer:: Driver initialization failed: %d", i);
 				delete _drivers[i];
 				_drivers[i] = 0;
 			}
@@ -129,40 +129,42 @@ void EuphonyPlayer::setLoopStatus(bool loop) {
 }
 
 int EuphonyPlayer::configPart_enable(int part, int val) {
-	if (part > 31)
+	uint8 enable = val & 0xff;
+	if (part > 31 || ((enable + 1) & 0xff) > 1)
 		return 3;
-	_partConfig_enable[part] = val;
+	_partConfig_enable[part] = enable;
 	return 0;
 }
 
 int EuphonyPlayer::configPart_setType(int part, int val) {
-	if (part > 31)
+	uint8 type = val & 0xff;
+	if (part > 31 || ((type + 1) & 0xff) > 8)
 		return 3;
-	_partConfig_type[part] = val;
+	_partConfig_type[part] = type;
 	return 0;
 }
 
 int EuphonyPlayer::configPart_remap(int part, int val) {
-	if (part > 31)
+	uint8 remap = val & 0xff;
+	if (part > 31 || ((remap + 1) & 0xff) > 16)
 		return 3;
-	if (val < 16)
-		_partConfig_ordr[part] = val;
+	_partConfig_ordr[part] = remap;
 	return 0;
 }
 
 int EuphonyPlayer::configPart_adjustVolume(int part, int val) {
-	if (part > 31)
+	int8 adjvol = val & 0xff;
+	if (part > 31 || adjvol < -40 || adjvol > 40)
 		return 3;
-	if (val <= 40)
-		_partConfig_volume[part] = (int8)(val & 0xff);
+	_partConfig_volume[part] = adjvol;
 	return 0;
 }
 
 int EuphonyPlayer::configPart_setTranspose(int part, int val) {
-	if (part > 31)
+	int8 trans = val & 0xff;
+	if (part > 31 || trans < -40 || trans > 40)
 		return 3;
-	if (val <= 40)
-		_partConfig_transpose[part] = (int8)(val & 0xff);
+	_partConfig_transpose[part] = trans;
 	return 0;
 }
 
@@ -281,9 +283,7 @@ void EuphonyPlayer::updateParser() {
 
 		} else {
 			if (_parseToBar == _bar) {
-				uint16 parseToBeat = READ_LE_UINT16(&_musicPos[2]);
-				uint8 l = (parseToBeat & 0xff) + (parseToBeat & 0xff);
-				parseToBeat = ((parseToBeat & 0xff00) | l) >> 1;
+				uint16 parseToBeat = ((_musicPos[3] << 8) | ((_musicPos[2] << 1) & 0xff)) >> 1;
 				if (parseToBeat > _beat)
 					loop = false;
 			}
@@ -313,7 +313,7 @@ bool EuphonyPlayer::parseEvent() {
 		EVENT(programChange_channelAftertouch),
 		EVENT(controlChange_pitchWheel),
 		
-		EVENT(loadInstrument),
+		EVENT(sysex),
 		EVENT(advanceBar),
 		EVENT(notImpl),
 		EVENT(notImpl),
@@ -437,7 +437,7 @@ bool EuphonyPlayer::event_noteOn() {
 		return true;
 
 	velo = _musicPos[5];
-	uint16 len = ((((_musicPos[1] << 4) | (_musicPos[2] << 8)) >> 4) & 0xff) | ((((_musicPos[3] << 4) | (_musicPos[4] << 8)) >> 4) << 8);
+	uint16 len = (_musicPos[1] & 0x0f) | ((_musicPos[2] & 0x0f) << 4) | ((_musicPos[3] & 0x0f) << 8) | ((_musicPos[4] & 0x0f) << 12);
 
 	int i = 0;
 	for (; i < 64; i++) {
@@ -506,7 +506,25 @@ bool EuphonyPlayer::event_programChange_channelAftertouch() {
 	return false;
 }
 
-bool EuphonyPlayer::event_loadInstrument() {
+bool EuphonyPlayer::event_sysex() {
+	uint8 type = _partConfig_type[_musicPos[1]];
+	sendEvent(type, 0xF0);
+	proceedToNextEvent();
+
+	for (bool loop = true; loop; ) {
+		for (int i = 0; i < 6; i++) {
+			if (_musicPos[i] != 0xFF) {
+				sendEvent(type, _musicPos[i]);
+				if (_musicPos[i] >= 0x80) {
+					loop = false;
+					break;
+				}
+			}
+		}
+		if (loop)
+			proceedToNextEvent();
+	}
+
 	return false;
 }
 
@@ -517,8 +535,7 @@ bool EuphonyPlayer::event_advanceBar() {
 }
 
 bool EuphonyPlayer::event_setTempo() {
-	uint8 l = _musicPos[4] << 1;
-	_trackTempo = (l | (_musicPos[5] << 8)) >> 1;
+	_trackTempo = ((_musicPos[5] << 8) | ((_musicPos[4] << 1) & 0xff)) >> 1;
 	sendTempo(_trackTempo);
 	return false;
 }
@@ -567,7 +584,7 @@ void EuphonyPlayer::sendEvent(uint8 type, uint8 command) {
 }
 
 void EuphonyPlayer::sendNoteEvent(int type, int evt, int note, int velo) {
-	if (!velo)
+	if (velo)
 		evt &= 0x8f;
 	sendEvent(type, evt);
 	sendEvent(type, note);
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index 2e935a3..68c5041 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -161,7 +161,7 @@ private:
 	bool event_controlChange_pitchWheel();
 	bool event_programChange_channelAftertouch();
 
-	bool event_loadInstrument();
+	bool event_sysex();
 	bool event_advanceBar();
 	bool event_setTempo();
 	bool event_typeOrdrChange();


Commit: 8c046f4826be1d2d85d04b1e3f83dcc62ac55e5c
    https://github.com/scummvm/scummvm/commit/8c046f4826be1d2d85d04b1e3f83dcc62ac55e5c
Author: athrxx (athrxx at scummvm.org)
Date: 2015-11-09T18:41:10+01:00

Commit Message:
AUDIO: (FM-TOWNS) - replace fixed hanging notes buffer with a dynamic chain

(This works around issues with some Indy 3 sound tracks. These tracks seem to be broken, since they have way too long duration values for some notes which would fill up the event buffer rather quickly. I tested with the UNZ emulator to be sure that this is an issue which also occurs with the original driver.)

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.h



diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index 79df54d..aea714f 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -26,7 +26,7 @@
 #include "common/textconsole.h"
 
 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),
+	_partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _savedEventsChain(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);
@@ -39,7 +39,12 @@ EuphonyPlayer::~EuphonyPlayer() {
 	for (int i = 0; i < 3; i++)
 		delete _drivers[i];
 
-	delete[] _timedEvents;
+	while (_savedEventsChain) {
+		SavedEvent *evt = _savedEventsChain;
+		_savedEventsChain = _savedEventsChain->next;
+		delete evt;
+	}
+
 	delete[] _partConfig_enable;
 	delete[] _partConfig_type;
 	delete[] _partConfig_ordr;
@@ -61,15 +66,18 @@ bool EuphonyPlayer::init() {
 	if (!_drivers[0] || !_drivers[1])
 		return false;
 
-	delete[] _timedEvents;
+	while (_savedEventsChain) {
+		SavedEvent *evt = _savedEventsChain;
+		_savedEventsChain = _savedEventsChain->next;
+		delete evt;
+	}
+
 	delete[] _partConfig_enable;
 	delete[] _partConfig_type;
 	delete[] _partConfig_ordr;
 	delete[] _partConfig_volume;
 	delete[] _partConfig_transpose;
 
-	_timedEvents = new TimedEvent[64];
-
 	_partConfig_enable = new uint8[32];
 	_partConfig_type = new uint8[32];
 	_partConfig_ordr = new uint8[32];
@@ -195,8 +203,11 @@ void EuphonyPlayer::reset() {
 
 	resetPartConfig();
 
-	memset(_timedEvents, 0, 64 * sizeof(TimedEvent));
-	_timedEventsCount = 0;
+	while (_savedEventsChain) {
+		SavedEvent *evt = _savedEventsChain;
+		_savedEventsChain = _savedEventsChain->next;
+		delete evt;
+	}
 
 	_playing = _endOfTrack = _paused = _loop = false;
 	_tempoMode1UpdateF8 = 0;
@@ -297,7 +308,7 @@ void EuphonyPlayer::updateParser() {
 }
 
 void EuphonyPlayer::updateCheckEot() {
-	if (!_endOfTrack || _timedEventsCount)
+	if (!_endOfTrack || _savedEventsChain)
 		return;
 	stop();
 }
@@ -357,30 +368,35 @@ void EuphonyPlayer::proceedToNextEvent() {
 }
 
 void EuphonyPlayer::updateHangingNotes() {
-	TimedEvent *e = _timedEvents;
-	for (int i = _timedEventsCount; i; e++) {
-		if (e->evt == 0)
-			continue;
+	SavedEvent *l = 0;
+	SavedEvent *e = _savedEventsChain;
+
+	while (e) {
 		if (--e->len) {
-			--i;
+			l = e;
+			e = e->next;
 			continue;
 		}
+
+		SavedEvent *n = e->next;
+		if (l)
+			l->next = n;
+		if (_savedEventsChain == e)
+			_savedEventsChain = n;
+
 		sendNoteEvent(e->type, e->evt, e->note, e->velo);
-		e->evt = 0;
-		--i;
-		--_timedEventsCount;
+		delete e;
+
+		e = n;
 	}
 }
 
 void EuphonyPlayer::clearHangingNotes() {
-	TimedEvent *e = _timedEvents;
-	for (int i = _timedEventsCount; i; e++) {
-		if (e->evt == 0)
-			continue;
+	while (_savedEventsChain) {
+		SavedEvent *e = _savedEventsChain;
+		_savedEventsChain = _savedEventsChain->next;
 		sendNoteEvent(e->type, e->evt, e->note, e->velo);
-		e->evt = 0;
-		--i;
-		--_timedEventsCount;
+		delete e;
 	}
 }
 
@@ -439,22 +455,7 @@ bool EuphonyPlayer::event_noteOn() {
 	velo = _musicPos[5];
 	uint16 len = (_musicPos[1] & 0x0f) | ((_musicPos[2] & 0x0f) << 4) | ((_musicPos[3] & 0x0f) << 8) | ((_musicPos[4] & 0x0f) << 12);
 
-	int i = 0;
-	for (; i < 64; i++) {
-		if (_timedEvents[i].evt == 0)
-			break;
-	}
-
-	if (i == 64) {
-		sendNoteEvent(type, evt, note, velo);
-	} else {
-		_timedEvents[i].evt = evt;
-		_timedEvents[i].type = type;
-		_timedEvents[i].note = note;
-		_timedEvents[i].velo = velo;
-		_timedEvents[i].len = len ? len : 1;
-		_timedEventsCount++;
-	}
+	_savedEventsChain = new SavedEvent(evt, type, note, velo, len ? len : 1, _savedEventsChain);
 
 	return false;
 }
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index 68c5041..76aa153 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -181,14 +181,17 @@ private:
 	int8 *_partConfig_volume;
 	int8 *_partConfig_transpose;
 
-	struct TimedEvent {
+	struct SavedEvent {
+		SavedEvent(int ev, int tp, int nt, int vl, int ln, SavedEvent *chain) : evt(ev), type(tp), note(nt), velo(vl), len(ln), next(chain) {}
 		uint8 evt;
 		uint8 type;
 		uint8 note;
 		uint8 velo;
 		uint16 len;
-	} *_timedEvents;
-	int _timedEventsCount;
+		SavedEvent *next;
+	};
+	
+	SavedEvent *_savedEventsChain;
 
 	uint8 _defaultBarLength;
 	uint8 _barLength;






More information about the Scummvm-git-logs mailing list