[Scummvm-cvs-logs] scummvm master -> 87571909be0c9f4c29eb1384665be064d2ee8f42

wjp wjp at usecode.org
Tue May 17 20:59:41 CEST 2011


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

Summary:
5c34e33c2c FM-TOWNS AUDIO: Some more midi driver code for FM-TOWNS monkey2 and indy4
63a7859351 FM-TOWNS AUDIO: Change internal interface layout
6845f25f54 SCUMM: Adapt code to latest FM-TOWNS audio driver changes
2f9c5de7be FM-TOWNS AUDIO: Implement some midi driver functions
d4325a0411 FM-TOWNS AUDIO: Implement some more midi driver code
8fe9e89c6c FM-TOWNS AUDIO: Some more midi driver code
25814e64ac FM-TOWNS AUDIO: Implement some midi commands
bd2c84be89 FM-TOWNS AUDIO: More midi driver code (effect processing)
d9772ff88f FM-TOWNS AUDIO: Some renaming in the euphony driver code
9fa1b9aa36 FM-TOWNS AUDIO: More midi driver code
cac67d0151 SCUMM: Set proper GUIO flags for monkey2/indy4 FM-TOWNS
ca0e9cca3d FM-TOWNS AUDIO: Start fixing midi driver tempo
75770ae691 FM-TOWNS AUDIO: Fix mod wheel setting
88896117da FM-TOWNS AUDIO: Some more midi driver code
90a300d86c FM-TOWNS AUDIO: Improve thread safety
8fb5906117 FM-TOWNS AUDIO: Some midi code fixes and some renaming
baaae9d97a SCUMM: Add missing imuse feature
c6f13d187e FM-TOWNS AUDIO: Fix some midi driver bugs
95c059598d FM-TOWNS AUDIO: Fix note off event in midi driver
15610b56db FM-TOWNS AUDIO: Fix some bugs and rename some stuff in the midi driver code
b3476fc801 FM-TOWNS AUDIO: Some fixes and renaming
d3e92f0b81 FM-TOWNS AUDIO: Fix several CppCheck warnings
726a7f3b1a FM-TOWNS AUDIO: Fix GCC warnings
87571909be SCUMM FM-TOWNS: iMUSE MIDI driver for INDY4/MONKEY2


Commit: 5c34e33c2c27b2b5083199b40306370d732f4e53
    https://github.com/scummvm/scummvm/commit/5c34e33c2c27b2b5083199b40306370d732f4e53
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:24:24-07:00

Commit Message:
FM-TOWNS AUDIO: Some more midi driver code for FM-TOWNS monkey2 and indy4

Changed paths:
  A audio/softsynth/fmtowns_pc98/towns_midi.cpp
  A audio/softsynth/fmtowns_pc98/towns_midi.h
  A audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
  R audio/softsynth/ym2612.cpp
  R audio/softsynth/ym2612.h
    audio/module.mk
    base/plugins.cpp
    engines/scumm/player_towns.cpp
    engines/scumm/player_towns.h
    engines/scumm/scumm.cpp



diff --git a/audio/module.mk b/audio/module.mk
index a9d9bfc..840b6d6 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -39,10 +39,11 @@ MODULE_OBJS := \
 	softsynth/opl/mame.o \
 	softsynth/fmtowns_pc98/towns_audio.o \
 	softsynth/fmtowns_pc98/towns_euphony.o \
+	softsynth/fmtowns_pc98/towns_midi.o \
 	softsynth/fmtowns_pc98/towns_pc98_driver.o \
 	softsynth/fmtowns_pc98/towns_pc98_fmsynth.o \
+	softsynth/fmtowns_pc98/towns_pc98_plugins.o \
 	softsynth/appleiigs.o \
