[Scummvm-cvs-logs] scummvm master -> 15ea9b15cbb1210b14490819c5bc04f72ed7e6c8

athrxx athrxx at scummvm.org
Mon May 16 23:21:55 CEST 2011


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

Summary:
ee89e9a086 VKEYBD: Update vkeybd_default.zip
b4d59f9ce5 FM-TOWNS AUDIO: some more midi driver code for FM-TOWNS versions of monkey2 and indy4
f98be17d74 FM-TOWNS AUDIO: fix compilation
afacbd459f FM-TOWNS AUDIO: change internal interface layout
61c5813ccf MONKEY2/INDY4 FM-TOWNS: adapt code to latest audio driver changes
ad991a7831 FM TOWNS AUDIO: implement some midi driver functions
0dce8bab37 FM-TOWNS AUDIO: implement some more midi driver code
df244dd3c1 FM TOWNS AUDIO: some more midi driver code
70b2466cd7 FM-TOWNS AUDIO: implement some midi commands
39e2aa17ed FM-TOWNS AUDIO: more midi driver code (effect processing)
0e819b8dfa FM-TOWNS AUDIO: some renaming in the euphony driver code
ed13e551d1 FM-TOWNS AUDIO: more midi driver code
17861037ba MONKEY2 / INDY4 FM-TOWNS: set proper GUIO flags
78130f940f FM-TOWNS AUDIO: start fixing midi driver tempo
214a70002f FM-TOWNS AUDIO: fixed mod wheel setting
41edb7c6b5 FM-TOWNS AUDIO: some more midi driver code
232cb2410c FM-TOWNS AUDIO: improve thread safety
66d19fde68 FM-TOWNS AUDIO: some midi code fixes and some renaming
e1ac2882bc SCUMM: add missing imuse feature
bbbde5aa67 FM-TOWNS AUDIO: fix some midi driver bugs
73d5b9f595 FM-TOWNS AUDIO: fix note off event in midi driver
13497a9b0f SCUMM: fix recent commit (proper initialize new detune parameter)
f9eb329c79 FM-TOWNS AUDIO: fix some bugs and rename some stuff in the midi driver code
a9f7888ad9 FM TOWNS AUDIO: some fixes and renaming
747b86433c SCUMM: partly revert / fix recent detune commit
52e4f162dd FMTOWNS AUDIO: fix several CppCheck warnings
cd359cab1b GOB: Add a non-interactive Adibou2 demo
7fd78c5998 FM-TOWNS AUDIO: fix GCC warnings
7a489ef005 Merge branch 'master' of git://github.com/scummvm/scummvm
15ea9b15cb SCUMM FM-TOWNS: iMUSE MIDI driver for INDY4/MONKEY2



Commit: ee89e9a0866fd0c292de8f29d236d1e7d4be70b3
    https://github.com/scummvm/scummvm/commit/ee89e9a0866fd0c292de8f29d236d1e7d4be70b3
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:14-07:00

Commit Message:
VKEYBD: Update vkeybd_default.zip

Specifically, in vkeybd_default.xml, 'centre' changed to 'center'.
SCUMM: formatting
README: Add partial translations of README file

This add an english template for translation of README file and
French and German translations (using UTF8 encoding).
ENGINES: Unify engine names

This unifies the engine names in MetaEngine::getName() and the
credits. In particular drop "Engine" or "engine" from the names when
it was present and use expanded names in credits when the
MetaEngine uses it (e.g. "Beneath a Steel Sky" instead of "BASS").
GUI: Apply graphics mode change when closing global options dialog
IPHONE: Fixed mouse position when the overlay is visible
TSAGE: Fix bad palette in the Fleeing planet cutscene

It was using out-of-bounds data to manipulate the palette, and a
missing break caused it to change palette again immediately. Still,
even after this change I had the impression that the temporary
palette was visible for a bit longer in DOSBox. Could be my
imagination, though.
TSAGE: Fix for crash when hiding cursor in Ringworld demo
TSAGE: Implemented the Exit dialog in the Ringworld demo
TSAGE: Bugfixes for dialogs correctly handling ESCAPE and ENTER
TSAGE: Changed demo quit dialog to correctly handle ESCAPE and ENTER keys
TSAGE: Added support for handling keypresses in the Game classes. Separated logic for full game versus demo into the respective Game classes.
COMMON: Set _capacity to just _size in Common::Array::operator=
COMMON: Change Array::insert_aux to immediately assign newly allocated memory to _storage
COMMON: Unify Array memory allocation

We also change how alloc failures are handled: Instead of using
assert(), which is usually disabled in release builds on various
platforms, we now *always* catch this situation and invoke error() if
necessary.
COMMON: Don't allocate zero-sized storage in array
AUDIO: Clarify required parameters for mixCallback.

Also, add an assert() to make invalid lengths obvious.
TEST: Explicitly disable exceptions and std lib usage
COMMON: Fix inserting an array into itself under certain conditions
SCUMM: fix regression
Merge branch 'master' of https://github.com/scummvm/scummvm
VKEYBD: Update vkeybd_default.zip

Specifically, in vkeybd_default.xml, 'centre' changed to 'center'.
SCUMM: formatting
README: Add partial translations of README file

This add an english template for translation of README file and
French and German translations (using UTF8 encoding).
ENGINES: Unify engine names

This unifies the engine names in MetaEngine::getName() and the
credits. In particular drop "Engine" or "engine" from the names when
it was present and use expanded names in credits when the
MetaEngine uses it (e.g. "Beneath a Steel Sky" instead of "BASS").
GUI: Apply graphics mode change when closing global options dialog
IPHONE: Fixed mouse position when the overlay is visible
TSAGE: Fix bad palette in the Fleeing planet cutscene

It was using out-of-bounds data to manipulate the palette, and a
missing break caused it to change palette again immediately. Still,
even after this change I had the impression that the temporary
palette was visible for a bit longer in DOSBox. Could be my
imagination, though.
Merge branch 'master' of git://github.com/scummvm/scummvm
TSAGE: Fix for crash when hiding cursor in Ringworld demo
TSAGE: Implemented the Exit dialog in the Ringworld demo
TSAGE: Bugfixes for dialogs correctly handling ESCAPE and ENTER
TSAGE: Changed demo quit dialog to correctly handle ESCAPE and ENTER keys
TSAGE: Added support for handling keypresses in the Game classes. Separated logic for full game versus demo into the respective Game classes.
COMMON: Set _capacity to just _size in Common::Array::operator=
COMMON: Change Array::insert_aux to immediately assign newly allocated memory to _storage
COMMON: Unify Array memory allocation

We also change how alloc failures are handled: Instead of using
assert(), which is usually disabled in release builds on various
platforms, we now *always* catch this situation and invoke error() if
necessary.
COMMON: Don't allocate zero-sized storage in array
AUDIO: Clarify required parameters for mixCallback.

Also, add an assert() to make invalid lengths obvious.
TEST: Explicitly disable exceptions and std lib usage
COMMON: Fix inserting an array into itself under certain conditions
SCUMM: fix regression
Merge branch 'master' of https://github.com/scummvm/scummvm
Merge branch 'master' of git://github.com/scummvm/scummvm

Changed paths:
  A doc/translations/README-de.txt
  A doc/translations/README-fr.txt
  A doc/translations/README-translation_template.txt
    AUTHORS
    audio/mixer.cpp
    audio/mixer_intern.h
    backends/platform/iphone/iphone_video.m
    backends/vkeybd/packs/vkeybd_default.zip
    common/array.h
    devtools/credits.pl
    engines/agi/detection.cpp
    engines/cine/detection.cpp
    engines/cruise/detection.cpp
    engines/draci/detection.cpp
    engines/drascula/detection.cpp
    engines/gob/detection.cpp
    engines/groovie/detection.cpp
    engines/hugo/detection.cpp
    engines/kyra/detection.cpp
    engines/lastexpress/detection.cpp
    engines/lure/detection.cpp
    engines/m4/detection.cpp
    engines/made/detection.cpp
    engines/mohawk/detection.cpp
    engines/parallaction/detection.cpp
    engines/saga/detection.cpp
    engines/sci/detection.cpp
    engines/scumm/detection.cpp
    engines/scumm/imuse/imuse.cpp
    engines/sword25/detection.cpp
    engines/teenagent/detection.cpp
    engines/tinsel/detection.cpp
    engines/toon/detection.cpp
    engines/touche/detection.cpp
    engines/tsage/core.cpp
    engines/tsage/detection.cpp
    engines/tsage/events.cpp
    engines/tsage/graphics.cpp
    engines/tsage/ringworld_demo.cpp
    engines/tsage/ringworld_demo.h
    engines/tsage/ringworld_logic.cpp
    engines/tsage/ringworld_logic.h
    engines/tsage/ringworld_scenes2.cpp
    engines/tsage/scenes.h
    engines/tsage/staticres.cpp
    engines/tsage/staticres.h
    engines/tucker/detection.cpp
    gui/credits.h
    gui/options.cpp
    test/common/array.h
    test/module.mk



diff --git a/AUTHORS b/AUTHORS
index ca6342d..d8d26ce 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -49,7 +49,7 @@ ScummVM Team
        Oliver Kiehl          - (retired)
        Ludvig Strigeus       - (retired)
 
-    BASS:
+    Beneath a Steel Sky:
        Robert Goeffringmann  - (retired)
        Oliver Kiehl          - (retired)
        Joost Peters
@@ -82,7 +82,7 @@ ScummVM Team
        Paul Gilbert
        Vincent Hamm          - (retired)
 
-    Draci:
+    Draci Historie:
        Denis Kasak
        Robert Spalek
 
@@ -90,7 +90,7 @@ ScummVM Team
        Filippos Karapetis
        Pawel Kolodziejski
 
-    FOTAQ:
+    Flight of the Amazon Queen:
        David Eriksson        - (retired)
        Gregory Montoir
        Joost Peters
@@ -111,7 +111,7 @@ ScummVM Team
        Oystein Eftevaag
        Eugene Sandulenko
 
-    Kyra:
+    Legend of Kyrandia:
        Torbjorn Andersson    - VQA Player
        Oystein Eftevaag
        Florian Kagerer
@@ -123,7 +123,7 @@ ScummVM Team
        Jordi Vilalta Prat
        Julien Templier
 
-    Lure:
+    Lure of the Temptress:
        Paul Gilbert
 
     M4:
@@ -164,7 +164,7 @@ ScummVM Team
        Jordi Vilalta Prat
        Lars Skovlund
 
-    TeenAgent:
+    Teen Agent:
        Robert Megone         - Help with callback rewriting
        Vladimir Menshakov
 
diff --git a/audio/mixer.cpp b/audio/mixer.cpp
index 3482bd3..fb4fffb 100644
--- a/audio/mixer.cpp
+++ b/audio/mixer.cpp
@@ -257,6 +257,8 @@ int MixerImpl::mixCallback(byte *samples, uint len) {
 	Common::StackLock lock(_mutex);
 
 	int16 *buf = (int16 *)samples;
+	// we store stereo, 16-bit samples
+	assert(len % 4 == 0);
 	len >>= 2;
 
 	// Since the mixer callback has been called, the mixer must be ready...
diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h
index 05e519c..a04eb55 100644
--- a/audio/mixer_intern.h
+++ b/audio/mixer_intern.h
@@ -126,6 +126,8 @@ public:
 	 * the backend (e.g. from an audio mixing thread). All the actual mixing
 	 * work is done from here.
 	 *
+	 * @param samples Sample buffer, in which stereo 16-bit samples will be stored.
+	 * @param len Length of the provided buffer to fill (in bytes, should be divisible by 4).
 	 * @return number of sample pairs processed (which can still be silence!)
 	 */
 	int mixCallback(byte *samples, uint len);
diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m
index 09832c7..006603d 100644
--- a/backends/platform/iphone/iphone_video.m
+++ b/backends/platform/iphone/iphone_video.m
@@ -175,13 +175,18 @@ const char* iPhone_getDocumentsDir() {
 }
 
 bool getLocalMouseCoords(CGPoint *point) {
-	if (point->x < _screenRect.origin.x || point->x >= _screenRect.origin.x + _screenRect.size.width ||
-		point->y < _screenRect.origin.y || point->y >= _screenRect.origin.y + _screenRect.size.height) {
-			return false;
-	}
+	if (_overlayIsEnabled) {
+		point->x = point->x / _overlayHeight;
+		point->y = point->y / _overlayWidth;
+	} else {
+		if (point->x < _screenRect.origin.x || point->x >= _screenRect.origin.x + _screenRect.size.width ||
+			point->y < _screenRect.origin.y || point->y >= _screenRect.origin.y + _screenRect.size.height) {
+				return false;
+		}
 
-	point->x = (point->x - _screenRect.origin.x) / _screenRect.size.width;
-	point->y = (point->y - _screenRect.origin.y) / _screenRect.size.height;
+		point->x = (point->x - _screenRect.origin.x) / _screenRect.size.width;
+		point->y = (point->y - _screenRect.origin.y) / _screenRect.size.height;
+	}
 
 	return true;
 }
diff --git a/backends/vkeybd/packs/vkeybd_default.zip b/backends/vkeybd/packs/vkeybd_default.zip
index 94c4649..960e943 100644
Binary files a/backends/vkeybd/packs/vkeybd_default.zip and b/backends/vkeybd/packs/vkeybd_default.zip differ
diff --git a/common/array.h b/common/array.h
index 9b94709..7ab4a1b 100644
--- a/common/array.h
+++ b/common/array.h
@@ -24,6 +24,7 @@
 
 #include "common/scummsys.h"
 #include "common/algorithm.h"
+#include "common/textconsole.h"	// For error()
 
 namespace Common {
 
@@ -72,8 +73,7 @@ public:
 
 	Array(const Array<T> &array) : _capacity(array._size), _size(array._size), _storage(0) {
 		if (array._storage) {
-			_storage = new T[_capacity];
-			assert(_storage);
+			allocCapacity(_size);
 			copy(array._storage, array._storage + _size, _storage);
 		}
 	}
@@ -83,9 +83,8 @@ public:
 	 */
 	template<class T2>
 	Array(const T2 *data, int n) {
-		_capacity = _size = n;
-		_storage = new T[_capacity];
-		assert(_storage);
+		_size = n;
+		allocCapacity(n);
 		copy(data, data + _size, _storage);
 	}
 
@@ -179,9 +178,7 @@ public:
 
 		delete[] _storage;
 		_size = array._size;
-		_capacity = _size + 32;
-		_storage = new T[_capacity];
-		assert(_storage);
+		allocCapacity(_size);
 		copy(array._storage, array._storage + _size, _storage);
 
 		return *this;
@@ -238,15 +235,13 @@ public:
 		if (newCapacity <= _capacity)
 			return;
 
-		T *old_storage = _storage;
-		_capacity = newCapacity;
-		_storage = new T[newCapacity];
-		assert(_storage);
+		T *oldStorage = _storage;
+		allocCapacity(newCapacity);
 
-		if (old_storage) {
+		if (oldStorage) {
 			// Copy old data
-			copy(old_storage, old_storage + _size, _storage);
-			delete[] old_storage;
+			copy(oldStorage, oldStorage + _size, _storage);
+			delete[] oldStorage;
 		}
 	}
 
@@ -267,6 +262,17 @@ protected:
 		return capa;
 	}
 
+	void allocCapacity(uint capacity) {
+		_capacity = capacity;
+		if (capacity) {
+			_storage = new T[capacity];
+			if (!_storage)
+				::error("Common::Array: failure to allocate %d bytes", capacity);
+		} else {
+			_storage = 0;
+		}
+	}
+
 	/**
 	 * Insert a range of elements coming from this or another array.
 	 * Unlike std::vector::insert, this method does not accept
@@ -286,29 +292,28 @@ protected:
 		const uint n = last - first;
 		if (n) {
 			const uint idx = pos - _storage;
-			T *newStorage = _storage;
-			if (_size + n > _capacity) {
+			T *oldStorage = _storage;
+			if (_size + n > _capacity || (_storage <= first && first <= _storage + _size) ) {
 				// If there is not enough space, allocate more and
 				// copy old elements over.
-				uint newCapacity = roundUpCapacity(_size + n);
-				newStorage = new T[newCapacity];
-				assert(newStorage);
-				copy(_storage, _storage + idx, newStorage);
-				pos = newStorage + idx;
+				// Likewise, if this is a self-insert, we allocate new
+				// storage to avoid conflicts. This is not the most efficient
+				// way to ensure that, but probably the simplest on.
+				allocCapacity(roundUpCapacity(_size + n));
+				copy(oldStorage, oldStorage + idx, _storage);
+				pos = _storage + idx;
 			}
 
 			// Make room for the new elements by shifting back
 			// existing ones.
-			copy_backward(_storage + idx, _storage + _size, newStorage + _size + n);
+			copy_backward(oldStorage + idx, oldStorage + _size, _storage + _size + n);
 
 			// Insert the new elements.
 			copy(first, last, pos);
 
 			// Finally, update the internal state
-			if (newStorage != _storage) {
-				delete[] _storage;
-				_capacity = roundUpCapacity(_size + n);
-				_storage = newStorage;
+			if (_storage != oldStorage) {
+				delete[] oldStorage;
 			}
 			_size += n;
 		}
diff --git a/devtools/credits.pl b/devtools/credits.pl
index 46c7540..8d02891 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -500,7 +500,7 @@ begin_credits("Credits");
 		  add_person("Ludvig Strigeus", "ludde", "(retired)");
 	  end_section();
 
-	  begin_section("BASS");	# Beneath a Steel Sky
+	  begin_section("Beneath a Steel Sky");
 		  add_person("Robert Göffringmann", "lavosspawn", "(retired)");
 		  add_person("Oliver Kiehl", "olki", "(retired)");
 		  add_person("Joost Peters", "joostp", "");
@@ -539,7 +539,7 @@ begin_credits("Credits");
 		  add_person("Vincent Hamm", "yaz0r", "(retired)");
 	  end_section();
 
-	  begin_section("Draci");
+	  begin_section("Draci Historie");
 		  add_person("Denis Kasak", "dkasak13", "");
 		  add_person("Robert Špalek", "spalek", "");
 	  end_section();
@@ -549,7 +549,7 @@ begin_credits("Credits");
 		  add_person("Paweł Kołodziejski", "aquadran", "");
 	  end_section();
 
-	  begin_section("FOTAQ");	# Flight of the Amazon Queen
+	  begin_section("Flight of the Amazon Queen");
 		  add_person("David Eriksson", "twogood", "(retired)");
 		  add_person("Gregory Montoir", "cyx", "");
 		  add_person("Joost Peters", "joostp", "");
@@ -574,7 +574,7 @@ begin_credits("Credits");
 		  add_person("Eugene Sandulenko", "sev", "");
 	  end_section();
 
-	  begin_section("Kyra");
+	  begin_section("Legend of Kyrandia");
 		  add_person("Torbjörn Andersson", "eriktorbjorn", "VQA Player");
 		  add_person("Oystein Eftevaag", "vinterstum", "");
 		  add_person("Florian Kagerer", "athrxx", "");
@@ -588,7 +588,7 @@ begin_credits("Credits");
 			add_person("Julien Templier", "littleboy", "");			
 	end_section();
 
-	  begin_section("Lure");
+	  begin_section("Lure of the Temptress");
 		  add_person("Paul Gilbert", "dreammaster", "");
 	  end_section();
 
@@ -636,7 +636,7 @@ begin_credits("Credits");
 		  add_person("Lars Skovlund", "lskovlun", "");
 	  end_section();
 
-	  begin_section("TeenAgent");
+	  begin_section("Teen Agent");
 		  add_person("Robert Megone", "sanguine", "Help with callback rewriting");
 		  add_person("Vladimir Menshakov", "whoozle", "");
 	  end_section();
diff --git a/doc/translations/README-de.txt b/doc/translations/README-de.txt
new file mode 100755
index 0000000..a1d7d6e
--- /dev/null
+++ b/doc/translations/README-de.txt
@@ -0,0 +1,178 @@
+Dieses Dokument ist eine auszugsweise Übersetzung der englischen
+REAMDE-Datei. Das Original-Dokument enthält viel mehr Informationen.
+Sollten Sie hier also nicht das finden, was Sie benötigen und ein wenig
+Englisch können, sollten Sie sich die englische README-Datei ansehen.
+
+Für weitere Informationen, Kompatiblitätslisten, Einzelheiten zu Spenden,
+die neusten veröffentlichten Versionen, Fortschrittberichte und mehr
+besuchen Sie bitte die ScummVM-Website unter der Adresse:
+http://www.scummvm.org/
+
+Inhaltsverzeichnis:
+------------------
+1.0) Einführung
+ * 1.1 Über ScummVM
+ * 1.2 Schnellstart
+2.0) Kontakt
+ * 2.1 Fehler berichten
+
+1.0) Einführung:
+---- -------------
+
+1.1) Über ScummVM:
+---- --------------
+ScummVM ist ein Programm, welches es Ihnen ermöglicht, bestimmte klassische
+Grafik-Adventure (unter anderem aus dem Point-and-Click-Bereich) zu spielen,
+vorausgesetzt, Sie sind im Besitz der Dateien des Spiels. Das Schlaue daran
+ist: ScummVM ersetzt lediglich die Funktion der ausführbaren Dateien,
+die mit den Spielen kamen, was ermöglicht, diese Spiele auf Systemen zu spielen,
+für welche sie nie erstellt wurden!
+
+Ursprünglich wurde dieses Programm dafür entwickelt, um SCUMM-Spiele von
+LucasArts auszuführen, wie beispielsweise Maniac Mansion, Monkey Island,
+Day of the Tentacle oder Sam and Max. SCUMM steht als Abkürzung für
+„Script Creation Utility for Maniac Mansion“ (deutsch etwa:
+Skripterstellungsdienstprogramm für Maniac Mansion), was das erste
+Spiel von LucasArts war, für welches LucasArts dieses System entworfen hatte.
+Und viel später verlieh es seinen Namen an ScummVM (wobei „VM“ für
+„Virtuelle Maschine“ steht).
+
+Mit der Zeit wurde Unterstützung für viele Nicht-SCUMM-Spiele hinzugefügt.
+Einige Adventures, die ScummVM unterstützt, sind unter anderem Simon the
+Sorcerer 1 und 2 von Adventure Soft, Beneath A Steel Sky und
+Baphomets Fluch 1 und 2 von Revolution, Flight of the Amazon Queen,
+Erben der Erde (Wyrmkeep), Gobliiins von Coktel Vision sowie
+The Legend of Kyrandia von Westwood Studios.
+Sie können eine genaue Liste mit Einzelheiten einsehen, welche Auskunft
+darüber gibt, welche Spiele unterstützt werden und wie gut. Gehen Sie
+hierfür auf die Kompatiblitätsseite. ScummVM wird kontinuierlich
+verbessert, also schauen Sie oft vorbei.
+
+Unter den Systemen, mit denen Sie diese Spiele spielen können, befinden
+sich Windows, Linux, Mac OS X, Dreamcast, PocketPC, PalmOS, iPhone,
+AmigaOS, BeOS, OS/2, PSP, PS2, SymbianOS/EPOC und viele mehr.
+
+Zurzeit befindet sich ScummVM immer noch stark in der Entwicklung.
+Seien Sie sich bewusst, dass wir zwar versuchen, dass viele Spiele
+mit wenigen erheblichen Fehlern durchgespielt werden können, aber es
+dennoch zu Abstürzen kommen kann und wir keine Gewähr übernehmen.
+Davon abgesehen: Einige Spiele werden seit längerer Zeit unterstützt
+und sollten in jeder stabilen veröffentlichten Version gut laufen.
+Sie können sich einen Eindruck davon verschaffen, wie gut jedes Spiel
+unter ScummVM läuft, indem Sie auf die Kompatiblitätsseite schauen.
+
+Wenn Sie sich ein wenig umsehen, können Sie herausfinden, dass
+ScummVM sogar kommerziell genutzt wird, um einige der unterstützen Spiele
+auf modernen Plattformen wiederzuveröffentlichen. Dies zeigt, dass
+verschiedene Firmen mit der Qualität der Software zufrieden sind und wie gut
+einige der Spiele mit ihrer Hilfe laufen.
+
+Wenn Ihnen ScummVM gefällt, können Sie uns gerne etwas Geld spenden,
+um uns finanziell zu unterstützen. Dies hilft uns dabei, notwendige
+Dienstprogramme zu kaufen, um ScummVM einfacher und schneller zu entwickeln.
+Wenn Sie nicht spenden können, dürfen Sie auch gerne einen Patch beisteuern.
+
+1.2) Schnellstart:
+---- ------------
+WICHTIG: In der unteren kurzen Anleitung wird davon ausgegangen, dass Sie
+ScummVM auf Deutsch benutzen. Standardmäßig wird ScummVM die Sprache
+Ihres Betriebssystems verwenden. Falls ScummVM auf Englisch statt auf
+Deutsch erscheint, sollten Sie folgende Schritte ausführen, wenn Sie bei
+Schritt 3 angelangt sind und ScummVM gestartet haben:
+-Klicken Sie auf "Options".
+-Klicken Sie auf den rechten Pfeil in der Reiterleiste und wählen den
+ Reiter "Misc" aus.
+-Wählen Sie im Feld "GUI Language" "Deutsch" aus und klicken auf "OK".
+-Bestätigen Sie die erscheinende Nachricht, klicken auf "Quit", um
+ ScummVM zu beenden und starten dann das Programm erneut.
+
+Wenn Sie ScummVM lieber in Englisch verwenden möchten, benutzen Sie bitte
+die Anleitung in der englischen README-Datei.
+
+
+Für die ungelduldigen unter den Benutzern ist hier in fünf einfachen
+Schritten kurz beschrieben, wie man ScummVM lauffähig macht und das
+Programm verwendet.
+
+1. Laden Sie ScummVM unter der Adresse
+<http://www.scummvm.org/downloads.php> herunter und installieren Sie es.
+
+2. Erstellen Sie ein Verzeichnis auf Ihrer Festplatte und kopieren Sie
+die Dateien des Spiels vom Original-Datenträger in dieses Verzeichnis.
+Wiederholen Sie diesen Vorgang für jedes Spiel, das Sie spielen möchten.
+
+3. Starten Sie ScummVM, wählen Sie "Spiel hinzufügen" aus, wählen Sie das
+Verzeichnis mit den Dateien des Spiels aus (versuchen Sie nicht, die
+Dateien des Spiels selbst auszuwählen!) und klicken Sie auf "Auswählen".
+
+4. Ein Dialog sollte erscheinen, der Ihnen ermöglicht, verschiedene
+Einstellungen vorzunehmn, sollten Sie dies wünschen (es sollte jedoch in
+Ordnung sein, alles voreingestellt zu belassen). Bestätigen Sie diesen
+Dialog.
+
+5. Wählen Sie das Spiel aus der Liste aus, welches Sie spielen möchten
+und klicken Sie auf "Starten".
+
+In Zukunft sollte es nun möglich sein, direkt zu Schritt 5 überzugehen,
+außer Sie wollen noch mehr Spiele hinzufügen.
+
+Tipp: Wenn Sie mehrere Spiele auf einmal hinzufügen möchten, drücken Sie
+die Umschalt-Taste (Shift), bevor Sie auf "Spiel hinzufügen" klicken.
+Diese Schaltfläche wird somit ihren Text zu "Durchsuchen" umändern und
+wenn Sie dann auf diese klicken, werden Sie auch dazu aufgefordert, ein
+Verzeichnis auszuwählen, nur dieses Mal wird ScummVM alle
+Unterverzeichnisse automatisch nach unterstützen Spielen durchsuchen.
+
+
+2.0) Kontakt:
+---- --------
+Der einfachste Weg, um mit dem ScummVM-Team in Verbindung zu treten, ist,
+Fehlerberichte einzusenden (siehe Abschnitt 2.1) oder durch Verwendung
+des Forums unter der Adresse http://forums.scummvm.org .
+Sie können ebenso der Mailing-Liste scummvm-devel betreiten und an diese
+E-Mails versenden oder mit uns im IRC chatten (#scummvm unter
+irc.freenode.net). Bitte fordern Sie uns nicht dazu auf, ein nicht
+unterstütztes Spiel zu unterstützen. Lesen Sie zuerst die Seite FAQ
+(Häufig gestellte Fragen) auf unserer Website.
+Bitte beachten Sie Kenntnis, dass die offizielle Sprache des Forums,
+der Mailing-Liste und des Chats Englisch ist und keine andere Sprache
+dort verwendet werden sollte.
+
+
+2.1) Fehler berichten:
+---- ---------------
+Um einen Fehler zu berichten, erstellen Sie bitte ein SourceForge-Konto
+und folgen Sie dem Link "Bug Tracker" auf der ScummVM-Website. Bitte
+stellen Sie sicher, dass sich der Bug wiedererzeugen lässt und immer noch
+in der neusten Version von SVN oder des Daily builds auftritt. Bitte
+sehen Sie auch auf der Problemliste unten und der Kompatiblitätsliste auf
+der ScummVM-Website für dieses Spiel nach, um sicherzustellen, dass das
+Problem nicht bereits bekannt ist:
+
+  http://www.scummvm.org/compatibility_stable.php
+
+Bitte berichten Sie keine Fehler zu Spielen, die nicht als durchspielbar
+im Bereich "Supported Games" oder der Kompatiblitätsliste aufgelistet
+sind. Wir -wissen-, dass diese Spiele Fehler aufweisen.
+
+Bitte liefern Sie folgende Informationen:
+    - ScummVM-Version (BITTE mit neuster Version von SVN oder
+      des Daily builds testen)
+    - Einzelheiten zum Fehler, einschließlich Anweisungen, um den Fehler
+      hervorzurufen
+    - Sprache des Spiels (Englisch, Deutsch, ...)
+    - Version des Spiels (Version mit Sprachausgabe [Talkie],
+      Disketten-Version, ...)
+    - Plattform und gegebenenfalls Compiler (Win32, Linux, FreeBSD, ...)
+    - Fügen Sie einen Speicherstand hinzu, wenn es möglich ist.
+    - Wenn dieser Fehler erst seit kurzem Auftritt, teilen Sie bitte die
+      letzte Version ohne den Fehler mit und die erste Version mit diesem
+      Fehler. Auf diese Weise können wir diesen schneller beseitigen,
+      indem wir die vorgenommen Veränderungen einsehen.
+
+Zum Schluss möchten wir Sie noch bitten, jeden Punkt einzeln zu
+berichten; bitte senden Sie nicht mehrere Punkte mit dem selben Ticket
+ein, ansonsten wird es schwierig, den Status jedes einzelnen Fehlers
+zu verfolgen. Denken Sie bitte auch daran, dass alle Fehlerberichte in
+Englisch verfasst sein müssen.
+
diff --git a/doc/translations/README-fr.txt b/doc/translations/README-fr.txt
new file mode 100755
index 0000000..186f0cd
--- /dev/null
+++ b/doc/translations/README-fr.txt
@@ -0,0 +1,172 @@
+Ce document est une traduction partielle du fichier README anglais. Le
+document original contient bien plus d'informations, donc si vous ne
+trouvez pas ce que vous cherchez dans ce document et que vous comprenez
+un peu l'anglais, jetez un coup d'oeil au fichier README anglais.
+
+Pour plus d'informations, liste des jeux compatibles, détails pour
+donner de l'argent, la dernière version disponibles et bien plus encore,
+visitez le site web de ScummVM à l'adresse http://www.scummvm.org/
+
+Table des matières:
+-------------------
+1.0) Introduction
+ * 1.1 À propos de ScummVM
+ * 1.2 Démarrage rapide
+2.0) Contact
+ * 2.1 Signaler des bogues
+
+1.0) Introduction:
+---- -------------
+
+1.1) À propos de ScummVM:
+---- --------------------
+ScummVM est un logiciel qui vous permet de jouer certain jeux
+d'aventures graphiques de type 'point-and-click' (pointer et cliquer), à
+condition que vous possédiez les fichiers de données du jeu. Le plus
+astucieux: ScummVM remplace juste les exécutables fournis avec les jeux,
+vous permettant de jouer sur les systèmes pour lesquels ils n'ont jamais
+été conçus!
+
+A l'origine il a été conçu pour exécuter les jeux basé sur le système
+SCUMM de LucasArts, tels que Maniac Mansion, Monkey Island, Day of the
+Tentacle ou Sam et Max. SCUMM est l'acronyme de 'Script Creation Utility
+for Maniac Mansion', qui a été le premier jeu pour lequel LucasArts a
+conçu ce système. Et beaucoup plus tard, il donna son nom à ScummVM
+('VM' signifiant Virtual Machine). 
+
+Au cours du temps de nombreux jeux non-SCUMM ont été ajouté, et ScummVM
+prend désormais en charge de nombreux jeux Sierra AGI et SCI (tels que
+King's Quest 1-6, Space Quest 1-5, ...), Discworld 1 et 2, Simon the
+Sorcerer 1 et 2, Beneath A Steel Sky, Lure of the Temptress, Les
+Chevaliers de Baphomet (Broken Sword I), Les Boucliers de Quetzalcoatl
+(Broken Sword II), L'amazone queen (Flight of the Amazon Queen),
+Gobliiins 1-3, la série des Legend of Kyrandia, un grand nombre de jeux
+pour enfants de Humongous Entertainment (incluant les jeux Marine Malice
+et Pouce-Pouce) et beaucoup plus. Vous pouvez trouver une liste complète
+et détaillée sur les aventures qui sont pris en charge et les problèmes
+connus sur la page de compatibilité. ScummVM évolue en permanence, donc
+vérifier cette liste de compatibilités souvent. 
+
+Vous pouvez jouer à ces jeux sur des ordinateurs de bureau classiques
+(sous Windows, Linux, Mac OS X, ...), sur des consoles (Dreamcast,
+Nintendo DS et Wii, PS2, PSP, ...), smartphones (Android, iPhone, Pocket
+PC, Symbian ...) et plus encore. 
+
+À ce stade ScummVM est encore en cours de développement. Soyez conscient
+que malgré tous nos efforts pour en faire un logiciel le plus stable
+possible, des plantages peuvent survenir. et nous n'offrons aucune
+garantie. Cela étant dit, certains jeux sont supportés depuis longtemps
+et devrait fonctionner correctement avec une version stable et récente
+de ScummVM. Vous pouvez vous faire une idée du niveau de support d'un
+jeu en regardant la page de compatibilité. En fait, si vous cherchez un
+peu vous pourrez découvrir que ScummVM est même utilisé dans le commerce
+pour la ré-édition sur les plates-formes modernes de quelques-uns des
+jeux supportés. Cela montre que plusieurs entreprises sont satisfaits de
+la qualité du logiciel.
+
+Si vous aimez ScummVM n'hésitez pas à faire un don en utilisant le
+bouton PayPal sur la page d'accueil ScummVM. Cela nous aidera à acheter
+les services nécessaires pour rendre le développement de ScummVM plus
+facile et plus rapide. Si vous ne pouvez pas faire de don, vous pouvez
+aussi proposer des patches!
+
+1.2) Démarrage rapide:
+---- ----------------
+IMPORTANT: Les instructions ci-dessous supposent que vous utilisez
+ScummVM en Français. Par défaut, ScummVM utilise la langue de votre
+système d'exploitation. Si vous préférez utiliser ScummVM en Anglais,
+vous pouvez plutôt utiliser le guide du fichier README Anglais.
+
+
+Pour les plus impatients, voici comment obtenir ScummVM en cinq étapes
+simples.
+
+1. Télécharger ScummVM sur <http://www.scummvm.org/downloads.php> et
+installer l'application.
+
+2. Créez un répertoire sur votre disque dur et copier les fichiers de
+données de jeu à partir du support original dans ce répertoire. Répétez
+cette opération pour chaque jeu que vous voulez jouer. Utilisez un
+répertoire séparé pour chaque jeu.
+
+3. Lancez ScummVM.
+
+Si ScummVM apparaît en anglais au lieu du français, procédez comme suit
+pour changer la langue:
+- Cliquez sur 'Options'.
+- Cliquez sur la flèche droite dans la barre d'onglets et sélectionnez
+  l'onglet 'Misc'.
+- Choisissez 'Francais' dans le champs 'GUI Language' et cliquez sur
+  'OK'. Confirmez-le message qui apparaît, cliquez sur 'Quit' pour
+  quitter ScummVM, puis redémarrer le programme.
+
+Maintenant cliquez sur 'Ajouter...', puis sélectionnez le répertoire
+contenant les fichiers de données du jeu (ne pas essayer de sélectionner
+les fichiers de données eux-mêmes!) et cliquez sur 'Choisir'.
+
+4. Une boîte de dialogue devrait apparaître vous permettant de
+configurer divers paramètres si vous le souhaitez (la valeur par défaut
+devrait convenir dans la plupart des cas). Confirmez la boîte de
+dialogue.
+
+5. Sélectionnez le jeu que vous voulez jouer dans la liste, et appuyez
+sur 'Démarrer'.
+
+ScummVM se souvient des jeux ajoutés. Donc si vous quittez ScummVM puis
+le relancez la liste des jeux contiendra tous les jeux que vous avez
+déjà ajoutés. Vous pouvez donc passer directement à l'étape 5, à moins
+que vous vouliez ajouter des jeux supplémentaires.
+
+Astuce: Si vous souhaitez ajouter plusieurs jeux d'un coup, essayez
+d'appuyer et de maintenir la touche Maj (Shift) tout en cliquant sur
+'Ajouter...' - son texte changera en 'Ajout Massif…'. Vous serez alors
+invitez à sélectioner un répertoire dans lequel ScummVM parcourra tous
+les sous-répertoire à la recherche de jeux supportés.
+
+
+2.0) Contact:
+---- --------
+La meilleure façon de contacter l'équipe de ScummVM est en soumettant
+des rapports de bogues (voir section 2.1) ou en utilisant nos forums
+http://forums.scummvm.org. Vous pouvez également envoyer un e-mail sur
+la liste de diffusion scummvm-devel, ou discuter avec nous sur IRC
+(#scummvm sur irc.freenode.net). S'il vous plaît ne nous demandez pas de
+supporter un jeu non pris en charge - lire la FAQ sur notre site web
+avant. Notez que la langue officielle de la liste de diffusion, forum et
+chat est l'Anglais, et aucune autre langues ne doivent être utilisée.
+
+
+2.1) Reporting Bugs:
+---- ---------------
+Pour signaler un bogue, veuillez créer un compte SourceForge et suivez
+le lien "Bug Tracker" depuis notre page d'accueil. S'il vous plaît
+vérifiez que le bogue est reproductible, et se produit encore dans la
+'Daily Build' la plus récente. Vérifiez également la liste des problèmes
+connus (ci-dessous) et la liste de compatibilité sur notre site Web pour
+ce jeu, pour s'assurer que le problème n'est pas déjà connue:
+
+   http://www.scummvm.org/compatibility_stable.php
+
+Veuillez ne pas rapporter de bogues sur les jeux qui ne sont pas
+répertoriés comme étant finissable sur la liste de compatibilité. Nous
+savons que ces jeux ont des bogues.
+
+Veuillez inclure les informations suivantes lorsque vous signalez un
+problème:
+     - Version de ScummVM (veuillez tester avec la 'Daily Build' la plus
+       récente)
+     - Détails du problème, incluant les instructions pour le reproduire
+     - Langue du jeu (anglais, allemand, ...)
+     - Version du jeu (talkie, disquette, ...)
+     - Plate-forme et compilateur (Win32, Linux, Mac, FreeBSD, ...)
+     - Joindre une sauvegarde si possible
+     - Si ce problème est récent, s'il vous plaît notez la dernière
+       version sans bogue, et la première version qui à le problème. De
+       cette façon, nous pouvons y remédier plus rapidement, en regardant
+       les modifications apportées entre ces deux versions.
+
+Enfin, veuillez signaler chaque problème séparément, sinon, il devient
+difficile de suivre l'état de chaque problème individuel. S'il vous
+plaît gardez à l'esprit également que tous les rapports de bogue doivent
+être rédigés en anglais.
+
diff --git a/doc/translations/README-translation_template.txt b/doc/translations/README-translation_template.txt
new file mode 100755
index 0000000..ec43ebe
--- /dev/null
+++ b/doc/translations/README-translation_template.txt
@@ -0,0 +1,158 @@
+This document is a partial translation of the English README file. The
+original document has much more information, so if you cannot find what
+you need here and can understand a bit of English, try to look at the
+English README file.
+
+For more information, compatibility lists, details on donating, the
+latest release, progress reports and more, please visit the ScummVM home
+page at: http://www.scummvm.org/
+
+Table of Contents:
+------------------
+1.0) Introduction
+ * 1.1 About ScummVM
+ * 1.2 Quick start
+2.0) Contact
+ * 2.1 Reporting Bugs
+
+1.0) Introduction:
+---- -------------
+
+1.1) About ScummVM:
+---- --------------
+ScummVM is a program which allows you to run certain classic graphical
+point-and-click adventure games, provided you already have their data
+files. The clever part about this: ScummVM just replaces the executables
+shipped with the game, allowing you to play them on systems for which
+they were never designed!
+
+Originally it was designed to run LucasArts' SCUMM games, such as Maniac
+Mansion, Monkey Island, Day of the Tentacle or Sam and Max. SCUMM stands
+for 'Script Creation Utility for Maniac Mansion', which was the first
+game for which LucasArts designed this system. And much later it gave
+its name to ScummVM ('VM' meaning Virtual Machine).
+
+Over time support for a lot of non-SCUMM games has been added, and
+ScummVM now also supports many of Sierra's AGI and SCI games (such as
+King's Quest 1-6, Space Quest 1-5, ...), Discworld 1 and 2, Simon the
+Sorcerer 1 and 2, Beneath A Steel Sky, Lure of the Temptress, Broken
+Sword I and II, Flight of the Amazon Queen, Gobliiins 1-3, The Legend of
+Kyrandia series, many of Humongous Entertainment's children's SCUMM
+games (including Freddi Fish and Putt Putt games) and many more. You can
+find a full list with details on which adventures are supported and how
+well on the compatibility page. ScummVM is continually improving, so
+check back often.
+
+Among the systems on which you can play those games are regular desktop
+computers (running Windows, Linux, Mac OS X, ...), game consoles
+(Dreamcast, Nintendo DS & Wii, PS2, PSP, ...), smartphones (Android,
+iPhone, PocketPC, Symbian ...) and more.
+
+At this time ScummVM is still under heavy development. Be aware that
+whilst we attempt to make sure that many games can be completed with few
+major bugs, crashes can happen and we offer no warranty. That being
+said, some of the games have been supported for a long time and should
+work fine with any recent stable release. You can get a feeling of how
+well each game is working in ScummVM by looking at the compatibility
+page. Actually if you browse a bit around you might discover that
+ScummVM is even being used commercially to re-release some of the
+supported games on modern platforms. This shows that several companies
+are happy with the quality of the software and how well it can run some
+of the games.
+
+If you enjoy ScummVM feel free to donate using the PayPal button on the
+ScummVM homepage. This will help us buy utilities needed to develop
+ScummVM easier and quicker. If you cannot donate, help and contribute a
+patch!
+
+1.2) Quick start:
+---- ------------
+IMPORTANT: This short guide assumes you are using ScummVM in <translated
+language>. By default, ScummVM will use your operating system's
+language. If you prefer to use ScummVM in English, You may also prefer
+to follow the guide from the English REAMDE file.
+
+For the impatient among you, here is how to get ScummVM running in five
+simple steps.
+
+1. Download ScummVM from <http://www.scummvm.org/downloads.php> and
+install it.
+
+2. Create a directory on your hard drive and copy the game datafiles
+from the original media to this directory. Repeat this for every game
+you want to play (it is better to use a separate directory for each
+game).
+
+3. Start ScummVM.
+
+If at this stage ScummVM appears in English instead of <translated
+language>, do as follow to change the language:
+- Click on 'Options'.
+- Click on the right arrow in the tab bar and select the 'Misc' tab.
+- Select "<translated language>" in the 'GUI Language' box and click on
+  'OK'.
+- Confirm the message box that pops-up, click on 'Quit' to quit ScummVM
+  and then restart the program.
+
+Now choose 'Add game', select the directory with the game datafiles (do
+not try to select the datafiles themselves!) and press 'Choose'
+
+4. A dialog should popup allowing you to configure various settings if
+you wish to (it should be just fine to leave everything at its default,
+though). Confirm the dialog.
+
+5. Select the game you want to play in the list, and press 'Start'.
+
+ScummVM remembers the games that you add. So if you close ScummVM, the
+next time you start it again the list of game will contain all the games
+you previously added. You can therefore go directly to step 5, unless
+you want to add more games.
+
+Hint: If you want to add multiple games in one go, try pressing and
+holding the shift key before clicking 'Add game' -- its label will
+change to 'Mass Add' and if you press it, you are again asked to select
+a directory, only this time ScummVM will search through all
+subdirectoriess for supported games.
+
+
+2.0) Contact:
+---- --------
+The easiest way to contact the ScummVM team is by submitting bug reports
+(see section 2.1) or by using our forums at http://forums.scummvm.org .
+You can also join and e-mail the scummvm-devel mailing list, or chat
+with us on IRC (#scummvm on irc.freenode.net) Please do not ask us to
+support an unsupported game -- read the FAQ on our web site first. Note
+that the official language of the forum, mailing list and chat is
+English and no other languages should be used.
+
+
+2.1) Reporting Bugs:
+---- ---------------
+To report a bug, please create a SourceForge account and follow the "Bug
+Tracker" link from our homepage. Please make sure the bug is
+reproducible, and still occurs in the latest SVN/Daily build version.
+Also check the known problems list (below) and the compatibility list on
+our website for that game, to ensure the issue is not already known:
+
+  http://www.scummvm.org/compatibility_stable.php
+
+Please do not report bugs on games that are not listed as being
+completeable in the 'Supported Games' section, or compatibility list. We
+-know- those games have bugs.
+
+Please include the following information:
+    - ScummVM version (PLEASE test the latest SVN/Daily build)
+    - Bug details, including instructions on reproducing
+    - Language of game (English, German, ...)
+    - Version of game (talkie, floppy, ...)
+    - Platform and Compiler (Win32, Linux, FreeBSD, ...)
+    - Attach a savegame if possible
+    - If this bug only occurred recently, please note the last version
+      without the bug, and the first version including the bug. That way
+      we can fix it quicker by looking at the changes made.
+
+Finally, please report each issue separately; do not file multiple
+issues on the same ticket. (Otherwise, it gets difficult to track the
+status of each individual bug). Please keep also in mind that all the
+bug reports must be written in English.
+
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index d273c2a..22d8adf 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -164,7 +164,7 @@ public:
 	AgiMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "AGI preAGI + v2 + v3 Engine";
+		return "AGI preAGI + v2 + v3";
 	}
 	virtual const char *getOriginalCopyright() const {
 		return "Sierra AGI Engine (C) Sierra On-Line Software";
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 2b7bf03..262798a 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -90,7 +90,7 @@ public:
 	CineMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Cinematique evo 1 engine";
+		return "Cinematique evo 1";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp
index d77d920..4aaaf03 100644
--- a/engines/cruise/detection.cpp
+++ b/engines/cruise/detection.cpp
@@ -247,7 +247,7 @@ public:
 	CruiseMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Cinematique evo 2 engine";
+		return "Cinematique evo 2";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index c3502cb..572ecce 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -113,7 +113,7 @@ public:
 	DraciMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Draci Historie Engine";
+		return "Draci Historie";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 58a0549..5a8903d 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -296,7 +296,7 @@ public:
 	DrasculaMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Drascula Engine";
+		return "Drascula";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp
index c165090..be44c05 100644
--- a/engines/gob/detection.cpp
+++ b/engines/gob/detection.cpp
@@ -116,7 +116,7 @@ public:
 	GobMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Gob Engine";
+		return "Gob";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp
index bde89f8..78ecac8 100644
--- a/engines/groovie/detection.cpp
+++ b/engines/groovie/detection.cpp
@@ -219,7 +219,7 @@ public:
 	GroovieMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	const char *getName() const {
-		return "Groovie Engine";
+		return "Groovie";
 	}
 
 	const char *getOriginalCopyright() const {
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index 2fdb63d..25b8b16 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -161,7 +161,7 @@ public:
 	HugoMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	const char *getName() const {
-		return "Hugo Engine";
+		return "Hugo";
 	}
 
 	const char *getOriginalCopyright() const {
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 3c59838..864228a 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -79,7 +79,7 @@ public:
 	KyraMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	const char *getName() const {
-		return "Legend of Kyrandia Engine";
+		return "Legend of Kyrandia";
 	}
 
 	const char *getOriginalCopyright() const {
diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp
index e55a6f6..bfcb415 100644
--- a/engines/lastexpress/detection.cpp
+++ b/engines/lastexpress/detection.cpp
@@ -207,7 +207,7 @@ public:
 	LastExpressMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	const char *getName() const {
-		return "LastExpress Engine";
+		return "Last Express";
 	}
 
 	const char *getOriginalCopyright() const {
diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp
index b40e60a..a69300e 100644
--- a/engines/lure/detection.cpp
+++ b/engines/lure/detection.cpp
@@ -205,7 +205,7 @@ public:
 	LureMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Lure of the Temptress Engine";
+		return "Lure of the Temptress";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/m4/detection.cpp b/engines/m4/detection.cpp
index 645855a..1aefe3d 100644
--- a/engines/m4/detection.cpp
+++ b/engines/m4/detection.cpp
@@ -414,7 +414,7 @@ public:
 	M4MetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "MADS/M4 engine";
+		return "MADS/M4";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index e5a1176..4576e2b 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -555,7 +555,7 @@ public:
 	MadeMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "MADE Engine";
+		return "MADE";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 3b7efe7..6a73b28 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -188,7 +188,7 @@ public:
 	MohawkMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Mohawk Engine";
+		return "Mohawk";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
index 7e5798b..c3719bc 100644
--- a/engines/parallaction/detection.cpp
+++ b/engines/parallaction/detection.cpp
@@ -250,7 +250,7 @@ public:
 	ParallactionMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Parallaction engine";
+		return "Parallaction";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index ca52ff5..b23baf4 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -131,7 +131,7 @@ public:
 	SagaMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Saga engine ["
+		return "SAGA ["
 
 #if defined(ENABLE_IHNM) && defined(ENABLE_SAGA2)
 			"all games"
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 28d6abb..61e6cc9 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -402,7 +402,7 @@ public:
 	SciMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "SCI Engine [SCI0, SCI01, SCI10, SCI11"
+		return "SCI [SCI0, SCI01, SCI10, SCI11"
 #ifdef ENABLE_SCI32
 			", SCI32"
 #endif
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index ec85f52..bba2696 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -1156,7 +1156,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co
 }
 
 const char *ScummMetaEngine::getName() const {
-	return "SCUMM Engine ["
+	return "SCUMM ["
 
 #if defined(ENABLE_SCUMM_7_8) && defined(ENABLE_HE)
 		"all games"
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index c17f914..fe23b88 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -926,7 +926,7 @@ void IMuseInternal::sequencer_timers(MidiDriver *midi) {
 }
 
 void IMuseInternal::handle_marker(uint id, byte data) {
-	if (_queue_adding && _queue_sound == id && data == _queue_marker)
+	if ((_queue_end == _queue_pos) || (_queue_adding && _queue_sound == id && data == _queue_marker))
 		return;
 
 	uint16 *p = _cmd_queue[_queue_end].array;
@@ -937,7 +937,7 @@ void IMuseInternal::handle_marker(uint id, byte data) {
 	_queue_cleared = false;
 	_queue_end = (_queue_end + 1) % ARRAYSIZE(_cmd_queue);
 	
-	while(_queue_end != _queue_pos && _cmd_queue[_queue_end].array[0] == COMMAND_ID && !_queue_cleared) {
+	while (_queue_end != _queue_pos && _cmd_queue[_queue_end].array[0] == COMMAND_ID && !_queue_cleared) {
 		p = _cmd_queue[_queue_end].array;
 		doCommand_internal(p[1], p[2], p[3], p[4], p[5], p[6], p[7], 0);
 		_queue_end = (_queue_end + 1) % ARRAYSIZE(_cmd_queue);
diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp
index 9ca44c6..caa1cf5 100644
--- a/engines/sword25/detection.cpp
+++ b/engines/sword25/detection.cpp
@@ -102,7 +102,7 @@ public:
 	Sword25MetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "The Broken Sword 2.5 Engine";
+		return "Broken Sword 2.5";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index 8db2b36..4784e2f 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -113,7 +113,7 @@ public:
 	}
 
 	virtual const char *getName() const {
-		return "Teen Agent Engine";
+		return "Teen Agent";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index b0af9a9..27b16c5 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -104,7 +104,7 @@ public:
 	TinselMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Tinsel Engine";
+		return "Tinsel";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index f98d09a..1056f6e 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -147,7 +147,7 @@ public:
 	ToonMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Toon Engine";
+		return "Toon";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index 9d159e8..b7f9c09 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -156,7 +156,7 @@ public:
 	ToucheMetaEngine() : AdvancedMetaEngine(detectionParams) {}
 
 	virtual const char *getName() const {
-		return "Touche Engine";
+		return "Touche";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp
index 2f05365..7534abd 100644
--- a/engines/tsage/core.cpp
+++ b/engines/tsage/core.cpp
@@ -3481,52 +3481,11 @@ void SceneHandler::postInit(SceneObjectList *OwnerList) {
 
 void SceneHandler::process(Event &event) {
 	// Main keypress handler
-	if ((event.eventType == EVENT_KEYPRESS) && !event.handled) {
-		switch (event.kbd.keycode) {
-		case Common::KEYCODE_F1:
-			// F1 - Help
-			MessageDialog::show((_vm->getFeatures() & GF_DEMO) ? DEMO_HELP_MSG : HELP_MSG, OK_BTN_STRING);
-			break;
-
-		case Common::KEYCODE_F2: {
-			// F2 - Sound Options
-			ConfigDialog *dlg = new ConfigDialog();
-			dlg->runModal();
-			delete dlg;
-			_globals->_events.setCursorFromFlag();
-			break;
-		}
-
-		case Common::KEYCODE_F3:
-			// F3 - Quit
-			_globals->_game->quitGame();
-			event.handled = false;
-			break;
-
-		case Common::KEYCODE_F4:
-			// F4 - Restart
-			_globals->_game->restartGame();
-			_globals->_events.setCursorFromFlag();
-			break;
-
-		case Common::KEYCODE_F7:
-			// F7 - Restore
-			_globals->_game->restoreGame();
-			_globals->_events.setCursorFromFlag();
-			break;
+	if (!event.handled) {
+		_globals->_game->processEvent(event);
 
-		case Common::KEYCODE_F10:
-			// F10 - Pause
-			GfxDialog::setPalette();
-			MessageDialog::show(GAME_PAUSED_MSG, OK_BTN_STRING);
+		if (event.eventType == EVENT_KEYPRESS)
 			_globals->_events.setCursorFromFlag();
-			break;
-
-		default:
-			break;
-		}
-
-		_globals->_events.setCursorFromFlag();
 	}
 
 	// Check for displaying right-click dialog
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index 4ab2142..20c2002 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -88,7 +88,7 @@ public:
 	}
 
 	virtual const char *getName() const {
-		return "TsAGE Engine";
+		return "TsAGE";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp
index 132225d..e889c56 100644
--- a/engines/tsage/events.cpp
+++ b/engines/tsage/events.cpp
@@ -151,8 +151,13 @@ void EventsClass::setCursor(CursorType cursorType) {
 	switch (cursorType) {
 	case CURSOR_NONE:
 		// No cursor
-		cursor = _resourceManager->getSubResource(4, 1, 6, &size);
 		_globals->setFlag(122);
+
+		if (_vm->getFeatures() & GF_DEMO) {
+			CursorMan.showMouse(false);
+			return;
+		}
+		cursor = _resourceManager->getSubResource(4, 1, 6, &size);
 		break;
 
 	case CURSOR_LOOK:
diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp
index 5da00e8..85dfc5d 100644
--- a/engines/tsage/graphics.cpp
+++ b/engines/tsage/graphics.cpp
@@ -967,9 +967,10 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) {
 	// Event loop
 	GfxButton *selectedButton = NULL;
 
-	while (!_vm->getEventManager()->shouldQuit()) {
+	bool breakFlag = false;
+	while (!_vm->getEventManager()->shouldQuit() && !breakFlag) {
 		Event event;
-		while (_globals->_events.getEvent(event)) {
+		while (_globals->_events.getEvent(event) && !breakFlag) {
 			// Adjust mouse positions to be relative within the dialog
 			event.mousePos.x -= _gfxManager._bounds.left;
 			event.mousePos.y -= _gfxManager._bounds.top;
@@ -978,19 +979,23 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) {
 				if ((*i)->process(event))
 					selectedButton = static_cast<GfxButton *>(*i);
 			}
-		}
 
-		if (selectedButton)
-			break;
-		else if (!event.handled) {
-			if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
-				selectedButton = NULL;
-				break;
-			} else if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_RETURN)) {
-				selectedButton = defaultButton;
+			if (selectedButton) {
+				breakFlag = true;
 				break;
+			} else if (!event.handled) {
+				if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) {
+					selectedButton = NULL;
+					breakFlag = true;
+					break;
+				} else if ((event.eventType == EVENT_KEYPRESS) && (event.kbd.keycode == Common::KEYCODE_RETURN)) {
+					selectedButton = defaultButton;
+					breakFlag = true;
+					break;
+				}
 			}
 		}
+
 		g_system->delayMillis(10);
 		g_system->updateScreen();
 	}
diff --git a/engines/tsage/ringworld_demo.cpp b/engines/tsage/ringworld_demo.cpp
index 2dacea6..3ad414f 100644
--- a/engines/tsage/ringworld_demo.cpp
+++ b/engines/tsage/ringworld_demo.cpp
@@ -39,6 +39,68 @@ Scene *RingworldDemoGame::createScene(int sceneNumber) {
 	return new RingworldDemoScene();
 }
 
+void RingworldDemoGame::quitGame() {
+	_globals->_events.setCursor(CURSOR_ARROW);
+	MessageDialog *dlg = new MessageDialog(DEMO_EXIT_MSG, EXIT_BTN_STRING, DEMO_BTN_STRING);
+	dlg->draw();
+
+	GfxButton *selectedButton = dlg->execute(&dlg->_btn2);
+	bool exitFlag  =  selectedButton != &dlg->_btn2;
+
+	delete dlg;
+	_globals->_events.hideCursor();
+
+	if (exitFlag)
+		_vm->quitGame();
+}
+
+void RingworldDemoGame::pauseGame() {
+	_globals->_events.setCursor(CURSOR_ARROW);
+	MessageDialog *dlg = new MessageDialog(DEMO_PAUSED_MSG, EXIT_BTN_STRING, DEMO_RESUME_BTN_STRING);
+	dlg->draw();
+
+	GfxButton *selectedButton = dlg->execute(&dlg->_btn2);
+	bool exitFlag  =  selectedButton != &dlg->_btn2;
+
+	delete dlg;
+	_globals->_events.hideCursor();
+
+	if (exitFlag)
+		_vm->quitGame();
+}
+
+void RingworldDemoGame::processEvent(Event &event) {
+	if (event.eventType == EVENT_KEYPRESS) {
+		switch (event.kbd.keycode) {
+		case Common::KEYCODE_F1:
+			// F1 - Help
+			MessageDialog::show(DEMO_HELP_MSG, OK_BTN_STRING);
+			break;
+
+		case Common::KEYCODE_F2: {
+			// F2 - Sound Options
+			ConfigDialog *dlg = new ConfigDialog();
+			dlg->runModal();
+			delete dlg;
+			_globals->_events.setCursorFromFlag();
+			break;
+		}
+
+		case Common::KEYCODE_F3:
+			// F3 - Quit
+			quitGame();
+			event.handled = false;
+			break;
+
+		default:
+			break;
+		}
+	} else if (event.eventType == EVENT_BUTTON_DOWN) {
+		pauseGame();
+		event.handled = true;
+	}
+}
+
 /*--------------------------------------------------------------------------
  * Ringworld Demo scene
  *
diff --git a/engines/tsage/ringworld_demo.h b/engines/tsage/ringworld_demo.h
index 8b69da8..7492c1e 100644
--- a/engines/tsage/ringworld_demo.h
+++ b/engines/tsage/ringworld_demo.h
@@ -32,9 +32,13 @@
 namespace tSage {
 
 class RingworldDemoGame: public Game {
+private:
+	void pauseGame();
 public:
 	virtual void start();
 	virtual Scene *createScene(int sceneNumber);
+	virtual void quitGame();
+	virtual void processEvent(Event &event);
 };
 
 class RingworldDemoScene: public Scene {
diff --git a/engines/tsage/ringworld_logic.cpp b/engines/tsage/ringworld_logic.cpp
index a03c408..2141fcc 100644
--- a/engines/tsage/ringworld_logic.cpp
+++ b/engines/tsage/ringworld_logic.cpp
@@ -1421,4 +1421,52 @@ void RingworldGame::endGame(int resNum, int lineNum) {
 	_globals->_events.setCursorFromFlag();
 }
 
+void RingworldGame::processEvent(Event &event) {
+	if (event.eventType == EVENT_KEYPRESS) {
+		switch (event.kbd.keycode) {
+		case Common::KEYCODE_F1:
+			// F1 - Help
+			MessageDialog::show(HELP_MSG, OK_BTN_STRING);
+			break;
+
+		case Common::KEYCODE_F2: {
+			// F2 - Sound Options
+			ConfigDialog *dlg = new ConfigDialog();
+			dlg->runModal();
+			delete dlg;
+			_globals->_events.setCursorFromFlag();
+			break;
+		}
+
+		case Common::KEYCODE_F3:
+			// F3 - Quit
+			quitGame();
+			event.handled = false;
+			break;
+
+		case Common::KEYCODE_F4:
+			// F4 - Restart
+			restartGame();
+			_globals->_events.setCursorFromFlag();
+			break;
+
+		case Common::KEYCODE_F7:
+			// F7 - Restore
+			restoreGame();
+			_globals->_events.setCursorFromFlag();
+			break;
+
+		case Common::KEYCODE_F10:
+			// F10 - Pause
+			GfxDialog::setPalette();
+			MessageDialog::show(GAME_PAUSED_MSG, OK_BTN_STRING);
+			_globals->_events.setCursorFromFlag();
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
 } // End of namespace tSage
diff --git a/engines/tsage/ringworld_logic.h b/engines/tsage/ringworld_logic.h
index 6fa92fa..19b0f10 100644
--- a/engines/tsage/ringworld_logic.h
+++ b/engines/tsage/ringworld_logic.h
@@ -453,6 +453,7 @@ public:
 	virtual void endGame(int resNum, int lineNum);
 
 	virtual Scene *createScene(int sceneNumber);
+	virtual void processEvent(Event &event);
 };
 
 } // End of namespace tSage
diff --git a/engines/tsage/ringworld_scenes2.cpp b/engines/tsage/ringworld_scenes2.cpp
index 906f648..4378eac 100644
--- a/engines/tsage/ringworld_scenes2.cpp
+++ b/engines/tsage/ringworld_scenes2.cpp
@@ -477,13 +477,14 @@ void Scene1001::Action1::signal() {
 	case 19: {
 		_globals->_soundHandler.startSound(91);
 		byte adjustData[4] = {0xff, 0xff, 0xff, 0};
-		_globals->_scenePalette.fade(adjustData, true, 0);
+		_globals->_scenePalette.fade(adjustData, false, 0);
 
 		scene->_object1._strip = 7;
 		scene->_object1._frame = 1;
 		scene->_object1.setPosition(Common::Point(314, 112));
 		scene->_object1.addMover(NULL);
 		setDelay(2);
+		break;
 	}
 	case 20:
 		_globals->_scenePalette.loadPalette(16);
diff --git a/engines/tsage/scenes.h b/engines/tsage/scenes.h
index a5aacba..b3c009c 100644
--- a/engines/tsage/scenes.h
+++ b/engines/tsage/scenes.h
@@ -129,6 +129,7 @@ public:
 	virtual void quitGame() {}
 	virtual void endGame(int resNum, int lineNum) {}
 	virtual Scene *createScene(int sceneNumber) = 0;
+	virtual void processEvent(Event &event) {}
 };
 
 } // End of namespace tSage
diff --git a/engines/tsage/staticres.cpp b/engines/tsage/staticres.cpp
index 6c2d924..9f36268 100644
--- a/engines/tsage/staticres.cpp
+++ b/engines/tsage/staticres.cpp
@@ -112,6 +112,10 @@ const char *SCENE6100_VERY_WELL = "Very well. I will retrieve the stasis box and
 Wait for it's return in the lander bay.";
 
 const char *DEMO_HELP_MSG = " Help...\rF2 - Sound Options\rF3 - Exit demo\r\rPress ENTER\rto continue";
-const char *DEMO_PAUSED_MSG = " demo is paused";
+const char *DEMO_PAUSED_MSG = "Ringworld\x14 demo is paused";
+const char *DEMO_EXIT_MSG = "Press ENTER to resume the Ringworld\x14 demo. Press ESC to exit";
+const char *EXIT_BTN_STRING = "Exit";
+const char *DEMO_BTN_STRING = "Demo";
+const char *DEMO_RESUME_BTN_STRING = "Resume";
 
 } // End of namespace tSage
diff --git a/engines/tsage/staticres.h b/engines/tsage/staticres.h
index bed9e0d..fa93511 100644
--- a/engines/tsage/staticres.h
+++ b/engines/tsage/staticres.h
@@ -79,6 +79,12 @@ extern const char *SCENE6100_VERY_WELL;
 // Demo messages
 extern const char *DEMO_HELP_MSG;
 extern const char *DEMO_PAUSED_MSG;
+extern const char *DEMO_HELP_MSG;
+extern const char *DEMO_PAUSED_MSG;
+extern const char *DEMO_EXIT_MSG;
+extern const char *EXIT_BTN_STRING;
+extern const char *DEMO_BTN_STRING;
+extern const char *DEMO_RESUME_BTN_STRING;
 
 } // End of namespace tSage
 
diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp
index 89b0b87..9b466d6 100644
--- a/engines/tucker/detection.cpp
+++ b/engines/tucker/detection.cpp
@@ -143,7 +143,7 @@ public:
 	}
 
 	virtual const char *getName() const {
-		return "Tucker Engine";
+		return "Tucker";
 	}
 
 	virtual const char *getOriginalCopyright() const {
diff --git a/gui/credits.h b/gui/credits.h
index 7ad4800..f8e9390 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -59,7 +59,7 @@ static const char *credits[] = {
 "C0""Ludvig Strigeus",
 "C2""(retired)",
 "",
-"C1""BASS",
+"C1""Beneath a Steel Sky",
 "C0""Robert G\366ffringmann",
 "C2""(retired)",
 "C0""Oliver Kiehl",
@@ -101,7 +101,7 @@ static const char *credits[] = {
 "C0""Vincent Hamm",
 "C2""(retired)",
 "",
-"C1""Draci",
+"C1""Draci Historie",
 "C0""Denis Kasak",
 "C0""Robert Spalek",
 "",
@@ -109,7 +109,7 @@ static const char *credits[] = {
 "C0""Filippos Karapetis",
 "C0""Pawel Kolodziejski",
 "",
-"C1""FOTAQ",
+"C1""Flight of the Amazon Queen",
 "C0""David Eriksson",
 "C2""(retired)",
 "C0""Gregory Montoir",
@@ -131,7 +131,7 @@ static const char *credits[] = {
 "C0""Oystein Eftevaag",
 "C0""Eugene Sandulenko",
 "",
-"C1""Kyra",
+"C1""Legend of Kyrandia",
 "C0""Torbj\366rn Andersson",
 "C2""VQA Player",
 "C0""Oystein Eftevaag",
@@ -144,7 +144,7 @@ static const char *credits[] = {
 "C0""Jordi Vilalta Prat",
 "C0""Julien Templier",
 "",
-"C1""Lure",
+"C1""Lure of the Temptress",
 "C0""Paul Gilbert",
 "",
 "C1""M4",
@@ -185,7 +185,7 @@ static const char *credits[] = {
 "C0""Jordi Vilalta Prat",
 "C0""Lars Skovlund",
 "",
-"C1""TeenAgent",
+"C1""Teen Agent",
 "C0""Robert Megone",
 "C2""Help with callback rewriting",
 "C0""Vladimir Menshakov",
diff --git a/gui/options.cpp b/gui/options.cpp
index d350139..e42d6c6 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -305,8 +305,14 @@ void OptionsDialog::close() {
 	if (getResult()) {
 
 		// Graphic options
+		bool graphicsModeChanged = false;
 		if (_fullscreenCheckbox) {
 			if (_enableGraphicSettings) {
+				if (ConfMan.getBool("fullscreen", _domain) != _fullscreenCheckbox->getState())
+					graphicsModeChanged = true;
+				if (ConfMan.getBool("aspect_ratio", _domain) != _aspectCheckbox->getState())
+					graphicsModeChanged = true;
+
 				ConfMan.setBool("fullscreen", _fullscreenCheckbox->getState(), _domain);
 				ConfMan.setBool("aspect_ratio", _aspectCheckbox->getState(), _domain);
 				ConfMan.setBool("disable_dithering", _disableDitheringCheckbox->getState(), _domain);
@@ -318,6 +324,8 @@ void OptionsDialog::close() {
 
 					while (gm->name) {
 						if (gm->id == (int)_gfxPopUp->getSelectedTag()) {
+							if (ConfMan.get("gfx_mode", _domain) != gm->name)
+								graphicsModeChanged = true;
 							ConfMan.set("gfx_mode", gm->name, _domain);
 							isSet = true;
 							break;
@@ -338,6 +346,48 @@ void OptionsDialog::close() {
 				ConfMan.removeKey("render_mode", _domain);
 			}
 		}
+		
+		// Setup graphics again if needed
+		if (_domain == Common::ConfigManager::kApplicationDomain && graphicsModeChanged) {
+			g_system->beginGFXTransaction();
+			g_system->setGraphicsMode(ConfMan.get("gfx_mode", _domain).c_str());
+			
+			if (ConfMan.hasKey("aspect_ratio"))
+				g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio", _domain));
+			if (ConfMan.hasKey("fullscreen"))
+				g_system->setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen", _domain));
+			OSystem::TransactionError gfxError = g_system->endGFXTransaction();
+			if (gfxError != OSystem::kTransactionSuccess) {
+				// Revert ConfMan to what OSystem is using.
+				Common::String message = "Failed to apply some of the graphic options changes:";
+
+				if (gfxError & OSystem::kTransactionModeSwitchFailed) {
+					const OSystem::GraphicsMode *gm = g_system->getSupportedGraphicsModes();
+					while (gm->name) {
+						if (gm->id == g_system->getGraphicsMode()) {
+							ConfMan.set("gfx_mode", gm->name, _domain);
+							break;
+						}
+						gm++;
+					}
+					message += "\nthe video mode could not be changed.";
+				}
+			
+				if (gfxError & OSystem::kTransactionAspectRatioFailed) {
+					ConfMan.setBool("aspect_ratio", g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection), _domain);
+					message += "\nthe fullscreen setting could not be changed";
+				}
+
+				if (gfxError & OSystem::kTransactionFullscreenFailed) {
+					ConfMan.setBool("fullscreen", g_system->getFeatureState(OSystem::kFeatureFullscreenMode), _domain);
+					message += "\nthe aspect ratio setting could not be changed";
+				}
+
+				// And display the error
+				GUI::MessageDialog dialog(message);
+				dialog.runModal();
+			}
+		}
 
 		// Volume options
 		if (_musicVolumeSlider) {
diff --git a/test/common/array.h b/test/common/array.h
index f17edd3..c102704 100644
--- a/test/common/array.h
+++ b/test/common/array.h
@@ -107,6 +107,34 @@ class ArrayTestSuite : public CxxTest::TestSuite
 
 	}
 
+	void test_self_insert() {
+		Common::Array<int> array;
+		int i;
+
+		// Insert some data -- and make sure we have enough space for
+		// *twice* as much data. This way, there is no need to allocate
+		// new storage, so if the insert() operation is "clever", it
+		// will try to reuse the existing storage.
+		// This in turn may uncover bugs if the insertion code does not
+		// expect self-insertions.
+		array.reserve(128);
+		for (i = 0; i < 64; ++i)
+			array.push_back(i);
+
+		// Now insert the array into the middle of itself
+		array.insert_at(12, array);
+
+		// Verify integrity
+		TS_ASSERT_EQUALS(array.size(), 128UL);
+
+		for (i = 0; i < 12; ++i)
+			TS_ASSERT_EQUALS(array[i], i);
+		for (i = 0; i < 64; ++i)
+			TS_ASSERT_EQUALS(array[i+12], i);
+		for (i = 12; i < 64; ++i)
+			TS_ASSERT_EQUALS(array[i+64], i);
+	}
+
 
 	void test_remove_at() {
 		Common::Array<int> array;
diff --git a/test/module.mk b/test/module.mk
index 3542ae2..4e5cbf6 100644
--- a/test/module.mk
+++ b/test/module.mk
@@ -9,7 +9,7 @@ TESTS        := $(srcdir)/test/common/*.h $(srcdir)/test/audio/*.h
 TEST_LIBS    := audio/libaudio.a common/libcommon.a
 
 #
-TEST_FLAGS   := --runner=StdioPrinter
+TEST_FLAGS   := --runner=StdioPrinter --no-std --no-eh
 TEST_CFLAGS  := -I$(srcdir)/test/cxxtest
 TEST_LDFLAGS := $(LIBS)
 TEST_CXXFLAGS := $(filter-out -Wglobal-constructors,$(CXXFLAGS))


Commit: b4d59f9ce50fe9db0ac64d22edb4e1c3451abff0
    https://github.com/scummvm/scummvm/commit/b4d59f9ce50fe9db0ac64d22edb4e1c3451abff0
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:16-07:00

Commit Message:
FM-TOWNS AUDIO: some more midi driver code for FM-TOWNS versions of 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
    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..8bf6d11
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -0,0 +1,238 @@
+/* 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"
+
+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..e4b3723
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
@@ -0,0 +1,86 @@
+/* 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"
+
+
+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/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 6e95846..63d87c3 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1834,7 +1834,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);
 		}
@@ -1842,7 +1842,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: f98be17d74c89558871993559e6486e6edea28e0
    https://github.com/scummvm/scummvm/commit/f98be17d74c89558871993559e6486e6edea28e0
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:17-07:00

Commit Message:
FM-TOWNS AUDIO: fix compilation

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_midi.cpp
    audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
    base/plugins.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index 8bf6d11..c223d44 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
+#include "common/textconsole.h"
 
 class MidiChannel_TOWNS : public MidiChannel {
 public:
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
index e4b3723..bbde75e 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp
@@ -25,6 +25,7 @@
 #include "audio/softsynth/fmtowns_pc98/towns_midi.h"
 #include "audio/musicplugin.h"
 #include "common/translation.h"
+#include "common/error.h"
 
 
 class TownsEmuMusicPlugin : public MusicPluginObject {
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


Commit: afacbd459fdd25975e5416b7ccefa6fb6b8e29ee
    https://github.com/scummvm/scummvm/commit/afacbd459fdd25975e5416b7ccefa6fb6b8e29ee
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:18-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: 61c5813ccffd232df939e16bd70e8e6f63dc39ce
    https://github.com/scummvm/scummvm/commit/61c5813ccffd232df939e16bd70e8e6f63dc39ce
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:19-07:00

Commit Message:
MONKEY2/INDY4 FM-TOWNS: adapt code to latest 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 63d87c3..b22a532 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1829,24 +1829,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;
 		}
@@ -1858,7 +1860,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: ad991a7831e2c636ea81507f51f30db26a6699dc
    https://github.com/scummvm/scummvm/commit/ad991a7831e2c636ea81507f51f30db26a6699dc
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:21-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: 0dce8bab37efc6ba27d51a61c220a8e5b43ed96c
    https://github.com/scummvm/scummvm/commit/0dce8bab37efc6ba27d51a61c220a8e5b43ed96c
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:22-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..e062024 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 TownsMidiInputChannel::_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() {
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: df244dd3c100c6cf7ea20b091339821d5458d732
    https://github.com/scummvm/scummvm/commit/df244dd3c100c6cf7ea20b091339821d5458d732
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:24-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 e062024..8506f35 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: 70b2466cd7cac3cf6dea90815e164e5c1ac05c43
    https://github.com/scummvm/scummvm/commit/70b2466cd7cac3cf6dea90815e164e5c1ac05c43
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:25-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 8506f35..653cab5 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: 39e2aa17ed41ea684c8b2960d53771dce5c355e9
    https://github.com/scummvm/scummvm/commit/39e2aa17ed41ea684c8b2960d53771dce5c355e9
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:26-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 653cab5..5bd9bda 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: 0e819b8dfa0c7761b7534272d1836e6f28a54335
    https://github.com/scummvm/scummvm/commit/0e819b8dfa0c7761b7534272d1836e6f28a54335
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:28-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 5bd9bda..22f7bc0 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 TownsMidiInputChannel::_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: ed13e551d15cc95b20af4837780e2f0995a337e3
    https://github.com/scummvm/scummvm/commit/ed13e551d15cc95b20af4837780e2f0995a337e3
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:29-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 22f7bc0..ab1fdbc 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;
@@ -827,4 +904,9 @@ TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(int pri) {
 		res->disconnect();
 
 	return res;
+}
+
+int MidiDriver_TOWNS::randomValue(int para) {
+	_rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1);
+	return (_rand * para) >> 8;
 }
\ 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 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: 17861037ba88f69548d5467e1f4f83d9e354498d
    https://github.com/scummvm/scummvm/commit/17861037ba88f69548d5467e1f4f83d9e354498d
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:30-07:00

Commit Message:
MONKEY2 / INDY4 FM-TOWNS: set proper GUIO flags

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: 78130f940ff9047756a5d9a0e219e8d2bfa066eb
    https://github.com/scummvm/scummvm/commit/78130f940ff9047756a5d9a0e219e8d2bfa066eb
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:32-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 ab1fdbc..095c7ba 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: 214a70002f5c75ea6bd59e808b73a309039ddd74
    https://github.com/scummvm/scummvm/commit/214a70002f5c75ea6bd59e808b73a309039ddd74
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:33-07:00

Commit Message:
FM-TOWNS AUDIO: fixed 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 095c7ba..6ea9a72 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: 41edb7c6b55417bf765d51c128e2e9747b3b72b2
    https://github.com/scummvm/scummvm/commit/41edb7c6b55417bf765d51c128e2e9747b3b72b2
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:34-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 6ea9a72..fe7fce7 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: 232cb2410c99b2282b96584543d756041ed9bfbe
    https://github.com/scummvm/scummvm/commit/232cb2410c99b2282b96584543d756041ed9bfbe
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:36-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 fe7fce7..95ba1eb 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: 66d19fde680c88bdc4be1656b88f0aa585e98a07
    https://github.com/scummvm/scummvm/commit/66d19fde680c88bdc4be1656b88f0aa585e98a07
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:37-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 95ba1eb..890c51a 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: e1ac2882bc214cc6198128f14f80b6f69b57215e
    https://github.com/scummvm/scummvm/commit/e1ac2882bc214cc6198128f14f80b6f69b57215e
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:38-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/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/saveload.h
    engines/scumm/scumm.cpp
    engines/scumm/sound.cpp



diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index ec60b22..b36bab4 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -302,7 +302,7 @@ struct Part : public Serializable {
 	byte _pitchbend_factor;
 	int8 _transpose, _transpose_eff;
 	byte _vol, _vol_eff;
-	int8 _detune, _detune_eff;
+	int8 _detune, _sysexDetune, _detune_eff;
 	int8 _pan, _pan_eff;
 	bool _on;
 	byte _modwheel;
@@ -345,6 +345,7 @@ struct Part : public Serializable {
 
 	void set_transpose(int8 transpose);
 	void set_detune(int8 detune);
+	void set_sysexDetune(int8 detune);
 	void set_pri(int8 pri);
 	void set_pan(int8 pan);
 
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 808af23..8ccd6d5 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -72,6 +72,7 @@ void Part::saveLoadWithSerializer(Serializer *ser) {
 		MKLINE(Part, _transpose, sleInt8, VER(8)),
 		MKLINE(Part, _vol, sleUint8, VER(8)),
 		MKLINE(Part, _detune, sleInt8, VER(8)),
+		MKLINE(Part, _sysexDetune, sleInt8, VER(85)),
 		MKLINE(Part, _pan, sleInt8, VER(8)),
 		MKLINE(Part, _on, sleUint8, VER(8)),
 		MKLINE(Part, _modwheel, sleUint8, VER(8)),
@@ -110,7 +111,12 @@ void Part::saveLoadWithSerializer(Serializer *ser) {
 }
 
 void Part::set_detune(int8 detune) {
-	_detune_eff = clamp((_detune = detune) + _player->getDetune(), -128, 127);
+	_detune_eff = clamp((_detune = detune) + _player->getDetune() + _sysexDetune, -128, 127);
+	sendPitchBend();
+}
+
+void Part::set_sysexDetune(int8 detune) {
+	_detune_eff = clamp((_sysexDetune = detune) + _player->getDetune() + _detune, -128, 127);
 	sendPitchBend();
 }
 
@@ -277,7 +283,7 @@ void Part::setup(Player *player) {
 	_pan = clamp(player->getPan(), -64, 63);
 	_transpose_eff = player->getTranspose();
 	_transpose = 0;
-	_detune = 0;
+	_detune = _sysexDetune = 0;
 	_detune_eff = player->getDetune();
 	_pitchbend_factor = 2;
 	_pitchbend = 0;
diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index d6cf2e1..0295b74 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_sysexDetune((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/saveload.h b/engines/scumm/saveload.h
index 776f40e..792a31d 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 84
+#define CURRENT_VER 85
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index b22a532..912bb87 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1834,12 +1834,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: bbbde5aa6706237e2427757402d4a5757d767cd4
    https://github.com/scummvm/scummvm/commit/bbbde5aa6706237e2427757402d4a5757d767cd4
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:40-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 890c51a..824637e 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: 73d5b9f595ce5ce3794e5c4b1efc1dac6ed87af8
    https://github.com/scummvm/scummvm/commit/73d5b9f595ce5ce3794e5c4b1efc1dac6ed87af8
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:41-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 824637e..addcf1a 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: 13497a9b0fa27431bc74cc5340c6b991586ea09d
    https://github.com/scummvm/scummvm/commit/13497a9b0fa27431bc74cc5340c6b991586ea09d
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:42-07:00

Commit Message:
SCUMM: fix recent commit (proper initialize new detune parameter)

Changed paths:
    engines/scumm/imuse/imuse_part.cpp



diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 8ccd6d5..8815757 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -49,6 +49,7 @@ Part::Part() {
 	_vol = 0;
 	_vol_eff = 0;
 	_detune = 0;
+	_sysexDetune = 0;
 	_detune_eff = 0;
 	_pan = 0;
 	_pan_eff = 0;


Commit: f9eb329c791e656ea474b9affd83a855be6e5b8a
    https://github.com/scummvm/scummvm/commit/f9eb329c791e656ea474b9affd83a855be6e5b8a
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:44-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 addcf1a..f467952 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: a9f7888ad993e292e43f7f4f25ae8fb086099372
    https://github.com/scummvm/scummvm/commit/a9f7888ad993e292e43f7f4f25ae8fb086099372
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:45-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 f467952..5e7d750 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: 747b86433cd7bafb8edacba29776c77653424433
    https://github.com/scummvm/scummvm/commit/747b86433cd7bafb8edacba29776c77653424433
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:47-07:00

Commit Message:
SCUMM: partly revert / fix recent detune commit

Changed paths:
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/saveload.h



diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index b36bab4..ec60b22 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -302,7 +302,7 @@ struct Part : public Serializable {
 	byte _pitchbend_factor;
 	int8 _transpose, _transpose_eff;
 	byte _vol, _vol_eff;
-	int8 _detune, _sysexDetune, _detune_eff;
+	int8 _detune, _detune_eff;
 	int8 _pan, _pan_eff;
 	bool _on;
 	byte _modwheel;
@@ -345,7 +345,6 @@ struct Part : public Serializable {
 
 	void set_transpose(int8 transpose);
 	void set_detune(int8 detune);
-	void set_sysexDetune(int8 detune);
 	void set_pri(int8 pri);
 	void set_pan(int8 pan);
 
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 8815757..808af23 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -49,7 +49,6 @@ Part::Part() {
 	_vol = 0;
 	_vol_eff = 0;
 	_detune = 0;
-	_sysexDetune = 0;
 	_detune_eff = 0;
 	_pan = 0;
 	_pan_eff = 0;
@@ -73,7 +72,6 @@ void Part::saveLoadWithSerializer(Serializer *ser) {
 		MKLINE(Part, _transpose, sleInt8, VER(8)),
 		MKLINE(Part, _vol, sleUint8, VER(8)),
 		MKLINE(Part, _detune, sleInt8, VER(8)),
-		MKLINE(Part, _sysexDetune, sleInt8, VER(85)),
 		MKLINE(Part, _pan, sleInt8, VER(8)),
 		MKLINE(Part, _on, sleUint8, VER(8)),
 		MKLINE(Part, _modwheel, sleUint8, VER(8)),
@@ -112,12 +110,7 @@ void Part::saveLoadWithSerializer(Serializer *ser) {
 }
 
 void Part::set_detune(int8 detune) {
-	_detune_eff = clamp((_detune = detune) + _player->getDetune() + _sysexDetune, -128, 127);
-	sendPitchBend();
-}
-
-void Part::set_sysexDetune(int8 detune) {
-	_detune_eff = clamp((_sysexDetune = detune) + _player->getDetune() + _detune, -128, 127);
+	_detune_eff = clamp((_detune = detune) + _player->getDetune(), -128, 127);
 	sendPitchBend();
 }
 
@@ -284,7 +277,7 @@ void Part::setup(Player *player) {
 	_pan = clamp(player->getPan(), -64, 63);
 	_transpose_eff = player->getTranspose();
 	_transpose = 0;
-	_detune = _sysexDetune = 0;
+	_detune = 0;
 	_detune_eff = player->getDetune();
 	_pitchbend_factor = 2;
 	_pitchbend = 0;
diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index 0295b74..6ab71c2 100644
--- a/engines/scumm/imuse/sysex_scumm.cpp
+++ b/engines/scumm/imuse/sysex_scumm.cpp
@@ -72,7 +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_sysexDetune((p[11] & 0x0F) << 4 | (p[12] & 0x0F));
+			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/saveload.h b/engines/scumm/saveload.h
index 792a31d..776f40e 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 85
+#define CURRENT_VER 84
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead


Commit: 52e4f162dd60c26eeaf9ea91dae3a2b73af4aa09
    https://github.com/scummvm/scummvm/commit/52e4f162dd60c26eeaf9ea91dae3a2b73af4aa09
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:06:48-07:00

Commit Message:
FMTOWNS 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 5e7d750..4ff2b98 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: cd359cab1bba820fa8decafb46173201afd02d4a
    https://github.com/scummvm/scummvm/commit/cd359cab1bba820fa8decafb46173201afd02d4a
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:07:01-07:00

Commit Message:
GOB: Add a non-interactive Adibou2 demo

Changed paths:
    engines/gob/demos/demoplayer.cpp
    engines/gob/detection_tables.h



diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp
index 5220b45..9aa7a41 100644
--- a/engines/gob/demos/demoplayer.cpp
+++ b/engines/gob/demos/demoplayer.cpp
@@ -50,6 +50,9 @@ DemoPlayer::Script DemoPlayer::_scripts[] = {
 		"slide xant.imd 20\nslide tum.imd 20\nslide voile.imd 20\n"     \
 		"slide int.imd 20\nslide voila.imd 1\nslide voilb.imd 1\n"},
 	{kScriptSourceFile, "coktelplayer.scn"},
+	{kScriptSourceFile, "demogb.scn"},
+	{kScriptSourceFile, "demoall.scn"},
+	{kScriptSourceFile, "demofra.scn"}
 };
 
 DemoPlayer::DemoPlayer(GobEngine *vm) : _vm(vm) {
diff --git a/engines/gob/detection_tables.h b/engines/gob/detection_tables.h
index 79cef9f..11cca2b 100644
--- a/engines/gob/detection_tables.h
+++ b/engines/gob/detection_tables.h
@@ -4791,6 +4791,60 @@ static const GOBGameDescription gameDescriptions[] = {
 		kFeaturesNone,
 		0, 0, 0
 	},
+	{
+		{
+			"adibou2",
+			"Non-Interactive Demo",
+			{
+				{"demogb.scn", 0, "9291455a908ac0e6aaaca686e532609b", 105},
+				{"demogb.vmd", 0, "bc9c1db97db7bec8f566332444fa0090", 14320840},
+				{0, 0, 0, 0}
+			},
+			EN_GRB,
+			kPlatformPC,
+			ADGF_DEMO,
+			GUIO_NOSUBTITLES | GUIO_NOSPEECH
+		},
+		kGameTypeAdibou2,
+		kFeatures640x480 | kFeaturesSCNDemo,
+		0, 0, 9
+	},
+	{
+		{
+			"adibou2",
+			"Non-Interactive Demo",
+			{
+				{"demoall.scn", 0, "c8fd308c037b829800006332b2c32674", 106},
+				{"demoall.vmd", 0, "4672b2deacc6fca97484840424b1921b", 14263433},
+				{0, 0, 0, 0}
+			},
+			DE_DEU,
+			kPlatformPC,
+			ADGF_DEMO,
+			GUIO_NOSUBTITLES | GUIO_NOSPEECH
+		},
+		kGameTypeAdibou2,
+		kFeatures640x480 | kFeaturesSCNDemo,
+		0, 0, 10
+	},
+	{
+		{
+			"adibou2",
+			"Non-Interactive Demo",
+			{
+				{"demofra.scn", 0, "d1b2b1618af384ea1120def8b986c02b", 106},
+				{"demofra.vmd", 0, "b494cdec1aac7e54c3f2480512d2880e", 14297100},
+				{0, 0, 0, 0}
+			},
+			FR_FRA,
+			kPlatformPC,
+			ADGF_DEMO,
+			GUIO_NOSUBTITLES | GUIO_NOSPEECH
+		},
+		kGameTypeAdibou2,
+		kFeatures640x480 | kFeaturesSCNDemo,
+		0, 0, 11
+	},
 	{ AD_TABLE_END_MARKER, kGameTypeNone, kFeaturesNone, 0, 0, 0}
 };
 


Commit: 7fd78c59987cfb40560a832c2aef9bf4e71fc39b
    https://github.com/scummvm/scummvm/commit/7fd78c59987cfb40560a832c2aef9bf4e71fc39b
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:07:02-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 4ff2b98..d3d2a66 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"
@@ -173,7 +171,7 @@ private:
 
 	MidiDriver_TOWNS *_driver;
 
-	static const uint8 TownsMidiInputChannel::_programAdjustLevel[];
+	static const uint8 _programAdjustLevel[];
 };
 
 class TownsMidiChanState {
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: 7a489ef005aea96aa636c83d9f3675e4ec5a58d5
    https://github.com/scummvm/scummvm/commit/7a489ef005aea96aa636c83d9f3675e4ec5a58d5
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T13:22:21-07:00

Commit Message:
Merge branch 'master' of git://github.com/scummvm/scummvm

Changed paths:
    engines/gob/demos/demoplayer.cpp
    engines/gob/detection_tables.h





Commit: 15ea9b15cbb1210b14490819c5bc04f72ed7e6c8
    https://github.com/scummvm/scummvm/commit/15ea9b15cbb1210b14490819c5bc04f72ed7e6c8
Author: athrxx (athrxx at scummvm.org)
Date: 2011-05-16T14:13:33-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 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.





<Auto Generated by Git>


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