-	softsynth/ym2612.o \
 	softsynth/fluidsynth.o \
 	softsynth/mt32.o \
 	softsynth/eas.o \
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
new file mode 100644
index 0000000..c223d44
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -0,0 +1,239 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL:  $
+ * $Id:  $
+ */
+
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "common/textconsole.h"
+
+class MidiChannel_TOWNS : public MidiChannel {
+public:
+	MidiChannel_TOWNS(MidiDriver_TOWNS *driver);
+	~MidiChannel_TOWNS();
+
+	MidiDriver *device() { return _driver; }
+	byte getNumber() { return 0; }
+	void release();
+
+	void send(uint32 b);
+
+	void noteOff(byte note);
+	void noteOn(byte note, byte velocity);
+	void programChange(byte program);
+	void pitchBend(int16 bend);
+	void controlChange(byte control, byte value);
+	void pitchBendFactor(byte value);
+	void priority(byte value);
+
+	void sysEx_customInstrument(uint32 type, const byte *instr);
+
+private:
+	MidiDriver_TOWNS *_driver;
+};
+
+MidiChannel_TOWNS::MidiChannel_TOWNS(MidiDriver_TOWNS *driver) : MidiChannel(), _driver(driver) {
+
+}
+
+MidiChannel_TOWNS::~MidiChannel_TOWNS() {
+
+}
+
+void MidiChannel_TOWNS::release() {
+
+}
+
+void MidiChannel_TOWNS::send(uint32 b) {
+
+}
+
+void MidiChannel_TOWNS::noteOff(byte note) {
+
+}
+
+void MidiChannel_TOWNS::noteOn(byte note, byte velocity) {
+
+}
+
+void MidiChannel_TOWNS::programChange(byte program) {
+
+}
+
+void MidiChannel_TOWNS::pitchBend(int16 bend) {
+
+}
+
+void MidiChannel_TOWNS::controlChange(byte control, byte value) {
+
+}
+
+void MidiChannel_TOWNS::pitchBendFactor(byte value) {
+
+}
+
+void MidiChannel_TOWNS::priority(byte value) {
+
+}
+
+void MidiChannel_TOWNS::sysEx_customInstrument(uint32 type, const byte *instr) {
+
+}
+
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timerBpara(0), _open(false) {
+	_intf = new TownsAudioInterface(mixer, this);
+	_channels = new MidiChannel_TOWNS*[16];
+	for (int i = 0; i < 16; i++)
+		_channels[i] = new MidiChannel_TOWNS(this);
+
+	_tickCounter = 0;
+	_curChan = 0;
+	//unbuffered write:	_intf->callback(17, part, reg, val);
+	//buffered write:	_intf->callback(19, part, reg, val);
+}
+
+MidiDriver_TOWNS::~MidiDriver_TOWNS() {
+	close();
+	delete _intf;
+	setTimerCallback(0, 0);
+
+	for (int i = 0; i < 16; i++)
+		delete _channels[i];
+	delete[] _channels;
+}
+
+int MidiDriver_TOWNS::open() {
+	if (_open)
+		return MERR_ALREADY_OPEN;
+
+	if (!_intf->init())
+		return MERR_CANNOT_CONNECT;
+
+	_intf->callback(0);
+
+	_intf->callback(21, 255, 1);
+	_intf->callback(21, 0, 1);
+	_intf->callback(22, 255, 221);
+
+	_intf->callback(33, 8);
+	_intf->setSoundEffectChanMask(~0x3f);
+
+	_open = true;
+
+	return 0;
+}
+
+void MidiDriver_TOWNS::close() {
+	_open = false;
+}
+
+void MidiDriver_TOWNS::send(uint32 b) {
+	byte param2 = (b >> 16) & 0xFF;
+	byte param1 = (b >> 8) & 0xFF;
+	byte cmd = b & 0xF0;
+
+	/*AdLibPart *part;
+	if (chan == 9)
+		part = &_percussion;
+	else**/
+	MidiChannel_TOWNS *c = _channels[b & 0x0F];
+
+	switch (cmd) {
+	case 0x80:
+		//part->noteOff(param1);
+		break;
+	case 0x90:
+		//part->noteOn(param1, param2);
+		if (param2)
+			c->noteOn(param1, param2);
+		else
+			c->noteOff(param1);
+		break;
+	case 0xB0:
+		// supported: 1, 7, 0x40
+		c->controlChange(param1, param2);
+		break;
+	case 0xC0:
+		c->programChange(param1);
+		break;
+	case 0xE0:
+		//part->pitchBend((param1 | (param2 << 7)) - 0x2000);
+		c->pitchBend((param1 | (param2 << 7)) - 0x2000);
+		break;
+	case 0xF0:
+		warning("MidiDriver_ADLIB: Receiving SysEx command on a send() call");
+		break;
+
+	default:
+		break;
+	}
+}
+
+void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
+	_timerBproc = timer_proc;
+	_timerBpara = timer_param;
+}
+
+uint32 MidiDriver_TOWNS::getBaseTempo() {
+	return 0;
+}
+
+MidiChannel *MidiDriver_TOWNS::allocateChannel() {
+	MidiChannel *res = 0;
+
+	for (int i = 0; i < 6; i++) {
+		if (++_curChan == 6)
+			_curChan = 0;
+
+		//if (_channels[i]->   //// )
+		//	return _channels[i];
+
+	}
+
+	//if (res)
+	//	res->noteOff();
+
+	return res;
+}
+
+MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
+	return 0;
+}
+
+void MidiDriver_TOWNS::timerCallback(int timerId) {
+	if (!_open)
+		return;
+
+	switch (timerId) {
+	case 1:
+		if (_timerBproc) {
+			_timerBproc(_timerBpara);
+			_tickCounter += 10000;
+			while (_tickCounter >= 4167) {
+				_tickCounter -= 4167;
+				//_timerBproc(_timerBpara);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
new file mode 100644
index 0000000..658c5a4
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL:  $
+ * $Id:  $
+ */
+
+#ifndef TOWNS_MIDI_H
+#define TOWNS_MIDI_H
+
+#include "audio/mididrv.h"
+#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
+
+class MidiChannel_TOWNS;
+class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
+friend class MidiChannel_TOWNS;
+public:
+	MidiDriver_TOWNS(Audio::Mixer *mixer);
+	~MidiDriver_TOWNS();
+
+	int open();
+	bool isOpen() const { return _open; }
+	void close();
+	void send(uint32 b);
+	//virtual uint32 property(int prop, uint32 param) { return 0; }
+	//virtual void sysEx(const byte *msg, uint16 length) { }
+	//virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
+	//virtual void metaEvent(byte type, byte *data, uint16 length) { }
+	void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+	uint32 getBaseTempo();
+	MidiChannel *allocateChannel();
+	MidiChannel *getPercussionChannel();
+
+	void timerCallback(int timerId);
+
+	TownsAudioInterface *intf() { return _intf; }
+	
+private:
+	MidiChannel_TOWNS **_channels;
+
+	Common::TimerManager::TimerProc _timerBproc;
+	void *_timerBpara;
+
+	TownsAudioInterface *_intf;
+
+	uint32 _tickCounter;
+	uint8 _curChan;
+	
+	bool _open;
+};
+
+#endif
+
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
new file mode 100644
index 0000000..bbde75e
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL:  $
+ * $Id:  $
+ */
+
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "audio/musicplugin.h"
+#include "common/translation.h"
+#include "common/error.h"
+
+
+class TownsEmuMusicPlugin : public MusicPluginObject {
+public:
+	const char *getName() const {
+		return _s("FM-Towns Audio");
+	}
+
+	const char *getId() const {
+		return "towns";
+	}
+
+	MusicDevices getDevices() const;
+	Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
+};
+
+MusicDevices TownsEmuMusicPlugin::getDevices() const {
+	MusicDevices devices;
+	devices.push_back(MusicDevice(this, "", MT_TOWNS));
+	return devices;
+}
+
+Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
+	*mididriver = new MidiDriver_TOWNS(g_system->getMixer());
+	return Common::kNoError;
+}
+
+class PC98EmuMusicPlugin : public MusicPluginObject {
+public:
+	const char *getName() const {
+		return _s("PC-98 Audio");
+	}
+
+	const char *getId() const {
+		return "pc98";
+	}
+
+	MusicDevices getDevices() const;
+	Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
+};
+
+MusicDevices PC98EmuMusicPlugin::getDevices() const {
+	MusicDevices devices;
+	devices.push_back(MusicDevice(this, "", MT_PC98));
+	return devices;
+}
+
+Common::Error PC98EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
+	//*mididriver = /**/
+	return Common::kNoError;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(TOWNS)
+	//REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+	//REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+//#else
+	REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
+	REGISTER_PLUGIN_STATIC(PC98, PLUGIN_TYPE_MUSIC, PC98EmuMusicPlugin);
+//#endif
diff --git a/audio/softsynth/ym2612.cpp b/audio/softsynth/ym2612.cpp
deleted file mode 100644
index d966595..0000000
--- a/audio/softsynth/ym2612.cpp
+++ /dev/null
@@ -1,790 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <math.h>
-
-#include "audio/softsynth/ym2612.h"
-#include "common/util.h"
-#include "audio/musicplugin.h"
-#include "common/error.h"
-#include "common/system.h"
-#include "common/textconsole.h"
-#include "common/translation.h"
-#include "common/types.h"
-
-////////////////////////////////////////
-//
-// Miscellaneous
-//
-////////////////////////////////////////
-
-static int *sintbl = 0;
-static int *powtbl = 0;
-static int *frequencyTable = 0;
-static int *keycodeTable = 0;
-static int *keyscaleTable = 0;
-static int *attackOut = 0;
-
-
-////////////////////////////////////////
-//
-// Operator2612 implementation
-//
-////////////////////////////////////////
-
-Operator2612::Operator2612 (Voice2612 *owner) :
-	_owner (owner),
-	_state (_s_ready),
-	_currentLevel ((int32)0x7f << 15),
-	_phase (0),
-	_lastOutput (0),
-	_feedbackLevel (0),
-	_detune (0),
-	_multiple (1),
-	_keyScale (0),
-	_specifiedTotalLevel (127),
-	_specifiedAttackRate (0),
-	_specifiedDecayRate (0),
-	_specifiedSustainRate (0),
-	_specifiedReleaseRate (15) {
-		velocity(0);
-}
-
-Operator2612::~Operator2612()
-{ }
-
-void Operator2612::velocity(int velo) {
-	_velocity = velo;
-	_totalLevel = ((int32)_specifiedTotalLevel << 15) +
-					((int32)(127-_velocity) << 13);
-	_sustainLevel = ((int32)_specifiedSustainLevel << 17);
-}
-
-void Operator2612::feedbackLevel(int level) {
-	_feedbackLevel = level;
-}
-
-void Operator2612::setInstrument(byte const *instrument) {
-	_detune = (instrument[8] >> 4) & 7;
-	_multiple = instrument[8] & 15;
-	_specifiedTotalLevel = instrument[12] & 127;
-	_keyScale = (instrument[16] >> 6) & 3;
-	_specifiedAttackRate = instrument[16] & 31;
-	_specifiedDecayRate = instrument[20] & 31;
-	_specifiedSustainRate = instrument[24] & 31;
-	_specifiedSustainLevel = (instrument[28] >> 4) & 15;
-	_specifiedReleaseRate = instrument[28] & 15;
-	_state = _s_ready;
-	velocity(_velocity);
-}
-
-void Operator2612::keyOn() {
-	_state = _s_attacking;
-	_tickCount = 0;
-	_phase = 0;
-	_currentLevel = ((int32)0x7f << 15);
-}
-
-void Operator2612::keyOff() {
-	if (_state != _s_ready)
-		_state = _s_releasing;
-}
-
-void Operator2612::frequency(int freq) {
-	double value; // Use for intermediate computations to avoid int64 arithmetic
-	int r;
-
-	_frequency = freq / _owner->_rate;
-
-	r = _specifiedAttackRate;
-	if (r != 0) {
-		r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
-		if (r >= 64)
-		r = 63;
-	}
-
-	r = 63 - r;
-	if (_specifiedTotalLevel >= 128)
-		value = 0;
-	else {
-		value = powtbl[(r&3) << 7];
-		value *= 1 << (r >> 2);
-		value *= 41;
-		value /= 1 << (15 + 5);
-		value *= 127 - _specifiedTotalLevel;
-		value /= 127;
-	}
-	_attackTime = (int32) value; // 1 ?? == (1 << 12)
-	if (_attackTime > 0)
-		_attackTime = (1 << (12+10)) / (_owner->_rate * _attackTime);
-
-	r = _specifiedDecayRate;
-	if (r != 0) {
-		r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
-		if (r >= 64)
-			r = 63;
-	}
-	value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
-	_decayRate = (int32) value / _owner->_rate;
-
-	r = _specifiedSustainRate;
-	if (r != 0) {
-		r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
-		if (r >= 64)
-			r = 63;
-	}
-	value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
-	_sustainRate = (int32) value / _owner->_rate;
-
-	r = _specifiedReleaseRate;
-	if (r != 0) {
-		r = r * 2 + 1;		// (Translated) I cannot know whether the timing is a good choice or not
-		r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
-		// KS
-		if (r >= 64)
-			r = 63;
-	}
-	value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
-	_releaseRate = (int32) value / _owner->_rate;
-}
-
-void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
-	if (_state == _s_ready)
-		return;
-	if (_state == _s_attacking && _attackTime <= 0) {
-		_currentLevel = 0;
-		_state = _s_decaying;
-	}
-
-	int32 levelIncrement = 0;
-	int32 target = 0;
-	State next_state = _s_ready;
-	const int32 zero_level = ((int32)0x7f << 15);
-	const int phaseIncrement = (_multiple > 0) ? (_frequency * _multiple) : (_frequency / 2);
-
-	int32 output = _lastOutput;
-	int32 level = _currentLevel + _totalLevel;
-
-	while (buflen) {
-		switch (_state) {
-		case _s_ready:
-			return;
-		case _s_attacking:
-			next_state = _s_attacking;
-			break;
-		case _s_decaying:
-			levelIncrement = _decayRate;
-			target = _sustainLevel + _totalLevel;
-			next_state = _s_sustaining;
-			break;
-		case _s_sustaining:
-			levelIncrement = _sustainRate;
-			target = zero_level + _totalLevel;
-			next_state = _s_ready;
-			break;
-		case _s_releasing:
-			levelIncrement = _releaseRate;
-			target = zero_level + _totalLevel;
-			next_state = _s_ready;
-			break;
-		}
-
-		bool switching = false;
-		do {
-			if (next_state == _s_attacking) {
-				// Attack phase
-				++_tickCount;
-				int i = (int) (_tickCount * _attackTime);
-				if (i >= 1024) {
-					level = _totalLevel;
-					_state = _s_decaying;
-					switching = true;
-				} else {
-					level = (attackOut[i] << (31 - 8 - 16)) + _totalLevel;
-				}
-			} else {
-				// Decay, Sustain and Release phases
-				level += levelIncrement;
-				if (level >= target) {
-					level = target;
-					_state = next_state;
-					switching = true;
-				}
-			}
-
-			if (level < zero_level) {
-				int phaseShift = *phasebuf >> 2;
-				if (_feedbackLevel)
-					phaseShift += (output << (_feedbackLevel - 1)) / 1024;
-				output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff];
-				output >>= (level >> 18);
-				// Here is the original code, which requires 64-bit ints
-//				output *= powtbl[511 - ((level>>25)&511)];
-//				output >>= 16;
-//				output >>= 1;
-				// And here's our 32-bit trick for doing it. (Props to Fingolfin!)
-				// Result varies from original code by max of 1.
-//				int powVal = powtbl[511 - ((level>>9)&511)];
-//				int outputHI = output / 256;
-//				int powHI = powVal / 256;
-//				output = (outputHI * powHI) / 2 + (outputHI * (powVal % 256) + powHI * (output % 256)) / 512;
-				// And here's the even faster code.
-				// Result varies from original code by max of 8.
-				output = ((output >> 4) * (powtbl[511-((level>>9)&511)] >> 3)) / 1024;
-
-				_phase += phaseIncrement;
-				_phase &= 0x3ffff;
-			} else
-				output = 0;
-
-			*outbuf += output;
-			 --buflen;
-			 ++phasebuf;
-			 ++outbuf;
-		} while (buflen && !switching);
-	}
-	_lastOutput = output;
-	_currentLevel = level - _totalLevel;
-}
-
-////////////////////////////////////////
-//
-// Voice2612 implementation
-//
-////////////////////////////////////////
-
-Voice2612::Voice2612() {
-	next = 0;
-	_control7 = 127;
-	_note = 40;
-	_frequency = 440;
-	_frequencyOffs = 0x2000;
-	_algorithm = 7;
-
-	_buffer = 0;
-	_buflen = 0;
-
-	int i;
-	for (i = 0; i < ARRAYSIZE(_opr); ++i)
-		_opr[i] = new Operator2612 (this);
-	velocity(0);
-}
-
-Voice2612::~Voice2612() {
-	int i;
-	for (i = 0; i < ARRAYSIZE(_opr); ++i)
-		delete _opr[i];
-	free(_buffer);
-}
-
-void Voice2612::velocity(int velo) {
-	_velocity = velo;
-#if 0
-	int v = (velo * _control7) >> 7;
-#else
-	int v = velo + (_control7 - 127) * 4;
-#endif
-	bool iscarrier[8][4] = {
-		{ false, false, false,  true, }, //0
-		{ false, false, false,  true, }, //1
-		{ false, false, false,  true, }, //2
-		{ false, false, false,  true, }, //3
-		{ false,  true, false,  true, }, //4
-		{ false,  true,  true,  true, }, //5
-		{ false,  true,  true,  true, }, //6
-		{  true,  true,  true,  true, }, //7
-	};
-	int opr;
-	for (opr = 0; opr < 4; opr++)
-		if (iscarrier[_algorithm][opr])
-			_opr[opr]->velocity(v);
-		else
-			_opr[opr]->velocity(127);
-}
-
-void Voice2612::setControlParameter(int control, int value) {
-	switch (control) {
-	case 7:
-		_control7 = value;
-		velocity(_velocity);
-		break;
-	case 123:
-		// All notes off
-		noteOff(_note);
-	};
-}
-
-void Voice2612::setInstrument(byte const *instrument) {
-	if (instrument == NULL)
-		return;
-
-	_algorithm = instrument[32] & 7;
-	_opr[0]->feedbackLevel((instrument[32] >> 3) & 7);
-	_opr[1]->feedbackLevel(0);
-	_opr[2]->feedbackLevel(0);
-	_opr[3]->feedbackLevel(0);
-	_opr[0]->setInstrument(instrument + 0);
-	_opr[1]->setInstrument(instrument + 2);
-	_opr[2]->setInstrument(instrument + 1);
-	_opr[3]->setInstrument(instrument + 3);
-}
-
-void Voice2612::nextTick(int *outbuf, int buflen) {
-	if (_velocity == 0)
-		return;
-
-	if (_buflen < buflen) {
-		free(_buffer);
-		_buflen = buflen;
-		_buffer = (int *) malloc(sizeof(int) * buflen * 2);
-	}
-
-	int *buf1 = _buffer;
-	int *buf2 = _buffer + buflen;
-	memset(_buffer, 0, sizeof(int) * buflen * 2);
-
-	switch (_algorithm) {
-	case 0:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf2, buf1, buflen);
-		memset (buf2, 0, sizeof (int) * buflen);
-		_opr[2]->nextTick(buf1, buf2, buflen);
-		_opr[3]->nextTick(buf2, outbuf, buflen);
-		break;
-	case 1:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf1, buf2, buflen);
-		_opr[2]->nextTick(buf2, buf1, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	case 2:
-		_opr[1]->nextTick(buf1, buf2, buflen);
-		_opr[2]->nextTick(buf2, buf1, buflen);
-		memset(buf2, 0, sizeof(int) * buflen);
-		_opr[0]->nextTick(buf2, buf1, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	case 3:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf2, buf1, buflen);
-		memset(buf2, 0, sizeof(int) * buflen);
-		_opr[2]->nextTick(buf2, buf1, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	case 4:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf2, outbuf, buflen);
-		_opr[2]->nextTick(buf1, buf1, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	case 5:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf2, outbuf, buflen);
-		_opr[2]->nextTick(buf2, outbuf, buflen);
-		_opr[3]->nextTick(buf2, outbuf, buflen);
-		break;
-	case 6:
-		_opr[0]->nextTick(buf1, buf2, buflen);
-		_opr[1]->nextTick(buf2, outbuf, buflen);
-		_opr[2]->nextTick(buf1, outbuf, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	case 7:
-		_opr[0]->nextTick(buf1, outbuf, buflen);
-		_opr[1]->nextTick(buf1, outbuf, buflen);
-		_opr[2]->nextTick(buf1, outbuf, buflen);
-		_opr[3]->nextTick(buf1, outbuf, buflen);
-		break;
-	};
-}
-
-void Voice2612::noteOn(int n, int onVelo) {
-	_note = n;
-	velocity(onVelo);
-	recalculateFrequency();
-	int i;
-	for (i = 0; i < ARRAYSIZE(_opr); i++)
-		_opr[i]->keyOn();
-}
-
-bool Voice2612::noteOff(int note) {
-	if (_note != note)
-		return false;
-	int i;
-	for (i = 0; i < ARRAYSIZE(_opr); i++)
-		_opr[i]->keyOff();
-	return true;
-}
-
-void Voice2612::pitchBend(int value) {
-	_frequencyOffs = value;
-	recalculateFrequency();
-}
-
-void Voice2612::recalculateFrequency() {
-	//
-	//
-	//
-	int32 basefreq = frequencyTable[_note];
-	int cfreq = frequencyTable[_note - (_note % 12)];
-	int oct = _note / 12;
-	int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq);
-	fnum += _frequencyOffs - 0x2000;
-	if (fnum < 0x2000) {
-		fnum += 0x2000;
-		oct--;
-	}
-	if (fnum >= 0x4000) {
-		fnum -= 0x2000;
-		oct++;
-	}
-
-	//
-	_frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8);
-
-	int i;
-	for (i = 0; i < ARRAYSIZE(_opr); i++)
-		_opr[i]->frequency(_frequency);
-}
-
-////////////////////////////////////////
-//
-// MidiChannel_YM2612
-//
-////////////////////////////////////////
-
-MidiChannel_YM2612::MidiChannel_YM2612() {
-	_voices = 0;
-	_next_voice = 0;
-}
-
-MidiChannel_YM2612::~MidiChannel_YM2612() {
-	removeAllVoices();
-}
-
-void MidiChannel_YM2612::removeAllVoices() {
-	if (!_voices)
-		return;
-	Voice2612 *last, *voice = _voices;
-	for (; voice; voice = last) {
-		last = voice->next;
-		delete voice;
-	}
-	_voices = _next_voice = 0;
-}
-
-void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
-	if (!_voices)
-		return;
-	_next_voice = _next_voice ? _next_voice : _voices;
-	_next_voice->noteOn(note, onVelo);
-	_next_voice = _next_voice->next;
-}
-
-void MidiChannel_YM2612::noteOff(byte note) {
-	if (!_voices)
-		return;
-	if (_next_voice == _voices)
-		_next_voice = 0;
-	Voice2612 *voice = _next_voice;
-	do {
-		if (!voice)
-			voice = _voices;
-		if (voice->noteOff(note)) {
-			_next_voice = voice;
-			break;
-		}
-		voice = voice->next;
-	} while (voice != _next_voice);
-}
-
-void MidiChannel_YM2612::controlChange(byte control, byte value) {
-	//
-	if (control == 121) {
-		// Reset controller
-		removeAllVoices();
-	} else {
-		Voice2612 *voice = _voices;
-		for (; voice; voice = voice->next)
-			voice->setControlParameter(control, value);
-	}
-}
-
-void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst) {
-	if (type != 'EUP ')
-		return;
-	Voice2612 *voice = new Voice2612;
-	voice->next = _voices;
-	_voices = voice;
-	voice->_rate = _rate;
-	voice->setInstrument(fmInst);
-}
-
-void MidiChannel_YM2612::pitchBend(int16 value) {
-  //
-	Voice2612 *voice = _voices;
-	for (; voice; voice = voice->next)
-		voice->pitchBend(value);
-}
-
-void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) {
-	Voice2612 *voice = _voices;
-	for (; voice; voice = voice->next)
-		voice->nextTick(outbuf, buflen);
-}
-
-void MidiChannel_YM2612::rate(uint16 r) {
-	_rate = r;
-	Voice2612 *voice = _voices;
-	for (; voice; voice = voice->next)
-		voice->_rate = r;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_YM2612
-//
-////////////////////////////////////////
-
-MidiDriver_YM2612::MidiDriver_YM2612(Audio::Mixer *mixer)
-	: MidiDriver_Emulated(mixer) {
-	_next_voice = 0;
-
-	createLookupTables();
-	_volume = 256;
-	int i;
-	for (i = 0; i < ARRAYSIZE(_channel); i++)
-		_channel[i] = new MidiChannel_YM2612;
-	rate(getRate());
-}
-
-MidiDriver_YM2612::~MidiDriver_YM2612() {
-	int i;
-	for (i = 0; i < ARRAYSIZE(_channel); i++)
-		delete _channel[i];
-	removeLookupTables();
-}
-
-int MidiDriver_YM2612::open() {
-	if (_isOpen)
-		return MERR_ALREADY_OPEN;
-
-	MidiDriver_Emulated::open();
-
-	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-	return 0;
-}
-
-void MidiDriver_YM2612::close() {
-	if (!_isOpen)
-		return;
-	_isOpen = false;
-
-	_mixer->stopHandle(_mixerSoundHandle);
-}
-
-void MidiDriver_YM2612::send(uint32 b) {
-	send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_YM2612::send(byte chan, uint32 b) {
-	//byte param3 = (byte) ((b >> 24) & 0xFF);
-	byte param2 = (byte) ((b >> 16) & 0xFF);
-	byte param1 = (byte) ((b >>  8) & 0xFF);
-	byte cmd    = (byte) (b & 0xF0);
-	if (chan > ARRAYSIZE(_channel))
-		return;
-
-	switch (cmd) {
-	case 0x80:// Note Off
-		_channel[chan]->noteOff(param1);
-		break;
-	case 0x90: // Note On
-		_channel[chan]->noteOn(param1, param2);
-		break;
-	case 0xA0: // Aftertouch
-		break; // Not supported.
-	case 0xB0: // Control Change
-		_channel[chan]->controlChange(param1, param2);
-		break;
-	case 0xC0: // Program Change
-		_channel[chan]->programChange(param1);
-		break;
-	case 0xD0: // Channel Pressure
-		break; // Not supported.
-	case 0xE0: // Pitch Bend
-		_channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
-		break;
-	case 0xF0: // SysEx
-		// We should never get here! SysEx information has to be
-		// sent via high-level semantic methods.
-		warning("MidiDriver_YM2612: Receiving SysEx command on a send() call");
-		break;
-
-	default:
-		warning("MidiDriver_YM2612: Unknown send() command 0x%02X", cmd);
-	}
-}
-
-void MidiDriver_YM2612::sysEx(const byte *msg, uint16 length) {
-	if (msg[0] != 0x7C || msg[1] >= ARRAYSIZE(_channel))
-		return;
-	_channel[msg[1]]->sysEx_customInstrument('EUP ', &msg[2]);
-}
-
-void MidiDriver_YM2612::generateSamples(int16 *data, int len) {
-	memset(data, 0, 2 * sizeof(int16) * len);
-	nextTick(data, len);
-}
-
-void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
-	int *buf0 = (int *)buf1;
-
-	int i;
-	for (i = 0; i < ARRAYSIZE(_channel); i++)
-		_channel[i]->nextTick(buf0, buflen);
-
-	for (i = 0; i < buflen; ++i)
-		buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff;
-}
-
-void MidiDriver_YM2612::rate(uint16 r)
-{
-	int i;
-	for (i = 0; i < ARRAYSIZE(_channel); i++)
-		_channel[i]->rate(r);
-}
-
-void MidiDriver_YM2612::createLookupTables() {
-	{
-		int i;
-		sintbl = new int [2048];
-		for (i = 0; i < 2048; i++)
-			sintbl[i] = (int)(0xffff * sin(i/2048.0 * 2.0 * M_PI));
-	}
-
-	{
-		int i;
-		powtbl = new int [1025];
-		for (i = 0; i <= 1024; i++)
-			powtbl[i] = (int)(0x10000 * pow(2.0, (i - 512) / 512.0));
-	}
-
-	{
-		int i;
-		int block;
-
-		static int fnum[] = {
-			0x026a, 0x028f, 0x02b6, 0x02df,
-			0x030b, 0x0339, 0x036a, 0x039e,
-			0x03d5, 0x0410, 0x044e, 0x048f,
-		};
-
-		// (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0))
-		//
-		frequencyTable = new int [120];
-		for (block = -1; block < 9; block++) {
-			for (i = 0; i < 12; i++) {
-				double freq = fnum[i] * (166400.0 / 3) * pow(2.0, block-21);
-				frequencyTable[(block+1)*12+i] = (int)(256.0 * freq);
-			}
-		}
-
-		keycodeTable = new int [120];
-		// detune
-		for (block = -1; block < 9; block++) {
-			for (i = 0; i < 12; i++) {
-				// see p.204
-				int  f8 = (fnum[i] >>  7) & 1;
-				int  f9 = (fnum[i] >>  8) & 1;
-				int f10 = (fnum[i] >>  9) & 1;
-				int f11 = (fnum[i] >> 10) & 1;
-				int  n4 = f11;
-				int  n3 = (f11&(f10|f9|f8)) | (~f11&f10&f9&f8);
-				int note = n4*2 + n3;
-				// see p.207
-				keycodeTable[(block+1)*12+i] = block*4 + note;
-			}
-		}
-	}
-
-	{
-		int freq;
-		keyscaleTable = new int [8192];
-		keyscaleTable[0] = 0;
-		for (freq = 1; freq < 8192; freq++) {
-			keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1;
-			// 8368[Hz] (o9c)
-		}
-	}
-
-	{
-		int i;
-		attackOut = new int [1024];
-		for (i = 0; i < 1024; i++)
-			attackOut[i] = (int)(((0x7fff+0x03a5)*30.0) / (30.0+i)) - 0x03a5;
-	}
-}
-
-void MidiDriver_YM2612::removeLookupTables() {
-	delete[] sintbl;
-	delete[] powtbl;
-	delete[] frequencyTable;
-	delete[] keycodeTable;
-	delete[] keyscaleTable;
-	delete[] attackOut;
-	sintbl = powtbl = frequencyTable = keycodeTable = keyscaleTable = attackOut = 0;
-}
-
-
-// Plugin interface
-
-class TownsEmuMusicPlugin : public MusicPluginObject {
-public:
-	const char *getName() const {
-		return _s("FM Towns Emulator");
-	}
-
-	const char *getId() const {
-		return "towns";
-	}
-
-	MusicDevices getDevices() const;
-	Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices TownsEmuMusicPlugin::getDevices() const {
-	MusicDevices devices;
-	devices.push_back(MusicDevice(this, "", MT_TOWNS));
-	return devices;
-}
-
-Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
-	*mididriver = new MidiDriver_YM2612(g_system->getMixer());
-
-	return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(TOWNS)
-	//REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#else
-	REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#endif
diff --git a/audio/softsynth/ym2612.h b/audio/softsynth/ym2612.h
deleted file mode 100644
index de91fc9..0000000
--- a/audio/softsynth/ym2612.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef SOUND_SOFTSYNTH_Y2612_H
-#define SOUND_SOFTSYNTH_Y2612_H
-
-#include "common/scummsys.h"
-
-#include "audio/softsynth/emumidi.h"
-
-////////////////////////////////////////
-//
-// Class declarations
-//
-////////////////////////////////////////
-
-class Voice2612;
-class Operator2612 {
-protected:
-	Voice2612 *_owner;
-	enum State { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
-	State _state;
-	int32 _currentLevel;
-	int _frequency;
-	uint32 _phase;
-	int _lastOutput;
-	int _feedbackLevel;
-	int _detune;
-	int _multiple;
-	int32 _totalLevel;
-	int _keyScale;
-	int _velocity;
-	int _specifiedTotalLevel;
-	int _specifiedAttackRate;
-	int _specifiedDecayRate;
-	int _specifiedSustainLevel;
-	int _specifiedSustainRate;
-	int _specifiedReleaseRate;
-	int _tickCount;
-	int _attackTime;
-	int32 _decayRate;
-	int32 _sustainLevel;
-	int32 _sustainRate;
-	int32 _releaseRate;
-
-public:
-	Operator2612 (Voice2612 *owner);
-	~Operator2612();
-	void feedbackLevel(int level);
-	void setInstrument(byte const *instrument);
-	void velocity(int velo);
-	void keyOn();
-	void keyOff();
-	void frequency(int freq);
-	void nextTick(const int *phaseShift, int *outbuf, int buflen);
-	bool inUse() { return (_state != _s_ready); }
-};
-
-class Voice2612 {
-public:
-	Voice2612 *next;
-	uint16 _rate;
-
-protected:
-	Operator2612 *_opr[4];
-	int _velocity;
-	int _control7;
-	int _note;
-	int _frequencyOffs;
-	int _frequency;
-	int _algorithm;
-
-	int *_buffer;
-	int _buflen;
-
-public:
-	Voice2612();
-	~Voice2612();
-	void setControlParameter(int control, int value);
-	void setInstrument(byte const *instrument);
-	void velocity(int velo);
-	void nextTick(int *outbuf, int buflen);
-	void noteOn(int n, int onVelo);
-	bool noteOff(int note);
-	void pitchBend(int value);
-	void recalculateFrequency();
-};
-
-class MidiChannel_YM2612 : public MidiChannel {
-protected:
-	uint16 _rate;
-	Voice2612 *_voices;
-	Voice2612 *_next_voice;
-
-public:
-	void removeAllVoices();
-	void nextTick(int *outbuf, int buflen);
-	void rate(uint16 r);
-
-public:
-	MidiChannel_YM2612();
-	virtual ~MidiChannel_YM2612();
-
-	// MidiChannel interface
-	MidiDriver *device() { return 0; }
-	byte getNumber() { return 0; }
-	void release() { }
-	void send(uint32 b) { }
-	void noteOff(byte note);
-	void noteOn(byte note, byte onVelo);
-	void programChange(byte program) { }
-	void pitchBend(int16 value);
-	void controlChange(byte control, byte value);
-	void pitchBendFactor(byte value) { }
-	void sysEx_customInstrument(uint32 type, const byte *instr);
-};
-
-class MidiDriver_YM2612 : public MidiDriver_Emulated {
-protected:
-	MidiChannel_YM2612 *_channel[16];
-
-	int _next_voice;
-	int _volume;
-
-protected:
-	void nextTick(int16 *buf1, int buflen);
-	int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; }
-	void rate(uint16 r);
-
-	void generateSamples(int16 *buf, int len);
-
-public:
-	MidiDriver_YM2612(Audio::Mixer *mixer);
-	virtual ~MidiDriver_YM2612();
-
-	static void createLookupTables();
-	static void removeLookupTables();
-
-	int open();
-	void close();
-	void send(uint32 b);
-	void send(byte channel, uint32 b); // Supports higher than channel 15
-	uint32 property(int prop, uint32 param) { return 0; }
-
-	void setPitchBendRange(byte channel, uint range) { }
-	void sysEx(const byte *msg, uint16 length);
-
-	MidiChannel *allocateChannel() { return 0; }
-	MidiChannel *getPercussionChannel() { return 0; }
-
-
-	// AudioStream API
-	bool isStereo() const { return true; }
-	int getRate() const { return _mixer->getOutputRate(); }
-};
-
-#endif
-
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 56bb1e6..4a3b201 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -225,6 +225,7 @@ public:
 		LINK_PLUGIN(AMIGA)
 		LINK_PLUGIN(APPLEIIGS)
 		LINK_PLUGIN(TOWNS)
+		LINK_PLUGIN(PC98)
 		#if defined(USE_TIMIDITY)
 		LINK_PLUGIN(TIMIDITY)
 		#endif
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index 8927e8d..2301b2a 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -26,10 +26,8 @@
 
 namespace Scumm {
 
-Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _numSoundMax(isVersion2 ? 256 : 200) {
+Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _intf(0), _numSoundMax(isVersion2 ? 256 : 200), _unkFlags(0x33) {
 	memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
-	_unkFlags = 0x33;
-	_intf = 0;
 }
 
 void Player_Towns::setSfxVolume(int vol) {
@@ -576,15 +574,16 @@ void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackV
 	_cdaCurrentSound = sound;
 }
 
-Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse) {
+Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver) : Player_Towns(vm, true), _imuse(imuse), _driver(driver), _imuseDispose(disposeIMuse), _driverDispose(disposeDriver), _sblData(0) {
 	_soundOverride = new SoundOvrParameters[_numSoundMax];
 	memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
-	_sblData = 0;
-	_intf = new TownsAudioInterface(mixer, 0);
+	if (_driver)
+		_intf = _driver->intf();
 }
 
 Player_Towns_v2::~Player_Towns_v2() {
-	delete _intf;
+	if (_driverDispose)
+		delete _driver;
 
 	if (_imuseDispose)
 		delete _imuse;
diff --git a/engines/scumm/player_towns.h b/engines/scumm/player_towns.h
index aa4a1bb..900ea59 100644
--- a/engines/scumm/player_towns.h
+++ b/engines/scumm/player_towns.h
@@ -26,6 +26,7 @@
 #include "scumm/scumm.h"
 #include "scumm/imuse/imuse.h"
 #include "audio/softsynth/fmtowns_pc98/towns_euphony.h"
+#include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 
 namespace Scumm {
 
@@ -141,7 +142,7 @@ private:
 
 class Player_Towns_v2 : public Player_Towns {
 public:
-	Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, bool disposeIMuse);
+	Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver);
 	~Player_Towns_v2();
 
 	bool init();
@@ -170,7 +171,10 @@ private:
 
 	uint8 *_sblData;
 	IMuse *_imuse;
+	MidiDriver_TOWNS *_driver;
+
 	const bool _imuseDispose;
+	const bool _driverDispose;
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 1b7f16b..ff51158 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1833,7 +1833,7 @@ void ScummEngine::setupMusic(int midi) {
 		if (nativeMidiDriver != NULL && _native_mt32)
 			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 		bool multi_midi = ConfMan.getBool("multi_midi") && _musicType != MDT_NONE && (midi & MDT_ADLIB);
-		if (_musicType == MDT_ADLIB || multi_midi) {
+		if (_musicType == MDT_ADLIB || (multi_midi && _musicType != MDT_TOWNS)) {
 			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB));
 			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
 		}
@@ -1841,7 +1841,9 @@ void ScummEngine::setupMusic(int midi) {
 		_imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver);
 		
 		if (_game.platform == Common::kPlatformFMTowns) {
-			_musicEngine = _townsPlayer = new Player_Towns_v2(this, _imuse, _mixer, true);
+			MidiDriver *townsDriver = 0;
+			townsDriver = (_musicType == MDT_TOWNS) ? nativeMidiDriver : MidiDriver::createMidi(MidiDriver::detectDevice(MDT_TOWNS));
+			_musicEngine = _townsPlayer = new Player_Towns_v2(this, _imuse, _mixer, (MidiDriver_TOWNS*)townsDriver, true, (_musicType != MDT_TOWNS));
 			if (!_townsPlayer->init())
 				error("Failed to initialize FM-Towns audio driver");
 		} else {


Commit: 63a78593516dc428f77ac01d90bc228fcf01de5d
    https://github.com/scummvm/scummvm/commit/63a78593516dc428f77ac01d90bc228fcf01de5d
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:24:28-07:00

Commit Message:
FM-TOWNS AUDIO: Change internal interface layout

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index ee8327f..065532f 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -21,13 +21,16 @@
  */
 
 #include "audio/softsynth/fmtowns_pc98/towns_audio.h"
+#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
+
 #include "common/endian.h"
 #include "common/util.h"
+#include "common/textconsole.h"
 #include "backends/audiocd/audiocd.h"
 
 
 class TownsAudio_PcmChannel {
-friend class TownsAudioInterface;
+friend class TownsAudioInterfaceIntern;
 public:
 	TownsAudio_PcmChannel();
 	~TownsAudio_PcmChannel();
@@ -77,7 +80,7 @@ private:
 };
 
 class TownsAudio_WaveTable {
-friend class TownsAudioInterface;
+friend class TownsAudioInterfaceIntern;
 public:
 	TownsAudio_WaveTable();
 	~TownsAudio_WaveTable();
@@ -98,14 +101,160 @@ private:
 	int8 *data;
 };
 
-TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns),
+class TownsAudioInterfaceIntern : public TownsPC98_FmSynth {
+public:
+	TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver);
+	~TownsAudioInterfaceIntern();
+
+	static TownsAudioInterfaceIntern *addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver);
+	static void releaseRef();
+	bool checkPluginDriver(TownsAudioInterfacePluginDriver *driver);
+
+	bool init();
+
+	int callback(int command, ...);
+	int processCommand(int command, va_list &args);
+
+	void setMusicVolume(int volume);
+	void setSoundEffectVolume(int volume);
+	// Defines the channels used as sound effect channels for the purpose of ScummVM GUI volume control.
+	// The first 6 bits are the 6 fm channels. The next 8 bits are pcm channels.
+	void setSoundEffectChanMask(int mask);
+
+private:
+	void nextTickEx(int32 *buffer, uint32 bufferSize);
+
+	void timerCallbackA();
+	void timerCallbackB();
+
+	typedef int (TownsAudioInterfaceIntern::*TownsAudioIntfCallback)(va_list &);
+	const TownsAudioIntfCallback *_intfOpcodes;
+
+	int intf_reset(va_list &args);
+	int intf_keyOn(va_list &args);
+	int intf_keyOff(va_list &args);
+	int intf_setPanPos(va_list &args);
+	int intf_setInstrument(va_list &args);
+	int intf_loadInstrument(va_list &args);
+	int intf_setPitch(va_list &args);
+	int intf_setLevel(va_list &args);
+	int intf_chanOff(va_list &args);
+	int intf_writeReg(va_list &args);
+	int intf_writeRegBuffer(va_list &args);
+	int intf_readRegBuffer(va_list &args);
+	int intf_setTimerA(va_list &args);
+	int intf_setTimerB(va_list &args);
+	int intf_enableTimerA(va_list &args);
+	int intf_enableTimerB(va_list &args);
+	int intf_loadSamples(va_list &args);
+	int intf_reserveEffectChannels(va_list &args);
+	int intf_loadWaveTable(va_list &args);
+	int intf_unloadWaveTable(va_list &args);
+	int intf_pcmPlayEffect(va_list &args);
+	int intf_pcmChanOff(va_list &args);
+	int intf_pcmEffectPlaying(va_list &args);
+	int intf_fmKeyOn(va_list &args);
+	int intf_fmKeyOff(va_list &args);
+	int intf_fmSetPanPos(va_list &args);
+	int intf_fmSetInstrument(va_list &args);
+	int intf_fmLoadInstrument(va_list &args);
+	int intf_fmSetPitch(va_list &args);
+	int intf_fmSetLevel(va_list &args);
+	int intf_fmReset(va_list &args);
+	int intf_setOutputVolume(va_list &args);
+	int intf_resetOutputVolume(va_list &args);
+	int intf_updateOutputVolume(va_list &args);
+	int intf_cdaToggle(va_list &args);
+	int intf_pcmUpdateEnvelopeGenerator(va_list &args);
+
+	int intf_notImpl(va_list &args);
+
+	void fmReset();
+	int fmKeyOn(int chan, int note, int velo);
+	int fmKeyOff(int chan);
+	int fmChanOff(int chan);
+	int fmSetPanPos(int chan, int mode);
+	int fmSetInstrument(int chan, int instrId);
+	int fmLoadInstrument(int instrId, const uint8 *data);
+	int fmSetPitch(int chan, int pitch);
+	int fmSetLevel(int chan, int lvl);
+
+	void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value);
+
+	uint8 _fmChanPlaying;
+	uint8 _fmChanNote[6];
+	int16 _fmChanPitch[6];
+
+	uint8 *_fmSaveReg[2];
+	uint8 *_fmInstruments;
+
+	void pcmReset();
+	int pcmKeyOn(int chan, int note, int velo);
+	int pcmKeyOff(int chan);
+	int pcmChanOff(int chan);
+	int pcmSetPanPos(int chan, int mode);
+	int pcmSetInstrument(int chan, int instrId);
+	int pcmLoadInstrument(int instrId, const uint8 *data);
+	int pcmSetPitch(int chan, int pitch);
+	int pcmSetLevel(int chan, int lvl);
+	void pcmUpdateEnvelopeGenerator(int chan);
+
+	TownsAudio_PcmChannel *_pcmChan;
+	uint8 _pcmChanOut;
+	uint8 _pcmChanReserved;
+	uint8 _pcmChanKeyPressed;
+	uint8 _pcmChanEffectPlaying;
+	uint8 _pcmChanKeyPlaying;
+
+	uint8 _pcmChanNote[8];
+	uint8 _pcmChanVelo[8];
+	uint8 _pcmChanLevel[8];
+
+	uint8 _numReservedChannels;
+	uint8 *_pcmInstruments;
+
+	TownsAudio_WaveTable *_waveTables;
+	uint8 _numWaveTables;
+	uint32 _waveTablesTotalDataSize;
+
+	void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w);
+
+	void updateOutputVolume();
+	uint8 _outputVolumeFlags;
+	uint8 _outputLevel[16];
+	uint8 _outputMuteFlags;
+
+	const float _baserate;
+	uint32 _timerBase;
+	uint32 _tickLength;
+	uint32 _timer;
+
+	uint16 _musicVolume;
+	uint16 _sfxVolume;
+	int _pcmSfxChanMask;
+
+	TownsAudioInterfacePluginDriver *_drv;
+	bool _ready;
+
+	static TownsAudioInterfaceIntern *_refInstance;
+	static int _refCount;
+
+	static const uint8 _chanFlags[];
+	static const uint16 _frequency[];
+	static const uint8 _carrier[];
+	static const uint8 _fmDefaultInstrument[];
+	static const uint16 _pcmPhase1[];
+	static const uint16 _pcmPhase2[];
+};
+
+TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns),
 	_fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0),
 	_baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver),
 	_pcmSfxChanMask(0),	_musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume),
 	_outputVolumeFlags(0), _outputMuteFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
 	_pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _ready(false) {
 
-#define INTCB(x) &TownsAudioInterface::intf_##x
+#define INTCB(x) &TownsAudioInterfaceIntern::intf_##x
 	static const TownsAudioIntfCallback intfCb[] = {
 		// 0
 		INTCB(reset),
@@ -222,7 +371,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac
 	_tickLength = 2 * _timerBase;
 }
 
-TownsAudioInterface::~TownsAudioInterface() {
+TownsAudioInterfaceIntern::~TownsAudioInterfaceIntern() {
 	_ready = false;
 	deinit();
 
@@ -234,7 +383,47 @@ TownsAudioInterface::~TownsAudioInterface() {
 	delete[] _pcmChan;
 }
 
-bool TownsAudioInterface::init() {
+TownsAudioInterfaceIntern *TownsAudioInterfaceIntern::addNewRef(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) {
+	_refCount++;
+	if (_refCount == 1 && _refInstance == 0)
+		_refInstance = new TownsAudioInterfaceIntern(mixer, driver);
+	else if (_refCount < 2 || _refInstance == 0)
+		error("TownsAudioInterfaceIntern::addNewRef(): Internal reference management failure");
+	else if (!_refInstance->checkPluginDriver(driver))
+		error("TownsAudioInterfaceIntern::addNewRef(): Plugin driver conflict");
+
+	return _refInstance;
+}
+
+void TownsAudioInterfaceIntern::releaseRef() {
+	if (!_refCount)
+		return;
+
+	_refCount--;
+	
+	if (!_refCount) {
+		delete _refInstance;
+		_refInstance = 0;
+	}
+}
+
+bool TownsAudioInterfaceIntern::checkPluginDriver(TownsAudioInterfacePluginDriver *driver) {
+	if (_refCount <= 1)
+		return true;
+
+	Common::StackLock lock(_mutex);
+
+	if (_drv) {
+		if (driver && driver != _drv)
+			return false;
+	} else {
+		_drv = driver;
+	}
+
+	return true;
+}
+
+bool TownsAudioInterfaceIntern::init() {
 	if (_ready)
 		return true;
 
@@ -258,41 +447,46 @@ bool TownsAudioInterface::init() {
 	return true;
 }
 
-int TownsAudioInterface::callback(int command, ...) {
+int TownsAudioInterfaceIntern::callback(int command, ...) {
 	if (!_ready)
 		return 1;
 
 	va_list args;
 	va_start(args, command);
 
-	if (command > 81) {
-		va_end(args);
-		return 4;
-	}
-
-	int res = (this->*_intfOpcodes[command])(args);
+	int res = processCommand(command, args);
 
 	va_end(args);
 	return res;
 }
 
-void TownsAudioInterface::setMusicVolume(int volume) {
+int TownsAudioInterfaceIntern::processCommand(int command, va_list &args) {
+	if (!_ready)
+		return 1;
+
+	if (command < 0 || command > 81)
+		return 4;
+	
+	return (this->*_intfOpcodes[command])(args);
+}
+
+void TownsAudioInterfaceIntern::setMusicVolume(int volume) {
 	_musicVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
 	setVolumeIntern(_musicVolume, _sfxVolume);
 }
 
-void TownsAudioInterface::setSoundEffectVolume(int volume) {
+void TownsAudioInterfaceIntern::setSoundEffectVolume(int volume) {
 	_sfxVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
 	setVolumeIntern(_musicVolume, _sfxVolume);
 }
 
-void TownsAudioInterface::setSoundEffectChanMask(int mask) {
+void TownsAudioInterfaceIntern::setSoundEffectChanMask(int mask) {
 	_pcmSfxChanMask = mask >> 6;
 	mask &= 0x3f;
 	setVolumeChannelMasks(~mask, mask);
 }
 
-void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) {
+void TownsAudioInterfaceIntern::nextTickEx(int32 *buffer, uint32 bufferSize) {
 	if (!_ready)
 		return;
 
@@ -343,13 +537,13 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) {
 	}
 }
 
-void TownsAudioInterface::timerCallbackA() {
+void TownsAudioInterfaceIntern::timerCallbackA() {
 	Common::StackLock lock(_mutex);
 	if (_drv && _ready)
 		_drv->timerCallback(0);
 }
 
-void TownsAudioInterface::timerCallbackB() {
+void TownsAudioInterfaceIntern::timerCallbackB() {
 	Common::StackLock lock(_mutex);
 	if (_ready) {
 		if (_drv)
@@ -358,62 +552,62 @@ void TownsAudioInterface::timerCallbackB() {
 	}
 }
 
-int TownsAudioInterface::intf_reset(va_list &args) {
+int TownsAudioInterfaceIntern::intf_reset(va_list &args) {
 	fmReset();
 	pcmReset();
 	callback(68);
 	return 0;
 }
 
-int TownsAudioInterface::intf_keyOn(va_list &args) {
+int TownsAudioInterfaceIntern::intf_keyOn(va_list &args) {
 	int chan = va_arg(args, int);
 	int note = va_arg(args, int);
 	int velo = va_arg(args, int);
 	return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo);
 }
 
-int TownsAudioInterface::intf_keyOff(va_list &args) {
+int TownsAudioInterfaceIntern::intf_keyOff(va_list &args) {
 	int chan = va_arg(args, int);
 	return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan);
 }
 
-int TownsAudioInterface::intf_setPanPos(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setPanPos(va_list &args) {
 	int chan = va_arg(args, int);
 	int mode = va_arg(args, int);
 	return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode);
 }
 
-int TownsAudioInterface::intf_setInstrument(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setInstrument(va_list &args) {
 	int chan = va_arg(args, int);
 	int instrId = va_arg(args, int);
 	return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId);
 }
 
-int TownsAudioInterface::intf_loadInstrument(va_list &args) {
+int TownsAudioInterfaceIntern::intf_loadInstrument(va_list &args) {
 	int chanType = va_arg(args, int);
 	int instrId = va_arg(args, int);
 	uint8 *instrData = va_arg(args, uint8 *);
 	return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData);
 }
 
-int TownsAudioInterface::intf_setPitch(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setPitch(va_list &args) {
 	int chan = va_arg(args, int);
 	int16 pitch = (int16)(va_arg(args, int) & 0xffff);
 	return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch);
 }
 
-int TownsAudioInterface::intf_setLevel(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setLevel(va_list &args) {
 	int chan = va_arg(args, int);
 	int lvl = va_arg(args, int);
 	return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl);
 }
 
-int TownsAudioInterface::intf_chanOff(va_list &args) {
+int TownsAudioInterfaceIntern::intf_chanOff(va_list &args) {
 	int chan = va_arg(args, int);
 	return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan);
 }
 
-int TownsAudioInterface::intf_writeReg(va_list &args) {
+int TownsAudioInterfaceIntern::intf_writeReg(va_list &args) {
 	int part = va_arg(args, int) ? 1 : 0;
 	int reg = va_arg(args, int);
 	int val = va_arg(args, int);
@@ -424,7 +618,7 @@ int TownsAudioInterface::intf_writeReg(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_writeRegBuffer(va_list &args) {
+int TownsAudioInterfaceIntern::intf_writeRegBuffer(va_list &args) {
 	int part = va_arg(args, int) ? 1 : 0;
 	int reg = va_arg(args, int);
 	int val = va_arg(args, int);
@@ -436,7 +630,7 @@ int TownsAudioInterface::intf_writeRegBuffer(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_readRegBuffer(va_list &args) {
+int TownsAudioInterfaceIntern::intf_readRegBuffer(va_list &args) {
 	int part = va_arg(args, int) ? 1 : 0;
 	int reg = va_arg(args, int);
 	uint8 *dst = va_arg(args, uint8 *);
@@ -449,7 +643,7 @@ int TownsAudioInterface::intf_readRegBuffer(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_setTimerA(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setTimerA(va_list &args) {
 	int enable = va_arg(args, int);
 	int tempo = va_arg(args, int);
 
@@ -464,7 +658,7 @@ int TownsAudioInterface::intf_setTimerA(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_setTimerB(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setTimerB(va_list &args) {
 	int enable = va_arg(args, int);
 	int tempo = va_arg(args, int);
 
@@ -478,17 +672,17 @@ int TownsAudioInterface::intf_setTimerB(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_enableTimerA(va_list &args) {
+int TownsAudioInterfaceIntern::intf_enableTimerA(va_list &args) {
 	bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15);
 	return 0;
 }
 
-int TownsAudioInterface::intf_enableTimerB(va_list &args) {
+int TownsAudioInterfaceIntern::intf_enableTimerB(va_list &args) {
 	bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a);
 	return 0;
 }
 
-int TownsAudioInterface::intf_loadSamples(va_list &args) {
+int TownsAudioInterfaceIntern::intf_loadSamples(va_list &args) {
 	uint32 dest = va_arg(args, uint32);
 	int size = va_arg(args, int);
 	uint8 *src = va_arg(args, uint8*);
@@ -511,7 +705,7 @@ int TownsAudioInterface::intf_loadSamples(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) {
+int TownsAudioInterfaceIntern::intf_reserveEffectChannels(va_list &args) {
 	int numChan = va_arg(args, int);
 	if (numChan > 8)
 		return 3;
@@ -543,7 +737,7 @@ int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_loadWaveTable(va_list &args) {
+int TownsAudioInterfaceIntern::intf_loadWaveTable(va_list &args) {
 	uint8 *data = va_arg(args, uint8 *);
 	if (_numWaveTables > 127)
 		return 3;
@@ -570,7 +764,7 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_unloadWaveTable(va_list &args) {
+int TownsAudioInterfaceIntern::intf_unloadWaveTable(va_list &args) {
 	int id = va_arg(args, int);
 
 	if (id == -1) {
@@ -597,7 +791,7 @@ int TownsAudioInterface::intf_unloadWaveTable(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) {
+int TownsAudioInterfaceIntern::intf_pcmPlayEffect(va_list &args) {
 	int chan = va_arg(args, int);
 	int note = va_arg(args, int);
 	int velo = va_arg(args, int);
@@ -647,13 +841,13 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_pcmChanOff(va_list &args) {
+int TownsAudioInterfaceIntern::intf_pcmChanOff(va_list &args) {
 	int chan = va_arg(args, int);
 	pcmChanOff(chan);
 	return 0;
 }
 
-int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) {
+int TownsAudioInterfaceIntern::intf_pcmEffectPlaying(va_list &args) {
 	int chan = va_arg(args, int);
 	if (chan < 0x40 || chan > 0x47)
 		return 1;
@@ -661,54 +855,54 @@ int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) {
 	return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0;
 }
 
-int TownsAudioInterface::intf_fmKeyOn(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmKeyOn(va_list &args) {
 	int chan = va_arg(args, int);
 	int note = va_arg(args, int);
 	int velo = va_arg(args, int);
 	return fmKeyOn(chan, note, velo);
 }
 
-int TownsAudioInterface::intf_fmKeyOff(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmKeyOff(va_list &args) {
 	int chan = va_arg(args, int);
 	return fmKeyOff(chan);
 }
 
-int TownsAudioInterface::intf_fmSetPanPos(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmSetPanPos(va_list &args) {
 	int chan = va_arg(args, int);
 	int mode = va_arg(args, int);
 	return fmSetPanPos(chan, mode);
 }
 
-int TownsAudioInterface::intf_fmSetInstrument(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmSetInstrument(va_list &args) {
 	int chan = va_arg(args, int);
 	int instrId = va_arg(args, int);
 	return fmSetInstrument(chan, instrId);
 }
 
-int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmLoadInstrument(va_list &args) {
 	int instrId = va_arg(args, int);
 	uint8 *instrData = va_arg(args, uint8 *);
 	return fmLoadInstrument(instrId, instrData);
 }
 
-int TownsAudioInterface::intf_fmSetPitch(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmSetPitch(va_list &args) {
 	int chan = va_arg(args, int);
 	uint16 freq = va_arg(args, int) & 0xffff;
 	return fmSetPitch(chan, freq);
 }
 
-int TownsAudioInterface::intf_fmSetLevel(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmSetLevel(va_list &args) {
 	int chan = va_arg(args, int);
 	int lvl = va_arg(args, int);
 	return fmSetLevel(chan, lvl);
 }
 
-int TownsAudioInterface::intf_fmReset(va_list &args) {
+int TownsAudioInterfaceIntern::intf_fmReset(va_list &args) {
 	fmReset();
 	return 0;
 }
 
-int TownsAudioInterface::intf_setOutputVolume(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) {
 	int chanType = va_arg(args, int);
 	int left = va_arg(args, int);
 	int right = va_arg(args, int);
@@ -743,7 +937,7 @@ int TownsAudioInterface::intf_setOutputVolume(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_resetOutputVolume(va_list &args) {
+int TownsAudioInterfaceIntern::intf_resetOutputVolume(va_list &args) {
 	memset(_outputLevel, 0, sizeof(_outputLevel));
 	_outputMuteFlags = 0;
 	_outputVolumeFlags = 0;
@@ -751,30 +945,30 @@ int TownsAudioInterface::intf_resetOutputVolume(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterface::intf_updateOutputVolume(va_list &args) {
+int TownsAudioInterfaceIntern::intf_updateOutputVolume(va_list &args) {
 	int flags = va_arg(args, int);
 	_outputMuteFlags = flags & 3;
 	updateOutputVolume();
 	return 0;
 }
 
-int TownsAudioInterface::intf_cdaToggle(va_list &args) {
+int TownsAudioInterfaceIntern::intf_cdaToggle(va_list &args) {
 	//int mode = va_arg(args, int);
 	//_unkMask = mode ? 0x7f : 0x3f;
 	return 0;
 }
 
-int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) {
+int TownsAudioInterfaceIntern::intf_pcmUpdateEnvelopeGenerator(va_list &args) {
 	for (int i = 0; i < 8; i++)
 		pcmUpdateEnvelopeGenerator(i);
 	return 0;
 }
 
-int TownsAudioInterface::intf_notImpl(va_list &args) {
+int TownsAudioInterfaceIntern::intf_notImpl(va_list &args) {
 	return 4;
 }
 
-void TownsAudioInterface::fmReset() {
+void TownsAudioInterfaceIntern::fmReset() {
 	TownsPC98_FmSynth::reset();
 
 	_fmChanPlaying = 0;
@@ -802,7 +996,7 @@ void TownsAudioInterface::fmReset() {
 	}
 }
 
-int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) {
+int TownsAudioInterfaceIntern::fmKeyOn(int chan, int note, int velo) {
 	if (chan > 5)
 		return 1;
 	if (note < 12 || note > 107 || (velo & 0x80))
@@ -882,7 +1076,7 @@ int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) {
 	return 0;
 }
 
-int TownsAudioInterface::fmKeyOff(int chan) {
+int TownsAudioInterfaceIntern::fmKeyOff(int chan) {
 	if (chan > 5)
 		return 1;
 	_fmChanPlaying &= ~_chanFlags[chan];
@@ -892,7 +1086,7 @@ int TownsAudioInterface::fmKeyOff(int chan) {
 	return 0;
 }
 
-int TownsAudioInterface::fmChanOff(int chan) {
+int TownsAudioInterfaceIntern::fmChanOff(int chan) {
 	if (chan > 5)
 		return 1;
 	_fmChanPlaying &= ~_chanFlags[chan];
@@ -910,7 +1104,7 @@ int TownsAudioInterface::fmChanOff(int chan) {
 	return 0;
 }
 
-int TownsAudioInterface::fmSetPanPos(int chan, int value) {
+int TownsAudioInterfaceIntern::fmSetPanPos(int chan, int value) {
 	if (chan > 5)
 		return 1;
 
@@ -929,7 +1123,7 @@ int TownsAudioInterface::fmSetPanPos(int chan, int value) {
 	return 0;
 }
 
-int TownsAudioInterface::fmSetInstrument(int chan, int instrId) {
+int TownsAudioInterfaceIntern::fmSetInstrument(int chan, int instrId) {
 	if (chan > 5)
 		return 1;
 	if (instrId > 127)
@@ -973,7 +1167,7 @@ int TownsAudioInterface::fmSetInstrument(int chan, int instrId) {
 	return 0;
 }
 
-int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) {
+int TownsAudioInterfaceIntern::fmLoadInstrument(int instrId, const uint8 *data) {
 	if (instrId > 127)
 		return 3;
 	assert(data);
@@ -981,7 +1175,7 @@ int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) {
 	return 0;
 }
 
-int TownsAudioInterface::fmSetPitch(int chan, int pitch) {
+int TownsAudioInterfaceIntern::fmSetPitch(int chan, int pitch) {
 	if (chan > 5)
 		return 1;
 
@@ -1068,7 +1262,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) {
 	return 0;
 }
 
-int TownsAudioInterface::fmSetLevel(int chan, int lvl) {
+int TownsAudioInterfaceIntern::fmSetLevel(int chan, int lvl) {
 	if (chan > 5)
 		return 1;
 	if (lvl > 127)
@@ -1091,12 +1285,12 @@ int TownsAudioInterface::fmSetLevel(int chan, int lvl) {
 	return 0;
 }
 
-void TownsAudioInterface::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) {
+void TownsAudioInterfaceIntern::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) {
 	_fmSaveReg[part][regAddress] = value;
 	writeReg(part, regAddress, value);
 }
 
-void TownsAudioInterface::pcmReset() {
+void TownsAudioInterfaceIntern::pcmReset() {
 	_pcmChanOut = 0;
 	_pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0;
 	_numReservedChannels = 0;
@@ -1124,7 +1318,7 @@ void TownsAudioInterface::pcmReset() {
 	}
 }
 
-int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) {
+int TownsAudioInterfaceIntern::pcmKeyOn(int chan, int note, int velo) {
 	if (chan < 0x40 || chan > 0x47)
 		return 1;
 
@@ -1195,7 +1389,7 @@ int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmKeyOff(int chan) {
+int TownsAudioInterfaceIntern::pcmKeyOff(int chan) {
 	if (chan < 0x40 || chan > 0x47)
 		return 1;
 
@@ -1205,7 +1399,7 @@ int TownsAudioInterface::pcmKeyOff(int chan) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmChanOff(int chan) {
+int TownsAudioInterfaceIntern::pcmChanOff(int chan) {
 	if (chan < 0x40 || chan > 0x47)
 		return 1;
 
@@ -1219,7 +1413,7 @@ int TownsAudioInterface::pcmChanOff(int chan) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmSetPanPos(int chan, int mode) {
+int TownsAudioInterfaceIntern::pcmSetPanPos(int chan, int mode) {
 	if (chan > 0x47)
 		return 1;
 	if (mode & 0x80)
@@ -1242,7 +1436,7 @@ int TownsAudioInterface::pcmSetPanPos(int chan, int mode) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) {
+int TownsAudioInterfaceIntern::pcmSetInstrument(int chan, int instrId) {
 	if (chan > 0x47)
 		return 1;
 	if (instrId > 31)
@@ -1252,7 +1446,7 @@ int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) {
+int TownsAudioInterfaceIntern::pcmLoadInstrument(int instrId, const uint8 *data) {
 	if (instrId > 31)
 		return 3;
 	assert(data);
@@ -1260,7 +1454,7 @@ int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmSetPitch(int chan, int pitch) {
+int TownsAudioInterfaceIntern::pcmSetPitch(int chan, int pitch) {
 	if (chan > 0x47)
 		return 1;
 
@@ -1290,7 +1484,7 @@ int TownsAudioInterface::pcmSetPitch(int chan, int pitch) {
 	return 0;
 }
 
-int TownsAudioInterface::pcmSetLevel(int chan, int lvl) {
+int TownsAudioInterfaceIntern::pcmSetLevel(int chan, int lvl) {
 	if (chan > 0x47)
 		return 1;
 
@@ -1319,7 +1513,7 @@ int TownsAudioInterface::pcmSetLevel(int chan, int lvl) {
 	return 0;
 }
 
-void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) {
+void TownsAudioInterfaceIntern::pcmUpdateEnvelopeGenerator(int chan) {
 	TownsAudio_PcmChannel *p = &_pcmChan[chan];
 	if (!p->envCurrentLevel) {
 		_pcmChanKeyPlaying &= ~_chanFlags[chan];
@@ -1361,7 +1555,7 @@ void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) {
 	p->velo = (p->envCurrentLevel >> 8) << 1;
 }
 
-void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) {
+void TownsAudioInterfaceIntern::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) {
 	int8 diff = p->note - w->baseNote;
 	uint16 r = w->rate + w->rateOffs;
 	uint16 bl = 0;
@@ -1390,7 +1584,7 @@ void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_
 	p->step = (s * p->stepPitch) >> 14;
 }
 
-void TownsAudioInterface::updateOutputVolume() {
+void TownsAudioInterfaceIntern::updateOutputVolume() {
 	// FM Towns seems to support volumes of 0 - 63 for each channel.
 	// We recalculate sane values for our 0 to 255 volume range and
 	// balance values for our -128 to 127 volume range
@@ -1405,30 +1599,34 @@ void TownsAudioInterface::updateOutputVolume() {
 	g_system->getAudioCDManager()->setBalance(balance);
 }
 
-const uint8 TownsAudioInterface::_chanFlags[] = {
+TownsAudioInterfaceIntern *TownsAudioInterfaceIntern::_refInstance = 0;
+
+int TownsAudioInterfaceIntern::_refCount = 0;
+
+const uint8 TownsAudioInterfaceIntern::_chanFlags[] = {
 	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
 };
 
-const uint16 TownsAudioInterface::_frequency[] = {
+const uint16 TownsAudioInterfaceIntern::_frequency[] = {
 	0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0
 };
 
-const uint8 TownsAudioInterface::_carrier[] = {
+const uint8 TownsAudioInterfaceIntern::_carrier[] = {
 	0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0
 };
 
-const uint8 TownsAudioInterface::_fmDefaultInstrument[] = {
+const uint8 TownsAudioInterfaceIntern::_fmDefaultInstrument[] = {
 	0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01,
 	0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08,
 	0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint16 TownsAudioInterface::_pcmPhase1[] =  {
+const uint16 TownsAudioInterfaceIntern::_pcmPhase1[] =  {
 	0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341
 };
 
-const uint16 TownsAudioInterface::_pcmPhase2[] =  {
+const uint16 TownsAudioInterfaceIntern::_pcmPhase2[] =  {
 	0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC
 };
 
@@ -1579,3 +1777,37 @@ void TownsAudio_WaveTable::clear() {
 	data = 0;
 }
 
+TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) {
+	_intf = TownsAudioInterfaceIntern::addNewRef(mixer, driver);
+}
+
+TownsAudioInterface::~TownsAudioInterface() {
+	TownsAudioInterfaceIntern::releaseRef();
+	_intf = 0;
+}
+
+bool TownsAudioInterface::init() {
+	return _intf->init();
+}
+
+int TownsAudioInterface::callback(int command, ...) {
+	va_list args;
+	va_start(args, command);
+
+	int res = _intf->processCommand(command, args);
+
+	va_end(args);
+	return res;
+}
+
+void TownsAudioInterface::setMusicVolume(int volume) {
+	_intf->setMusicVolume(volume);
+}
+
+void TownsAudioInterface::setSoundEffectVolume(int volume) {
+	_intf->setSoundEffectVolume(volume);
+}
+
+void TownsAudioInterface::setSoundEffectChanMask(int mask) {
+	_intf->setSoundEffectChanMask(mask);
+}
\ No newline at end of file
diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.h b/audio/softsynth/fmtowns_pc98/towns_audio.h
index f3d863b..2c58d46 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.h
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.h
@@ -23,7 +23,9 @@
 #ifndef TOWNS_AUDIO_H
 #define TOWNS_AUDIO_H
 
-#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
+#include "audio/mixer.h"
+
+class TownsAudioInterfaceIntern;
 
 class TownsAudioInterfacePluginDriver {
 public:
@@ -31,10 +33,7 @@ public:
 	virtual void timerCallback(int timerId) = 0;
 };
 
-class TownsAudio_PcmChannel;
-class TownsAudio_WaveTable;
-
-class TownsAudioInterface : public TownsPC98_FmSynth {
+class TownsAudioInterface {
 public:
 	TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver);
 	~TownsAudioInterface();
@@ -50,126 +49,7 @@ public:
 	void setSoundEffectChanMask(int mask);
 
 private:
-	void nextTickEx(int32 *buffer, uint32 bufferSize);
-
-	void timerCallbackA();
-	void timerCallbackB();
-
-	typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list &);
-	const TownsAudioIntfCallback *_intfOpcodes;
-
-	int intf_reset(va_list &args);
-	int intf_keyOn(va_list &args);
-	int intf_keyOff(va_list &args);
-	int intf_setPanPos(va_list &args);
-	int intf_setInstrument(va_list &args);
-	int intf_loadInstrument(va_list &args);
-	int intf_setPitch(va_list &args);
-	int intf_setLevel(va_list &args);
-	int intf_chanOff(va_list &args);
-	int intf_writeReg(va_list &args);
-	int intf_writeRegBuffer(va_list &args);
-	int intf_readRegBuffer(va_list &args);
-	int intf_setTimerA(va_list &args);
-	int intf_setTimerB(va_list &args);
-	int intf_enableTimerA(va_list &args);
-	int intf_enableTimerB(va_list &args);
-	int intf_loadSamples(va_list &args);
-	int intf_reserveEffectChannels(va_list &args);
-	int intf_loadWaveTable(va_list &args);
-	int intf_unloadWaveTable(va_list &args);
-	int intf_pcmPlayEffect(va_list &args);
-	int intf_pcmChanOff(va_list &args);
-	int intf_pcmEffectPlaying(va_list &args);
-	int intf_fmKeyOn(va_list &args);
-	int intf_fmKeyOff(va_list &args);
-	int intf_fmSetPanPos(va_list &args);
-	int intf_fmSetInstrument(va_list &args);
-	int intf_fmLoadInstrument(va_list &args);
-	int intf_fmSetPitch(va_list &args);
-	int intf_fmSetLevel(va_list &args);
-	int intf_fmReset(va_list &args);
-	int intf_setOutputVolume(va_list &args);
-	int intf_resetOutputVolume(va_list &args);
-	int intf_updateOutputVolume(va_list &args);
-	int intf_cdaToggle(va_list &args);
-	int intf_pcmUpdateEnvelopeGenerator(va_list &args);
-
-	int intf_notImpl(va_list &args);
-
-	void fmReset();
-	int fmKeyOn(int chan, int note, int velo);
-	int fmKeyOff(int chan);
-	int fmChanOff(int chan);
-	int fmSetPanPos(int chan, int mode);
-	int fmSetInstrument(int chan, int instrId);
-	int fmLoadInstrument(int instrId, const uint8 *data);
-	int fmSetPitch(int chan, int pitch);
-	int fmSetLevel(int chan, int lvl);
-
-	void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value);
-
-	uint8 _fmChanPlaying;
-	uint8 _fmChanNote[6];
-	int16 _fmChanPitch[6];
-
-	uint8 *_fmSaveReg[2];
-	uint8 *_fmInstruments;
-
-	void pcmReset();
-	int pcmKeyOn(int chan, int note, int velo);
-	int pcmKeyOff(int chan);
-	int pcmChanOff(int chan);
-	int pcmSetPanPos(int chan, int mode);
-	int pcmSetInstrument(int chan, int instrId);
-	int pcmLoadInstrument(int instrId, const uint8 *data);
-	int pcmSetPitch(int chan, int pitch);
-	int pcmSetLevel(int chan, int lvl);
-	void pcmUpdateEnvelopeGenerator(int chan);
-
-	TownsAudio_PcmChannel *_pcmChan;
-	uint8 _pcmChanOut;
-	uint8 _pcmChanReserved;
-	uint8 _pcmChanKeyPressed;
-	uint8 _pcmChanEffectPlaying;
-	uint8 _pcmChanKeyPlaying;
-
-	uint8 _pcmChanNote[8];
-	uint8 _pcmChanVelo[8];
-	uint8 _pcmChanLevel[8];
-
-	uint8 _numReservedChannels;
-	uint8 *_pcmInstruments;
-
-	TownsAudio_WaveTable *_waveTables;
-	uint8 _numWaveTables;
-	uint32 _waveTablesTotalDataSize;
-
-	void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w);
-
-	void updateOutputVolume();
-	uint8 _outputVolumeFlags;
-	uint8 _outputLevel[16];
-	uint8 _outputMuteFlags;
-
-	const float _baserate;
-	uint32 _timerBase;
-	uint32 _tickLength;
-	uint32 _timer;
-
-	uint16 _musicVolume;
-	uint16 _sfxVolume;
-	int _pcmSfxChanMask;
-
-	TownsAudioInterfacePluginDriver *_drv;
-	bool _ready;
-
-	static const uint8 _chanFlags[];
-	static const uint16 _frequency[];
-	static const uint8 _carrier[];
-	static const uint8 _fmDefaultInstrument[];
-	static const uint16 _pcmPhase1[];
-	static const uint16 _pcmPhase2[];
+	TownsAudioInterfaceIntern *_intf;
 };
 
 #endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
index bbde75e..3b46aca 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
@@ -26,6 +26,7 @@
 #include "audio/musicplugin.h"
 #include "common/translation.h"
 #include "common/error.h"
+#include "common/system.h"
 
 
 class TownsEmuMusicPlugin : public MusicPluginObject {


Commit: 6845f25f541707786f81dded25485c4ff5c8d62d
    https://github.com/scummvm/scummvm/commit/6845f25f541707786f81dded25485c4ff5c8d62d
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:24:30-07:00

Commit Message:
SCUMM: Adapt code to latest FM-TOWNS audio driver changes

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_midi.h
    engines/scumm/player_towns.cpp
    engines/scumm/player_towns.h
    engines/scumm/scumm.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 658c5a4..cc390a2 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -25,8 +25,8 @@
 #ifndef TOWNS_MIDI_H
 #define TOWNS_MIDI_H
 
-#include "audio/mididrv.h"
 #include "audio/softsynth/fmtowns_pc98/towns_audio.h"
+#include "audio/mididrv.h"
 
 class MidiChannel_TOWNS;
 class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index 2301b2a..a100af7 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -574,16 +574,15 @@ void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackV
 	_cdaCurrentSound = sound;
 }
 
-Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver) : Player_Towns(vm, true), _imuse(imuse), _driver(driver), _imuseDispose(disposeIMuse), _driverDispose(disposeDriver), _sblData(0) {
+Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *imuse, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse), _sblData(0) {
 	_soundOverride = new SoundOvrParameters[_numSoundMax];
 	memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
-	if (_driver)
-		_intf = _driver->intf();
+	_intf = new TownsAudioInterface(mixer, 0);
 }
 
 Player_Towns_v2::~Player_Towns_v2() {
-	if (_driverDispose)
-		delete _driver;
+	delete _intf;
+	_intf = 0;
 
 	if (_imuseDispose)
 		delete _imuse;
diff --git a/engines/scumm/player_towns.h b/engines/scumm/player_towns.h
index 900ea59..470020d 100644
--- a/engines/scumm/player_towns.h
+++ b/engines/scumm/player_towns.h
@@ -142,7 +142,7 @@ private:
 
 class Player_Towns_v2 : public Player_Towns {
 public:
-	Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, MidiDriver_TOWNS *driver, bool disposeIMuse, bool disposeDriver);
+	Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *imuse, bool disposeIMuse);
 	~Player_Towns_v2();
 
 	bool init();
@@ -170,11 +170,9 @@ private:
 	SoundOvrParameters *_soundOverride;
 
 	uint8 *_sblData;
+	
 	IMuse *_imuse;
-	MidiDriver_TOWNS *_driver;
-
 	const bool _imuseDispose;
-	const bool _driverDispose;
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index ff51158..c37ff25 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1828,24 +1828,26 @@ void ScummEngine::setupMusic(int midi) {
 		MidiDriver *nativeMidiDriver = 0;
 		MidiDriver *adlibMidiDriver = 0;
 
-		if (_musicType != MDT_ADLIB)
+		if (_musicType != MDT_ADLIB && _musicType != MDT_TOWNS)
 			nativeMidiDriver = MidiDriver::createMidi(dev);
 		if (nativeMidiDriver != NULL && _native_mt32)
 			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 		bool multi_midi = ConfMan.getBool("multi_midi") && _musicType != MDT_NONE && (midi & MDT_ADLIB);
-		if (_musicType == MDT_ADLIB || (multi_midi && _musicType != MDT_TOWNS)) {
+		if (_musicType == MDT_ADLIB || multi_midi) {
 			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB));
 			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
 		}
+		if (_musicType == MDT_TOWNS) {
+			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_TOWNS));
+			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
+		}
 
 		_imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver);
 		
 		if (_game.platform == Common::kPlatformFMTowns) {
-			MidiDriver *townsDriver = 0;
-			townsDriver = (_musicType == MDT_TOWNS) ? nativeMidiDriver : MidiDriver::createMidi(MidiDriver::detectDevice(MDT_TOWNS));
-			_musicEngine = _townsPlayer = new Player_Towns_v2(this, _imuse, _mixer, (MidiDriver_TOWNS*)townsDriver, true, (_musicType != MDT_TOWNS));
+			_musicEngine = _townsPlayer = new Player_Towns_v2(this, _mixer, _imuse, true);
 			if (!_townsPlayer->init())
-				error("Failed to initialize FM-Towns audio driver");
+				error("ScummEngine::setupMusic(): Failed to initialize FM-Towns audio driver");
 		} else {
 			_musicEngine = _imuse;
 		}
@@ -1857,7 +1859,6 @@ void ScummEngine::setupMusic(int midi) {
 			_imuse->property(IMuse::PROP_GAME_ID, _game.id);
 			if (ConfMan.hasKey("tempo"))
 				_imuse->property(IMuse::PROP_TEMPO_BASE, ConfMan.getInt("tempo"));
-			// YM2162 driver can't handle midi->getPercussionChannel(), NULL shouldn't init MT-32/GM/GS
 			if (midi != MDT_NONE) {
 				_imuse->property(IMuse::PROP_NATIVE_MT32, _native_mt32);
 				if (MidiDriver::getMusicType(dev) != MT_MT32) // MT-32 Emulation shouldn't be GM/GS initialized


Commit: 2f9c5de7bedfc02c7b5a99da471dafa518a78379
    https://github.com/scummvm/scummvm/commit/2f9c5de7bedfc02c7b5a99da471dafa518a78379
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:24:30-07:00

Commit Message:
FM-TOWNS AUDIO: Implement some midi driver functions

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index c223d44..737e977 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -25,13 +25,62 @@
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 #include "common/textconsole.h"
 
-class MidiChannel_TOWNS : public MidiChannel {
+class TownsMidiOutputChannel {
+friend class TownsMidiInputChannel;
 public:
-	MidiChannel_TOWNS(MidiDriver_TOWNS *driver);
-	~MidiChannel_TOWNS();
+	TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanId);
+	~TownsMidiOutputChannel();
+
+	void noteOn(uint8 msb, uint16 lsb);
+	void noteOnAdjust(uint8 msb, uint16 lsb);
+	void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2);
+	
+	void connect(TownsMidiInputChannel *chan);
+	void disconnect();
+
+	enum CheckPriorityStatus {
+		kDisconnected = -3,
+		kHighPriority = -2
+	};
+
+	int checkPriority(int pri);
+
+private:
+	void keyOn();
+	void keyOff();
+	void internKeyOnFrq(uint16 frq);
+	void out(uint8 chan, uint8 reg, uint8 val);
+
+	TownsMidiInputChannel *_midi;
+	TownsMidiOutputChannel *_prev;
+	TownsMidiOutputChannel *_next;
+	uint8 _fld_f;
+	uint8 _note;
+	uint8 _tl;
+	uint8 _noteOffMarker;
+	uint8 _fld_12;
+	uint8 _fld_13;
+	uint8 _prg;
+	uint8 _chan;
+
+	uint16 _freq;
+	int16 _freqAdjust;
+
+	MidiDriver_TOWNS *_driver;
+
+	static const uint8 _freqMSB[];
+	static const uint16 _freqLSB[];
+};
+
+class TownsMidiInputChannel : public MidiChannel {
+friend class TownsMidiOutputChannel;
+public:
+	TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex);
+	~TownsMidiInputChannel();
 
 	MidiDriver *device() { return _driver; }
-	byte getNumber() { return 0; }
+	byte getNumber() { return _chanIndex; }
+	bool allocate();
 	void release();
 
 	void send(uint32 b);
@@ -43,71 +92,247 @@ public:
 	void controlChange(byte control, byte value);
 	void pitchBendFactor(byte value);
 	void priority(byte value);
-
 	void sysEx_customInstrument(uint32 type, const byte *instr);
 
 private:
+	TownsMidiOutputChannel *_outChan;
+	//TownsMidiInputChannel *_prev;
+	//TownsMidiInputChannel *_next;
+	
+	uint8 *_instrument;
+	uint8 _prg;
+	uint8 _chanIndex;
+	uint8 _effectLevel;
+	uint8 _priority;
+	uint8 _vol;
+	uint8 _volEff;
+	uint8 _pan;
+	uint8 _panEff;
+	uint8 _perc;
+	uint8 _percS;
+	uint8 _fld_22;
+	uint8 _pitchBendFactor;
+
+	bool _allocated;
+
 	MidiDriver_TOWNS *_driver;
 };
 
-MidiChannel_TOWNS::MidiChannel_TOWNS(MidiDriver_TOWNS *driver) : MidiChannel(), _driver(driver) {
+TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
+	_midi(0), _prev(0), _next(0), _fld_f(0), _note(0), _tl(0), _noteOffMarker(0), _fld_12(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+}
 
+TownsMidiOutputChannel::~TownsMidiOutputChannel() {
 }
 
-MidiChannel_TOWNS::~MidiChannel_TOWNS() {
+void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
+	_freq = (msb << 7) + lsb;
+	_freqAdjust = 0;
+	internKeyOnFrq(_freq);
+}
 
+void TownsMidiOutputChannel::noteOnAdjust(uint8 msb, uint16 lsb) {
+	_freq = (msb << 7) + lsb;
+	internKeyOnFrq(_freq + _freqAdjust);
 }
 
-void MidiChannel_TOWNS::release() {
+void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 vol2) {
+	const uint8 *pos = data;
 
 }
 
-void MidiChannel_TOWNS::send(uint32 b) {
+void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
+	if (!chan)
+		return;
+	_midi = chan;
+	_next = chan->_outChan;
+	_prev = 0;
+	chan->_outChan = this;
+	if (_next)
+		_next->_prev = this;
+}
 
+void TownsMidiOutputChannel::disconnect() {
+	keyOff();
+	TownsMidiOutputChannel *p = _prev;
+	TownsMidiOutputChannel *n = _next;
+
+	if (n)
+		n->_prev = p;
+	if (p)
+		p->_next = n;
+	else
+		_midi->_outChan = n;
+	_midi = 0;
 }
 
-void MidiChannel_TOWNS::noteOff(byte note) {
+int TownsMidiOutputChannel::checkPriority(int pri) {
+	if (!_midi)
+		return kDisconnected;
+
+	if (!_next && pri >= _midi->_priority)
+		return _midi->_priority;
 
+	return kHighPriority;
 }
 
-void MidiChannel_TOWNS::noteOn(byte note, byte velocity) {
+void TownsMidiOutputChannel::keyOn() {
+	out(_chan, 0x28, 0xf0/*0x30*/ /*???*/);
+}
+
+void TownsMidiOutputChannel::keyOff() {
+	out(_chan, 0x28, 0);
+}
 
+void TownsMidiOutputChannel::internKeyOnFrq(uint16 frq) {
+	uint8 t = (frq << 1) >> 8;	
+	frq = (_freqMSB[t] << 3) | _freqLSB[t] ;
+	out(_chan, 0xa4, frq >> 8);
+	out(_chan, 0xa0, frq & 0xff);
+	out(_chan, 0x28, 0);
+	out(_chan, 0x28, 0xf0/*0x30*/ /*???*/);
 }
 
-void MidiChannel_TOWNS::programChange(byte program) {
+void TownsMidiOutputChannel::out(uint8 chan, uint8 reg, uint8 val) {
+	static const uint8 chanRegOffs[] = { 0, 1, 2, 0, 1, 2 };
+	static const uint8 keyValOffs[] = { 0, 1, 2, 4, 5, 6 };
 
+	if (reg == 0x28)
+		val = (val & 0xf0) | keyValOffs[chan];
+	if (reg < 0x30)
+		_driver->_intf->callback(19, 0, reg, val);
+	else
+		_driver->_intf->callback(19, chan / 3, (reg & ~3) | chanRegOffs[chan], val);
 }
 
-void MidiChannel_TOWNS::pitchBend(int16 bend) {
+const uint8 TownsMidiOutputChannel::_freqMSB[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+	0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+	0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+	0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+	0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+	0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+	0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x80, 0x81, 0x83, 0x85,
+	0x87, 0x88, 0x8A, 0x8C, 0x8E, 0x8F, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A,
+	0x9C, 0x9E, 0x9F, 0xA1, 0xA3, 0xA5, 0xA6, 0xA8, 0xAA, 0xAC, 0xAD, 0xAF,
+	0xB1, 0xB3, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBD, 0xBF, 0xC1, 0xC3, 0xC4,
+	0xC6, 0xC8, 0xCA, 0xCB, 0xCD, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA,
+	0xDB, 0xDD, 0xDF, 0xE1, 0xE2, 0xE4, 0xE6, 0xE8, 0xE9, 0xEB, 0xED, 0xEF
+};
 
+const uint16 TownsMidiOutputChannel::_freqLSB[] = {
+	0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6,
+	0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x0301, 0x032F,
+	0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E,
+	0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403,
+	0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F,
+	0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E,
+	0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403,
+	0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F,
+	0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E,
+	0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403,
+	0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F,
+	0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E,
+	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B,
+	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B,
+	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B,
+	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B
+};
+
+TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _outChan(0), _prg(0), _chanIndex(chanIndex),
+	_effectLevel(0), _priority(0), _vol(0), _volEff(0), _pan(0), _panEff(0), _perc(0), _percS(0), _pitchBendFactor(0), _fld_22(0), _allocated(false) {
+	_instrument = new uint8[30];
+	memset(_instrument, 0, 30);
 }
 
-void MidiChannel_TOWNS::controlChange(byte control, byte value) {
+TownsMidiInputChannel::~TownsMidiInputChannel() {
+	delete _instrument;
+}
 
+bool TownsMidiInputChannel::allocate() {
+	if (_allocated)
+		return false;
+	_allocated = true;
+	return true;
 }
 
-void MidiChannel_TOWNS::pitchBendFactor(byte value) {
+void TownsMidiInputChannel::release() {
+	_allocated = false;
+}
 
+void TownsMidiInputChannel::send(uint32 b) {
+	_driver->send(b | _chanIndex);
 }
 
-void MidiChannel_TOWNS::priority(byte value) {
+void TownsMidiInputChannel::noteOff(byte note) {
+	if (!_outChan)
+		return;
 
+	if (_outChan->_note != note)
+		return;
+
+	if (_fld_22)
+		_outChan->_noteOffMarker = 1;
+	else
+		_outChan->disconnect();
+}
+
+void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
+	TownsMidiOutputChannel *oc = _driver->allocateOutputChannel(_priority);
+	
+	if (!oc)
+		return;
+
+	oc->connect(this);
+
+	
+	int vol1 = 0;
+	int vol2 = 0;
+	oc->setupProgram(_instrument, vol1, vol2);
+	//oc->noteOn(m, l);
+	
 }
 
-void MidiChannel_TOWNS::sysEx_customInstrument(uint32 type, const byte *instr) {
+void TownsMidiInputChannel::programChange(byte program) {
 
 }
 
+void TownsMidiInputChannel::pitchBend(int16 bend) {
+
+}
+
+void TownsMidiInputChannel::controlChange(byte control, byte value) {
+
+}
+
+void TownsMidiInputChannel::pitchBendFactor(byte value) {
+
+}
+
+void TownsMidiInputChannel::priority(byte value) {
+	_priority = value;
+}
+
+void TownsMidiInputChannel::sysEx_customInstrument(uint32 type, const byte *instr) {
+	memcpy(_instrument, instr, 30);
+}
+
 MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timerBpara(0), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
-	_channels = new MidiChannel_TOWNS*[16];
-	for (int i = 0; i < 16; i++)
-		_channels[i] = new MidiChannel_TOWNS(this);
+
+	_channels = new TownsMidiInputChannel*[32];
+	for (int i = 0; i < 32; i++)
+		_channels[i] = new TownsMidiInputChannel(this, i);
+	_out = new TownsMidiOutputChannel*[6];
+	for (int i = 0; i < 6; i++)
+		_out[i] = new TownsMidiOutputChannel(this, i);
 
 	_tickCounter = 0;
 	_curChan = 0;
-	//unbuffered write:	_intf->callback(17, part, reg, val);
-	//buffered write:	_intf->callback(19, part, reg, val);
 }
 
 MidiDriver_TOWNS::~MidiDriver_TOWNS() {
@@ -115,9 +340,12 @@ MidiDriver_TOWNS::~MidiDriver_TOWNS() {
 	delete _intf;
 	setTimerCallback(0, 0);
 
-	for (int i = 0; i < 16; i++)
+	for (int i = 0; i < 32; i++)
 		delete _channels[i];
 	delete[] _channels;
+	for (int i = 0; i < 6; i++)
+		delete _out[i];
+	delete[] _out;
 }
 
 int MidiDriver_TOWNS::open() {
@@ -154,14 +382,13 @@ void MidiDriver_TOWNS::send(uint32 b) {
 	if (chan == 9)
 		part = &_percussion;
 	else**/
-	MidiChannel_TOWNS *c = _channels[b & 0x0F];
+	TownsMidiInputChannel *c = _channels[b & 0x0F];
 
 	switch (cmd) {
 	case 0x80:
-		//part->noteOff(param1);
+		c->noteOff(param1);
 		break;
 	case 0x90:
-		//part->noteOn(param1, param2);
 		if (param2)
 			c->noteOn(param1, param2);
 		else
@@ -179,7 +406,7 @@ void MidiDriver_TOWNS::send(uint32 b) {
 		c->pitchBend((param1 | (param2 << 7)) - 0x2000);
 		break;
 	case 0xF0:
-		warning("MidiDriver_ADLIB: Receiving SysEx command on a send() call");
+		warning("MidiDriver_TOWNS: Receiving SysEx command on a send() call");
 		break;
 
 	default:
@@ -193,25 +420,17 @@ void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager:
 }
 
 uint32 MidiDriver_TOWNS::getBaseTempo() {
-	return 0;
+	return 4167;
 }
 
 MidiChannel *MidiDriver_TOWNS::allocateChannel() {
-	MidiChannel *res = 0;
-
-	for (int i = 0; i < 6; i++) {
-		if (++_curChan == 6)
-			_curChan = 0;
-
-		//if (_channels[i]->   //// )
-		//	return _channels[i];
-
+	for (int i = 0; i < 32; ++i) {		
+		TownsMidiInputChannel *chan = _channels[i];
+		if (chan->allocate())
+			return chan;
 	}
 
-	//if (res)
-	//	res->noteOff();
-
-	return res;
+	return 0;
 }
 
 MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
@@ -237,3 +456,26 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
 		break;
 	}
 }
+
+TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
+	TownsMidiOutputChannel *res = 0;
+
+	for (int i = 0; i < 6; i++) {
+		if (++_curChan == 6)
+			_curChan = 0;
+
+		int s = _out[i]->checkPriority(pri);
+		if (s == TownsMidiOutputChannel::kDisconnected)
+			return _out[i];
+
+		if (s != TownsMidiOutputChannel::kHighPriority) {
+			pri = s;
+			res = _out[i];
+		}
+	}
+	
+	if (res)
+		res->disconnect();
+
+	return res;
+}
\ No newline at end of file
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index cc390a2..1151429 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -28,9 +28,12 @@
 #include "audio/softsynth/fmtowns_pc98/towns_audio.h"
 #include "audio/mididrv.h"
 
-class MidiChannel_TOWNS;
+class TownsMidiOutputChannel;
+class TownsMidiInputChannel;
+
 class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
-friend class MidiChannel_TOWNS;
+friend class TownsMidiInputChannel;
+friend class TownsMidiOutputChannel;
 public:
 	MidiDriver_TOWNS(Audio::Mixer *mixer);
 	~MidiDriver_TOWNS();
@@ -53,7 +56,10 @@ public:
 	TownsAudioInterface *intf() { return _intf; }
 	
 private:
-	MidiChannel_TOWNS **_channels;
+	TownsMidiOutputChannel *allocateOutputChannel(int pri);
+
+	TownsMidiInputChannel **_channels;
+	TownsMidiOutputChannel **_out;	
 
 	Common::TimerManager::TimerProc _timerBproc;
 	void *_timerBpara;


Commit: d4325a0411f2f6c86a117543a4dcbf588ac84fe7
    https://github.com/scummvm/scummvm/commit/d4325a0411f2f6c86a117543a4dcbf588ac84fe7
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:32:53-07:00

Commit Message:
FM-TOWNS AUDIO: Implement some more midi driver code

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 737e977..86ff7e2 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -34,6 +34,7 @@ public:
 	void noteOn(uint8 msb, uint16 lsb);
 	void noteOnAdjust(uint8 msb, uint16 lsb);
 	void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2);
+	void noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr);
 	
 	void connect(TownsMidiInputChannel *chan);
 	void disconnect();
@@ -49,25 +50,45 @@ private:
 	void keyOn();
 	void keyOff();
 	void internKeyOnFrq(uint16 frq);
-	void out(uint8 chan, uint8 reg, uint8 val);
+	void out(uint8 reg, uint8 val);
 
 	TownsMidiInputChannel *_midi;
 	TownsMidiOutputChannel *_prev;
 	TownsMidiOutputChannel *_next;
-	uint8 _fld_f;
+	uint8 _fld_c;
+	uint8 _chan;
 	uint8 _note;
-	uint8 _tl;
+	uint8 _tl2;
+	uint8 _tl1;
 	uint8 _noteOffMarker;
-	uint8 _fld_12;
+	uint32 _duration;
 	uint8 _fld_13;
-	uint8 _prg;
-	uint8 _chan;
+	uint8 _prg;	
 
 	uint16 _freq;
 	int16 _freqAdjust;
 
+	struct StateA {
+		uint8 a[50];
+	} *_stateA;
+
+	struct StateB {
+		uint8 b1;
+		uint8 b2;
+		uint8 b3;
+		uint8 b4;
+		uint8 b5;
+		uint8 b6;
+		uint8 b7;
+		uint8 b8;
+		uint8 b9;
+		uint8 b10;
+		uint8 b11;
+	} *_stateB;
+
 	MidiDriver_TOWNS *_driver;
 
+	static const uint8 _chanMap[];
 	static const uint8 _freqMSB[];
 	static const uint16 _freqLSB[];
 };
@@ -105,24 +126,33 @@ private:
 	uint8 _effectLevel;
 	uint8 _priority;
 	uint8 _vol;
-	uint8 _volEff;
+	uint8 _tl;
 	uint8 _pan;
 	uint8 _panEff;
-	uint8 _perc;
+	int8 _transpose;
 	uint8 _percS;
 	uint8 _fld_22;
 	uint8 _pitchBendFactor;
+	uint16 _freqLSB;
 
 	bool _allocated;
 
 	MidiDriver_TOWNS *_driver;
+
+	static const uint8 _programAdjustLevel[];
 };
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_midi(0), _prev(0), _next(0), _fld_f(0), _note(0), _tl(0), _noteOffMarker(0), _fld_12(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+	_midi(0), _prev(0), _next(0), _fld_c(0), _tl2(0), _note(0), _tl1(0), _noteOffMarker(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+	_stateA = new StateA[2];
+	memset(_stateA, 0, 2 * sizeof(StateA));
+	_stateB = new StateB[2];
+	memset(_stateB, 0, 2 * sizeof(StateB));
 }
 
 TownsMidiOutputChannel::~TownsMidiOutputChannel() {
+	delete[] _stateA;
+	delete[] _stateB;
 }
 
 void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
@@ -137,8 +167,54 @@ void TownsMidiOutputChannel::noteOnAdjust(uint8 msb, uint16 lsb) {
 }
 
 void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 vol2) {
+	static const uint8 mul[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 };
 	const uint8 *pos = data;
+	uint8 chan = _chanMap[_chan];	
+	
+	uint8 mulAmsFms1 = _driver->_chanState[chan].mulAmsFms = *pos++;
+	uint8 tl1 = _driver->_chanState[chan].tl = (*pos++ | 0x3f) - vol1;
+	uint8 attDec1 = _driver->_chanState[chan].attDec = !(*pos++);
+	uint8 sus1 = _driver->_chanState[chan].sus = !(*pos++);
+	uint8 unk1 = _driver->_chanState[chan].unk = *pos++;
+	chan += 3;
+
+	out(0x30, mul[mulAmsFms1 & 0x0f]);
+	out(0x40, (tl1 & 0x3f) + 15);
+	out(0x50, ((attDec1 >> 4) << 1) | ((attDec1 >> 4) & 1));
+	out(0x60, ((attDec1 << 1) | (attDec1 & 1)) & 0x1f);
+	out(0x70, (mulAmsFms1 & 0x20) ^ 0x20 ? ((sus1 & 0x0f) << 1) | 1: 0);
+	out(0x80, sus1);
+
+	uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = *pos++;
+	uint8 tl2 = _driver->_chanState[chan].tl = (*pos++ | 0x3f) - vol2;
+	uint8 attDec2 = _driver->_chanState[chan].attDec = !(*pos++);
+	uint8 sus2 = _driver->_chanState[chan].sus = !(*pos++);
+	uint8 unk2 = _driver->_chanState[chan].unk = *pos++;
+
+	uint8 mul2 = mul[mulAmsFms2 & 0x0f];
+	tl2 = (tl2 & 0x3f) + 15;
+	uint8 ar2 = ((attDec2 >> 4) << 1) | ((attDec2 >> 4) & 1);
+	uint8 dec2 = ((attDec2 << 1) | (attDec2 & 1)) & 0x1f;
+	uint8 sus2r = (mulAmsFms2 & 0x20) ^ 0x20 ? ((sus2 & 0x0f) << 1) | 1: 0;
+
+	for (int i = 4; i < 16; i += 4) {
+		out(0x30 + i, mul2);
+		out(0x40 + i, tl2);
+		out(0x50 + i, ar2);
+		out(0x60 + i, dec2);
+		out(0x70 + i, sus2r);
+		out(0x80 + i, sus2);
+	}
+
+	uint8 t = _driver->_chanState[chan /*_chan*/ /*???*/].fgAlg = *pos;
+	out(0xb0, ((t & 0x0e) << 2) | (((t & 1) << 1) + 5));
+	t = mulAmsFms1 | mulAmsFms2;
+	out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5));
+}
 
+void TownsMidiOutputChannel::noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr) {
+	StateA *a = &_stateA[index];
+	StateB *b = &_stateB[index];
 }
 
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
@@ -177,34 +253,38 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 }
 
 void TownsMidiOutputChannel::keyOn() {
-	out(_chan, 0x28, 0xf0/*0x30*/ /*???*/);
+	out(0x28, 0xf0/*0x30*/ /*???*/);
 }
 
 void TownsMidiOutputChannel::keyOff() {
-	out(_chan, 0x28, 0);
+	out(0x28, 0);
 }
 
 void TownsMidiOutputChannel::internKeyOnFrq(uint16 frq) {
 	uint8 t = (frq << 1) >> 8;	
 	frq = (_freqMSB[t] << 3) | _freqLSB[t] ;
-	out(_chan, 0xa4, frq >> 8);
-	out(_chan, 0xa0, frq & 0xff);
-	out(_chan, 0x28, 0);
-	out(_chan, 0x28, 0xf0/*0x30*/ /*???*/);
+	out(0xa4, frq >> 8);
+	out(0xa0, frq & 0xff);
+	out(0x28, 0);
+	out(0x28, 0xf0/*0x30*/ /*???*/);
 }
 
-void TownsMidiOutputChannel::out(uint8 chan, uint8 reg, uint8 val) {
+void TownsMidiOutputChannel::out(uint8 reg, uint8 val) {
 	static const uint8 chanRegOffs[] = { 0, 1, 2, 0, 1, 2 };
 	static const uint8 keyValOffs[] = { 0, 1, 2, 4, 5, 6 };
 
 	if (reg == 0x28)
-		val = (val & 0xf0) | keyValOffs[chan];
+		val = (val & 0xf0) | keyValOffs[_chan];
 	if (reg < 0x30)
-		_driver->_intf->callback(19, 0, reg, val);
+		_driver->_intf->callback(17, 0, reg, val);
 	else
-		_driver->_intf->callback(19, chan / 3, (reg & ~3) | chanRegOffs[chan], val);
+		_driver->_intf->callback(17, _chan / 3, (reg & ~3) | chanRegOffs[_chan], val);
 }
 
+const uint8 TownsMidiOutputChannel::_chanMap[] = {
+	0, 1, 2, 8, 9, 10
+};
+
 const uint8 TownsMidiOutputChannel::_freqMSB[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -244,7 +324,7 @@ const uint16 TownsMidiOutputChannel::_freqLSB[] = {
 };
 
 TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _outChan(0), _prg(0), _chanIndex(chanIndex),
-	_effectLevel(0), _priority(0), _vol(0), _volEff(0), _pan(0), _panEff(0), _perc(0), _percS(0), _pitchBendFactor(0), _fld_22(0), _allocated(false) {
+	_effectLevel(0), _priority(0), _vol(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _fld_22(0), _freqLSB(0), _allocated(false) {
 	_instrument = new uint8[30];
 	memset(_instrument, 0, 30);
 }
@@ -289,12 +369,31 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 
 	oc->connect(this);
 
+	oc->_fld_c = _instrument[10] & 1;
+	oc->_note = note;
+	oc->_noteOffMarker = 0;
+	oc->_duration = _instrument[29] * 72;
 	
-	int vol1 = 0;
-	int vol2 = 0;
-	oc->setupProgram(_instrument, vol1, vol2);
-	//oc->noteOn(m, l);
-	
+	oc->_tl1 = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+	if (oc->_tl1 > 63)
+		oc->_tl1 = 63;
+
+	oc->_tl2 = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+	if (oc->_tl2 > 63)
+		oc->_tl2 = 63;
+
+	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl1 << 5)]] : oc->_tl1, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl2 << 5)]]);
+	oc->noteOn(note + _transpose, _freqLSB);
+
+	if (_instrument[11] & 0x80)
+		oc->noteOnSubSubSub_s1(0, _instrument[11], &_instrument[12]);
+	else
+		oc->_stateA[0].a[0] = 0;
+
+	if (_instrument[20] & 0x80)
+		oc->noteOnSubSubSub_s1(1, _instrument[20], &_instrument[21]);
+	else
+		oc->_stateA[1].a[0] = 0;	
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
@@ -321,16 +420,39 @@ void TownsMidiInputChannel::sysEx_customInstrument(uint32 type, const byte *inst
 	memcpy(_instrument, instr, 30);
 }
 
+const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
+	0x00, 0x04, 0x07, 0x0B, 0x0D, 0x10, 0x12, 0x14,
+	0x16, 0x18, 0x1A, 0x1B, 0x1D, 0x1E, 0x1F, 0x21,
+	0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+	0x2A, 0x2B, 0x2C, 0x2C, 0x2D, 0x2E, 0x2F, 0x2F,
+	0x30, 0x31, 0x31, 0x32, 0x33, 0x33, 0x34, 0x35,
+	0x35, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39,
+	0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C,
+	0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
+};
+
 MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timerBpara(0), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
 
 	_channels = new TownsMidiInputChannel*[32];
 	for (int i = 0; i < 32; i++)
 		_channels[i] = new TownsMidiInputChannel(this, i);
+	
 	_out = new TownsMidiOutputChannel*[6];
 	for (int i = 0; i < 6; i++)
 		_out[i] = new TownsMidiOutputChannel(this, i);
 
+	_chanState = new ChanState[32];
+	memset(_chanState, 0, 32 * sizeof(ChanState));
+
+	_chanOutputLevel = new uint8[2048];
+	for (int i = 0; i < 64; i++) {
+		for (int ii = 0; ii < 32; ii++)
+			_chanOutputLevel[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
+	}
+	for (int i = 0; i < 64; i++)
+		_chanOutputLevel[i << 5] = 0;
+
 	_tickCounter = 0;
 	_curChan = 0;
 }
@@ -343,9 +465,13 @@ MidiDriver_TOWNS::~MidiDriver_TOWNS() {
 	for (int i = 0; i < 32; i++)
 		delete _channels[i];
 	delete[] _channels;
+
 	for (int i = 0; i < 6; i++)
 		delete _out[i];
 	delete[] _out;
+
+	delete[] _chanState;
+	delete[] _chanOutputLevel;
 }
 
 int MidiDriver_TOWNS::open() {
@@ -478,4 +604,4 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 		res->disconnect();
 
 	return res;
-}
\ No newline at end of file
+}
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 1151429..6ff8a99 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -61,6 +61,15 @@ private:
 	TownsMidiInputChannel **_channels;
 	TownsMidiOutputChannel **_out;	
 
+	struct ChanState {
+		uint8 mulAmsFms;
+		uint8 tl;
+		uint8 attDec;
+		uint8 sus;
+		uint8 fgAlg;
+		uint8 unk;
+	} *_chanState;
+
 	Common::TimerManager::TimerProc _timerBproc;
 	void *_timerBpara;
 
@@ -70,6 +79,8 @@ private:
 	uint8 _curChan;
 	
 	bool _open;
+
+	uint8 *_chanOutputLevel;
 };
 
 #endif


Commit: 8fe9e89c6c7c0b232b492fc9fe771e882d442718
    https://github.com/scummvm/scummvm/commit/8fe9e89c6c7c0b232b492fc9fe771e882d442718
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:33:03-07:00

Commit Message:
FM-TOWNS AUDIO: Some more midi driver code

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 86ff7e2..1eb9f13 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -49,7 +49,7 @@ public:
 private:
 	void keyOn();
 	void keyOff();
-	void internKeyOnFrq(uint16 frq);
+	void internKeySetFreq(uint16 frq);
 	void out(uint8 reg, uint8 val);
 
 	TownsMidiInputChannel *_midi;
@@ -158,24 +158,29 @@ TownsMidiOutputChannel::~TownsMidiOutputChannel() {
 void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
 	_freq = (msb << 7) + lsb;
 	_freqAdjust = 0;
-	internKeyOnFrq(_freq);
+	internKeySetFreq(_freq);
 }
 
 void TownsMidiOutputChannel::noteOnAdjust(uint8 msb, uint16 lsb) {
 	_freq = (msb << 7) + lsb;
-	internKeyOnFrq(_freq + _freqAdjust);
+	internKeySetFreq(_freq + _freqAdjust);
 }
 
 void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 vol2) {
+	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
+	// since it is just a modified AdLib driver. It also uses AdLib programs.
+	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
+	// music being so bad compared to AdLib (unsuitable data is just forced into the
+	// wrong audio device).
+
 	static const uint8 mul[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 };
-	const uint8 *pos = data;
 	uint8 chan = _chanMap[_chan];	
-	
-	uint8 mulAmsFms1 = _driver->_chanState[chan].mulAmsFms = *pos++;
-	uint8 tl1 = _driver->_chanState[chan].tl = (*pos++ | 0x3f) - vol1;
-	uint8 attDec1 = _driver->_chanState[chan].attDec = !(*pos++);
-	uint8 sus1 = _driver->_chanState[chan].sus = !(*pos++);
-	uint8 unk1 = _driver->_chanState[chan].unk = *pos++;
+
+	uint8 mulAmsFms1 = _driver->_chanState[chan].mulAmsFms = data[0];
+	uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - vol1;
+	uint8 attDec1 = _driver->_chanState[chan].attDec = ~data[2];
+	uint8 sus1 = _driver->_chanState[chan].sus = ~data[3];
+	uint8 unk1 = _driver->_chanState[chan].unk = data[4];
 	chan += 3;
 
 	out(0x30, mul[mulAmsFms1 & 0x0f]);
@@ -185,11 +190,11 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	out(0x70, (mulAmsFms1 & 0x20) ^ 0x20 ? ((sus1 & 0x0f) << 1) | 1: 0);
 	out(0x80, sus1);
 
-	uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = *pos++;
-	uint8 tl2 = _driver->_chanState[chan].tl = (*pos++ | 0x3f) - vol2;
-	uint8 attDec2 = _driver->_chanState[chan].attDec = !(*pos++);
-	uint8 sus2 = _driver->_chanState[chan].sus = !(*pos++);
-	uint8 unk2 = _driver->_chanState[chan].unk = *pos++;
+	uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = data[5];
+	uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - vol2;
+	uint8 attDec2 = _driver->_chanState[chan].attDec = ~data[7];
+	uint8 sus2 = _driver->_chanState[chan].sus = ~data[8];
+	uint8 unk2 = _driver->_chanState[chan].unk = data[9];
 
 	uint8 mul2 = mul[mulAmsFms2 & 0x0f];
 	tl2 = (tl2 & 0x3f) + 15;
@@ -206,9 +211,11 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 		out(0x80 + i, sus2);
 	}
 
-	uint8 t = _driver->_chanState[chan /*_chan*/ /*???*/].fgAlg = *pos;
-	out(0xb0, ((t & 0x0e) << 2) | (((t & 1) << 1) + 5));
-	t = mulAmsFms1 | mulAmsFms2;
+	_driver->_chanState[chan].fgAlg = data[10];
+	uint8 alg = 5 + 2 * (data[10] & 1);
+	uint8 fb = 4 * (data[10] & 0x0e);
+	out(0xb0, fb | alg);
+	uint8 t = mulAmsFms1 | mulAmsFms2;
 	out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5));
 }
 
@@ -253,20 +260,30 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 }
 
 void TownsMidiOutputChannel::keyOn() {
-	out(0x28, 0xf0/*0x30*/ /*???*/);
+	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
+	// since it is just a modified AdLib driver. It also uses AdLib programs.
+	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
+	// music being so bad compared to AdLib (unsuitable data is just forced into the
+	// wrong audio device).
+	out(0x28, 0x30);
 }
 
 void TownsMidiOutputChannel::keyOff() {
 	out(0x28, 0);
 }
 
-void TownsMidiOutputChannel::internKeyOnFrq(uint16 frq) {
+void TownsMidiOutputChannel::internKeySetFreq(uint16 frq) {
 	uint8 t = (frq << 1) >> 8;	
-	frq = (_freqMSB[t] << 3) | _freqLSB[t] ;
+	frq = (_freqMSB[t] << 11) | _freqLSB[t] ;
 	out(0xa4, frq >> 8);
 	out(0xa0, frq & 0xff);
 	out(0x28, 0);
-	out(0x28, 0xf0/*0x30*/ /*???*/);
+	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
+	// since it is just a modified AdLib driver. It also uses AdLib programs.
+	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
+	// music being so bad compared to AdLib (unsuitable data is just forced into the
+	// wrong audio device).
+	out(0x28, 0x30);
 }
 
 void TownsMidiOutputChannel::out(uint8 reg, uint8 val) {
@@ -574,7 +591,7 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
 			_tickCounter += 10000;
 			while (_tickCounter >= 4167) {
 				_tickCounter -= 4167;
-				//_timerBproc(_timerBpara);
+				_timerBproc(_timerBpara);
 			}
 		}
 		break;


Commit: 25814e64ac091e70c1a5419c57184acb7dd05e8a
    https://github.com/scummvm/scummvm/commit/25814e64ac091e70c1a5419c57184acb7dd05e8a
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:33:03-07:00

Commit Message:
FM-TOWNS AUDIO: Implement some midi commands

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 1eb9f13..81f561a 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -32,9 +32,10 @@ public:
 	~TownsMidiOutputChannel();
 
 	void noteOn(uint8 msb, uint16 lsb);
-	void noteOnAdjust(uint8 msb, uint16 lsb);
+	void noteOnPitchBend(uint8 msb, uint16 lsb);
 	void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2);
 	void noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr);
+	void setModWheel(uint8 value);
 	
 	void connect(TownsMidiInputChannel *chan);
 	void disconnect();
@@ -60,7 +61,7 @@ private:
 	uint8 _note;
 	uint8 _tl2;
 	uint8 _tl1;
-	uint8 _noteOffMarker;
+	uint8 _sustainNoteOff;
 	uint32 _duration;
 	uint8 _fld_13;
 	uint8 _prg;	
@@ -69,7 +70,9 @@ private:
 	int16 _freqAdjust;
 
 	struct StateA {
-		uint8 a[50];
+		uint8 active;
+		uint8 a[48];
+		uint8 modWheel;
 	} *_stateA;
 
 	struct StateB {
@@ -78,7 +81,7 @@ private:
 		uint8 b3;
 		uint8 b4;
 		uint8 b5;
-		uint8 b6;
+		uint8 mwu;
 		uint8 b7;
 		uint8 b8;
 		uint8 b9;
@@ -113,9 +116,15 @@ public:
 	void controlChange(byte control, byte value);
 	void pitchBendFactor(byte value);
 	void priority(byte value);
-	void sysEx_customInstrument(uint32 type, const byte *instr);
+	void sysEx_customInstrument(uint32 type, const byte *instr);	
 
 private:
+	void controlModulationWheel(byte value);
+	void controlVolume(byte value);
+	void controlPanPos(byte value);
+	void controlSustain(byte value);
+	void controlRelease();
+
 	TownsMidiOutputChannel *_outChan;
 	//TownsMidiInputChannel *_prev;
 	//TownsMidiInputChannel *_next;
@@ -125,14 +134,18 @@ private:
 	uint8 _chanIndex;
 	uint8 _effectLevel;
 	uint8 _priority;
-	uint8 _vol;
+	uint8 _ctrlVolume;
 	uint8 _tl;
 	uint8 _pan;
 	uint8 _panEff;
-	int8 _transpose;
 	uint8 _percS;
-	uint8 _fld_22;
+	int8 _transpose;
+	uint8 _fld_1f;
+	int8 _detune;
+	uint8 _modWheel;
+	uint8 _sustain;
 	uint8 _pitchBendFactor;
+	int16 _pitchBend;
 	uint16 _freqLSB;
 
 	bool _allocated;
@@ -143,7 +156,7 @@ private:
 };
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_midi(0), _prev(0), _next(0), _fld_c(0), _tl2(0), _note(0), _tl1(0), _noteOffMarker(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+	_midi(0), _prev(0), _next(0), _fld_c(0), _tl2(0), _note(0), _tl1(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
 	_stateA = new StateA[2];
 	memset(_stateA, 0, 2 * sizeof(StateA));
 	_stateB = new StateB[2];
@@ -161,7 +174,7 @@ void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
 	internKeySetFreq(_freq);
 }
 
-void TownsMidiOutputChannel::noteOnAdjust(uint8 msb, uint16 lsb) {
+void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) {
 	_freq = (msb << 7) + lsb;
 	internKeySetFreq(_freq + _freqAdjust);
 }
@@ -224,6 +237,14 @@ void TownsMidiOutputChannel::noteOnSubSubSub_s1(int index, uint8 c, const uint8
 	StateB *b = &_stateB[index];
 }
 
+void TownsMidiOutputChannel::setModWheel(uint8 value) {
+	if (_stateA[0].active && _stateB[0].mwu)
+		_stateA[0].modWheel = value >> 2;
+
+	if (_stateA[1].active && _stateB[1].mwu)
+		_stateA[1].modWheel = value >> 2;
+}
+
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
 	if (!chan)
 		return;
@@ -341,7 +362,8 @@ const uint16 TownsMidiOutputChannel::_freqLSB[] = {
 };
 
 TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _outChan(0), _prg(0), _chanIndex(chanIndex),
-	_effectLevel(0), _priority(0), _vol(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _fld_22(0), _freqLSB(0), _allocated(false) {
+	_effectLevel(0), _priority(0), _ctrlVolume(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0),
+	_fld_1f(0), _detune(0), _modWheel(0), _allocated(false) {
 	_instrument = new uint8[30];
 	memset(_instrument, 0, 30);
 }
@@ -372,8 +394,8 @@ void TownsMidiInputChannel::noteOff(byte note) {
 	if (_outChan->_note != note)
 		return;
 
-	if (_fld_22)
-		_outChan->_noteOffMarker = 1;
+	if (_sustain)
+		_outChan->_sustainNoteOff = 1;
 	else
 		_outChan->disconnect();
 }
@@ -388,7 +410,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 
 	oc->_fld_c = _instrument[10] & 1;
 	oc->_note = note;
-	oc->_noteOffMarker = 0;
+	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 72;
 	
 	oc->_tl1 = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
@@ -405,28 +427,49 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	if (_instrument[11] & 0x80)
 		oc->noteOnSubSubSub_s1(0, _instrument[11], &_instrument[12]);
 	else
-		oc->_stateA[0].a[0] = 0;
+		oc->_stateA[0].active = 0;
 
 	if (_instrument[20] & 0x80)
 		oc->noteOnSubSubSub_s1(1, _instrument[20], &_instrument[21]);
 	else
-		oc->_stateA[1].a[0] = 0;	
+		oc->_stateA[1].active = 0;	
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
-
+	// Dysfunctional since this is all done inside the imuse code 
 }
 
 void TownsMidiInputChannel::pitchBend(int16 bend) {
-
+	_pitchBend = bend;
+	_freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune;
+	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
+		oc->noteOnPitchBend(oc->_note + oc->_midi->_transpose, _freqLSB);
 }
 
 void TownsMidiInputChannel::controlChange(byte control, byte value) {
-
+	switch (control) {
+	case 1:
+		controlModulationWheel(value);
+		break;
+	case 7:
+		controlVolume(value);
+		break;
+	case 10:
+		controlPanPos(value);
+		break;
+	case 64:
+		controlSustain(value);
+		break;
+	default:
+		break;
+	}
 }
 
 void TownsMidiInputChannel::pitchBendFactor(byte value) {
-
+	_pitchBendFactor = value;
+	_freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune;
+	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
+		oc->noteOnPitchBend(oc->_note + oc->_midi->_transpose, _freqLSB);
 }
 
 void TownsMidiInputChannel::priority(byte value) {
@@ -437,6 +480,47 @@ void TownsMidiInputChannel::sysEx_customInstrument(uint32 type, const byte *inst
 	memcpy(_instrument, instr, 30);
 }
 
+void TownsMidiInputChannel::controlModulationWheel(byte value) {
+	_modWheel = value;
+	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
+		oc->setModWheel(value);
+}
+
+void TownsMidiInputChannel::controlVolume(byte value) {
+	/* This is all done inside the imuse code
+
+	uint16 v1 = _ctrlVolume + 1;
+	uint16 v2 = value;
+	if (_chanIndex != 16) {
+		_ctrlVolume = value;
+		v2 = value;
+	}
+	_tl = (v1 * v2) >> 7;*/
+
+	_tl = value;
+	
+	/* nullsub
+	_outChan->setVolume(_tl);
+	*/
+}
+
+void TownsMidiInputChannel::controlPanPos(byte value) {
+	// not supported
+}
+
+void TownsMidiInputChannel::controlSustain(byte value) {
+	_sustain = value;
+	if (!value)
+		controlRelease();
+}
+
+void TownsMidiInputChannel::controlRelease() {
+	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next) {
+		if (oc->_sustainNoteOff)
+			oc->disconnect();
+	}
+}
+
 const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 	0x00, 0x04, 0x07, 0x0B, 0x0D, 0x10, 0x12, 0x14,
 	0x16, 0x18, 0x1A, 0x1B, 0x1D, 0x1E, 0x1F, 0x21,
@@ -521,10 +605,6 @@ void MidiDriver_TOWNS::send(uint32 b) {
 	byte param1 = (b >> 8) & 0xFF;
 	byte cmd = b & 0xF0;
 
-	/*AdLibPart *part;
-	if (chan == 9)
-		part = &_percussion;
-	else**/
 	TownsMidiInputChannel *c = _channels[b & 0x0F];
 
 	switch (cmd) {
@@ -538,14 +618,12 @@ void MidiDriver_TOWNS::send(uint32 b) {
 			c->noteOff(param1);
 		break;
 	case 0xB0:
-		// supported: 1, 7, 0x40
 		c->controlChange(param1, param2);
 		break;
 	case 0xC0:
 		c->programChange(param1);
 		break;
 	case 0xE0:
-		//part->pitchBend((param1 | (param2 << 7)) - 0x2000);
 		c->pitchBend((param1 | (param2 << 7)) - 0x2000);
 		break;
 	case 0xF0:
@@ -577,7 +655,7 @@ MidiChannel *MidiDriver_TOWNS::allocateChannel() {
 }
 
 MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
-	return 0;
+	return 0;//_channels[16];
 }
 
 void MidiDriver_TOWNS::timerCallback(int timerId) {


Commit: bd2c84be89068757531399b32e099ec7287ee2a6
    https://github.com/scummvm/scummvm/commit/bd2c84be89068757531399b32e099ec7287ee2a6
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:33:03-07:00

Commit Message:
FM-TOWNS AUDIO: More midi driver code (effect processing)

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 81f561a..5b2dc7b 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -25,6 +25,38 @@
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 #include "common/textconsole.h"
 
+struct ChanState {
+	uint8 get(uint8 type) {
+		switch (type) {
+		case 0:
+			return unk1;
+		case 1:
+			return mulAmsFms;
+		case 2:
+			return tl;
+		case 3:
+			return attDec;
+		case 4:
+			return sus;
+		case 5:
+			return fgAlg;
+		case 6:
+			return unk2;
+		default:
+			break;
+		}
+		return 0;
+	}
+
+	uint8 unk1;
+	uint8 mulAmsFms;
+	uint8 tl;
+	uint8 attDec;
+	uint8 sus;
+	uint8 fgAlg;
+	uint8 unk2;
+};
+
 class TownsMidiOutputChannel {
 friend class TownsMidiInputChannel;
 public:
@@ -34,7 +66,7 @@ public:
 	void noteOn(uint8 msb, uint16 lsb);
 	void noteOnPitchBend(uint8 msb, uint16 lsb);
 	void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2);
-	void noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr);
+	void setupEffects(int index, uint8 c, const uint8 *effectData);
 	void setModWheel(uint8 value);
 	
 	void connect(TownsMidiInputChannel *chan);
@@ -48,6 +80,43 @@ public:
 	int checkPriority(int pri);
 
 private:
+	struct StateA {
+		uint8 active;
+		uint8 fld_1;
+		uint8 fld_2;
+		uint8 fld_3;
+		uint8 fld_4;
+		uint8 fld_5;
+		uint8 fld_6;
+		uint8 fld_7;
+		uint8 fld_8;
+		uint32 fld_9;
+		uint32 effectState;
+		uint8 fld_11;
+		uint8 fld_12;
+		uint8 fld_13;
+		uint8 fld_14;
+		uint8 fld_15;
+		uint8 fld_16;
+		uint8 fld_17;
+		uint8 fld_18;
+		uint8 fld_19;
+		uint8 fld_1a;
+		uint8 modWheelImpact;
+		uint8 modWheel;
+	} *_stateA;
+
+	struct StateB {
+		uint32 fld_0;
+		uint8 type;
+		uint8 useModWheel;
+		uint8 fld_6;
+		StateA *a;
+	} *_stateB;
+
+	uint32 getEffectState(uint8 type);
+	void processEffect(StateA *a, const uint8 *effectData);
+
 	void keyOn();
 	void keyOff();
 	void internKeySetFreq(uint16 frq);
@@ -59,8 +128,8 @@ private:
 	uint8 _fld_c;
 	uint8 _chan;
 	uint8 _note;
-	uint8 _tl2;
-	uint8 _tl1;
+	uint8 _carrierTl;
+	uint8 _modulatorTl;
 	uint8 _sustainNoteOff;
 	uint32 _duration;
 	uint8 _fld_13;
@@ -69,29 +138,11 @@ private:
 	uint16 _freq;
 	int16 _freqAdjust;
 
-	struct StateA {
-		uint8 active;
-		uint8 a[48];
-		uint8 modWheel;
-	} *_stateA;
-
-	struct StateB {
-		uint8 b1;
-		uint8 b2;
-		uint8 b3;
-		uint8 b4;
-		uint8 b5;
-		uint8 mwu;
-		uint8 b7;
-		uint8 b8;
-		uint8 b9;
-		uint8 b10;
-		uint8 b11;
-	} *_stateB;
-
 	MidiDriver_TOWNS *_driver;
 
 	static const uint8 _chanMap[];
+	static const uint8 _chanMap2[];
+	static const uint8 _effectDefs[];
 	static const uint8 _freqMSB[];
 	static const uint16 _freqLSB[];
 };
@@ -123,11 +174,10 @@ private:
 	void controlVolume(byte value);
 	void controlPanPos(byte value);
 	void controlSustain(byte value);
-	void controlRelease();
+
+	void releasePedal();
 
 	TownsMidiOutputChannel *_outChan;
-	//TownsMidiInputChannel *_prev;
-	//TownsMidiInputChannel *_next;
 	
 	uint8 *_instrument;
 	uint8 _prg;
@@ -156,7 +206,7 @@ private:
 };
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_midi(0), _prev(0), _next(0), _fld_c(0), _tl2(0), _note(0), _tl1(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+	_midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
 	_stateA = new StateA[2];
 	memset(_stateA, 0, 2 * sizeof(StateA));
 	_stateB = new StateB[2];
@@ -193,7 +243,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - vol1;
 	uint8 attDec1 = _driver->_chanState[chan].attDec = ~data[2];
 	uint8 sus1 = _driver->_chanState[chan].sus = ~data[3];
-	uint8 unk1 = _driver->_chanState[chan].unk = data[4];
+	uint8 unk1 = _driver->_chanState[chan].unk2 = data[4];
 	chan += 3;
 
 	out(0x30, mul[mulAmsFms1 & 0x0f]);
@@ -207,7 +257,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - vol2;
 	uint8 attDec2 = _driver->_chanState[chan].attDec = ~data[7];
 	uint8 sus2 = _driver->_chanState[chan].sus = ~data[8];
-	uint8 unk2 = _driver->_chanState[chan].unk = data[9];
+	uint8 unk2 = _driver->_chanState[chan].unk2 = data[9];
 
 	uint8 mul2 = mul[mulAmsFms2 & 0x0f];
 	tl2 = (tl2 & 0x3f) + 15;
@@ -232,16 +282,50 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5));
 }
 
-void TownsMidiOutputChannel::noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr) {
+void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effectData) {
+	uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
+	uint8 para1[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
+	
 	StateA *a = &_stateA[index];
 	StateB *b = &_stateB[index];
+
+	b->fld_0 = 0;
+	b->useModWheel = c & 0x40;
+	a->fld_11 = c & 0x20;
+	b->fld_6 = c & 0x10;
+	b->type = para1[c & 0x0f];
+	a->fld_9 = maxVal[c & 0x0f];
+	a->fld_1a = 0x1f;
+	a->modWheelImpact = b->useModWheel ? _midi->_modWheel >> 2 : 0x1f;
+
+	switch (b->type) {
+	case 0:
+		a->effectState = _carrierTl;
+		break;
+	case 13:
+		a->effectState = _modulatorTl;
+		break;
+	case 30:
+		a->effectState = 0x1f;
+		b->a->modWheelImpact = 0;
+		break;
+	case 31:
+		a->effectState = 0;
+		b->a->fld_1a = 0;
+		break;
+	default:
+		a->effectState = getEffectState(b->type);
+		break;
+	}
+
+	processEffect(a, effectData);
 }
 
 void TownsMidiOutputChannel::setModWheel(uint8 value) {
-	if (_stateA[0].active && _stateB[0].mwu)
+	if (_stateA[0].active && _stateB[0].type)
 		_stateA[0].modWheel = value >> 2;
 
-	if (_stateA[1].active && _stateB[1].mwu)
+	if (_stateA[1].active && _stateB[1].type)
 		_stateA[1].modWheel = value >> 2;
 }
 
@@ -280,6 +364,30 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 	return kHighPriority;
 }
 
+uint32 TownsMidiOutputChannel::getEffectState(uint8 type) {
+	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
+	
+	if (type == 28)
+		return 15;
+	else if (type == 29)
+		return 383;
+	else if (type > 29)
+		return 0;
+	else if (type > 12)
+		type -= 13;
+
+	uint32 res = 0;
+	uint8 cs = (_driver->_chanState[chan].get(_effectDefs[type * 4] >> 5) & _effectDefs[type * 4 + 2]) >> _effectDefs[type * 4 + 1];
+	if (_effectDefs[type * 4 + 3])
+		res = _effectDefs[type * 4 + 3] - cs;
+	
+	return res;	
+}
+
+void TownsMidiOutputChannel::processEffect(StateA *a, const uint8 *effectData) {
+
+}
+
 void TownsMidiOutputChannel::keyOn() {
 	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
 	// since it is just a modified AdLib driver. It also uses AdLib programs.
@@ -323,6 +431,18 @@ const uint8 TownsMidiOutputChannel::_chanMap[] = {
 	0, 1, 2, 8, 9, 10
 };
 
+const uint8 TownsMidiOutputChannel::_chanMap2[] = {
+	3, 4, 5, 11, 12, 13
+};
+
+const uint8 TownsMidiOutputChannel::_effectDefs[] = {
+	0x40, 0x00, 0x3F, 0x3F, 0xE0, 0x02, 0x00, 0x00, 0x40, 0x06, 0xC0, 0x00,
+	0x20, 0x00, 0x0F, 0x00, 0x60, 0x04, 0xF0, 0x0F, 0x60, 0x00, 0x0F, 0x0F,
+	0x80, 0x04, 0xF0, 0x0F, 0x80, 0x00, 0x0F, 0x0F, 0xE0, 0x00, 0x03, 0x00,
+	0x20, 0x07, 0x80, 0x00, 0x20, 0x06, 0x40, 0x00, 0x20, 0x05, 0x20, 0x00,
+	0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00
+};
+
 const uint8 TownsMidiOutputChannel::_freqMSB[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -413,24 +533,24 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 72;
 	
-	oc->_tl1 = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
-	if (oc->_tl1 > 63)
-		oc->_tl1 = 63;
+	oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+	if (oc->_modulatorTl > 63)
+		oc->_modulatorTl = 63;
 
-	oc->_tl2 = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
-	if (oc->_tl2 > 63)
-		oc->_tl2 = 63;
+	oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+	if (oc->_carrierTl > 63)
+		oc->_carrierTl = 63;
 
-	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl1 << 5)]] : oc->_tl1, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl2 << 5)]]);
+	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
 	oc->noteOn(note + _transpose, _freqLSB);
 
 	if (_instrument[11] & 0x80)
-		oc->noteOnSubSubSub_s1(0, _instrument[11], &_instrument[12]);
+		oc->setupEffects(0, _instrument[11], &_instrument[12]);
 	else
 		oc->_stateA[0].active = 0;
 
 	if (_instrument[20] & 0x80)
-		oc->noteOnSubSubSub_s1(1, _instrument[20], &_instrument[21]);
+		oc->setupEffects(1, _instrument[20], &_instrument[21]);
 	else
 		oc->_stateA[1].active = 0;	
 }
@@ -511,10 +631,10 @@ void TownsMidiInputChannel::controlPanPos(byte value) {
 void TownsMidiInputChannel::controlSustain(byte value) {
 	_sustain = value;
 	if (!value)
-		controlRelease();
+		releasePedal();
 }
 
-void TownsMidiInputChannel::controlRelease() {
+void TownsMidiInputChannel::releasePedal() {
 	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next) {
 		if (oc->_sustainNoteOff)
 			oc->disconnect();
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 6ff8a99..8cffdd7 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -28,8 +28,10 @@
 #include "audio/softsynth/fmtowns_pc98/towns_audio.h"
 #include "audio/mididrv.h"
 
+
 class TownsMidiOutputChannel;
 class TownsMidiInputChannel;
+struct ChanState;
 
 class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
 friend class TownsMidiInputChannel;
@@ -61,14 +63,7 @@ private:
 	TownsMidiInputChannel **_channels;
 	TownsMidiOutputChannel **_out;	
 
-	struct ChanState {
-		uint8 mulAmsFms;
-		uint8 tl;
-		uint8 attDec;
-		uint8 sus;
-		uint8 fgAlg;
-		uint8 unk;
-	} *_chanState;
+	ChanState *_chanState;
 
 	Common::TimerManager::TimerProc _timerBproc;
 	void *_timerBpara;


Commit: d9772ff88f29e37fa7b91b7b6e43d846bcfad008
    https://github.com/scummvm/scummvm/commit/d9772ff88f29e37fa7b91b7b6e43d846bcfad008
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:33:03-07:00

Commit Message:
FM-TOWNS AUDIO: Some renaming in the euphony driver code

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index 49c156f..cb6cfc5 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -27,7 +27,7 @@
 
 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),
+	_tDetune(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0),
 	_tempoControlMode(0) {
 	_para[0] = _para[1] = 0;
 	_intf = new TownsAudioInterface(mixer, this);
@@ -44,7 +44,7 @@ TownsEuphonyDriver::~TownsEuphonyDriver() {
 	delete[] _tMode;
 	delete[] _tOrdr;
 	delete[] _tLevel;
-	delete[] _tTranspose;
+	delete[] _tDetune;
 }
 
 bool TownsEuphonyDriver::init() {
@@ -59,7 +59,7 @@ bool TownsEuphonyDriver::init() {
 	delete[] _tMode;
 	delete[] _tOrdr;
 	delete[] _tLevel;
-	delete[] _tTranspose;
+	delete[] _tDetune;
 
 	_activeChannels = new int8[16];
 	_sustainChannels = new int8[16];
@@ -70,7 +70,7 @@ bool TownsEuphonyDriver::init() {
 	_tMode = new uint8[32];
 	_tOrdr = new uint8[32];
 	_tLevel = new int8[32];
-	_tTranspose = new int8[32];
+	_tDetune = new int8[32];
 
 	reset();
 
@@ -220,21 +220,21 @@ void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) {
 	_intf->callback(67, mode, volLeft, volRight);
 }
 
-int TownsEuphonyDriver::chanEnable(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_enable(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	_tEnable[tableEntry] = val;
 	return 0;
 }
 
-int TownsEuphonyDriver::chanMode(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_setMode(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	_tMode[tableEntry] = val;
 	return 0;
 }
 
-int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_remap(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	if (val < 16)
@@ -242,7 +242,7 @@ int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) {
 	return 0;
 }
 
-int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_adjustVolume(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	if (val <= 40)
@@ -250,11 +250,11 @@ int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) {
 	return 0;
 }
 
-int TownsEuphonyDriver::chanNoteShift(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_setDetune(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	if (val <= 40)
-		_tTranspose[tableEntry] = (int8)(val & 0xff);
+		_tDetune[tableEntry] = (int8)(val & 0xff);
 	return 0;
 }
 
@@ -325,7 +325,7 @@ void TownsEuphonyDriver::resetTables() {
 	for (int i = 0; i < 32; i++)
 		_tOrdr[i] = i & 0x0f;
 	memset(_tLevel, 0, 32);
-	memset(_tTranspose, 0, 32);
+	memset(_tDetune, 0, 32);
 }
 
 void TownsEuphonyDriver::resetTempo() {
@@ -672,8 +672,8 @@ bool TownsEuphonyDriver::evtSetupNote() {
 	uint8 velo = _musicPos[5];
 
 	sendEvent(mode, evt);
-	sendEvent(mode, applyNoteShift(note));
-	sendEvent(mode, applyVolumeShift(velo));
+	sendEvent(mode, applyDetune(note));
+	sendEvent(mode, applyVolumeAdjust(velo));
 
 	jumpNextLoop();
 	if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd)
@@ -712,7 +712,7 @@ bool TownsEuphonyDriver::evtPolyphonicAftertouch() {
 	uint8 mode = _tMode[_musicPos[1]];
 
 	sendEvent(mode, evt);
-	sendEvent(mode, applyNoteShift(_musicPos[4]));
+	sendEvent(mode, applyDetune(_musicPos[4]));
 	sendEvent(mode, _musicPos[5]);
 
 	return false;
@@ -780,8 +780,8 @@ bool TownsEuphonyDriver::evtModeOrdrChange() {
 	return false;
 }
 
-uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) {
-	int out = _tTranspose[_musicPos[1]];
+uint8 TownsEuphonyDriver::applyDetune(uint8 in) {
+	int out = _tDetune[_musicPos[1]];
 	if (!out)
 		return in;
 	out += (in & 0x7f);
@@ -795,7 +795,7 @@ uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) {
 	return out & 0xff;
 }
 
-uint8 TownsEuphonyDriver::applyVolumeShift(uint8 in) {
+uint8 TownsEuphonyDriver::applyVolumeAdjust(uint8 in) {
 	int out = _tLevel[_musicPos[1]];
 	out += (in & 0x7f);
 	out = CLIP(out, 1, 127);
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index a8f22f5..ae36d12 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -55,11 +55,11 @@ public:
 
 	void setOutputVolume(int chanType, int volLeft, int volRight);
 
-	int chanEnable(int tableEntry, int val);
-	int chanMode(int tableEntry, int val);
-	int chanOrdr(int tableEntry, int val);
-	int chanVolumeShift(int tableEntry, int val);
-	int chanNoteShift(int tableEntry, int val);
+	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_setDetune(int tableEntry, int val);
 
 	int assignChannel(int chan, int tableEntry);
 
@@ -111,8 +111,8 @@ private:
 		return false;
 	}
 
-	uint8 applyNoteShift(uint8 in);
-	uint8 applyVolumeShift(uint8 in);
+	uint8 applyDetune(uint8 in);
+	uint8 applyVolumeAdjust(uint8 in);
 
 	void sendNoteOff();
 	void sendNoteOn();
@@ -136,7 +136,7 @@ private:
 	uint8 *_tMode;
 	uint8 *_tOrdr;
 	int8 *_tLevel;
-	int8 *_tTranspose;
+	int8 *_tDetune;
 
 	struct DlEvent {
 		uint8 evt;
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 5b2dc7b..c492a97 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -25,38 +25,6 @@
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 #include "common/textconsole.h"
 
-struct ChanState {
-	uint8 get(uint8 type) {
-		switch (type) {
-		case 0:
-			return unk1;
-		case 1:
-			return mulAmsFms;
-		case 2:
-			return tl;
-		case 3:
-			return attDec;
-		case 4:
-			return sus;
-		case 5:
-			return fgAlg;
-		case 6:
-			return unk2;
-		default:
-			break;
-		}
-		return 0;
-	}
-
-	uint8 unk1;
-	uint8 mulAmsFms;
-	uint8 tl;
-	uint8 attDec;
-	uint8 sus;
-	uint8 fgAlg;
-	uint8 unk2;
-};
-
 class TownsMidiOutputChannel {
 friend class TownsMidiInputChannel;
 public:
@@ -119,7 +87,7 @@ private:
 
 	void keyOn();
 	void keyOff();
-	void internKeySetFreq(uint16 frq);
+	void keyOnSetFreq(uint16 frq);
 	void out(uint8 reg, uint8 val);
 
 	TownsMidiInputChannel *_midi;
@@ -205,6 +173,47 @@ private:
 	static const uint8 _programAdjustLevel[];
 };
 
+class TownsMidiChanState {
+public:
+	TownsMidiChanState();
+	~TownsMidiChanState() {}	
+	uint8 get(uint8 type);
+
+	uint8 unk1;
+	uint8 mulAmsFms;
+	uint8 tl;
+	uint8 attDec;
+	uint8 sus;
+	uint8 fgAlg;
+	uint8 unk2;
+};
+
+TownsMidiChanState::TownsMidiChanState() {
+	unk1 = mulAmsFms = tl =	attDec = sus = fgAlg = unk2 = 0;
+}
+
+uint8 TownsMidiChanState::get(uint8 type) {
+	switch (type) {
+	case 0:
+		return unk1;
+	case 1:
+		return mulAmsFms;
+	case 2:
+		return tl;
+	case 3:
+		return attDec;
+	case 4:
+		return sus;
+	case 5:
+		return fgAlg;
+	case 6:
+		return unk2;
+	default:
+		break;
+	}
+	return 0;
+}
+
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
 	_midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
 	_stateA = new StateA[2];
@@ -221,12 +230,12 @@ TownsMidiOutputChannel::~TownsMidiOutputChannel() {
 void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
 	_freq = (msb << 7) + lsb;
 	_freqAdjust = 0;
-	internKeySetFreq(_freq);
+	keyOnSetFreq(_freq);
 }
 
 void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) {
 	_freq = (msb << 7) + lsb;
-	internKeySetFreq(_freq + _freqAdjust);
+	keyOnSetFreq(_freq + _freqAdjust);
 }
 
 void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 vol2) {
@@ -401,7 +410,7 @@ void TownsMidiOutputChannel::keyOff() {
 	out(0x28, 0);
 }
 
-void TownsMidiOutputChannel::internKeySetFreq(uint16 frq) {
+void TownsMidiOutputChannel::keyOnSetFreq(uint16 frq) {
 	uint8 t = (frq << 1) >> 8;	
 	frq = (_freqMSB[t] << 11) | _freqLSB[t] ;
 	out(0xa4, frq >> 8);
@@ -556,7 +565,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
-	// Dysfunctional since this is all done inside the imuse code 
+	// Dysfunctional since this is all done inside the imuse code
 }
 
 void TownsMidiInputChannel::pitchBend(int16 bend) {
@@ -663,8 +672,7 @@ MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timer
 	for (int i = 0; i < 6; i++)
 		_out[i] = new TownsMidiOutputChannel(this, i);
 
-	_chanState = new ChanState[32];
-	memset(_chanState, 0, 32 * sizeof(ChanState));
+	_chanState = new TownsMidiChanState[32];
 
 	_chanOutputLevel = new uint8[2048];
 	for (int i = 0; i < 64; i++) {
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 8cffdd7..005c77c 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -31,7 +31,7 @@
 
 class TownsMidiOutputChannel;
 class TownsMidiInputChannel;
-struct ChanState;
+class TownsMidiChanState;
 
 class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver {
 friend class TownsMidiInputChannel;
@@ -61,9 +61,8 @@ private:
 	TownsMidiOutputChannel *allocateOutputChannel(int pri);
 
 	TownsMidiInputChannel **_channels;
-	TownsMidiOutputChannel **_out;	
-
-	ChanState *_chanState;
+	TownsMidiOutputChannel **_out;
+	TownsMidiChanState *_chanState;
 
 	Common::TimerManager::TimerProc _timerBproc;
 	void *_timerBpara;
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index acf069d..5f4e5a5 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -113,7 +113,7 @@ void SoundTowns::haltTrack() {
 	for (int i = 0x40; i < 0x46; i++)
 		_driver->chanVolume(i, 0);	
 	for (int i = 0; i < 32; i++)
-		_driver->chanEnable(i, 0);
+		_driver->configChan_enable(i, 0);
 	_driver->stopParser();
 }
 
@@ -330,15 +330,15 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
 
 	const uint8 *src = _musicTrackData + 852;
 	for (int i = 0; i < 32; i++)
-		_driver->chanEnable(i, *src++);
+		_driver->configChan_enable(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanMode(i, *src++);
+		_driver->configChan_setMode(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanOrdr(i, *src++);
+		_driver->configChan_remap(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanVolumeShift(i, *src++);
+		_driver->configChan_adjustVolume(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanNoteShift(i, *src++);
+		_driver->configChan_setDetune(i, *src++);
 
 	src = _musicTrackData + 1748;
 	for (int i = 0; i < 6; i++)
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index a100af7..f3b790a 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -500,15 +500,15 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) {
 	const uint8 *trackData = src + 150;
 
 	for (int i = 0; i < 32; i++)
-		_driver->chanEnable(i, *src++);
+		_driver->configChan_enable(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanMode(i, 0xff);
+		_driver->configChan_setMode(i, 0xff);
 	for (int i = 0; i < 32; i++)
-		_driver->chanOrdr(i, *src++);
+		_driver->configChan_remap(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanVolumeShift(i, *src++);
+		_driver->configChan_adjustVolume(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->chanNoteShift(i, *src++);
+		_driver->configChan_setDetune(i, *src++);
 
 	src += 8;
 	for (int i = 0; i < 6; i++)


Commit: 9fa1b9aa361d204ca98e60917c4c7e2e3b3c4f64
    https://github.com/scummvm/scummvm/commit/9fa1b9aa361d204ca98e60917c4c7e2e3b3c4f64
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:26-07:00

Commit Message:
FM-TOWNS AUDIO: More midi driver code

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index c492a97..0cf8a0d 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -49,28 +49,25 @@ public:
 
 private:
 	struct StateA {
-		uint8 active;
-		uint8 fld_1;
-		uint8 fld_2;
-		uint8 fld_3;
-		uint8 fld_4;
-		uint8 fld_5;
-		uint8 fld_6;
-		uint8 fld_7;
-		uint8 fld_8;
-		uint32 fld_9;
-		uint32 effectState;
+		uint8 numLoop;
+		int32 fld_1;
+		uint32 fld_5;
+		int32 fld_9;
+		int32 effectState;
 		uint8 fld_11;
-		uint8 fld_12;
-		uint8 fld_13;
-		uint8 fld_14;
-		uint8 fld_15;
-		uint8 fld_16;
-		uint8 fld_17;
-		uint8 fld_18;
-		uint8 fld_19;
+		uint8 ar1[4];
+		uint8 ar2[4];
 		uint8 fld_1a;
 		uint8 modWheelImpact;
+		uint8 fld_1c;
+		uint32 fld_1d;
+		uint32 fld_21;
+		uint32 fld_25;
+		int8 dir;
+		uint32 fld_2a;
+		uint8 fld_2b;
+		uint8 fld_2c;
+		uint8 fld_2d;
 		uint8 modWheel;
 	} *_stateA;
 
@@ -83,7 +80,9 @@ private:
 	} *_stateB;
 
 	uint32 getEffectState(uint8 type);
-	void processEffect(StateA *a, const uint8 *effectData);
+	void initEffect(StateA *a, const uint8 *effectData);
+	void updateEffect(StateA *a);
+	int lookupVolume(int a, int b);
 
 	void keyOn();
 	void keyOff();
@@ -101,7 +100,7 @@ private:
 	uint8 _sustainNoteOff;
 	uint32 _duration;
 	uint8 _fld_13;
-	uint8 _prg;	
+	uint8 _prg;
 
 	uint16 _freq;
 	int16 _freqAdjust;
@@ -111,6 +110,7 @@ private:
 	static const uint8 _chanMap[];
 	static const uint8 _chanMap2[];
 	static const uint8 _effectDefs[];
+	static const uint16 _effectData[];
 	static const uint8 _freqMSB[];
 	static const uint16 _freqLSB[];
 };
@@ -327,14 +327,14 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 		break;
 	}
 
-	processEffect(a, effectData);
+	initEffect(a, effectData);
 }
 
 void TownsMidiOutputChannel::setModWheel(uint8 value) {
-	if (_stateA[0].active && _stateB[0].type)
+	if (_stateA[0].numLoop && _stateB[0].type)
 		_stateA[0].modWheel = value >> 2;
 
-	if (_stateA[1].active && _stateB[1].type)
+	if (_stateA[1].numLoop && _stateB[1].type)
 		_stateA[1].modWheel = value >> 2;
 }
 
@@ -393,8 +393,81 @@ uint32 TownsMidiOutputChannel::getEffectState(uint8 type) {
 	return res;	
 }
 
-void TownsMidiOutputChannel::processEffect(StateA *a, const uint8 *effectData) {
+void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
+	a->numLoop = 1;
+	a->fld_1 = 0;
+	a->fld_1c = 0x1f;
+	a->fld_5 = effectData[0];
+	a->ar1[0] = effectData[1];
+	a->ar1[1] = effectData[3];
+	a->ar1[2] = effectData[5];
+	a->ar1[3] = effectData[6];
+	a->ar2[0] = effectData[2];
+	a->ar2[1] = effectData[3];
+	a->ar2[2] = 0;
+	a->ar2[3] = effectData[7];
+	updateEffect(a);
+}
+
+void TownsMidiOutputChannel::updateEffect(StateA *a) {
+	uint8 c = --a->numLoop;
+	uint16 v = a->ar1[c];
+	int e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->fld_1a]];
+
+	if (v & 0x80)
+		e = _driver->randomValue(e);
+	
+	if (!e)
+		e = 1;
+
+	a->fld_1d = a->fld_21 = e;
+	int32 d = 0;
 
+	if (c + 1 != 3) {
+		v = a->ar2[c];
+		e = lookupVolume(a->fld_9, (v & 0x7f) - 31);
+
+		if (v & 0x80)
+			e = _driver->randomValue(e);
+
+		if (e + a->effectState > a->fld_9) {
+			e = a->fld_9 - a->effectState;
+		} else {
+			if (e + a->effectState + 1 <= 0)
+				e = -e;
+		}
+
+		d = e - a->fld_1;
+	}
+
+	a->fld_25 = d / a->fld_1d;
+	a->dir = d < 0 ? -1 : 1;
+	a->fld_2a = d % a->fld_1d;
+
+	a->fld_2b = a->fld_2c = a->fld_2d = a->modWheel = 0;
+}
+
+int TownsMidiOutputChannel::lookupVolume(int a, int b) {
+	if (b == 0)
+		return 0;
+
+	if (b == 31)
+		return a;
+
+	if (a > 63)
+		return ((a + 1) * b) >> 5;
+
+	if (b < 0) {
+		if (a < 0)			
+			return _driver->_chanOutputLevel[(-a << 5) - b];
+		else
+			return -_driver->_chanOutputLevel[(a << 5) - b];
+	} else {
+		if (a < 0)			
+			return -_driver->_chanOutputLevel[(-a << 5) + b];
+		else
+			return _driver->_chanOutputLevel[(-a << 5) + b];
+	}
 }
 
 void TownsMidiOutputChannel::keyOn() {
@@ -452,6 +525,13 @@ const uint8 TownsMidiOutputChannel::_effectDefs[] = {
 	0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00
 };
 
+const uint16 TownsMidiOutputChannel::_effectData[] = {
+	0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007,	0x0008, 0x0009,
+	0x000A, 0x000C, 0x000E, 0x0010,	0x0012, 0x0015, 0x0018, 0x001E,
+	0x0024, 0x0032,	0x0040, 0x0052, 0x0064, 0x0088, 0x00A0, 0x00C0,
+	0x00F0, 0x0114, 0x0154, 0x01CC, 0x0258, 0x035C,	0x04B0, 0x0640
+};
+
 const uint8 TownsMidiOutputChannel::_freqMSB[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -556,12 +636,12 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	if (_instrument[11] & 0x80)
 		oc->setupEffects(0, _instrument[11], &_instrument[12]);
 	else
-		oc->_stateA[0].active = 0;
+		oc->_stateA[0].numLoop = 0;
 
 	if (_instrument[20] & 0x80)
 		oc->setupEffects(1, _instrument[20], &_instrument[21]);
 	else
-		oc->_stateA[1].active = 0;	
+		oc->_stateA[1].numLoop = 0;	
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
@@ -661,7 +741,7 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 	0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
 };
 
-MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timerBpara(0), _open(false) {
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _tickCounter(0), _curChan(0), _rand(1), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
 
 	_channels = new TownsMidiInputChannel*[32];
@@ -681,9 +761,6 @@ MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerBproc(0), _timer
 	}
 	for (int i = 0; i < 64; i++)
 		_chanOutputLevel[i << 5] = 0;
-
-	_tickCounter = 0;
-	_curChan = 0;
 }
 
 MidiDriver_TOWNS::~MidiDriver_TOWNS() {
@@ -764,8 +841,8 @@ void MidiDriver_TOWNS::send(uint32 b) {
 }
 
 void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
-	_timerBproc = timer_proc;
-	_timerBpara = timer_param;
+	_timerProc = timer_proc;
+	_timerProcPara = timer_param;
 }
 
 uint32 MidiDriver_TOWNS::getBaseTempo() {
@@ -792,12 +869,12 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
 
 	switch (timerId) {
 	case 1:
-		if (_timerBproc) {
-			_timerBproc(_timerBpara);
+		if (_timerProc) {
+			_timerProc(_timerProcPara);
 			_tickCounter += 10000;
 			while (_tickCounter >= 4167) {
 				_tickCounter -= 4167;
-				_timerBproc(_timerBpara);
+				_timerProc(_timerProcPara);
 			}
 		}
 		break;
@@ -828,3 +905,8 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 
 	return res;
 }
+
+int MidiDriver_TOWNS::randomValue(int para) {
+	_rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1);
+	return (_rand * para) >> 8;
+}
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 005c77c..1a4a861 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -59,18 +59,21 @@ public:
 	
 private:
 	TownsMidiOutputChannel *allocateOutputChannel(int pri);
+	
+	int randomValue(int para);
 
 	TownsMidiInputChannel **_channels;
 	TownsMidiOutputChannel **_out;
 	TownsMidiChanState *_chanState;
 
-	Common::TimerManager::TimerProc _timerBproc;
-	void *_timerBpara;
+	Common::TimerManager::TimerProc _timerProc;
+	void *_timerProcPara;
 
 	TownsAudioInterface *_intf;
 
 	uint32 _tickCounter;
 	uint8 _curChan;
+	uint8 _rand;
 	
 	bool _open;
 


Commit: cac67d0151a1889add4d20c429f5488a5887deb5
    https://github.com/scummvm/scummvm/commit/cac67d0151a1889add4d20c429f5488a5887deb5
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
SCUMM: Set proper GUIO flags for monkey2/indy4 FM-TOWNS

Changed paths:
    engines/scumm/detection_tables.h



diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 4234664..7eb1e80 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -184,6 +184,8 @@ using Common::GUIO_NOLAUNCHLOAD;
 using Common::GUIO_NOMIDI;
 using Common::GUIO_NOSPEECH;
 using Common::GUIO_MIDITOWNS;
+using Common::GUIO_MIDIADLIB;
+using Common::GUIO_MIDIMT32;
 
 // The following table contains information about variants of our various
 // games. We index into it with help of md5table (from scumm-md5.h), to find
@@ -242,11 +244,11 @@ static const GameSettings gameVariantsTable[] = {
 	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO_NOSPEECH | GUIO_NOMIDI},
 
 	{"monkey2",  "", 0, GID_MONKEY2,  5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH},
-	{"monkey2", "FM-TOWNS", 0, GID_MONKEY2,  5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_NOSPEECH},
+	{"monkey2", "FM-TOWNS", 0, GID_MONKEY2,  5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_MIDITOWNS | GUIO_MIDIADLIB | GUIO_MIDIMT32},
 
 	{"atlantis", "", 0, GID_INDY4,    5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NONE},
 	{"atlantis", "Floppy", 0, GID_INDY4,    5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH},
-	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_NONE},
+	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO_MIDITOWNS | GUIO_MIDIADLIB | GUIO_MIDIMT32},
 
 	{"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO_NONE},
 	{"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO_NOSPEECH},


Commit: ca0e9cca3d50759e86aaa54bdfa5d5c5fdf85efb
    https://github.com/scummvm/scummvm/commit/ca0e9cca3d50759e86aaa54bdfa5d5c5fdf85efb
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
FM-TOWNS AUDIO: Start fixing midi driver tempo

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 0cf8a0d..c28f9a1 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -40,6 +40,8 @@ public:
 	void connect(TownsMidiInputChannel *chan);
 	void disconnect();
 
+	bool update();
+
 	enum CheckPriorityStatus {
 		kDisconnected = -3,
 		kHighPriority = -2
@@ -81,7 +83,9 @@ private:
 
 	uint32 getEffectState(uint8 type);
 	void initEffect(StateA *a, const uint8 *effectData);
-	void updateEffect(StateA *a);
+	void updateEffectOuter3(StateA *a, StateB *b);
+	void updateEffectOuter(StateA *a, StateB *b);
+	void updateEffect(StateA *a);	
 	int lookupVolume(int a, int b);
 
 	void keyOn();
@@ -98,10 +102,8 @@ private:
 	uint8 _carrierTl;
 	uint8 _modulatorTl;
 	uint8 _sustainNoteOff;
-	uint32 _duration;
-	uint8 _fld_13;
-	uint8 _prg;
-
+	int32 _duration;
+	
 	uint16 _freq;
 	int16 _freqAdjust;
 
@@ -215,7 +217,7 @@ uint8 TownsMidiChanState::get(uint8 type) {
 }
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) {
+	_midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
 	_stateA = new StateA[2];
 	memset(_stateA, 0, 2 * sizeof(StateA));
 	_stateB = new StateB[2];
@@ -363,6 +365,24 @@ void TownsMidiOutputChannel::disconnect() {
 	_midi = 0;
 }
 
+bool TownsMidiOutputChannel::update() {
+	if (!_midi)
+		return false;
+
+	_duration -= 17;
+	if (_duration <=0) {
+		disconnect();
+		return true;
+	}
+
+	for (int i = 0; i < 2; i++) {
+		if (_stateA[i].numLoop)
+			updateEffectOuter3(&_stateA[i], &_stateB[i]);
+	}
+
+	return false;
+}
+
 int TownsMidiOutputChannel::checkPriority(int pri) {
 	if (!_midi)
 		return kDisconnected;
@@ -409,6 +429,14 @@ void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
 	updateEffect(a);
 }
 
+void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
+
+}
+
+void TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
+
+}
+
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	uint8 c = --a->numLoop;
 	uint16 v = a->ar1[c];
@@ -741,7 +769,7 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 	0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
 };
 
-MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _tickCounter(0), _curChan(0), _rand(1), _open(false) {
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _tickCounter1(0), _tickCounter2(0), _curChan(0), _rand(1), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
 
 	_channels = new TownsMidiInputChannel*[32];
@@ -846,7 +874,7 @@ void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager:
 }
 
 uint32 MidiDriver_TOWNS::getBaseTempo() {
-	return 4167;
+	return 10080;
 }
 
 MidiChannel *MidiDriver_TOWNS::allocateChannel() {
@@ -869,14 +897,14 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
 
 	switch (timerId) {
 	case 1:
-		if (_timerProc) {
-			_timerProc(_timerProcPara);
-			_tickCounter += 10000;
-			while (_tickCounter >= 4167) {
-				_tickCounter -= 4167;
-				_timerProc(_timerProcPara);
-			}
-		}
+		updateParser();
+		updateOutputChannels();
+
+		/*_tickCounter1 += 10000;
+		while (_tickCounter1 >= 4167) {
+			_tickCounter1 -= 4167;
+			unkUpdate();
+		}*/
 		break;
 	default:
 		break;
@@ -906,6 +934,23 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 	return res;
 }
 
+void MidiDriver_TOWNS::updateParser() {
+	if (_timerProc)
+		_timerProc(_timerProcPara);
+}
+
+void MidiDriver_TOWNS::updateOutputChannels() {
+	_tickCounter2 += 10000;
+	while (_tickCounter2 >= 16667) {
+		_tickCounter2 -= 16667;
+		for (int i = 0; i < 6; i++) {
+			TownsMidiOutputChannel *oc = _out[i];
+			if (oc->update())
+				return;
+		}
+	}
+}
+
 int MidiDriver_TOWNS::randomValue(int para) {
 	_rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1);
 	return (_rand * para) >> 8;
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 1a4a861..a525226 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -59,7 +59,10 @@ public:
 	
 private:
 	TownsMidiOutputChannel *allocateOutputChannel(int pri);
-	
+
+	void updateParser();
+	void updateOutputChannels();
+		
 	int randomValue(int para);
 
 	TownsMidiInputChannel **_channels;
@@ -71,7 +74,8 @@ private:
 
 	TownsAudioInterface *_intf;
 
-	uint32 _tickCounter;
+	uint32 _tickCounter1;
+	uint32 _tickCounter2;
 	uint8 _curChan;
 	uint8 _rand;
 	


Commit: 75770ae691438217b7ee613fbfed1f51562d794d
    https://github.com/scummvm/scummvm/commit/75770ae691438217b7ee613fbfed1f51562d794d
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
FM-TOWNS AUDIO: Fix mod wheel setting

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index c28f9a1..0c04044 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -59,18 +59,15 @@ private:
 		uint8 fld_11;
 		uint8 ar1[4];
 		uint8 ar2[4];
-		uint8 fld_1a;
-		uint8 modWheelImpact;
+		int8 modWheelSensitivity;
+		uint8 modWheelState;
 		uint8 fld_1c;
 		uint32 fld_1d;
 		uint32 fld_21;
 		uint32 fld_25;
 		int8 dir;
 		uint32 fld_2a;
-		uint8 fld_2b;
-		uint8 fld_2c;
-		uint8 fld_2d;
-		uint8 modWheel;
+		uint32 fld_2e;
 	} *_stateA;
 
 	struct StateB {
@@ -84,7 +81,7 @@ private:
 	uint32 getEffectState(uint8 type);
 	void initEffect(StateA *a, const uint8 *effectData);
 	void updateEffectOuter3(StateA *a, StateB *b);
-	void updateEffectOuter(StateA *a, StateB *b);
+	int updateEffectOuter(StateA *a, StateB *b);
 	void updateEffect(StateA *a);	
 	int lookupVolume(int a, int b);
 
@@ -306,8 +303,8 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 	b->fld_6 = c & 0x10;
 	b->type = para1[c & 0x0f];
 	a->fld_9 = maxVal[c & 0x0f];
-	a->fld_1a = 0x1f;
-	a->modWheelImpact = b->useModWheel ? _midi->_modWheel >> 2 : 0x1f;
+	a->modWheelSensitivity = 0x1f;
+	a->modWheelState = b->useModWheel ? _midi->_modWheel >> 2 : 0x1f;
 
 	switch (b->type) {
 	case 0:
@@ -318,11 +315,11 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 		break;
 	case 30:
 		a->effectState = 0x1f;
-		b->a->modWheelImpact = 0;
+		b->a->modWheelState = 0;
 		break;
 	case 31:
 		a->effectState = 0;
-		b->a->fld_1a = 0;
+		b->a->modWheelSensitivity = 0;
 		break;
 	default:
 		a->effectState = getEffectState(b->type);
@@ -334,10 +331,10 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 
 void TownsMidiOutputChannel::setModWheel(uint8 value) {
 	if (_stateA[0].numLoop && _stateB[0].type)
-		_stateA[0].modWheel = value >> 2;
+		_stateA[0].modWheelState = value >> 2;
 
 	if (_stateA[1].numLoop && _stateB[1].type)
-		_stateA[1].modWheel = value >> 2;
+		_stateA[1].modWheelState = value >> 2;
 }
 
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
@@ -369,10 +366,12 @@ bool TownsMidiOutputChannel::update() {
 	if (!_midi)
 		return false;
 
-	_duration -= 17;
-	if (_duration <=0) {
-		disconnect();
-		return true;
+	if (_duration) {
+		_duration -= 17;
+		if (_duration <=0) {
+			disconnect();
+			return true;
+		}
 	}
 
 	for (int i = 0; i < 2; i++) {
@@ -433,14 +432,14 @@ void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
 
 }
 
-void TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
-
+int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
+	return 0;
 }
 
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	uint8 c = --a->numLoop;
 	uint16 v = a->ar1[c];
-	int e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->fld_1a]];
+	int e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
 
 	if (v & 0x80)
 		e = _driver->randomValue(e);
@@ -471,8 +470,7 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	a->fld_25 = d / a->fld_1d;
 	a->dir = d < 0 ? -1 : 1;
 	a->fld_2a = d % a->fld_1d;
-
-	a->fld_2b = a->fld_2c = a->fld_2d = a->modWheel = 0;
+	a->fld_2e = 0;
 }
 
 int TownsMidiOutputChannel::lookupVolume(int a, int b) {


Commit: 88896117da13a9222b7bf27bb2890705cf48d5ef
    https://github.com/scummvm/scummvm/commit/88896117da13a9222b7bf27bb2890705cf48d5ef
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
FM-TOWNS AUDIO: Some more midi driver code

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 065532f..3360612 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -467,6 +467,7 @@ int TownsAudioInterfaceIntern::processCommand(int command, va_list &args) {
 	if (command < 0 || command > 81)
 		return 4;
 	
+	Common::StackLock lock(_mutex);
 	return (this->*_intfOpcodes[command])(args);
 }
 
@@ -918,7 +919,7 @@ int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) {
 	left = (left & 0x7e) >> 1;
 	right = (right & 0x7e) >> 1;
 
-	if (chan)
+	if (chan == 12)
 		_outputVolumeFlags |= flags[chanType];
 	else
 		_outputVolumeFlags &= ~flags[chanType];
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 0c04044..7072149 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -53,9 +53,9 @@ private:
 	struct StateA {
 		uint8 numLoop;
 		int32 fld_1;
-		uint32 fld_5;
+		int32 duration;
 		int32 fld_9;
-		int32 effectState;
+		int16 effectState;
 		uint8 fld_11;
 		uint8 ar1[4];
 		uint8 ar2[4];
@@ -63,7 +63,7 @@ private:
 		uint8 modWheelState;
 		uint8 fld_1c;
 		uint32 fld_1d;
-		uint32 fld_21;
+		int32 fld_21;
 		uint32 fld_25;
 		int8 dir;
 		uint32 fld_2a;
@@ -71,14 +71,14 @@ private:
 	} *_stateA;
 
 	struct StateB {
-		uint32 fld_0;
+		int8 inc;
 		uint8 type;
 		uint8 useModWheel;
 		uint8 fld_6;
 		StateA *a;
 	} *_stateB;
 
-	uint32 getEffectState(uint8 type);
+	uint16 getEffectState(uint8 type);
 	void initEffect(StateA *a, const uint8 *effectData);
 	void updateEffectOuter3(StateA *a, StateB *b);
 	int updateEffectOuter(StateA *a, StateB *b);
@@ -292,19 +292,19 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 
 void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effectData) {
 	uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
-	uint8 para1[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
+	uint8 effectType[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
 	
 	StateA *a = &_stateA[index];
 	StateB *b = &_stateB[index];
 
-	b->fld_0 = 0;
+	b->inc = 0;
 	b->useModWheel = c & 0x40;
 	a->fld_11 = c & 0x20;
 	b->fld_6 = c & 0x10;
-	b->type = para1[c & 0x0f];
+	b->type = effectType[c & 0x0f];
 	a->fld_9 = maxVal[c & 0x0f];
-	a->modWheelSensitivity = 0x1f;
-	a->modWheelState = b->useModWheel ? _midi->_modWheel >> 2 : 0x1f;
+	a->modWheelSensitivity = 31;
+	a->modWheelState = b->useModWheel ? _midi->_modWheel >> 2 : 31;
 
 	switch (b->type) {
 	case 0:
@@ -314,7 +314,7 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 		a->effectState = _modulatorTl;
 		break;
 	case 30:
-		a->effectState = 0x1f;
+		a->effectState = 31;
 		b->a->modWheelState = 0;
 		break;
 	case 31:
@@ -392,7 +392,7 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 	return kHighPriority;
 }
 
-uint32 TownsMidiOutputChannel::getEffectState(uint8 type) {
+uint16 TownsMidiOutputChannel::getEffectState(uint8 type) {
 	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
 	
 	if (type == 28)
@@ -415,8 +415,8 @@ uint32 TownsMidiOutputChannel::getEffectState(uint8 type) {
 void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
 	a->numLoop = 1;
 	a->fld_1 = 0;
-	a->fld_1c = 0x1f;
-	a->fld_5 = effectData[0];
+	a->fld_1c = 31;
+	a->duration = effectData[0] * 63;
 	a->ar1[0] = effectData[1];
 	a->ar1[1] = effectData[3];
 	a->ar1[2] = effectData[5];
@@ -429,15 +429,80 @@ void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
 }
 
 void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
+	uint8 f = updateEffectOuter(a, b);
+
+	if (f & 1) {
+		switch (b->type) {
+		case 0:
+			_carrierTl = (a->effectState & 0xff) + b->inc; /*???*/
+			break;
+		case 13:
+			_modulatorTl = (a->effectState & 0xff) + b->inc; /*???*/
+			break;
+		case 30:
+			b->a->modWheelState = b->inc;
+			break;
+		case 31:
+			b->a->modWheelSensitivity = b->inc;
+			break;
+		default:
+			break;
+		}
+	}
 
+	if (f & 2) {
+		if (b->fld_6)
+			keyOn();
+	}
 }
 
 int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
-	return 0;
+	if (a->duration) {
+		a->duration -= 17;
+		if (a->duration <= 0) {
+			a->numLoop = 0;
+			return 0;
+		}
+	} 
+
+	int32 t = a->fld_1 + a->fld_25;
+	
+	a->fld_2e += a->fld_2a;
+	if (a->fld_2e >= a->fld_1d) {
+		a->fld_2e -= a->fld_1d;
+		t += a->dir;
+	}
+
+	int retFlags = 0;
+
+	if (t != a->fld_1 || a->modWheelState != a->fld_1c) {
+		a->fld_1 = t;
+		a->fld_1c = a->modWheelState;
+		t = lookupVolume(t, a->modWheelState);
+		if (t != b->inc)
+			b->inc = t;
+		retFlags |= 1;
+	}
+
+	if (--a->fld_21 != 0)
+		return retFlags;
+
+	if (++a->numLoop > 4) {
+		if (a->fld_11 == 0) {
+			a->numLoop = 0;
+			return retFlags;
+		}
+		a->numLoop = 1;
+		retFlags |= 2;
+	}
+
+	updateEffect(a);
+
+	return retFlags;
 }
 
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
-	uint8 c = --a->numLoop;
+	uint8 c = a->numLoop - 1;
 	uint16 v = a->ar1[c];
 	int e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
 
@@ -461,7 +526,7 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
 			e = a->fld_9 - a->effectState;
 		} else {
 			if (e + a->effectState + 1 <= 0)
-				e = -e;
+				e = -a->effectState;
 		}
 
 		d = e - a->fld_1;
@@ -646,7 +711,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	oc->_fld_c = _instrument[10] & 1;
 	oc->_note = note;
 	oc->_sustainNoteOff = 0;
-	oc->_duration = _instrument[29] * 72;
+	oc->_duration = _instrument[29] * 63;
 	
 	oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
 	if (oc->_modulatorTl > 63)


Commit: 90a300d86cf25ddaa15b8080f3551076a4f6e3ee
    https://github.com/scummvm/scummvm/commit/90a300d86cf25ddaa15b8080f3551076a4f6e3ee
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
FM-TOWNS AUDIO: Improve thread safety

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_audio.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 3360612..51c2000 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -411,13 +411,13 @@ bool TownsAudioInterfaceIntern::checkPluginDriver(TownsAudioInterfacePluginDrive
 	if (_refCount <= 1)
 		return true;
 
-	Common::StackLock lock(_mutex);
-
 	if (_drv) {
 		if (driver && driver != _drv)
 			return false;
 	} else {
+		lock();
 		_drv = driver;
+		unlock();
 	}
 
 	return true;
@@ -467,8 +467,11 @@ int TownsAudioInterfaceIntern::processCommand(int command, va_list &args) {
 	if (command < 0 || command > 81)
 		return 4;
 	
-	Common::StackLock lock(_mutex);
-	return (this->*_intfOpcodes[command])(args);
+	lock();
+	int res = (this->*_intfOpcodes[command])(args);
+	unlock();
+
+	return res;
 }
 
 void TownsAudioInterfaceIntern::setMusicVolume(int volume) {
@@ -539,13 +542,11 @@ void TownsAudioInterfaceIntern::nextTickEx(int32 *buffer, uint32 bufferSize) {
 }
 
 void TownsAudioInterfaceIntern::timerCallbackA() {
-	Common::StackLock lock(_mutex);
 	if (_drv && _ready)
 		_drv->timerCallback(0);
 }
 
 void TownsAudioInterfaceIntern::timerCallbackB() {
-	Common::StackLock lock(_mutex);
 	if (_ready) {
 		if (_drv)
 			_drv->timerCallback(1);
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 7072149..ff14bb1 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -52,7 +52,7 @@ public:
 private:
 	struct StateA {
 		uint8 numLoop;
-		int32 fld_1;
+		uint32 fld_1;
 		int32 duration;
 		int32 fld_9;
 		int16 effectState;
@@ -60,10 +60,10 @@ private:
 		uint8 ar1[4];
 		uint8 ar2[4];
 		int8 modWheelSensitivity;
-		uint8 modWheelState;
+		int8 modWheelState;
 		uint8 fld_1c;
 		uint32 fld_1d;
-		int32 fld_21;
+		uint32 fld_21;
 		uint32 fld_25;
 		int8 dir;
 		uint32 fld_2a;
@@ -71,14 +71,14 @@ private:
 	} *_stateA;
 
 	struct StateB {
-		int8 inc;
+		int16 inc;
 		uint8 type;
 		uint8 useModWheel;
 		uint8 fld_6;
 		StateA *a;
 	} *_stateB;
 
-	uint16 getEffectState(uint8 type);
+	int16 getEffectState(uint8 type);
 	void initEffect(StateA *a, const uint8 *effectData);
 	void updateEffectOuter3(StateA *a, StateB *b);
 	int updateEffectOuter(StateA *a, StateB *b);
@@ -159,7 +159,7 @@ private:
 	int8 _transpose;
 	uint8 _fld_1f;
 	int8 _detune;
-	uint8 _modWheel;
+	int8 _modWheel;
 	uint8 _sustain;
 	uint8 _pitchBendFactor;
 	int16 _pitchBend;
@@ -392,7 +392,7 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 	return kHighPriority;
 }
 
-uint16 TownsMidiOutputChannel::getEffectState(uint8 type) {
+int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
 	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
 	
 	if (type == 28)
@@ -404,7 +404,7 @@ uint16 TownsMidiOutputChannel::getEffectState(uint8 type) {
 	else if (type > 12)
 		type -= 13;
 
-	uint32 res = 0;
+	int32 res = 0;
 	uint8 cs = (_driver->_chanState[chan].get(_effectDefs[type * 4] >> 5) & _effectDefs[type * 4 + 2]) >> _effectDefs[type * 4 + 1];
 	if (_effectDefs[type * 4 + 3])
 		res = _effectDefs[type * 4 + 3] - cs;
@@ -422,7 +422,7 @@ void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
 	a->ar1[2] = effectData[5];
 	a->ar1[3] = effectData[6];
 	a->ar2[0] = effectData[2];
-	a->ar2[1] = effectData[3];
+	a->ar2[1] = effectData[4];
 	a->ar2[2] = 0;
 	a->ar2[3] = effectData[7];
 	updateEffect(a);
@@ -434,10 +434,10 @@ void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
 	if (f & 1) {
 		switch (b->type) {
 		case 0:
-			_carrierTl = (a->effectState & 0xff) + b->inc; /*???*/
+			_carrierTl = a->effectState + b->inc; /*???*/
 			break;
 		case 13:
-			_modulatorTl = (a->effectState & 0xff) + b->inc; /*???*/
+			_modulatorTl = a->effectState + b->inc; /*???*/
 			break;
 		case 30:
 			b->a->modWheelState = b->inc;
@@ -504,7 +504,7 @@ int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	uint8 c = a->numLoop - 1;
 	uint16 v = a->ar1[c];
-	int e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
+	int32 e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
 
 	if (v & 0x80)
 		e = _driver->randomValue(e);
@@ -545,7 +545,7 @@ int TownsMidiOutputChannel::lookupVolume(int a, int b) {
 	if (b == 31)
 		return a;
 
-	if (a > 63)
+	if (a > 63 || a < -63)
 		return ((a + 1) * b) >> 5;
 
 	if (b < 0) {
@@ -760,6 +760,10 @@ void TownsMidiInputChannel::controlChange(byte control, byte value) {
 	case 64:
 		controlSustain(value);
 		break;
+	case 123:
+		while (_outChan)
+			_outChan->disconnect();
+		break;
 	default:
 		break;
 	}
@@ -793,7 +797,7 @@ void TownsMidiInputChannel::controlVolume(byte value) {
 	uint16 v2 = value;
 	if (_chanIndex != 16) {
 		_ctrlVolume = value;
-		v2 = value;
+		v2 = _player->getEffectiveVolume();
 	}
 	_tl = (v1 * v2) >> 7;*/
 
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index 289cc95..e35da91 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -1145,7 +1145,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
 
 	reset();
 
-	Common::StackLock lock(_mutex);
+	lock();
 	uint8 *src_a = _trackPtr = _musicBuffer = data;
 
 	for (uint8 i = 0; i < 3; i++) {
@@ -1176,6 +1176,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
 	_finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0;
 
 	_musicPlaying = (loadPaused ? false : true);
+	unlock();
 }
 
 void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
@@ -1194,16 +1195,17 @@ void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
 		return;
 	}
 
-	Common::StackLock lock(_mutex);
+	lock();
 	_sfxData = _sfxBuffer = data;
 	_sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]);
 	_sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]);
 	_sfxPlaying = true;
 	_finishedSfxFlag = 0;
+	unlock();
 }
 
 void TownsPC98_AudioDriver::reset() {
-	Common::StackLock lock(_mutex);
+	lock();
 
 	_musicPlaying = false;
 	_sfxPlaying = false;
@@ -1230,13 +1232,13 @@ void TownsPC98_AudioDriver::reset() {
 	if (_rhythmChannel)
 		_rhythmChannel->reset();
 #endif
+	unlock();
 }
 
 void TownsPC98_AudioDriver::fadeStep() {
 	if (!_musicPlaying)
 		return;
 
-	Common::StackLock lock(_mutex);
 	for (int j = 0; j < _numChan; j++) {
 		if (_updateChannelsFlag & _channels[j]->_idFlag)
 			_channels[j]->fadeStep();
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 57ab8d9..9412538 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -837,8 +837,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) :
 	_hasPercussion(type == kType86 ? true : false),
 	_oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0),
 	 _rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()),
-	_volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255),
-	_regProtectionFlag(false), _ready(false) {
+	_volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _externLock(0), _ready(false) {
 
 	memset(&_timers[0], 0, sizeof(ChipTimer));
 	memset(&_timers[1], 0, sizeof(ChipTimer));
@@ -931,9 +930,9 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
 	if (_regProtectionFlag || !_ready)
 		return;
 
-	static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
+	lock();
 
-	Common::StackLock lock(_mutex);
+	static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
 
 	uint8 h = regAddress & 0xf0;
 	uint8 l = (regAddress & 0x0f);
@@ -1081,6 +1080,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
 		if (l == 0) {
 			c->frqTemp = (c->frqTemp & 0xff00) | value;
 			c->updateEnvelopeParameters = true;
+			c->fmIndex = (c->frqTemp >> 4 & 0x7f);
 			for (int i = 0; i < 4; i++)
 				co[i]->frequency(c->frqTemp);
 		} else if (l == 4) {
@@ -1112,18 +1112,17 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
 	default:
 		warning("TownsPC98_FmSynth: UNKNOWN ADDRESS %d", regAddress);
 	}
+	unlock();
 }
 
 int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
-	Common::StackLock lock(_mutex);
-
 	memset(buffer, 0, sizeof(int16) * numSamples);
 	int32 *tmp = new int32[numSamples];
 	int32 *tmpStart = tmp;
 	memset(tmp, 0, sizeof(int32) * numSamples);
 	int32 samplesLeft = numSamples >> 1;
 
-	while (_ready && samplesLeft) {
+	while (_ready && !_externLock && samplesLeft) {
 		int32 render = samplesLeft;
 
 		for (int i = 0; i < 2; i++) {
@@ -1173,6 +1172,7 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
 	}
 
 	delete[] tmpStart;
+
 	return numSamples;
 }
 
@@ -1187,7 +1187,7 @@ uint8 TownsPC98_FmSynth::readSSGStatus() {
 }
 
 void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) {
-	Common::StackLock lock(_mutex);
+	lock();
 	_volumeA = CLIP<uint16>(volA, 0, Audio::Mixer::kMaxMixerVolume);
 	_volumeB = CLIP<uint16>(volB, 0, Audio::Mixer::kMaxMixerVolume);
 	if (_ssg)
@@ -1196,10 +1196,11 @@ void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) {
 	if (_prc)
 		_prc->setVolumeIntern(_volumeA, _volumeB);
 #endif
+	unlock();
 }
 
 void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) {
-	Common::StackLock lock(_mutex);
+	lock();
 	_volMaskA = channelMaskA;
 	_volMaskB = channelMaskB;
 	if (_ssg)
@@ -1208,6 +1209,17 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB
 	if (_prc)
 		_prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG));
 #endif
+	unlock();
+}
+
+void TownsPC98_FmSynth::lock() {
+	_mutex.lock();
+	_externLock++;
+}
+
+void  TownsPC98_FmSynth::unlock() {
+	_mutex.unlock();
+	_externLock--;
 }
 
 void TownsPC98_FmSynth::generateTables() {
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index 5edd1a3..f1494b6 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -102,11 +102,13 @@ protected:
 	void setVolumeIntern(int volA, int volB);
 	void setVolumeChannelMasks(int channelMaskA, int channelMaskB);
 
+	void lock();
+	void unlock();
+
 	const int _numChan;
 	const int _numSSG;
 	const bool _hasPercussion;
 
-	Common::Mutex _mutex;
 private:
 	void generateTables();
 	void nextTick(int32 *buffer, uint32 bufferSize);
@@ -124,6 +126,7 @@ private:
 		}
 
 		uint16 frqTemp;
+		uint8 fmIndex;
 		bool enableLeft;
 		bool enableRight;
 		bool updateEnvelopeParameters;
@@ -179,6 +182,9 @@ private:
 	Audio::Mixer *_mixer;
 	Audio::SoundHandle _soundHandle;
 
+	int _externLock;
+	Common::Mutex _mutex;
+
 #ifndef DISABLE_PC98_RHYTHM_CHANNEL
 	static const uint8 _percussionData[];
 #endif


Commit: 8fb5906117c67f4265e868b33aa343698bceac73
    https://github.com/scummvm/scummvm/commit/8fb5906117c67f4265e868b33aa343698bceac73
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:31-07:00

Commit Message:
FM-TOWNS AUDIO: Some midi code fixes and some renaming

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_audio.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.h
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.h
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
    engines/kyra/sound_towns.cpp
    engines/scumm/player_towns.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 51c2000..6679e65 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -163,8 +163,10 @@ private:
 	int intf_fmReset(va_list &args);
 	int intf_setOutputVolume(va_list &args);
 	int intf_resetOutputVolume(va_list &args);
-	int intf_updateOutputVolume(va_list &args);
+	int intf_setOutputMute(va_list &args);
 	int intf_cdaToggle(va_list &args);
+	int intf_getOutputVolume(va_list &args);
+	int intf_getOutputMute(va_list &args);
 	int intf_pcmUpdateEnvelopeGenerator(va_list &args);
 
 	int intf_notImpl(va_list &args);
@@ -344,13 +346,13 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 		// 68
 		INTCB(resetOutputVolume),
 		INTCB(notImpl),
-		INTCB(updateOutputVolume),
+		INTCB(setOutputMute),
 		INTCB(notImpl),
 		// 72
 		INTCB(notImpl),
 		INTCB(cdaToggle),
-		INTCB(notImpl),
-		INTCB(notImpl),
+		INTCB(getOutputVolume),
+		INTCB(getOutputMute),
 		// 76
 		INTCB(notImpl),
 		INTCB(notImpl),
@@ -947,7 +949,7 @@ int TownsAudioInterfaceIntern::intf_resetOutputVolume(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterfaceIntern::intf_updateOutputVolume(va_list &args) {
+int TownsAudioInterfaceIntern::intf_setOutputMute(va_list &args) {
 	int flags = va_arg(args, int);
 	_outputMuteFlags = flags & 3;
 	updateOutputVolume();
@@ -960,6 +962,14 @@ int TownsAudioInterfaceIntern::intf_cdaToggle(va_list &args) {
 	return 0;
 }
 
+int TownsAudioInterfaceIntern::intf_getOutputVolume (va_list &args) {
+	return 0;
+}
+
+int TownsAudioInterfaceIntern::intf_getOutputMute (va_list &args) {
+	return 0;
+}
+
 int TownsAudioInterfaceIntern::intf_pcmUpdateEnvelopeGenerator(va_list &args) {
 	for (int i = 0; i < 8; i++)
 		pcmUpdateEnvelopeGenerator(i);
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index cb6cfc5..f161228 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -27,7 +27,7 @@
 
 TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0),
 	_assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0),
-	_tDetune(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0),
+	_tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0),
 	_tempoControlMode(0) {
 	_para[0] = _para[1] = 0;
 	_intf = new TownsAudioInterface(mixer, this);
@@ -44,7 +44,7 @@ TownsEuphonyDriver::~TownsEuphonyDriver() {
 	delete[] _tMode;
 	delete[] _tOrdr;
 	delete[] _tLevel;
-	delete[] _tDetune;
+	delete[] _tTranspose;
 }
 
 bool TownsEuphonyDriver::init() {
@@ -59,7 +59,7 @@ bool TownsEuphonyDriver::init() {
 	delete[] _tMode;
 	delete[] _tOrdr;
 	delete[] _tLevel;
-	delete[] _tDetune;
+	delete[] _tTranspose;
 
 	_activeChannels = new int8[16];
 	_sustainChannels = new int8[16];
@@ -70,7 +70,7 @@ bool TownsEuphonyDriver::init() {
 	_tMode = new uint8[32];
 	_tOrdr = new uint8[32];
 	_tLevel = new int8[32];
-	_tDetune = new int8[32];
+	_tTranspose = new int8[32];
 
 	reset();
 
@@ -250,11 +250,11 @@ int TownsEuphonyDriver::configChan_adjustVolume(int tableEntry, int val) {
 	return 0;
 }
 
-int TownsEuphonyDriver::configChan_setDetune(int tableEntry, int val) {
+int TownsEuphonyDriver::configChan_setTranspose(int tableEntry, int val) {
 	if (tableEntry > 31)
 		return 3;
 	if (val <= 40)
-		_tDetune[tableEntry] = (int8)(val & 0xff);
+		_tTranspose[tableEntry] = (int8)(val & 0xff);
 	return 0;
 }
 
@@ -325,7 +325,7 @@ void TownsEuphonyDriver::resetTables() {
 	for (int i = 0; i < 32; i++)
 		_tOrdr[i] = i & 0x0f;
 	memset(_tLevel, 0, 32);
-	memset(_tDetune, 0, 32);
+	memset(_tTranspose, 0, 32);
 }
 
 void TownsEuphonyDriver::resetTempo() {
@@ -672,7 +672,7 @@ bool TownsEuphonyDriver::evtSetupNote() {
 	uint8 velo = _musicPos[5];
 
 	sendEvent(mode, evt);
-	sendEvent(mode, applyDetune(note));
+	sendEvent(mode, applyTranspose(note));
 	sendEvent(mode, applyVolumeAdjust(velo));
 
 	jumpNextLoop();
@@ -712,7 +712,7 @@ bool TownsEuphonyDriver::evtPolyphonicAftertouch() {
 	uint8 mode = _tMode[_musicPos[1]];
 
 	sendEvent(mode, evt);
-	sendEvent(mode, applyDetune(_musicPos[4]));
+	sendEvent(mode, applyTranspose(_musicPos[4]));
 	sendEvent(mode, _musicPos[5]);
 
 	return false;
@@ -780,8 +780,8 @@ bool TownsEuphonyDriver::evtModeOrdrChange() {
 	return false;
 }
 
-uint8 TownsEuphonyDriver::applyDetune(uint8 in) {
-	int out = _tDetune[_musicPos[1]];
+uint8 TownsEuphonyDriver::applyTranspose(uint8 in) {
+	int out = _tTranspose[_musicPos[1]];
 	if (!out)
 		return in;
 	out += (in & 0x7f);
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index ae36d12..6b30bfb 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -59,7 +59,7 @@ public:
 	int configChan_setMode(int tableEntry, int val);
 	int configChan_remap(int tableEntry, int val);
 	int configChan_adjustVolume(int tableEntry, int val);
-	int configChan_setDetune(int tableEntry, int val);
+	int configChan_setTranspose(int tableEntry, int val);
 
 	int assignChannel(int chan, int tableEntry);
 
@@ -111,7 +111,7 @@ private:
 		return false;
 	}
 
-	uint8 applyDetune(uint8 in);
+	uint8 applyTranspose(uint8 in);
 	uint8 applyVolumeAdjust(uint8 in);
 
 	void sendNoteOff();
@@ -136,7 +136,7 @@ private:
 	uint8 *_tMode;
 	uint8 *_tOrdr;
 	int8 *_tLevel;
-	int8 *_tDetune;
+	int8 *_tTranspose;
 
 	struct DlEvent {
 		uint8 evt;
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index ff14bb1..ac6a89f 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -24,6 +24,7 @@
 
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 #include "common/textconsole.h"
+#include "common/system.h"
 
 class TownsMidiOutputChannel {
 friend class TownsMidiInputChannel;
@@ -33,8 +34,8 @@ public:
 
 	void noteOn(uint8 msb, uint16 lsb);
 	void noteOnPitchBend(uint8 msb, uint16 lsb);
-	void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2);
-	void setupEffects(int index, uint8 c, const uint8 *effectData);
+	void setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara);
+	void setupEffects(int index, uint8 flags, const uint8 *effectData);
 	void setModWheel(uint8 value);
 	
 	void connect(TownsMidiInputChannel *chan);
@@ -52,26 +53,26 @@ public:
 private:
 	struct StateA {
 		uint8 numLoop;
-		uint32 fld_1;
+		int32 fld_1;
 		int32 duration;
-		int32 fld_9;
-		int16 effectState;
+		uint32 fld_9;
+		int32 effectState;
 		uint8 fld_11;
 		uint8 ar1[4];
 		uint8 ar2[4];
 		int8 modWheelSensitivity;
 		int8 modWheelState;
-		uint8 fld_1c;
-		uint32 fld_1d;
+		uint8 modWheelLast;
+		uint16 fld_1d;
 		uint32 fld_21;
-		uint32 fld_25;
+		int32 fld_25;
 		int8 dir;
 		uint32 fld_2a;
 		uint32 fld_2e;
 	} *_stateA;
 
 	struct StateB {
-		int16 inc;
+		int32 inc;
 		uint8 type;
 		uint8 useModWheel;
 		uint8 fld_6;
@@ -99,7 +100,7 @@ private:
 	uint8 _carrierTl;
 	uint8 _modulatorTl;
 	uint8 _sustainNoteOff;
-	int32 _duration;
+	int16 _duration;
 	
 	uint16 _freq;
 	int16 _freqAdjust;
@@ -237,7 +238,7 @@ void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) {
 	keyOnSetFreq(_freq + _freqAdjust);
 }
 
-void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 vol2) {
+void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara) {
 	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
 	// since it is just a modified AdLib driver. It also uses AdLib programs.
 	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
@@ -248,10 +249,10 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	uint8 chan = _chanMap[_chan];	
 
 	uint8 mulAmsFms1 = _driver->_chanState[chan].mulAmsFms = data[0];
-	uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - vol1;
+	uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - mLevelPara;
 	uint8 attDec1 = _driver->_chanState[chan].attDec = ~data[2];
 	uint8 sus1 = _driver->_chanState[chan].sus = ~data[3];
-	uint8 unk1 = _driver->_chanState[chan].unk2 = data[4];
+	_driver->_chanState[chan].unk2 = data[4];
 	chan += 3;
 
 	out(0x30, mul[mulAmsFms1 & 0x0f]);
@@ -262,10 +263,10 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	out(0x80, sus1);
 
 	uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = data[5];
-	uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - vol2;
+	uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - tLevelPara;
 	uint8 attDec2 = _driver->_chanState[chan].attDec = ~data[7];
 	uint8 sus2 = _driver->_chanState[chan].sus = ~data[8];
-	uint8 unk2 = _driver->_chanState[chan].unk2 = data[9];
+	_driver->_chanState[chan].unk2 = data[9];
 
 	uint8 mul2 = mul[mulAmsFms2 & 0x0f];
 	tl2 = (tl2 & 0x3f) + 15;
@@ -290,7 +291,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v
 	out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5));
 }
 
-void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effectData) {
+void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) {
 	uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
 	uint8 effectType[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
 	
@@ -298,11 +299,11 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effec
 	StateB *b = &_stateB[index];
 
 	b->inc = 0;
-	b->useModWheel = c & 0x40;
-	a->fld_11 = c & 0x20;
-	b->fld_6 = c & 0x10;
-	b->type = effectType[c & 0x0f];
-	a->fld_9 = maxVal[c & 0x0f];
+	b->useModWheel = flags & 0x40;
+	a->fld_11 = flags & 0x20;
+	b->fld_6 = flags & 0x10;
+	b->type = effectType[flags & 0x0f];
+	a->fld_9 = maxVal[flags & 0x0f];
 	a->modWheelSensitivity = 31;
 	a->modWheelState = b->useModWheel ? _midi->_modWheel >> 2 : 31;
 
@@ -368,8 +369,9 @@ bool TownsMidiOutputChannel::update() {
 
 	if (_duration) {
 		_duration -= 17;
-		if (_duration <=0) {
+		if (_duration <= 0) {
 			disconnect();
+			//_duration = 0;
 			return true;
 		}
 	}
@@ -415,7 +417,7 @@ int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
 void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
 	a->numLoop = 1;
 	a->fld_1 = 0;
-	a->fld_1c = 31;
+	a->modWheelLast = 31;
 	a->duration = effectData[0] * 63;
 	a->ar1[0] = effectData[1];
 	a->ar1[1] = effectData[3];
@@ -475,16 +477,17 @@ int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
 
 	int retFlags = 0;
 
-	if (t != a->fld_1 || a->modWheelState != a->fld_1c) {
+	if (t != a->fld_1 || a->modWheelState != a->modWheelLast) {
 		a->fld_1 = t;
-		a->fld_1c = a->modWheelState;
+		a->modWheelLast = a->modWheelState;
 		t = lookupVolume(t, a->modWheelState);
 		if (t != b->inc)
 			b->inc = t;
 		retFlags |= 1;
 	}
 
-	if (--a->fld_21 != 0)
+	--a->fld_21;/*???*/
+	if (a->fld_21 != 0)
 		return retFlags;
 
 	if (++a->numLoop > 4) {
@@ -504,7 +507,7 @@ int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	uint8 c = a->numLoop - 1;
 	uint16 v = a->ar1[c];
-	int32 e = _effectData[_driver->_chanOutputLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
+	int32 e = _effectData[_driver->_chanEffectLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
 
 	if (v & 0x80)
 		e = _driver->randomValue(e);
@@ -515,7 +518,7 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	a->fld_1d = a->fld_21 = e;
 	int32 d = 0;
 
-	if (c + 1 != 3) {
+	if (c != 2) {
 		v = a->ar2[c];
 		e = lookupVolume(a->fld_9, (v & 0x7f) - 31);
 
@@ -533,7 +536,8 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	}
 
 	a->fld_25 = d / a->fld_1d;
-	a->dir = d < 0 ? -1 : 1;
+	a->dir = (d < 0) ? -1 : 1;
+	d *= a->dir;
 	a->fld_2a = d % a->fld_1d;
 	a->fld_2e = 0;
 }
@@ -550,14 +554,14 @@ int TownsMidiOutputChannel::lookupVolume(int a, int b) {
 
 	if (b < 0) {
 		if (a < 0)			
-			return _driver->_chanOutputLevel[(-a << 5) - b];
+			return _driver->_chanEffectLevel[((-a) << 5) - b];
 		else
-			return -_driver->_chanOutputLevel[(a << 5) - b];
+			return -_driver->_chanEffectLevel[(a << 5) - b];
 	} else {
 		if (a < 0)			
-			return -_driver->_chanOutputLevel[(-a << 5) + b];
+			return -_driver->_chanEffectLevel[((-a) << 5) + b];
 		else
-			return _driver->_chanOutputLevel[(-a << 5) + b];
+			return _driver->_chanEffectLevel[((-a) << 5) + b];
 	}
 }
 
@@ -713,15 +717,15 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 63;
 	
-	oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+	oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
 	if (oc->_modulatorTl > 63)
 		oc->_modulatorTl = 63;
 
-	oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+	oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
 	if (oc->_carrierTl > 63)
 		oc->_carrierTl = 63;
 
-	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
+	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
 	oc->noteOn(note + _transpose, _freqLSB);
 
 	if (_instrument[11] & 0x80)
@@ -838,6 +842,19 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 
 MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _tickCounter1(0), _tickCounter2(0), _curChan(0), _rand(1), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
+}
+
+MidiDriver_TOWNS::~MidiDriver_TOWNS() {
+	close();
+	delete _intf;
+}
+
+int MidiDriver_TOWNS::open() {
+	if (_open)
+		return MERR_ALREADY_OPEN;
+
+	if (!_intf->init())
+		return MERR_CANNOT_CONNECT;
 
 	_channels = new TownsMidiInputChannel*[32];
 	for (int i = 0; i < 32; i++)
@@ -849,38 +866,13 @@ MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerP
 
 	_chanState = new TownsMidiChanState[32];
 
-	_chanOutputLevel = new uint8[2048];
+	_chanEffectLevel = new uint8[2048];
 	for (int i = 0; i < 64; i++) {
 		for (int ii = 0; ii < 32; ii++)
-			_chanOutputLevel[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
+			_chanEffectLevel[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
 	}
 	for (int i = 0; i < 64; i++)
-		_chanOutputLevel[i << 5] = 0;
-}
-
-MidiDriver_TOWNS::~MidiDriver_TOWNS() {
-	close();
-	delete _intf;
-	setTimerCallback(0, 0);
-
-	for (int i = 0; i < 32; i++)
-		delete _channels[i];
-	delete[] _channels;
-
-	for (int i = 0; i < 6; i++)
-		delete _out[i];
-	delete[] _out;
-
-	delete[] _chanState;
-	delete[] _chanOutputLevel;
-}
-
-int MidiDriver_TOWNS::open() {
-	if (_open)
-		return MERR_ALREADY_OPEN;
-
-	if (!_intf->init())
-		return MERR_CANNOT_CONNECT;
+		_chanEffectLevel[i << 5] = 0;
 
 	_intf->callback(0);
 
@@ -897,10 +889,38 @@ int MidiDriver_TOWNS::open() {
 }
 
 void MidiDriver_TOWNS::close() {
+	if (!_open)
+		return;
+
 	_open = false;
+
+	setTimerCallback(0, 0);
+	g_system->delayMillis(20);
+	
+	if (_channels) {
+		for (int i = 0; i < 32; i++)
+			delete _channels[i];
+		delete[] _channels;
+	}
+	_channels = 0;
+
+	if (_out) {
+		for (int i = 0; i < 6; i++)
+			delete _out[i];
+		delete[] _out;
+	}
+	_out = 0;
+
+	delete[] _chanState;
+	_chanState = 0;
+	delete[] _chanEffectLevel;
+	_chanEffectLevel = 0;
 }
 
 void MidiDriver_TOWNS::send(uint32 b) {
+	if (!_open)
+		return;
+
 	byte param2 = (b >> 16) & 0xFF;
 	byte param1 = (b >> 8) & 0xFF;
 	byte cmd = b & 0xF0;
@@ -945,6 +965,9 @@ uint32 MidiDriver_TOWNS::getBaseTempo() {
 }
 
 MidiChannel *MidiDriver_TOWNS::allocateChannel() {
+	if (!_open)
+		return 0;
+
 	for (int i = 0; i < 32; ++i) {		
 		TownsMidiInputChannel *chan = _channels[i];
 		if (chan->allocate())
@@ -978,6 +1001,23 @@ void MidiDriver_TOWNS::timerCallback(int timerId) {
 	}
 }
 
+void MidiDriver_TOWNS::updateParser() {
+	if (_timerProc)
+		_timerProc(_timerProcPara);
+}
+
+void MidiDriver_TOWNS::updateOutputChannels() {
+	_tickCounter2 += 10000;
+	while (_tickCounter2 >= 16667) {
+		_tickCounter2 -= 16667;
+		for (int i = 0; i < 6; i++) {
+			TownsMidiOutputChannel *oc = _out[i];
+			if (oc->update())
+				return;
+		}
+	}
+}
+
 TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 	TownsMidiOutputChannel *res = 0;
 
@@ -1001,23 +1041,6 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 	return res;
 }
 
-void MidiDriver_TOWNS::updateParser() {
-	if (_timerProc)
-		_timerProc(_timerProcPara);
-}
-
-void MidiDriver_TOWNS::updateOutputChannels() {
-	_tickCounter2 += 10000;
-	while (_tickCounter2 >= 16667) {
-		_tickCounter2 -= 16667;
-		for (int i = 0; i < 6; i++) {
-			TownsMidiOutputChannel *oc = _out[i];
-			if (oc->update())
-				return;
-		}
-	}
-}
-
 int MidiDriver_TOWNS::randomValue(int para) {
 	_rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1);
 	return (_rand * para) >> 8;
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index a525226..5164e04 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -43,25 +43,22 @@ public:
 	int open();
 	bool isOpen() const { return _open; }
 	void close();
+
 	void send(uint32 b);
-	//virtual uint32 property(int prop, uint32 param) { return 0; }
-	//virtual void sysEx(const byte *msg, uint16 length) { }
-	//virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
-	//virtual void metaEvent(byte type, byte *data, uint16 length) { }
+
 	void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
+
 	uint32 getBaseTempo();
 	MidiChannel *allocateChannel();
 	MidiChannel *getPercussionChannel();
 
 	void timerCallback(int timerId);
 
-	TownsAudioInterface *intf() { return _intf; }
-	
 private:
-	TownsMidiOutputChannel *allocateOutputChannel(int pri);
-
 	void updateParser();
 	void updateOutputChannels();
+
+	TownsMidiOutputChannel *allocateOutputChannel(int pri);
 		
 	int randomValue(int para);
 
@@ -81,7 +78,7 @@ private:
 	
 	bool _open;
 
-	uint8 *_chanOutputLevel;
+	uint8 *_chanEffectLevel;
 };
 
 #endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 9412538..263986e 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -837,7 +837,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) :
 	_hasPercussion(type == kType86 ? true : false),
 	_oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0),
 	 _rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()),
-	_volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _externLock(0), _ready(false) {
+	_volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _lock(0), _ready(false) {
 
 	memset(&_timers[0], 0, sizeof(ChipTimer));
 	memset(&_timers[1], 0, sizeof(ChipTimer));
@@ -1121,8 +1121,9 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
 	int32 *tmpStart = tmp;
 	memset(tmp, 0, sizeof(int32) * numSamples);
 	int32 samplesLeft = numSamples >> 1;
+	_lock |= 0x10000;
 
-	while (_ready && !_externLock && samplesLeft) {
+	while (_ready && !(_lock & 0xffff) && samplesLeft) {
 		int32 render = samplesLeft;
 
 		for (int i = 0; i < 2; i++) {
@@ -1171,6 +1172,7 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
 		tmp += (render << 1);
 	}
 
+	_lock &= ~0x10000;
 	delete[] tmpStart;
 
 	return numSamples;
@@ -1178,6 +1180,8 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
 
 void TownsPC98_FmSynth::deinit() {
 	_ready = false;
+	while (_lock)
+		g_system->delayMillis(20);
 	_mixer->stopHandle(_soundHandle);
 	_timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
 }
@@ -1214,12 +1218,12 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB
 
 void TownsPC98_FmSynth::lock() {
 	_mutex.lock();
-	_externLock++;
+	_lock++;
 }
 
 void  TownsPC98_FmSynth::unlock() {
 	_mutex.unlock();
-	_externLock--;
+	_lock--;
 }
 
 void TownsPC98_FmSynth::generateTables() {
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index f1494b6..cbf856c 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -182,7 +182,7 @@ private:
 	Audio::Mixer *_mixer;
 	Audio::SoundHandle _soundHandle;
 
-	int _externLock;
+	int _lock;
 	Common::Mutex _mutex;
 
 #ifndef DISABLE_PC98_RHYTHM_CHANNEL
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 5f4e5a5..9a9892c 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -338,7 +338,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
 	for (int i = 0; i < 32; i++)
 		_driver->configChan_adjustVolume(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->configChan_setDetune(i, *src++);
+		_driver->configChan_setTranspose(i, *src++);
 
 	src = _musicTrackData + 1748;
 	for (int i = 0; i < 6; i++)
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index f3b790a..5d49478 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -508,7 +508,7 @@ void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) {
 	for (int i = 0; i < 32; i++)
 		_driver->configChan_adjustVolume(i, *src++);
 	for (int i = 0; i < 32; i++)
-		_driver->configChan_setDetune(i, *src++);
+		_driver->configChan_setTranspose(i, *src++);
 
 	src += 8;
 	for (int i = 0; i < 6; i++)


Commit: baaae9d97a92da28ec8d8293a391cbca955cbbea
    https://github.com/scummvm/scummvm/commit/baaae9d97a92da28ec8d8293a391cbca955cbbea
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
SCUMM: Add missing imuse feature

This adds an extra detune parameter which is assigned via sysex code 0.
Most tracks don't use this (= assign a value of 0), so it isn't really a
very noticeable feature.

Changed paths:
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/scumm.cpp
    engines/scumm/sound.cpp



diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index d6cf2e1..6ab71c2 100644
--- a/engines/scumm/imuse/sysex_scumm.cpp
+++ b/engines/scumm/imuse/sysex_scumm.cpp
@@ -72,6 +72,7 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
 			part->volume((p[5] & 0x0F) << 4 |(p[6] & 0x0F));
 			part->set_pan((p[7] & 0x0F) << 4 | (p[8] & 0x0F));
 			part->_percussion = player->_isMIDI ? ((p[9] & 0x08) > 0) : false;
+			part->set_detune((p[11] & 0x0F) << 4 | (p[12] & 0x0F));
 			part->pitchBendFactor((p[13] & 0x0F) << 4 | (p[14] & 0x0F));
 			if (part->_percussion) {
 				if (part->_mc) {
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c37ff25..e8dd6cb 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1833,12 +1833,8 @@ void ScummEngine::setupMusic(int midi) {
 		if (nativeMidiDriver != NULL && _native_mt32)
 			nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 		bool multi_midi = ConfMan.getBool("multi_midi") && _musicType != MDT_NONE && (midi & MDT_ADLIB);
-		if (_musicType == MDT_ADLIB || multi_midi) {
-			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB));
-			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
-		}
-		if (_musicType == MDT_TOWNS) {
-			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_TOWNS));
+		if (_musicType == MDT_ADLIB || MDT_TOWNS || multi_midi) {
+			adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
 			adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
 		}
 
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 9d14c16..c22da8e 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -1118,7 +1118,7 @@ int ScummEngine::readSoundResource(ResId idx) {
 				break;
 			case MKTAG('A','D','L',' '):
 				pri = 1;
-				if (_musicType == MDT_ADLIB)
+				if (_musicType == MDT_ADLIB || _musicType == MDT_TOWNS)
 					pri = 10;
 				break;
 			case MKTAG('A','M','I',' '):


Commit: c6f13d187e31d5642f4a789a2e1eb2b5f2708775
    https://github.com/scummvm/scummvm/commit/c6f13d187e31d5642f4a789a2e1eb2b5f2708775
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Fix some midi driver bugs

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index ac6a89f..9fa6a8c 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -44,8 +44,8 @@ public:
 	bool update();
 
 	enum CheckPriorityStatus {
-		kDisconnected = -3,
-		kHighPriority = -2
+		kDisconnected = -2,
+		kHighPriority = -1
 	};
 
 	int checkPriority(int pri);
@@ -55,14 +55,14 @@ private:
 		uint8 numLoop;
 		int32 fld_1;
 		int32 duration;
-		uint32 fld_9;
+		uint16 fld_9;
 		int32 effectState;
 		uint8 fld_11;
 		uint8 ar1[4];
 		uint8 ar2[4];
 		int8 modWheelSensitivity;
 		int8 modWheelState;
-		uint8 modWheelLast;
+		int8 modWheelLast;
 		uint16 fld_1d;
 		uint32 fld_21;
 		int32 fld_25;
@@ -91,10 +91,10 @@ private:
 	void keyOnSetFreq(uint16 frq);
 	void out(uint8 reg, uint8 val);
 
-	TownsMidiInputChannel *_midi;
+	TownsMidiInputChannel *_in;
 	TownsMidiOutputChannel *_prev;
 	TownsMidiOutputChannel *_next;
-	uint8 _fld_c;
+	uint8 _adjustModTl;
 	uint8 _chan;
 	uint8 _note;
 	uint8 _carrierTl;
@@ -145,7 +145,7 @@ private:
 
 	void releasePedal();
 
-	TownsMidiOutputChannel *_outChan;
+	TownsMidiOutputChannel *_out;
 	
 	uint8 *_instrument;
 	uint8 _prg;
@@ -215,11 +215,13 @@ uint8 TownsMidiChanState::get(uint8 type) {
 }
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
+	_in(0), _prev(0), _next(0), _adjustModTl(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
 	_stateA = new StateA[2];
 	memset(_stateA, 0, 2 * sizeof(StateA));
 	_stateB = new StateB[2];
 	memset(_stateB, 0, 2 * sizeof(StateB));
+	_stateB[0].a = &_stateA[1];
+	_stateB[1].a = &_stateA[0];
 }
 
 TownsMidiOutputChannel::~TownsMidiOutputChannel() {
@@ -259,7 +261,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
 	out(0x40, (tl1 & 0x3f) + 15);
 	out(0x50, ((attDec1 >> 4) << 1) | ((attDec1 >> 4) & 1));
 	out(0x60, ((attDec1 << 1) | (attDec1 & 1)) & 0x1f);
-	out(0x70, (mulAmsFms1 & 0x20) ^ 0x20 ? ((sus1 & 0x0f) << 1) | 1: 0);
+	out(0x70, (mulAmsFms1 & 0x20) ^ 0x20 ? (((sus1 & 0x0f) << 1) | 1) : 0);
 	out(0x80, sus1);
 
 	uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = data[5];
@@ -272,7 +274,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
 	tl2 = (tl2 & 0x3f) + 15;
 	uint8 ar2 = ((attDec2 >> 4) << 1) | ((attDec2 >> 4) & 1);
 	uint8 dec2 = ((attDec2 << 1) | (attDec2 & 1)) & 0x1f;
-	uint8 sus2r = (mulAmsFms2 & 0x20) ^ 0x20 ? ((sus2 & 0x0f) << 1) | 1: 0;
+	uint8 sus2r = (mulAmsFms2 & 0x20) ^ 0x20 ? (((sus2 & 0x0f) << 1) | 1) : 0;
 
 	for (int i = 4; i < 16; i += 4) {
 		out(0x30 + i, mul2);
@@ -284,11 +286,12 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
 	}
 
 	_driver->_chanState[chan].fgAlg = data[10];
+
 	uint8 alg = 5 + 2 * (data[10] & 1);
 	uint8 fb = 4 * (data[10] & 0x0e);
 	out(0xb0, fb | alg);
 	uint8 t = mulAmsFms1 | mulAmsFms2;
-	out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5));
+	out(0xb4, (0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5)));
 }
 
 void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) {
@@ -305,7 +308,7 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *e
 	b->type = effectType[flags & 0x0f];
 	a->fld_9 = maxVal[flags & 0x0f];
 	a->modWheelSensitivity = 31;
-	a->modWheelState = b->useModWheel ? _midi->_modWheel >> 2 : 31;
+	a->modWheelState = b->useModWheel ? _in->_modWheel >> 2 : 31;
 
 	switch (b->type) {
 	case 0:
@@ -341,16 +344,18 @@ void TownsMidiOutputChannel::setModWheel(uint8 value) {
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
 	if (!chan)
 		return;
-	_midi = chan;
-	_next = chan->_outChan;
+
+	_in = chan;
+	_next = chan->_out;
 	_prev = 0;
-	chan->_outChan = this;
+	chan->_out = this;
 	if (_next)
 		_next->_prev = this;
 }
 
 void TownsMidiOutputChannel::disconnect() {
 	keyOff();
+	
 	TownsMidiOutputChannel *p = _prev;
 	TownsMidiOutputChannel *n = _next;
 
@@ -359,19 +364,18 @@ void TownsMidiOutputChannel::disconnect() {
 	if (p)
 		p->_next = n;
 	else
-		_midi->_outChan = n;
-	_midi = 0;
+		_in->_out = n;
+	_in = 0;
 }
 
 bool TownsMidiOutputChannel::update() {
-	if (!_midi)
+	if (!_in)
 		return false;
 
 	if (_duration) {
 		_duration -= 17;
 		if (_duration <= 0) {
 			disconnect();
-			//_duration = 0;
 			return true;
 		}
 	}
@@ -385,11 +389,11 @@ bool TownsMidiOutputChannel::update() {
 }
 
 int TownsMidiOutputChannel::checkPriority(int pri) {
-	if (!_midi)
+	if (!_in)
 		return kDisconnected;
 
-	if (!_next && pri >= _midi->_priority)
-		return _midi->_priority;
+	if (!_next && pri >= _in->_priority)
+		return _in->_priority;
 
 	return kHighPriority;
 }
@@ -486,12 +490,11 @@ int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
 		retFlags |= 1;
 	}
 
-	--a->fld_21;/*???*/
-	if (a->fld_21 != 0)
+	if (--a->fld_21)
 		return retFlags;
 
 	if (++a->numLoop > 4) {
-		if (a->fld_11 == 0) {
+		if (!a->fld_11) {
 			a->numLoop = 0;
 			return retFlags;
 		}
@@ -506,7 +509,7 @@ int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
 
 void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	uint8 c = a->numLoop - 1;
-	uint16 v = a->ar1[c];
+	uint8 v = a->ar1[c];
 	int32 e = _effectData[_driver->_chanEffectLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
 
 	if (v & 0x80)
@@ -665,7 +668,7 @@ const uint16 TownsMidiOutputChannel::_freqLSB[] = {
 	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B
 };
 
-TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _outChan(0), _prg(0), _chanIndex(chanIndex),
+TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _out(0), _prg(0), _chanIndex(chanIndex),
 	_effectLevel(0), _priority(0), _ctrlVolume(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0),
 	_fld_1f(0), _detune(0), _modWheel(0), _allocated(false) {
 	_instrument = new uint8[30];
@@ -692,16 +695,16 @@ void TownsMidiInputChannel::send(uint32 b) {
 }
 
 void TownsMidiInputChannel::noteOff(byte note) {
-	if (!_outChan)
+	if (!_out)
 		return;
 
-	if (_outChan->_note != note)
+	if (_out->_note != note)
 		return;
 
 	if (_sustain)
-		_outChan->_sustainNoteOff = 1;
+		_out->_sustainNoteOff = 1;
 	else
-		_outChan->disconnect();
+		_out->disconnect();
 }
 
 void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
@@ -712,7 +715,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 
 	oc->connect(this);
 
-	oc->_fld_c = _instrument[10] & 1;
+	oc->_adjustModTl = _instrument[10] & 1;
 	oc->_note = note;
 	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 63;
@@ -725,7 +728,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	if (oc->_carrierTl > 63)
 		oc->_carrierTl = 63;
 
-	oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
+	oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
 	oc->noteOn(note + _transpose, _freqLSB);
 
 	if (_instrument[11] & 0x80)
@@ -736,7 +739,7 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	if (_instrument[20] & 0x80)
 		oc->setupEffects(1, _instrument[20], &_instrument[21]);
 	else
-		oc->_stateA[1].numLoop = 0;	
+		oc->_stateA[1].numLoop = 0;
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
@@ -746,8 +749,8 @@ void TownsMidiInputChannel::programChange(byte program) {
 void TownsMidiInputChannel::pitchBend(int16 bend) {
 	_pitchBend = bend;
 	_freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune;
-	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
-		oc->noteOnPitchBend(oc->_note + oc->_midi->_transpose, _freqLSB);
+	for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next)
+		oc->noteOnPitchBend(oc->_note + oc->_in->_transpose, _freqLSB);
 }
 
 void TownsMidiInputChannel::controlChange(byte control, byte value) {
@@ -765,8 +768,8 @@ void TownsMidiInputChannel::controlChange(byte control, byte value) {
 		controlSustain(value);
 		break;
 	case 123:
-		while (_outChan)
-			_outChan->disconnect();
+		while (_out)
+			_out->disconnect();
 		break;
 	default:
 		break;
@@ -776,8 +779,8 @@ void TownsMidiInputChannel::controlChange(byte control, byte value) {
 void TownsMidiInputChannel::pitchBendFactor(byte value) {
 	_pitchBendFactor = value;
 	_freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune;
-	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
-		oc->noteOnPitchBend(oc->_note + oc->_midi->_transpose, _freqLSB);
+	for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next)
+		oc->noteOnPitchBend(oc->_note + oc->_in->_transpose, _freqLSB);
 }
 
 void TownsMidiInputChannel::priority(byte value) {
@@ -790,7 +793,7 @@ void TownsMidiInputChannel::sysEx_customInstrument(uint32 type, const byte *inst
 
 void TownsMidiInputChannel::controlModulationWheel(byte value) {
 	_modWheel = value;
-	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next)
+	for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next)
 		oc->setModWheel(value);
 }
 
@@ -808,7 +811,7 @@ void TownsMidiInputChannel::controlVolume(byte value) {
 	_tl = value;
 	
 	/* nullsub
-	_outChan->setVolume(_tl);
+	_out->setVolume(_tl);
 	*/
 }
 
@@ -823,7 +826,7 @@ void TownsMidiInputChannel::controlSustain(byte value) {
 }
 
 void TownsMidiInputChannel::releasePedal() {
-	for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next) {
+	for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) {
 		if (oc->_sustainNoteOff)
 			oc->disconnect();
 	}
@@ -840,7 +843,7 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 	0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
 };
 
-MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _tickCounter1(0), _tickCounter2(0), _curChan(0), _rand(1), _open(false) {
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
 }
 
@@ -883,6 +886,10 @@ int MidiDriver_TOWNS::open() {
 	_intf->callback(33, 8);
 	_intf->setSoundEffectChanMask(~0x3f);
 
+	 _tickCounter1 = _tickCounter2 = 0;
+	 _allocCurPos = 0;
+	 _rand = 1;
+
 	_open = true;
 
 	return 0;
@@ -978,7 +985,7 @@ MidiChannel *MidiDriver_TOWNS::allocateChannel() {
 }
 
 MidiChannel *MidiDriver_TOWNS::getPercussionChannel() {
-	return 0;//_channels[16];
+	return 0;
 }
 
 void MidiDriver_TOWNS::timerCallback(int timerId) {
@@ -1018,20 +1025,20 @@ void MidiDriver_TOWNS::updateOutputChannels() {
 	}
 }
 
-TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
+TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(uint8 pri) {
 	TownsMidiOutputChannel *res = 0;
 
 	for (int i = 0; i < 6; i++) {
-		if (++_curChan == 6)
-			_curChan = 0;
+		if (++_allocCurPos == 6)
+			_allocCurPos = 0;
 
-		int s = _out[i]->checkPriority(pri);
+		int s = _out[_allocCurPos]->checkPriority(pri);
 		if (s == TownsMidiOutputChannel::kDisconnected)
-			return _out[i];
+			return _out[_allocCurPos];
 
 		if (s != TownsMidiOutputChannel::kHighPriority) {
 			pri = s;
-			res = _out[i];
+			res = _out[_allocCurPos];
 		}
 	}
 	
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 5164e04..8dc71f3 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -58,7 +58,7 @@ private:
 	void updateParser();
 	void updateOutputChannels();
 
-	TownsMidiOutputChannel *allocateOutputChannel(int pri);
+	TownsMidiOutputChannel *allocateOutputChannel(uint8 pri);
 		
 	int randomValue(int para);
 
@@ -73,7 +73,7 @@ private:
 
 	uint32 _tickCounter1;
 	uint32 _tickCounter2;
-	uint8 _curChan;
+	uint8 _allocCurPos;
 	uint8 _rand;
 	
 	bool _open;


Commit: 95c059598d31ebdb871b97a528ad361472fcd217
    https://github.com/scummvm/scummvm/commit/95c059598d31ebdb871b97a528ad361472fcd217
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Fix note off event in midi driver

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



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 9fa6a8c..e221826 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -569,11 +569,7 @@ int TownsMidiOutputChannel::lookupVolume(int a, int b) {
 }
 
 void TownsMidiOutputChannel::keyOn() {
-	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
-	// since it is just a modified AdLib driver. It also uses AdLib programs.
-	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
-	// music being so bad compared to AdLib (unsuitable data is just forced into the
-	// wrong audio device).
+	// This driver uses only 2 operators since it is just a modified AdLib driver.
 	out(0x28, 0x30);
 }
 
@@ -587,11 +583,7 @@ void TownsMidiOutputChannel::keyOnSetFreq(uint16 frq) {
 	out(0xa4, frq >> 8);
 	out(0xa0, frq & 0xff);
 	out(0x28, 0);
-	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
-	// since it is just a modified AdLib driver. It also uses AdLib programs.
-	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
-	// music being so bad compared to AdLib (unsuitable data is just forced into the
-	// wrong audio device).
+	// This driver uses only 2 operators since it is just a modified AdLib driver.
 	out(0x28, 0x30);
 }
 
@@ -698,13 +690,15 @@ void TownsMidiInputChannel::noteOff(byte note) {
 	if (!_out)
 		return;
 
-	if (_out->_note != note)
-		return;
+	for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) {
+		if (oc->_note != note)
+			continue;
 
-	if (_sustain)
-		_out->_sustainNoteOff = 1;
-	else
-		_out->disconnect();
+		if (_sustain)
+			oc->_sustainNoteOff = 1;
+		else
+			oc->disconnect();
+	}
 }
 
 void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
@@ -743,7 +737,9 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
-	// Dysfunctional since this is all done inside the imuse code
+	// Not implemented (The loading and assignment of programs
+	// is handled externally by the SCUMM engine. The programs
+	// get sent via sysEx_customInstrument.)
 }
 
 void TownsMidiInputChannel::pitchBend(int16 bend) {
@@ -816,7 +812,7 @@ void TownsMidiInputChannel::controlVolume(byte value) {
 }
 
 void TownsMidiInputChannel::controlPanPos(byte value) {
-	// not supported
+	// not implemented
 }
 
 void TownsMidiInputChannel::controlSustain(byte value) {


Commit: 15610b56db9f655ad0c8df0ffe730d123f048bac
    https://github.com/scummvm/scummvm/commit/15610b56db9f655ad0c8df0ffe730d123f048bac
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Fix some bugs and rename some stuff in the midi driver code

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.h
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index e221826..6843a35 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -51,40 +51,40 @@ public:
 	int checkPriority(int pri);
 
 private:
-	struct StateA {
-		uint8 numLoop;
-		int32 fld_1;
+	struct EffectState {
+		uint8 envState;
+		int32 envStepLen;
 		int32 duration;
-		uint16 fld_9;
-		int32 effectState;
-		uint8 fld_11;
-		uint8 ar1[4];
-		uint8 ar2[4];
+		int32 envTargetLevel;
+		int32 currentLevel;
+		uint8 loop;
+		uint8 envStepping[4];
+		uint8 envMod[4];
 		int8 modWheelSensitivity;
 		int8 modWheelState;
 		int8 modWheelLast;
-		uint16 fld_1d;
-		uint32 fld_21;
-		int32 fld_25;
+		uint16 envStateNumSteps;
+		uint32 envStateStepCounter;
+		int32 envChangePerStep;
 		int8 dir;
-		uint32 fld_2a;
-		uint32 fld_2e;
-	} *_stateA;
+		uint32 envChangePerStepRem;
+		uint32 envChangeCountRem;
+	} *_effectStates;
 
-	struct StateB {
-		int32 inc;
+	struct EffectDef {
+		int32 phase;
 		uint8 type;
 		uint8 useModWheel;
-		uint8 fld_6;
-		StateA *a;
-	} *_stateB;
+		uint8 loopRefresh;
+		EffectState *s;
+	} *_effectDefs;
 
-	int16 getEffectState(uint8 type);
-	void initEffect(StateA *a, const uint8 *effectData);
-	void updateEffectOuter3(StateA *a, StateB *b);
-	int updateEffectOuter(StateA *a, StateB *b);
-	void updateEffect(StateA *a);	
-	int lookupVolume(int a, int b);
+	int16 getEffectLevel(uint8 type);
+	void initEffect(EffectState *s, const uint8 *effectData);
+	void updateEffectGenerator(EffectState *s, EffectDef *d);
+	int updateEffectEnvelope(EffectState *s, EffectDef *d);
+	void updateEffect(EffectState *s);	
+	int calcModWheelLevel(int lvl, int mod);
 
 	void keyOn();
 	void keyOff();
@@ -97,8 +97,8 @@ private:
 	uint8 _adjustModTl;
 	uint8 _chan;
 	uint8 _note;
-	uint8 _carrierTl;
-	uint8 _modulatorTl;
+	uint8 _operator2Tl;
+	uint8 _operator1Tl;
 	uint8 _sustainNoteOff;
 	int16 _duration;
 	
@@ -109,8 +109,8 @@ private:
 
 	static const uint8 _chanMap[];
 	static const uint8 _chanMap2[];
-	static const uint8 _effectDefs[];
-	static const uint16 _effectData[];
+	static const uint8 _effectDefaults[];
+	static const uint16 _effectEnvStepTable[];
 	static const uint8 _freqMSB[];
 	static const uint16 _freqLSB[];
 };
@@ -215,18 +215,19 @@ uint8 TownsMidiChanState::get(uint8 type) {
 }
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
-	_in(0), _prev(0), _next(0), _adjustModTl(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
-	_stateA = new StateA[2];
-	memset(_stateA, 0, 2 * sizeof(StateA));
-	_stateB = new StateB[2];
-	memset(_stateB, 0, 2 * sizeof(StateB));
-	_stateB[0].a = &_stateA[1];
-	_stateB[1].a = &_stateA[0];
+	_in(0), _prev(0), _next(0), _adjustModTl(0), _operator2Tl(0), _note(0), _operator1Tl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
+	_effectStates = new EffectState[2];
+	_effectDefs = new EffectDef[2];
+
+	memset(_effectStates, 0, 2 * sizeof(EffectState));
+	memset(_effectDefs, 0, 2 * sizeof(EffectDef));
+	_effectDefs[0].s = &_effectStates[1];
+	_effectDefs[1].s = &_effectStates[0];
 }
 
 TownsMidiOutputChannel::~TownsMidiOutputChannel() {
-	delete[] _stateA;
-	delete[] _stateB;
+	delete[] _effectStates;
+	delete[] _effectDefs;
 }
 
 void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
@@ -243,9 +244,8 @@ void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) {
 void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara) {
 	// This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7),
 	// since it is just a modified AdLib driver. It also uses AdLib programs.
-	// There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
-	// music being so bad compared to AdLib (unsuitable data is just forced into the
-	// wrong audio device).
+	// There are no FM-TOWNS specific programs. This is the reason for the low quality of the FM-TOWNS
+	// music (unsuitable data is just forced into the wrong audio device).
 
 	static const uint8 mul[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 };
 	uint8 chan = _chanMap[_chan];	
@@ -295,50 +295,50 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
 }
 
 void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) {
-	uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
+	uint16 effectTargetLevel[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
 	uint8 effectType[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
 	
-	StateA *a = &_stateA[index];
-	StateB *b = &_stateB[index];
-
-	b->inc = 0;
-	b->useModWheel = flags & 0x40;
-	a->fld_11 = flags & 0x20;
-	b->fld_6 = flags & 0x10;
-	b->type = effectType[flags & 0x0f];
-	a->fld_9 = maxVal[flags & 0x0f];
-	a->modWheelSensitivity = 31;
-	a->modWheelState = b->useModWheel ? _in->_modWheel >> 2 : 31;
-
-	switch (b->type) {
+	EffectState *s = &_effectStates[index];
+	EffectDef *d = &_effectDefs[index];
+
+	d->phase = 0;
+	d->useModWheel = flags & 0x40;
+	s->loop = flags & 0x20;
+	d->loopRefresh = flags & 0x10;
+	d->type = effectType[flags & 0x0f];
+	s->envTargetLevel = effectTargetLevel[flags & 0x0f];
+	s->modWheelSensitivity = 31;
+	s->modWheelState = d->useModWheel ? _in->_modWheel >> 2 : 31;
+
+	switch (d->type) {
 	case 0:
-		a->effectState = _carrierTl;
+		s->currentLevel = _operator2Tl;
 		break;
 	case 13:
-		a->effectState = _modulatorTl;
+		s->currentLevel = _operator1Tl;
 		break;
 	case 30:
-		a->effectState = 31;
-		b->a->modWheelState = 0;
+		s->currentLevel = 31;
+		d->s->modWheelState = 0;
 		break;
 	case 31:
-		a->effectState = 0;
-		b->a->modWheelSensitivity = 0;
+		s->currentLevel = 0;
+		d->s->modWheelSensitivity = 0;
 		break;
 	default:
-		a->effectState = getEffectState(b->type);
+		s->currentLevel = getEffectLevel(d->type);
 		break;
 	}
 
-	initEffect(a, effectData);
+	initEffect(s, effectData);
 }
 
 void TownsMidiOutputChannel::setModWheel(uint8 value) {
-	if (_stateA[0].numLoop && _stateB[0].type)
-		_stateA[0].modWheelState = value >> 2;
+	if (_effectStates[0].envState && _effectDefs[0].type)
+		_effectStates[0].modWheelState = value >> 2;
 
-	if (_stateA[1].numLoop && _stateB[1].type)
-		_stateA[1].modWheelState = value >> 2;
+	if (_effectStates[1].envState && _effectDefs[1].type)
+		_effectStates[1].modWheelState = value >> 2;
 }
 
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
@@ -381,8 +381,8 @@ bool TownsMidiOutputChannel::update() {
 	}
 
 	for (int i = 0; i < 2; i++) {
-		if (_stateA[i].numLoop)
-			updateEffectOuter3(&_stateA[i], &_stateB[i]);
+		if (_effectStates[i].envState)
+			updateEffectGenerator(&_effectStates[i], &_effectDefs[i]);
 	}
 
 	return false;
@@ -398,7 +398,7 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 	return kHighPriority;
 }
 
-int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
+int16 TownsMidiOutputChannel::getEffectLevel(uint8 type) {
 	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
 	
 	if (type == 28)
@@ -411,45 +411,45 @@ int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
 		type -= 13;
 
 	int32 res = 0;
-	uint8 cs = (_driver->_chanState[chan].get(_effectDefs[type * 4] >> 5) & _effectDefs[type * 4 + 2]) >> _effectDefs[type * 4 + 1];
-	if (_effectDefs[type * 4 + 3])
-		res = _effectDefs[type * 4 + 3] - cs;
+	uint8 cs = (_driver->_chanState[chan].get(_effectDefaults[type * 4] >> 5) & _effectDefaults[type * 4 + 2]) >> _effectDefaults[type * 4 + 1];
+	if (_effectDefaults[type * 4 + 3])
+		res = _effectDefaults[type * 4 + 3] - cs;
 	
 	return res;	
 }
 
-void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
-	a->numLoop = 1;
-	a->fld_1 = 0;
-	a->modWheelLast = 31;
-	a->duration = effectData[0] * 63;
-	a->ar1[0] = effectData[1];
-	a->ar1[1] = effectData[3];
-	a->ar1[2] = effectData[5];
-	a->ar1[3] = effectData[6];
-	a->ar2[0] = effectData[2];
-	a->ar2[1] = effectData[4];
-	a->ar2[2] = 0;
-	a->ar2[3] = effectData[7];
-	updateEffect(a);
+void TownsMidiOutputChannel::initEffect(EffectState *s, const uint8 *effectData) {
+	s->envState = 1;
+	s->envStepLen = 0;
+	s->modWheelLast = 31;
+	s->duration = effectData[0] * 63;
+	s->envStepping[0] = effectData[1];
+	s->envStepping[1] = effectData[3];
+	s->envStepping[2] = effectData[5];
+	s->envStepping[3] = effectData[6];
+	s->envMod[0] = effectData[2];
+	s->envMod[1] = effectData[4];
+	s->envMod[2] = 0;
+	s->envMod[3] = effectData[7];
+	updateEffect(s);
 }
 
-void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
-	uint8 f = updateEffectOuter(a, b);
+void TownsMidiOutputChannel::updateEffectGenerator(EffectState *s, EffectDef *d) {
+	uint8 f = updateEffectEnvelope(s, d);
 
 	if (f & 1) {
-		switch (b->type) {
+		switch (d->type) {
 		case 0:
-			_carrierTl = a->effectState + b->inc; /*???*/
+			_operator2Tl = s->currentLevel + d->phase;
 			break;
 		case 13:
-			_modulatorTl = a->effectState + b->inc; /*???*/
+			_operator1Tl = s->currentLevel + d->phase;
 			break;
 		case 30:
-			b->a->modWheelState = b->inc;
+			d->s->modWheelState = d->phase;
 			break;
 		case 31:
-			b->a->modWheelSensitivity = b->inc;
+			d->s->modWheelSensitivity = d->phase;
 			break;
 		default:
 			break;
@@ -457,60 +457,60 @@ void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
 	}
 
 	if (f & 2) {
-		if (b->fld_6)
+		if (d->loopRefresh)
 			keyOn();
 	}
 }
 
-int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
-	if (a->duration) {
-		a->duration -= 17;
-		if (a->duration <= 0) {
-			a->numLoop = 0;
+int TownsMidiOutputChannel::updateEffectEnvelope(EffectState *s, EffectDef *d) {
+	if (s->duration) {
+		s->duration -= 17;
+		if (s->duration <= 0) {
+			s->envState = 0;
 			return 0;
 		}
 	} 
 
-	int32 t = a->fld_1 + a->fld_25;
+	int32 t = s->envStepLen + s->envChangePerStep;
 	
-	a->fld_2e += a->fld_2a;
-	if (a->fld_2e >= a->fld_1d) {
-		a->fld_2e -= a->fld_1d;
-		t += a->dir;
+	s->envChangeCountRem += s->envChangePerStepRem;
+	if (s->envChangeCountRem >= s->envStateNumSteps) {
+		s->envChangeCountRem -= s->envStateNumSteps;
+		t += s->dir;
 	}
 
 	int retFlags = 0;
 
-	if (t != a->fld_1 || a->modWheelState != a->modWheelLast) {
-		a->fld_1 = t;
-		a->modWheelLast = a->modWheelState;
-		t = lookupVolume(t, a->modWheelState);
-		if (t != b->inc)
-			b->inc = t;
+	if (t != s->envStepLen || (s->modWheelState != s->modWheelLast)) {
+		s->envStepLen = t;
+		s->modWheelLast = s->modWheelState;
+		t = calcModWheelLevel(t, s->modWheelState);
+		if (t != d->phase)
+			d->phase = t;
 		retFlags |= 1;
 	}
 
-	if (--a->fld_21)
+	if (--s->envStateStepCounter)
 		return retFlags;
 
-	if (++a->numLoop > 4) {
-		if (!a->fld_11) {
-			a->numLoop = 0;
+	if (++s->envState > 4) {
+		if (!s->loop) {
+			s->envState = 0;
 			return retFlags;
 		}
-		a->numLoop = 1;
+		s->envState = 1;
 		retFlags |= 2;
 	}
 
-	updateEffect(a);
+	updateEffect(s);
 
 	return retFlags;
 }
 
-void TownsMidiOutputChannel::updateEffect(StateA *a) {
-	uint8 c = a->numLoop - 1;
-	uint8 v = a->ar1[c];
-	int32 e = _effectData[_driver->_chanEffectLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
+void TownsMidiOutputChannel::updateEffect(EffectState *s) {
+	uint8 st= s->envState - 1;
+	uint8 v = s->envStepping[st];
+	int32 e = _effectEnvStepTable[_driver->_chanEffectLevelModifier[((v & 0x7f) << 5) + s->modWheelSensitivity]];
 
 	if (v & 0x80)
 		e = _driver->randomValue(e);
@@ -518,58 +518,59 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
 	if (!e)
 		e = 1;
 
-	a->fld_1d = a->fld_21 = e;
+	s->envStateNumSteps = s->envStateStepCounter = e;
 	int32 d = 0;
 
-	if (c != 2) {
-		v = a->ar2[c];
-		e = lookupVolume(a->fld_9, (v & 0x7f) - 31);
+	if (st != 2) {
+		v = s->envMod[st];
+		e = calcModWheelLevel(s->envTargetLevel, (v & 0x7f) - 31);
 
 		if (v & 0x80)
 			e = _driver->randomValue(e);
 
-		if (e + a->effectState > a->fld_9) {
-			e = a->fld_9 - a->effectState;
+		if (e + s->currentLevel > s->envTargetLevel) {
+			e = s->envTargetLevel - s->currentLevel;
 		} else {
-			if (e + a->effectState + 1 <= 0)
-				e = -a->effectState;
+			if (e + s->currentLevel + 1 <= 0)
+				e = -s->currentLevel;
 		}
 
-		d = e - a->fld_1;
+		d = e - s->envStepLen;
 	}
 
-	a->fld_25 = d / a->fld_1d;
-	a->dir = (d < 0) ? -1 : 1;
-	d *= a->dir;
-	a->fld_2a = d % a->fld_1d;
-	a->fld_2e = 0;
+	s->envChangePerStep = d / s->envStateNumSteps;
+	s->dir = (d < 0) ? -1 : 1;
+	d *= s->dir;
+	s->envChangePerStepRem = d % s->envStateNumSteps;
+	s->envChangeCountRem = 0;
 }
 
-int TownsMidiOutputChannel::lookupVolume(int a, int b) {
-	if (b == 0)
+int TownsMidiOutputChannel::calcModWheelLevel(int lvl, int mod) {
+	if (mod == 0)
 		return 0;
 
-	if (b == 31)
-		return a;
+	if (mod == 31)
+		return lvl;
 
-	if (a > 63 || a < -63)
-		return ((a + 1) * b) >> 5;
+	if (lvl > 63 || lvl < -63)
+		return ((lvl + 1) * mod) >> 5;
 
-	if (b < 0) {
-		if (a < 0)			
-			return _driver->_chanEffectLevel[((-a) << 5) - b];
+	if (mod < 0) {
+		if (mod < 0)			
+			return _driver->_chanEffectLevelModifier[((-lvl) << 5) - mod];
 		else
-			return -_driver->_chanEffectLevel[(a << 5) - b];
+			return -_driver->_chanEffectLevelModifier[(lvl << 5) - mod];
 	} else {
-		if (a < 0)			
-			return -_driver->_chanEffectLevel[((-a) << 5) + b];
+		if (mod < 0)			
+			return -_driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
 		else
-			return _driver->_chanEffectLevel[((-a) << 5) + b];
+			return _driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
 	}
+
+	return 0;
 }
 
 void TownsMidiOutputChannel::keyOn() {
-	// This driver uses only 2 operators since it is just a modified AdLib driver.
 	out(0x28, 0x30);
 }
 
@@ -578,12 +579,11 @@ void TownsMidiOutputChannel::keyOff() {
 }
 
 void TownsMidiOutputChannel::keyOnSetFreq(uint16 frq) {
-	uint8 t = (frq << 1) >> 8;	
-	frq = (_freqMSB[t] << 11) | _freqLSB[t] ;
+	uint16 note = (frq << 1) >> 8;	
+	frq = (_freqMSB[note] << 11) | _freqLSB[note] ;
 	out(0xa4, frq >> 8);
 	out(0xa0, frq & 0xff);
-	out(0x28, 0);
-	// This driver uses only 2 operators since it is just a modified AdLib driver.
+	//out(0x28, 0x00);
 	out(0x28, 0x30);
 }
 
@@ -607,7 +607,7 @@ const uint8 TownsMidiOutputChannel::_chanMap2[] = {
 	3, 4, 5, 11, 12, 13
 };
 
-const uint8 TownsMidiOutputChannel::_effectDefs[] = {
+const uint8 TownsMidiOutputChannel::_effectDefaults[] = {
 	0x40, 0x00, 0x3F, 0x3F, 0xE0, 0x02, 0x00, 0x00, 0x40, 0x06, 0xC0, 0x00,
 	0x20, 0x00, 0x0F, 0x00, 0x60, 0x04, 0xF0, 0x0F, 0x60, 0x00, 0x0F, 0x0F,
 	0x80, 0x04, 0xF0, 0x0F, 0x80, 0x00, 0x0F, 0x0F, 0xE0, 0x00, 0x03, 0x00,
@@ -615,7 +615,7 @@ const uint8 TownsMidiOutputChannel::_effectDefs[] = {
 	0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00
 };
 
-const uint16 TownsMidiOutputChannel::_effectData[] = {
+const uint16 TownsMidiOutputChannel::_effectEnvStepTable[] = {
 	0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007,	0x0008, 0x0009,
 	0x000A, 0x000C, 0x000E, 0x0010,	0x0012, 0x0015, 0x0018, 0x001E,
 	0x0024, 0x0032,	0x0040, 0x0052, 0x0064, 0x0088, 0x00A0, 0x00C0,
@@ -714,26 +714,26 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 63;
 	
-	oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
-	if (oc->_modulatorTl > 63)
-		oc->_modulatorTl = 63;
+	oc->_operator1Tl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+	if (oc->_operator1Tl > 63)
+		oc->_operator1Tl = 63;
 
-	oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
-	if (oc->_carrierTl > 63)
-		oc->_carrierTl = 63;
+	oc->_operator2Tl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+	if (oc->_operator2Tl > 63)
+		oc->_operator2Tl = 63;
 
-	oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
+	oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator1Tl << 5)]] : oc->_operator1Tl, _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator2Tl << 5)]]);
 	oc->noteOn(note + _transpose, _freqLSB);
 
 	if (_instrument[11] & 0x80)
 		oc->setupEffects(0, _instrument[11], &_instrument[12]);
 	else
-		oc->_stateA[0].numLoop = 0;
+		oc->_effectStates[0].envState = 0;
 
 	if (_instrument[20] & 0x80)
 		oc->setupEffects(1, _instrument[20], &_instrument[21]);
 	else
-		oc->_stateA[1].numLoop = 0;
+		oc->_effectStates[1].envState = 0;
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
@@ -795,7 +795,6 @@ void TownsMidiInputChannel::controlModulationWheel(byte value) {
 
 void TownsMidiInputChannel::controlVolume(byte value) {
 	/* This is all done inside the imuse code
-
 	uint16 v1 = _ctrlVolume + 1;
 	uint16 v2 = value;
 	if (_chanIndex != 16) {
@@ -805,10 +804,6 @@ void TownsMidiInputChannel::controlVolume(byte value) {
 	_tl = (v1 * v2) >> 7;*/
 
 	_tl = value;
-	
-	/* nullsub
-	_out->setVolume(_tl);
-	*/
 }
 
 void TownsMidiInputChannel::controlPanPos(byte value) {
@@ -865,13 +860,13 @@ int MidiDriver_TOWNS::open() {
 
 	_chanState = new TownsMidiChanState[32];
 
-	_chanEffectLevel = new uint8[2048];
+	_chanEffectLevelModifier = new uint8[2048];
 	for (int i = 0; i < 64; i++) {
 		for (int ii = 0; ii < 32; ii++)
-			_chanEffectLevel[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
+			_chanEffectLevelModifier[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
 	}
 	for (int i = 0; i < 64; i++)
-		_chanEffectLevel[i << 5] = 0;
+		_chanEffectLevelModifier[i << 5] = 0;
 
 	_intf->callback(0);
 
@@ -916,8 +911,8 @@ void MidiDriver_TOWNS::close() {
 
 	delete[] _chanState;
 	_chanState = 0;
-	delete[] _chanEffectLevel;
-	_chanEffectLevel = 0;
+	delete[] _chanEffectLevelModifier;
+	_chanEffectLevelModifier = 0;
 }
 
 void MidiDriver_TOWNS::send(uint32 b) {
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 8dc71f3..52298d7 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -78,7 +78,7 @@ private:
 	
 	bool _open;
 
-	uint8 *_chanEffectLevel;
+	uint8 *_chanEffectLevelModifier;
 };
 
 #endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 263986e..09d3ca3 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -39,45 +39,22 @@ public:
 	void recalculateRates();
 	void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);
 
-	void feedbackLevel(int32 level) {
-		_feedbackLevel = level ? level + 6 : 0;
-	}
-	void detune(int value) {
-		_detn = &_detnTbl[value << 5];
-	}
-	void multiple(uint32 value) {
-		_multiple = value ? (value << 1) : 1;
-	}
-	void attackRate(uint32 value) {
-		_specifiedAttackRate = value;
-	}
+	void feedbackLevel(int32 level);
+	void detune(int value);
+	void multiple(uint32 value);
+	void attackRate(uint32 value);
 	bool scaleRate(uint8 value);
-	void decayRate(uint32 value) {
-		_specifiedDecayRate = value;
-		recalculateRates();
-	}
-	void sustainRate(uint32 value) {
-		_specifiedSustainRate = value;
-		recalculateRates();
-	}
-	void sustainLevel(uint32 value) {
-		_sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
-	}
-	void releaseRate(uint32 value) {
-		_specifiedReleaseRate = value;
-		recalculateRates();
-	}
-	void totalLevel(uint32 value) {
-		_totalLevel = value << 3;
-	}
-	void ampModulation(bool enable) {
-		_ampMod = enable;
-	}
+	void decayRate(uint32 value);
+	void sustainRate(uint32 value);
+	void sustainLevel(uint32 value);
+	void releaseRate(uint32 value);
+	void totalLevel(uint32 value);
+	void ampModulation(bool enable);
 	void reset();
 
 protected:
 	EnvelopeState _state;
-	bool _playing;
+	bool _holdKey;
 	uint32 _feedbackLevel;
 	uint32 _multiple;
 	uint32 _totalLevel;
@@ -122,7 +99,7 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
 	_rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
 	_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
 	_specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
-	_phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0),
+	_phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
 	_keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) {
 
 	fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
@@ -131,19 +108,19 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
 }
 
 void TownsPC98_FmSynthOperator::keyOn() {
-	if (_playing)
+	if (_holdKey)
 		return;
 
-	_playing = true;
+	_holdKey = true;
 	_state = kEnvAttacking;
 	_phase = 0;
 }
 
 void TownsPC98_FmSynthOperator::keyOff() {
-	if (!_playing)
+	if (!_holdKey)
 		return;
 
-	_playing = false;
+	_holdKey = false;
 	if (_state != kEnvReady)
 		_state = kEnvReleasing;
 }
@@ -199,39 +176,42 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
 		int32 targetLevel = 0;
 		EnvelopeState nextState = kEnvReady;
 
-		switch (_state) {
-		case kEnvReady:
-			return;
-		case kEnvAttacking:
-			targetLevel = 0;
-			nextState = kEnvDecaying;
-			if ((_specifiedAttackRate << 1) + _keyScale2 < 64) {
-				targetTime = (1 << fs_a.shift) - 1;
-				levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
+		for (bool loop = true; loop;) {
+			switch (_state) {
+			case kEnvReady:
+				return;
+			case kEnvAttacking:
+				targetLevel = 0;
+				nextState = _sustainLevel ? kEnvDecaying : kEnvSustaining;
+				if ((_specifiedAttackRate << 1) + _keyScale2 < 62) {
+					targetTime = (1 << fs_a.shift) - 1;
+					levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
+				} else {
+					_currentLevel = targetLevel;
+					_state = nextState;
+					continue;
+				}
+				break;
+			case kEnvDecaying:
+				targetTime = (1 << fs_d.shift) - 1;
+				nextState = kEnvSustaining;
+				targetLevel = _sustainLevel;
+				levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
+				break;
+			case kEnvSustaining:
+				targetTime = (1 << fs_s.shift) - 1;
+				nextState = kEnvSustaining;
+				targetLevel = 1023;
+				levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
+				break;
+			case kEnvReleasing:
+				targetTime = (1 << fs_r.shift) - 1;
+				nextState = kEnvReady;
+				targetLevel = 1023;
+				levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
 				break;
-			} else {
-				_currentLevel = targetLevel;
-				_state = nextState;
 			}
-			// Fall through
-		case kEnvDecaying:
-			targetTime = (1 << fs_d.shift) - 1;
-			nextState = kEnvSustaining;
-			targetLevel = _sustainLevel;
-			levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
-			break;
-		case kEnvSustaining:
-			targetTime = (1 << fs_s.shift) - 1;
-			nextState = kEnvSustaining;
-			targetLevel = 1023;
-			levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
-			break;
-		case kEnvReleasing:
-			targetTime = (1 << fs_r.shift) - 1;
-			nextState = kEnvReady;
-			targetLevel = 1023;
-			levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
-			break;
+			loop = false;
 		}
 
 		if (!(_tickCount & targetTime)) {
@@ -272,6 +252,63 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
 	out += *o;
 }
 
+void TownsPC98_FmSynthOperator::feedbackLevel(int32 level) {
+	_feedbackLevel = level ? level + 6 : 0;
+}
+
+void TownsPC98_FmSynthOperator::detune(int value) {
+	_detn = &_detnTbl[value << 5];
+}
+
+void TownsPC98_FmSynthOperator::multiple(uint32 value) {
+	_multiple = value ? (value << 1) : 1;
+}
+
+void TownsPC98_FmSynthOperator::attackRate(uint32 value) {
+	_specifiedAttackRate = value;
+}
+
+bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) {
+	value = 3 - value;
+	if (_keyScale1 != value) {
+		_keyScale1 = value;
+		return true;
+	}
+
+	int k = _keyScale2;
+	int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
+	fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
+	fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
+	return false;
+}
+
+void TownsPC98_FmSynthOperator::decayRate(uint32 value) {
+	_specifiedDecayRate = value;
+	recalculateRates();
+}
+
+void TownsPC98_FmSynthOperator::sustainRate(uint32 value) {
+		_specifiedSustainRate = value;
+		recalculateRates();
+	}
+
+void TownsPC98_FmSynthOperator::sustainLevel(uint32 value) {
+	_sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
+}
+
+void TownsPC98_FmSynthOperator::releaseRate(uint32 value) {
+	_specifiedReleaseRate = value;
+	recalculateRates();
+}
+
+void TownsPC98_FmSynthOperator::totalLevel(uint32 value) {
+	_totalLevel = value << 3;
+}
+
+void TownsPC98_FmSynthOperator::ampModulation(bool enable) {
+	_ampMod = enable;
+}
+
 void TownsPC98_FmSynthOperator::reset() {
 	keyOff();
 	_timer = 0;
@@ -292,20 +329,6 @@ void TownsPC98_FmSynthOperator::reset() {
 	ampModulation(false);
 }
 
-bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) {
-	value = 3 - value;
-	if (_keyScale1 != value) {
-		_keyScale1 = value;
-		return true;
-	}
-
-	int k = _keyScale2;
-	int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
-	fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
-	fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
-	return false;
-}
-
 class TownsPC98_FmSynthSquareSineSource {
 public:
 	TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt);


Commit: b3476fc8016e3a62812eb9c7b5602e1f05f529cb
    https://github.com/scummvm/scummvm/commit/b3476fc8016e3a62812eb9c7b5602e1f05f529cb
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Some fixes and renaming

- renamed some stuff in the new midi driver code
- fixed minor bug in midi driver code
- fixed minor bug in euphony driver code
- add some functionality to towns audio interface

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_audio.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.h
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index 6679e65..f2d249b 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -163,9 +163,10 @@ private:
 	int intf_fmReset(va_list &args);
 	int intf_setOutputVolume(va_list &args);
 	int intf_resetOutputVolume(va_list &args);
+	int intf_getOutputVolume(va_list &args);
 	int intf_setOutputMute(va_list &args);
 	int intf_cdaToggle(va_list &args);
-	int intf_getOutputVolume(va_list &args);
+	int intf_getOutputVolume2(va_list &args);
 	int intf_getOutputMute(va_list &args);
 	int intf_pcmUpdateEnvelopeGenerator(va_list &args);
 
@@ -224,7 +225,7 @@ private:
 	void updateOutputVolume();
 	uint8 _outputVolumeFlags;
 	uint8 _outputLevel[16];
-	uint8 _outputMuteFlags;
+	uint8 _outputMute[16];
 
 	const float _baserate;
 	uint32 _timerBase;
@@ -253,7 +254,7 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 	_fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0),
 	_baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver),
 	_pcmSfxChanMask(0),	_musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume),
-	_outputVolumeFlags(0), _outputMuteFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
+	_outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
 	_pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _ready(false) {
 
 #define INTCB(x) &TownsAudioInterfaceIntern::intf_##x
@@ -345,13 +346,13 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 		INTCB(setOutputVolume),
 		// 68
 		INTCB(resetOutputVolume),
-		INTCB(notImpl),
+		INTCB(getOutputVolume),
 		INTCB(setOutputMute),
 		INTCB(notImpl),
 		// 72
 		INTCB(notImpl),
 		INTCB(cdaToggle),
-		INTCB(getOutputVolume),
+		INTCB(getOutputVolume2),
 		INTCB(getOutputMute),
 		// 76
 		INTCB(notImpl),
@@ -368,6 +369,7 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 
 	memset(_fmSaveReg, 0, sizeof(_fmSaveReg));
 	memset(_outputLevel, 0, sizeof(_outputLevel));
+	memset(_outputMute, 0, sizeof(_outputMute));
 
 	_timerBase = (uint32)(_baserate * 1000000.0f);
 	_tickLength = 2 * _timerBase;
@@ -929,11 +931,13 @@ int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) {
 
 	if (chanType > 1) {
 		_outputLevel[chan + chanType] = left;
+		_outputMute[chan + chanType] = 0;
 	} else {
 		if (chanType == 0)
 			chan -= 8;
 		_outputLevel[chan] = left;
 		_outputLevel[chan + 1] = right;
+		_outputMute[chan] = _outputMute[chan + 1] = 0;
 	}
 
 	updateOutputVolume();
@@ -943,15 +947,56 @@ int TownsAudioInterfaceIntern::intf_setOutputVolume(va_list &args) {
 
 int TownsAudioInterfaceIntern::intf_resetOutputVolume(va_list &args) {
 	memset(_outputLevel, 0, sizeof(_outputLevel));
-	_outputMuteFlags = 0;
 	_outputVolumeFlags = 0;
 	updateOutputVolume();
 	return 0;
 }
 
+int TownsAudioInterfaceIntern::intf_getOutputVolume(va_list &args) {
+	int chanType = va_arg(args, int);
+	int *left = va_arg(args, int*);
+	int *right = va_arg(args, int*);
+
+	uint8 chan = (chanType & 0x40) ? 8 : 12;
+	chanType &= 3;
+
+	if (chanType > 1) {
+		*left = _outputLevel[chan + chanType] & 0x3f;
+	} else {
+		if (chanType == 0)
+			chan -= 8;
+		*left = _outputLevel[chan] & 0x3f;
+		*right = _outputLevel[chan + 1] & 0x3f;
+	}
+
+	return 0;
+}
+
 int TownsAudioInterfaceIntern::intf_setOutputMute(va_list &args) {
 	int flags = va_arg(args, int);
-	_outputMuteFlags = flags & 3;
+	_outputVolumeFlags = flags;
+	uint8 mute = flags & 3;
+	uint8 f = flags & 0xff;
+
+	memset(_outputMute, 1, 8);
+	if (mute & 2)
+		memset(_outputMute + 12, 1, 4);
+	if (mute & 1)
+		memset(_outputMute + 8, 1, 4);	
+
+	_outputMute[(f < 0x80) ? 11 : 15] = 0;
+	f += f;
+	_outputMute[(f < 0x80) ? 10 : 14] = 0;
+	f += f;
+	_outputMute[(f < 0x80) ? 8 : 12] = 0;
+	f += f;
+	_outputMute[(f < 0x80) ? 9 : 13] = 0;
+	f += f;
+	_outputMute[(f < 0x80) ? 0 : 4] = 0;
+	f += f;
+	_outputMute[(f < 0x80) ? 1 : 5] = 0;
+	f += f;	
+	
 	updateOutputVolume();
 	return 0;
 }
@@ -962,7 +1007,7 @@ int TownsAudioInterfaceIntern::intf_cdaToggle(va_list &args) {
 	return 0;
 }
 
-int TownsAudioInterfaceIntern::intf_getOutputVolume (va_list &args) {
+int TownsAudioInterfaceIntern::intf_getOutputVolume2(va_list &args) {
 	return 0;
 }
 
@@ -1602,10 +1647,10 @@ void TownsAudioInterfaceIntern::updateOutputVolume() {
 	// balance values for our -128 to 127 volume range
 
 	// CD-AUDIO
-	uint32 maxVol = MAX(_outputLevel[12], _outputLevel[13]);
+	uint32 maxVol = MAX(_outputLevel[12] * (_outputMute[12] ^ 1), _outputLevel[13] * (_outputMute[13] ^ 1));
 
 	int volume = (int)(((float)(maxVol * 255) / 63.0f));
-	int balance = maxVol ? (int)( ( ((int)_outputLevel[13] - _outputLevel[12]) * 127) / (float)maxVol) : 0;
+	int balance = maxVol ? (int)( ( ((int)_outputLevel[13] * (_outputMute[13] ^ 1) - _outputLevel[12] * (_outputMute[12] ^ 1)) * 127) / (float)maxVol) : 0;
 
 	g_system->getAudioCDManager()->setVolume(volume);
 	g_system->getAudioCDManager()->setBalance(balance);
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index f161228..f7aa33f 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -81,7 +81,7 @@ void TownsEuphonyDriver::reset() {
 	_intf->callback(0);
 
 	_intf->callback(74);
-	_intf->callback(70);
+	_intf->callback(70, 0);
 	_intf->callback(75, 3);
 
 	setTimerA(true, 1);
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 6843a35..6b31ea1 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -23,9 +23,12 @@
  */
 
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
 #include "common/textconsole.h"
 #include "common/system.h"
 
+enum EnvelopeState;
+
 class TownsMidiOutputChannel {
 friend class TownsMidiInputChannel;
 public:
@@ -51,40 +54,40 @@ public:
 	int checkPriority(int pri);
 
 private:
-	struct EffectState {
-		uint8 envState;
-		int32 envStepLen;
-		int32 duration;
-		int32 envTargetLevel;
+	struct EffectEnvelope {
+		uint8 state;
 		int32 currentLevel;
+		int32 duration;
+		int32 maxLevel;
+		int32 startLevel;
 		uint8 loop;
-		uint8 envStepping[4];
-		uint8 envMod[4];
+		uint8 stateTargetLevels[4];
+		uint8 stateModWheelLevels[4];
 		int8 modWheelSensitivity;
 		int8 modWheelState;
 		int8 modWheelLast;
-		uint16 envStateNumSteps;
-		uint32 envStateStepCounter;
-		int32 envChangePerStep;
+		uint16 numSteps;
+		uint32 stepCounter;
+		int32 incrPerStep;
 		int8 dir;
-		uint32 envChangePerStepRem;
-		uint32 envChangeCountRem;
-	} *_effectStates;
+		uint32 incrPerStepRem;
+		uint32 incrCountRem;
+	} *_effectEnvelopes;
 
 	struct EffectDef {
 		int32 phase;
 		uint8 type;
 		uint8 useModWheel;
 		uint8 loopRefresh;
-		EffectState *s;
+		EffectEnvelope *s;
 	} *_effectDefs;
 
-	int16 getEffectLevel(uint8 type);
-	void initEffect(EffectState *s, const uint8 *effectData);
-	void updateEffectGenerator(EffectState *s, EffectDef *d);
-	int updateEffectEnvelope(EffectState *s, EffectDef *d);
-	void updateEffect(EffectState *s);	
-	int calcModWheelLevel(int lvl, int mod);
+	void startEffect(EffectEnvelope *s, const uint8 *effectData);
+	void updateEffectGenerator(EffectEnvelope *s, EffectDef *d);
+	int advanceEffectEnvelope(EffectEnvelope *s, EffectDef *d);
+	void initNextEnvelopeState(EffectEnvelope *s);
+	int16 getEffectStartLevel(uint8 type);
+	int getEffectModLevel(int lvl, int mod);
 
 	void keyOn();
 	void keyOff();
@@ -216,17 +219,17 @@ uint8 TownsMidiChanState::get(uint8 type) {
 
 TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
 	_in(0), _prev(0), _next(0), _adjustModTl(0), _operator2Tl(0), _note(0), _operator1Tl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
-	_effectStates = new EffectState[2];
+	_effectEnvelopes = new EffectEnvelope[2];
 	_effectDefs = new EffectDef[2];
 
-	memset(_effectStates, 0, 2 * sizeof(EffectState));
+	memset(_effectEnvelopes, 0, 2 * sizeof(EffectEnvelope));
 	memset(_effectDefs, 0, 2 * sizeof(EffectDef));
-	_effectDefs[0].s = &_effectStates[1];
-	_effectDefs[1].s = &_effectStates[0];
+	_effectDefs[0].s = &_effectEnvelopes[1];
+	_effectDefs[1].s = &_effectEnvelopes[0];
 }
 
 TownsMidiOutputChannel::~TownsMidiOutputChannel() {
-	delete[] _effectStates;
+	delete[] _effectEnvelopes;
 	delete[] _effectDefs;
 }
 
@@ -295,10 +298,10 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
 }
 
 void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) {
-	uint16 effectTargetLevel[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
+	uint16 effectMaxLevel[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
 	uint8 effectType[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 };
 	
-	EffectState *s = &_effectStates[index];
+	EffectEnvelope *s = &_effectEnvelopes[index];
 	EffectDef *d = &_effectDefs[index];
 
 	d->phase = 0;
@@ -306,39 +309,39 @@ void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *e
 	s->loop = flags & 0x20;
 	d->loopRefresh = flags & 0x10;
 	d->type = effectType[flags & 0x0f];
-	s->envTargetLevel = effectTargetLevel[flags & 0x0f];
+	s->maxLevel = effectMaxLevel[flags & 0x0f];
 	s->modWheelSensitivity = 31;
 	s->modWheelState = d->useModWheel ? _in->_modWheel >> 2 : 31;
 
 	switch (d->type) {
 	case 0:
-		s->currentLevel = _operator2Tl;
+		s->startLevel = _operator2Tl;
 		break;
 	case 13:
-		s->currentLevel = _operator1Tl;
+		s->startLevel = _operator1Tl;
 		break;
 	case 30:
-		s->currentLevel = 31;
+		s->startLevel = 31;
 		d->s->modWheelState = 0;
 		break;
 	case 31:
-		s->currentLevel = 0;
+		s->startLevel = 0;
 		d->s->modWheelSensitivity = 0;
 		break;
 	default:
-		s->currentLevel = getEffectLevel(d->type);
+		s->startLevel = getEffectStartLevel(d->type);
 		break;
 	}
 
-	initEffect(s, effectData);
+	startEffect(s, effectData);
 }
 
 void TownsMidiOutputChannel::setModWheel(uint8 value) {
-	if (_effectStates[0].envState && _effectDefs[0].type)
-		_effectStates[0].modWheelState = value >> 2;
+	if (_effectEnvelopes[0].state != kEnvReady && _effectDefs[0].type)
+		_effectEnvelopes[0].modWheelState = value >> 2;
 
-	if (_effectStates[1].envState && _effectDefs[1].type)
-		_effectStates[1].modWheelState = value >> 2;
+	if (_effectEnvelopes[1].state != kEnvReady && _effectDefs[1].type)
+		_effectEnvelopes[1].modWheelState = value >> 2;
 }
 
 void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
@@ -381,8 +384,8 @@ bool TownsMidiOutputChannel::update() {
 	}
 
 	for (int i = 0; i < 2; i++) {
-		if (_effectStates[i].envState)
-			updateEffectGenerator(&_effectStates[i], &_effectDefs[i]);
+		if (_effectEnvelopes[i].state != kEnvReady)
+			updateEffectGenerator(&_effectEnvelopes[i], &_effectDefs[i]);
 	}
 
 	return false;
@@ -398,52 +401,32 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
 	return kHighPriority;
 }
 
-int16 TownsMidiOutputChannel::getEffectLevel(uint8 type) {
-	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
-	
-	if (type == 28)
-		return 15;
-	else if (type == 29)
-		return 383;
-	else if (type > 29)
-		return 0;
-	else if (type > 12)
-		type -= 13;
-
-	int32 res = 0;
-	uint8 cs = (_driver->_chanState[chan].get(_effectDefaults[type * 4] >> 5) & _effectDefaults[type * 4 + 2]) >> _effectDefaults[type * 4 + 1];
-	if (_effectDefaults[type * 4 + 3])
-		res = _effectDefaults[type * 4 + 3] - cs;
-	
-	return res;	
-}
-
-void TownsMidiOutputChannel::initEffect(EffectState *s, const uint8 *effectData) {
-	s->envState = 1;
-	s->envStepLen = 0;
+void TownsMidiOutputChannel::startEffect(EffectEnvelope *s, const uint8 *effectData) {
+	s->state = kEnvAttacking;
+	s->currentLevel = 0;
 	s->modWheelLast = 31;
 	s->duration = effectData[0] * 63;
-	s->envStepping[0] = effectData[1];
-	s->envStepping[1] = effectData[3];
-	s->envStepping[2] = effectData[5];
-	s->envStepping[3] = effectData[6];
-	s->envMod[0] = effectData[2];
-	s->envMod[1] = effectData[4];
-	s->envMod[2] = 0;
-	s->envMod[3] = effectData[7];
-	updateEffect(s);
+	s->stateTargetLevels[0] = effectData[1];
+	s->stateTargetLevels[1] = effectData[3];
+	s->stateTargetLevels[2] = effectData[5];
+	s->stateTargetLevels[3] = effectData[6];
+	s->stateModWheelLevels[0] = effectData[2];
+	s->stateModWheelLevels[1] = effectData[4];
+	s->stateModWheelLevels[2] = 0;
+	s->stateModWheelLevels[3] = effectData[7];
+	initNextEnvelopeState(s);
 }
 
-void TownsMidiOutputChannel::updateEffectGenerator(EffectState *s, EffectDef *d) {
-	uint8 f = updateEffectEnvelope(s, d);
+void TownsMidiOutputChannel::updateEffectGenerator(EffectEnvelope *s, EffectDef *d) {
+	uint8 f = advanceEffectEnvelope(s, d);
 
 	if (f & 1) {
 		switch (d->type) {
 		case 0:
-			_operator2Tl = s->currentLevel + d->phase;
+			_operator2Tl = s->startLevel + d->phase;
 			break;
 		case 13:
-			_operator1Tl = s->currentLevel + d->phase;
+			_operator1Tl = s->startLevel + d->phase;
 			break;
 		case 30:
 			d->s->modWheelState = d->phase;
@@ -462,55 +445,54 @@ void TownsMidiOutputChannel::updateEffectGenerator(EffectState *s, EffectDef *d)
 	}
 }
 
-int TownsMidiOutputChannel::updateEffectEnvelope(EffectState *s, EffectDef *d) {
+int TownsMidiOutputChannel::advanceEffectEnvelope(EffectEnvelope *s, EffectDef *d) {
 	if (s->duration) {
 		s->duration -= 17;
 		if (s->duration <= 0) {
-			s->envState = 0;
+			s->state = kEnvReady;
 			return 0;
 		}
 	} 
 
-	int32 t = s->envStepLen + s->envChangePerStep;
+	int32 t = s->currentLevel + s->incrPerStep;
 	
-	s->envChangeCountRem += s->envChangePerStepRem;
-	if (s->envChangeCountRem >= s->envStateNumSteps) {
-		s->envChangeCountRem -= s->envStateNumSteps;
+	s->incrCountRem += s->incrPerStepRem;
+	if (s->incrCountRem >= s->numSteps) {
+		s->incrCountRem -= s->numSteps;
 		t += s->dir;
 	}
 
 	int retFlags = 0;
 
-	if (t != s->envStepLen || (s->modWheelState != s->modWheelLast)) {
-		s->envStepLen = t;
+	if (t != s->currentLevel || (s->modWheelState != s->modWheelLast)) {
+		s->currentLevel = t;
 		s->modWheelLast = s->modWheelState;
-		t = calcModWheelLevel(t, s->modWheelState);
+		t = getEffectModLevel(t, s->modWheelState);
 		if (t != d->phase)
 			d->phase = t;
 		retFlags |= 1;
 	}
 
-	if (--s->envStateStepCounter)
+	if (--s->stepCounter)
 		return retFlags;
 
-	if (++s->envState > 4) {
+	if (++s->state > kEnvReleasing) {
 		if (!s->loop) {
-			s->envState = 0;
+			s->state = kEnvReady;
 			return retFlags;
 		}
-		s->envState = 1;
+		s->state = kEnvAttacking;
 		retFlags |= 2;
 	}
 
-	updateEffect(s);
+	initNextEnvelopeState(s);
 
 	return retFlags;
 }
 
-void TownsMidiOutputChannel::updateEffect(EffectState *s) {
-	uint8 st= s->envState - 1;
-	uint8 v = s->envStepping[st];
-	int32 e = _effectEnvStepTable[_driver->_chanEffectLevelModifier[((v & 0x7f) << 5) + s->modWheelSensitivity]];
+void TownsMidiOutputChannel::initNextEnvelopeState(EffectEnvelope *s) {
+	uint8 v = s->stateTargetLevels[s->state - 1];
+	int32 e = _effectEnvStepTable[_driver->_operatorLevelTable[((v & 0x7f) << 5) + s->modWheelSensitivity]];
 
 	if (v & 0x80)
 		e = _driver->randomValue(e);
@@ -518,34 +500,54 @@ void TownsMidiOutputChannel::updateEffect(EffectState *s) {
 	if (!e)
 		e = 1;
 
-	s->envStateNumSteps = s->envStateStepCounter = e;
+	s->numSteps = s->stepCounter = e;
 	int32 d = 0;
 
-	if (st != 2) {
-		v = s->envMod[st];
-		e = calcModWheelLevel(s->envTargetLevel, (v & 0x7f) - 31);
+	if (s->state != kEnvSustaining) {
+		v = s->stateModWheelLevels[s->state - 1];
+		e = getEffectModLevel(s->maxLevel, (v & 0x7f) - 31);
 
 		if (v & 0x80)
 			e = _driver->randomValue(e);
 
-		if (e + s->currentLevel > s->envTargetLevel) {
-			e = s->envTargetLevel - s->currentLevel;
+		if (e + s->startLevel > s->maxLevel) {
+			e = s->maxLevel - s->startLevel;
 		} else {
-			if (e + s->currentLevel + 1 <= 0)
-				e = -s->currentLevel;
+			if (e + s->startLevel < 0)
+				e = -s->startLevel;
 		}
 
-		d = e - s->envStepLen;
+		d = e - s->currentLevel;
 	}
 
-	s->envChangePerStep = d / s->envStateNumSteps;
+	s->incrPerStep = d / s->numSteps;
 	s->dir = (d < 0) ? -1 : 1;
 	d *= s->dir;
-	s->envChangePerStepRem = d % s->envStateNumSteps;
-	s->envChangeCountRem = 0;
+	s->incrPerStepRem = d % s->numSteps;
+	s->incrCountRem = 0;
+}
+
+int16 TownsMidiOutputChannel::getEffectStartLevel(uint8 type) {
+	uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
+	
+	if (type == 28)
+		return 15;
+	else if (type == 29)
+		return 383;
+	else if (type > 29)
+		return 0;
+	else if (type > 12)
+		type -= 13;
+
+	const uint8 *def = &_effectDefaults[type << 2];
+	uint8 res = (_driver->_chanState[chan].get(def[0] >> 5) & def[2]) >> def[1];
+	if (def[3])
+		res = def[3] - res;
+	
+	return res;	
 }
 
-int TownsMidiOutputChannel::calcModWheelLevel(int lvl, int mod) {
+int TownsMidiOutputChannel::getEffectModLevel(int lvl, int mod) {
 	if (mod == 0)
 		return 0;
 
@@ -556,15 +558,15 @@ int TownsMidiOutputChannel::calcModWheelLevel(int lvl, int mod) {
 		return ((lvl + 1) * mod) >> 5;
 
 	if (mod < 0) {
-		if (mod < 0)			
-			return _driver->_chanEffectLevelModifier[((-lvl) << 5) - mod];
+		if (lvl < 0)			
+			return _driver->_operatorLevelTable[((-lvl) << 5) - mod];
 		else
-			return -_driver->_chanEffectLevelModifier[(lvl << 5) - mod];
+			return -_driver->_operatorLevelTable[(lvl << 5) - mod];
 	} else {
-		if (mod < 0)			
-			return -_driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
+		if (lvl < 0)			
+			return -_driver->_operatorLevelTable[((-lvl) << 5) + mod];
 		else
-			return _driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
+			return _driver->_operatorLevelTable[((-lvl) << 5) + mod];
 	}
 
 	return 0;
@@ -714,26 +716,26 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
 	oc->_sustainNoteOff = 0;
 	oc->_duration = _instrument[29] * 63;
 	
-	oc->_operator1Tl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+	oc->_operator1Tl = (_instrument[1] & 0x3f) + _driver->_operatorLevelTable[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
 	if (oc->_operator1Tl > 63)
 		oc->_operator1Tl = 63;
 
-	oc->_operator2Tl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+	oc->_operator2Tl = (_instrument[6] & 0x3f) + _driver->_operatorLevelTable[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
 	if (oc->_operator2Tl > 63)
 		oc->_operator2Tl = 63;
 
-	oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator1Tl << 5)]] : oc->_operator1Tl, _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator2Tl << 5)]]);
+	oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_operatorLevelTable[(_tl >> 2) + (oc->_operator1Tl << 5)]] : oc->_operator1Tl, _programAdjustLevel[_driver->_operatorLevelTable[(_tl >> 2) + (oc->_operator2Tl << 5)]]);
 	oc->noteOn(note + _transpose, _freqLSB);
 
 	if (_instrument[11] & 0x80)
 		oc->setupEffects(0, _instrument[11], &_instrument[12]);
 	else
-		oc->_effectStates[0].envState = 0;
+		oc->_effectEnvelopes[0].state = kEnvReady;
 
 	if (_instrument[20] & 0x80)
 		oc->setupEffects(1, _instrument[20], &_instrument[21]);
 	else
-		oc->_effectStates[1].envState = 0;
+		oc->_effectEnvelopes[1].state = kEnvReady;
 }
 
 void TownsMidiInputChannel::programChange(byte program) {
@@ -852,7 +854,7 @@ int MidiDriver_TOWNS::open() {
 
 	_channels = new TownsMidiInputChannel*[32];
 	for (int i = 0; i < 32; i++)
-		_channels[i] = new TownsMidiInputChannel(this, i);
+		_channels[i] = new TownsMidiInputChannel(this, i > 8 ? (i + 1) : i);
 	
 	_out = new TownsMidiOutputChannel*[6];
 	for (int i = 0; i < 6; i++)
@@ -860,13 +862,13 @@ int MidiDriver_TOWNS::open() {
 
 	_chanState = new TownsMidiChanState[32];
 
-	_chanEffectLevelModifier = new uint8[2048];
+	_operatorLevelTable = new uint8[2048];
 	for (int i = 0; i < 64; i++) {
 		for (int ii = 0; ii < 32; ii++)
-			_chanEffectLevelModifier[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
+			_operatorLevelTable[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
 	}
 	for (int i = 0; i < 64; i++)
-		_chanEffectLevelModifier[i << 5] = 0;
+		_operatorLevelTable[i << 5] = 0;
 
 	_intf->callback(0);
 
@@ -911,8 +913,8 @@ void MidiDriver_TOWNS::close() {
 
 	delete[] _chanState;
 	_chanState = 0;
-	delete[] _chanEffectLevelModifier;
-	_chanEffectLevelModifier = 0;
+	delete[] _operatorLevelTable;
+	_operatorLevelTable = 0;
 }
 
 void MidiDriver_TOWNS::send(uint32 b) {
@@ -1009,8 +1011,7 @@ void MidiDriver_TOWNS::updateOutputChannels() {
 	while (_tickCounter2 >= 16667) {
 		_tickCounter2 -= 16667;
 		for (int i = 0; i < 6; i++) {
-			TownsMidiOutputChannel *oc = _out[i];
-			if (oc->update())
+			if (_out[i]->update())
 				return;
 		}
 	}
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 52298d7..2b6e1df 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -78,7 +78,7 @@ private:
 	
 	bool _open;
 
-	uint8 *_chanEffectLevelModifier;
+	uint8 *_operatorLevelTable;
 };
 
 #endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index cbf856c..f7bcc90 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -44,7 +44,7 @@ class TownsPC98_FmSynthPercussionSource;
 #endif
 
 enum EnvelopeState {
-	kEnvReady,
+	kEnvReady = 0,
 	kEnvAttacking,
 	kEnvDecaying,
 	kEnvSustaining,


Commit: d3e92f0b8105638b8fae45822006aa33bb8ed35a
    https://github.com/scummvm/scummvm/commit/d3e92f0b8105638b8fae45822006aa33bb8ed35a
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Fix several CppCheck warnings

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_audio.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
index f2d249b..dd9bf61 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -255,7 +255,8 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 	_baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver),
 	_pcmSfxChanMask(0),	_musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume),
 	_outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
-	_pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _ready(false) {
+	_pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _fmChanPlaying(0), 
+	_numReservedChannels(0), _numWaveTables(0), _ready(false) {
 
 #define INTCB(x) &TownsAudioInterfaceIntern::intf_##x
 	static const TownsAudioIntfCallback intfCb[] = {
@@ -368,6 +369,11 @@ TownsAudioInterfaceIntern::TownsAudioInterfaceIntern(Audio::Mixer *mixer, TownsA
 	_intfOpcodes = intfCb;
 
 	memset(_fmSaveReg, 0, sizeof(_fmSaveReg));
+	memset(_fmChanNote, 0, sizeof(_fmChanNote));
+	memset(_fmChanPitch, 0, sizeof(_fmChanPitch));
+	memset(_pcmChanNote, 0, sizeof(_pcmChanNote));	
+	memset(_pcmChanVelo, 0, sizeof(_pcmChanVelo));
+	memset(_pcmChanLevel, 0, sizeof(_pcmChanLevel));
 	memset(_outputLevel, 0, sizeof(_outputLevel));
 	memset(_outputMute, 0, sizeof(_outputMute));
 
@@ -980,9 +986,9 @@ int TownsAudioInterfaceIntern::intf_setOutputMute(va_list &args) {
 
 	memset(_outputMute, 1, 8);
 	if (mute & 2)
-		memset(_outputMute + 12, 1, 4);
+		memset(&_outputMute[12], 1, 4);
 	if (mute & 1)
-		memset(_outputMute + 8, 1, 4);	
+		memset(&_outputMute[8], 1, 4);	
 
 	_outputMute[(f < 0x80) ? 11 : 15] = 0;
 	f += f;
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index f7aa33f..bc2c88b 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -28,7 +28,8 @@
 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) {
+	_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);
 	resetTempo();
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 6b31ea1..0743409 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -670,7 +670,7 @@ TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanI
 }
 
 TownsMidiInputChannel::~TownsMidiInputChannel() {
-	delete _instrument;
+	delete[] _instrument;
 }
 
 bool TownsMidiInputChannel::allocate() {
@@ -836,7 +836,8 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 	0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F
 };
 
-MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _open(false) {
+MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _channels(0), _out(0),
+	_chanState(0), _operatorLevelTable(0), _tickCounter1(0), _tickCounter2(0), _rand(1), _allocCurPos(0), _open(false) {
 	_intf = new TownsAudioInterface(mixer, this);
 }
 
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 09d3ca3..46ac7e5 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -99,7 +99,7 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
 	_rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
 	_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
 	_specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
-	_phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
+	_sustainLevel(0), _phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
 	_keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) {
 
 	fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
@@ -653,7 +653,8 @@ void TownsPC98_FmSynthSquareSineSource::updateRegs() {
 
 #ifndef DISABLE_PC98_RHYTHM_CHANNEL
 TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt) :
-	_rtt(rtt), _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
+	_rtt(rtt), _tickLength(timerbase * 2), _timer(0), _totalLevel(0), _volMaskA(0), _volMaskB(0),
+	_volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume), _ready(false) {
 
 	memset(_rhChan, 0, sizeof(RhtChannel) * 6);
 	_reg = new uint8 *[40];
@@ -1256,7 +1257,7 @@ void TownsPC98_FmSynth::generateTables() {
 	WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018);
 	WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018);
 	memset(_oprRates, 0x90, 32);
-	memset(_oprRates + 96, 0x80, 32);
+	memset(&_oprRates[96], 0x80, 32);
 	uint8 *dst = (uint8 *)_oprRates + 40;
 	for (int i = 0; i < 40; i += 4)
 		WRITE_BE_UINT32(dst + i, 0x00081018);
@@ -1313,8 +1314,8 @@ void TownsPC98_FmSynth::generateTables() {
 
 	uint8 *dtt = new uint8[128];
 	memset(dtt, 0, 36);
-	memset(dtt + 36, 1, 8);
-	memcpy(dtt + 44, _detSrc, 84);
+	memset(&dtt[36], 1, 8);
+	memcpy(&dtt[44], _detSrc, 84);
 
 	delete[] _oprDetune;
 	_oprDetune = new int32[256];


Commit: 726a7f3b1aee4abd7c1fe198cbd317664685e21f
    https://github.com/scummvm/scummvm/commit/726a7f3b1aee4abd7c1fe198cbd317664685e21f
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:36:32-07:00

Commit Message:
FM-TOWNS AUDIO: Fix GCC warnings

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 0743409..e66d6be 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -18,8 +18,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * $URL:  $
- * $Id:  $
  */
 
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 46ac7e5..bc5aa32 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -928,7 +928,7 @@ bool TownsPC98_FmSynth::init() {
 }
 
 void TownsPC98_FmSynth::reset() {
-	Common::StackLock lock(_mutex);
+	lock();
 	for (int i = 0; i < _numChan; i++) {
 		for (int ii = 0; ii < 4; ii++)
 			_chanInternal[i].opr[ii]->reset();
@@ -948,6 +948,7 @@ void TownsPC98_FmSynth::reset() {
 	if (_prc)
 		_prc->reset();
 #endif
+	unlock();
 }
 
 void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {


Commit: 87571909be0c9f4c29eb1384665be064d2ee8f42
    https://github.com/scummvm/scummvm/commit/87571909be0c9f4c29eb1384665be064d2ee8f42
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-17T11:42:47-07:00

Commit Message:
SCUMM FM-TOWNS: iMUSE MIDI driver for INDY4/MONKEY2

- This adds an accurate imuse midi driver implementation for the
FM-Towns versions of MI2 and INDY4. Until now you could only use the
PC devices for these two games (which was not a real issue since the
audio tracks are dedicated AdLib and MT-32 tracks anyway; for FM-Towns
the AdLib music simply gets converted which is not really satisfactory).
Anyway, the new driver it will sound just like when using an emulator
like UNZ.

- The YM2612 code was removed since it was not used anymore (except for
the plugin code which was moved to a separate file).  Some explanation
about this: The YM2612 code was an incomplete (no instrument support, no
pcm support, no proper tempo handling, etc.) implementation of the
FM-Towns euphony driver which is used for some sound effects in SCUMM3
games (e.g. LOOM distaff). We do have a rather complete and accurate
implementation of that driver in fmtowns_pc98\towns_euphony.cpp (used
only in KYRA 1 FM-Towns at first, but also in SCUMM3 since last summer).
So this is safe to be removed.

Changed paths:
  A audio/softsynth/fmtowns_pc98/towns_midi.cpp
  A audio/softsynth/fmtowns_pc98/towns_midi.h
  A audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
  R audio/softsynth/ym2612.cpp
  R audio/softsynth/ym2612.h
    audio/module.mk
    audio/softsynth/fmtowns_pc98/towns_audio.cpp
    audio/softsynth/fmtowns_pc98/towns_audio.h
    audio/softsynth/fmtowns_pc98/towns_euphony.cpp
    audio/softsynth/fmtowns_pc98/towns_euphony.h
    audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
    base/plugins.cpp
    engines/kyra/sound_towns.cpp
    engines/scumm/detection_tables.h
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/player_towns.cpp
    engines/scumm/player_towns.h
    engines/scumm/scumm.cpp
    engines/scumm/sound.cpp









More information about the Scummvm-git-logs mailing list