[Scummvm-cvs-logs] SF.net SVN: scummvm: [20960] scummvm/trunk/engines/kyra

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Mon Feb 27 14:41:02 CET 2006


Revision: 20960
Author:   lordhoto
Date:     2006-02-27 14:39:55 -0800 (Mon, 27 Feb 2006)
ViewCVS:  http://svn.sourceforge.net/scummvm?rev=20960&view=rev

Log Message:
-----------
Added WIP Adlib sound playing code to kyra.
It needs some checks since it doesn't work correctly in every case at the moment.

Modified Paths:
--------------
    scummvm/trunk/engines/kyra/kyra.cpp
    scummvm/trunk/engines/kyra/kyra.h
    scummvm/trunk/engines/kyra/module.mk
    scummvm/trunk/engines/kyra/sound.cpp
    scummvm/trunk/engines/kyra/sound.h
    scummvm/trunk/engines/kyra/staticres.cpp

Added Paths:
-----------
    scummvm/trunk/engines/kyra/sound_adlib.cpp
Modified: scummvm/trunk/engines/kyra/kyra.cpp
===================================================================
--- scummvm/trunk/engines/kyra/kyra.cpp	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/kyra.cpp	2006-02-27 22:39:55 UTC (rev 20960)
@@ -326,19 +326,27 @@
 
 	// for now we prefer MIDI-to-Adlib conversion over native midi
 	int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/);
-	bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
 
-	MidiDriver *driver = MidiDriver::createMidi(midiDriver);
 	if (midiDriver == MD_ADLIB) {
-		// In this case we should play the Adlib tracks, but for now
-		// the automagic MIDI-to-Adlib conversion will do.
-	} else if (native_mt32) {
-		driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+		_sound = new SoundAdlibPC(_mixer, this);
+		assert(_sound);
+	} else {
+		bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+
+		MidiDriver *driver = MidiDriver::createMidi(midiDriver);
+		assert(driver);
+		if (native_mt32) {
+			driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+		}
+
+		SoundMidiPC *soundMidiPc = new SoundMidiPC(driver, _mixer, this);
+		_sound = soundMidiPc;
+		assert(_sound);
+		soundMidiPc->hasNativeMT32(native_mt32);
 	}
-
-	_sound = new SoundPC(driver, _mixer, this);
-	assert(_sound);
-	static_cast<SoundPC*>(_sound)->hasNativeMT32(native_mt32);
+	if (!_sound->init()) {
+		error("Couldn't init sound");
+	}
 	_sound->setVolume(255);
 	
 	_saveFileMan = _system->getSavefileManager();

Modified: scummvm/trunk/engines/kyra/kyra.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra.h	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/kyra.h	2006-02-27 22:39:55 UTC (rev 20960)
@@ -938,8 +938,8 @@
 
 	Timer _timers[34];
 	uint32 _timerNextRun;	
-	static const char *_xmidiFiles[];
-	static const int _xmidiFilesCount;
+	static const char *_musicFiles[];
+	static const int _musicFilesCount;
 	
 	static const int8 _charXPosTable[];
 	static const int8 _addXPosTable[];

Modified: scummvm/trunk/engines/kyra/module.mk
===================================================================
--- scummvm/trunk/engines/kyra/module.mk	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/module.mk	2006-02-27 22:39:55 UTC (rev 20960)
@@ -8,6 +8,7 @@
 	script.o \
 	seqplayer.o \
 	sound.o \
+	sound_adlib.o \
 	staticres.o \
 	sprites.o \
 	wsamovie.o \

Modified: scummvm/trunk/engines/kyra/sound.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sound.cpp	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/sound.cpp	2006-02-27 22:39:55 UTC (rev 20960)
@@ -35,8 +35,58 @@
 
 namespace Kyra {
 
-SoundPC::SoundPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine) : Sound() {
-	_engine = engine;
+Sound::Sound(KyraEngine *engine, Audio::Mixer *mixer)
+	: _engine(engine), _mixer(mixer), _currentVocFile(0), _vocHandle(), _compressHandle() {
+}
+
+Sound::~Sound() {
+}
+
+void Sound::voicePlay(const char *file) {
+	uint32 fileSize = 0;
+	byte *fileData = 0;
+	bool found = false;
+	char filenamebuffer[25];
+
+	for (int i = 0; _supportedCodes[i].fileext; ++i) {
+		strcpy(filenamebuffer, file);
+		strcat(filenamebuffer, _supportedCodes[i].fileext);
+
+		_engine->resource()->fileHandle(filenamebuffer, &fileSize, _compressHandle);
+		if (!_compressHandle.isOpen())
+			continue;
+		
+		_currentVocFile = _supportedCodes[i].streamFunc(&_compressHandle, fileSize);
+		found = true;
+		break;
+	}
+
+	if (!found) {
+		strcpy(filenamebuffer, file);
+		strcat(filenamebuffer, ".VOC");
+		
+		fileData = _engine->resource()->fileData(filenamebuffer, &fileSize);
+		if (!fileData)
+			return;
+
+		Common::MemoryReadStream vocStream(fileData, fileSize);
+		_mixer->stopHandle(_vocHandle);
+		_currentVocFile = makeVOCStream(vocStream);
+	}
+
+	if (_currentVocFile)
+		_mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandle, _currentVocFile);
+	delete [] fileData;
+	fileSize = 0;
+}
+
+bool Sound::voiceIsPlaying() {
+	return _mixer->isSoundHandleActive(_vocHandle);
+}
+
+#pragma mark -
+
+SoundMidiPC::SoundMidiPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine) : Sound(engine, mixer) {
 	_driver = driver;
 	_passThrough = false;
 	_eventFromMusic = false;
@@ -58,17 +108,14 @@
 	if (ret != MERR_ALREADY_OPEN && ret != 0) {
 		error("couldn't open midi driver");
 	}
-	
-	_currentVocFile = 0;
-	_mixer = mixer;
 }
 
-SoundPC::~SoundPC() {
+SoundMidiPC::~SoundMidiPC() {
 	_driver->setTimerCallback(NULL, NULL);
 	close();
 }
 
-void SoundPC::setVolume(int volume) {
+void SoundMidiPC::setVolume(int volume) {
 	if (volume < 0)
 		volume = 0;
 	else if (volume > 255)
@@ -89,7 +136,7 @@
 	}
 }
 
-int SoundPC::open() {
+int SoundMidiPC::open() {
 	// Don't ever call open without first setting the output driver!
 	if (!_driver)
 		return 255;
@@ -102,13 +149,13 @@
 	return 0;
 }
 
-void SoundPC::close() {
+void SoundMidiPC::close() {
 	if (_driver)
 		_driver->close();
 	_driver = 0;
 }
 
-void SoundPC::send(uint32 b) {
+void SoundMidiPC::send(uint32 b) {
 	if (_passThrough) {
 		if ((b & 0xFFF0) == 0x007BB0)
 			return;
@@ -152,7 +199,7 @@
 		_channel[_virChannel[channel]]->send(b);
 }
 
-void SoundPC::metaEvent(byte type, byte *data, uint16 length) {
+void SoundMidiPC::metaEvent(byte type, byte *data, uint16 length) {
 	switch (type) {
 	case 0x2F:	// End of Track
 		if (_eventFromMusic) {
@@ -173,19 +220,22 @@
 	}
 }
 
-void SoundPC::playMusic(const char *file) {
+void SoundMidiPC::playMusic(const char *file) {
+	char filename[25];
+	sprintf(filename, "%s.XMI", file);
+
 	uint32 size;
-	uint8 *data = (_engine->resource())->fileData(file, &size);
+	uint8 *data = (_engine->resource())->fileData(filename, &size);
 
 	if (!data) {
-		warning("couldn't load '%s'", file);
+		warning("couldn't load '%s'", filename);
 		return;
 	}
 
 	playMusic(data, size);
 }
 
-void SoundPC::playMusic(uint8 *data, uint32 size) {
+void SoundMidiPC::playMusic(uint8 *data, uint32 size) {
 	stopMusic();
 
 	_parserSource = data;
@@ -205,19 +255,22 @@
 	_parser->property(MidiParser::mpAutoLoop, false);
 }
 
-void SoundPC::loadSoundEffectFile(const char *file) {
+void SoundMidiPC::loadSoundEffectFile(const char *file) {
+	char filename[25];
+	sprintf(filename, "%s.XMI", file);
+
 	uint32 size;
-	uint8 *data = (_engine->resource())->fileData(file, &size);
+	uint8 *data = (_engine->resource())->fileData(filename, &size);
 
 	if (!data) {
-		warning("couldn't load '%s'", file);
+		warning("couldn't load '%s'", filename);
 		return;
 	}
 
 	loadSoundEffectFile(data, size);
 }
 
-void SoundPC::loadSoundEffectFile(uint8 *data, uint32 size) {
+void SoundMidiPC::loadSoundEffectFile(uint8 *data, uint32 size) {
 	stopSoundEffect();
 
 	_soundEffectSource = data;
@@ -237,7 +290,7 @@
 	_soundEffect->property(MidiParser::mpAutoLoop, false);
 }
 
-void SoundPC::stopMusic() {
+void SoundMidiPC::stopMusic() {
 	_isLooping = false;
 	_isPlaying = false;
 	if (_parser) {
@@ -253,7 +306,7 @@
 	}
 }
 
-void SoundPC::stopSoundEffect() {
+void SoundMidiPC::stopSoundEffect() {
 	_sfxIsPlaying = false;
 	if (_soundEffect) {
 		_soundEffect->unloadMusic();
@@ -264,8 +317,8 @@
 	}
 }
 
-void SoundPC::onTimer(void *refCon) {
-	SoundPC *music = (SoundPC *)refCon;
+void SoundMidiPC::onTimer(void *refCon) {
+	SoundMidiPC *music = (SoundMidiPC *)refCon;
 
 	// this should be set to the fadeToBlack value
 	static const uint32 musicFadeTime = 2 * 1000;
@@ -307,7 +360,7 @@
 	}
 }
 
-void SoundPC::playTrack(uint8 track, bool loop) {
+void SoundMidiPC::playTrack(uint8 track, bool loop) {
 	if (_parser) {
 		_isPlaying = true;
 		_isLooping = loop;
@@ -318,7 +371,7 @@
 	}
 }
 
-void SoundPC::playSoundEffect(uint8 track) {
+void SoundMidiPC::playSoundEffect(uint8 track) {
 	if (_soundEffect) {
 		_sfxIsPlaying = true;
 		_soundEffect->setTrack(track);
@@ -327,70 +380,30 @@
 	}
 }
 
-void SoundPC::beginFadeOut() {
+void SoundMidiPC::beginFadeOut() {
 	// this should be something like fade out...
 	_fadeMusicOut = true;
 	_fadeStartTime = _engine->_system->getMillis();
 }
 
-void SoundPC::voicePlay(const char *file) {
-	uint32 fileSize = 0;
-	byte *fileData = 0;
-	bool found = false;
-	char filenamebuffer[25];
+#pragma mark -
 
-	for (int i = 0; _supportedCodes[i].fileext; ++i) {
-		strcpy(filenamebuffer, file);
-		strcat(filenamebuffer, _supportedCodes[i].fileext);
-
-		_engine->resource()->fileHandle(filenamebuffer, &fileSize, _compressHandle);
-		if (!_compressHandle.isOpen())
-			continue;
-		
-		_currentVocFile = _supportedCodes[i].streamFunc(&_compressHandle, fileSize);
-		found = true;
-		break;
-	}
-
-	if (!found) {
-		strcpy(filenamebuffer, file);
-		strcat(filenamebuffer, ".VOC");
-		
-		fileData = _engine->resource()->fileData(filenamebuffer, &fileSize);
-		if (!fileData)
-			return;
-
-		Common::MemoryReadStream vocStream(fileData, fileSize);
-		_mixer->stopHandle(_vocHandle);
-		_currentVocFile = makeVOCStream(vocStream);
-	}
-
-	if (_currentVocFile)
-		_mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_vocHandle, _currentVocFile);
-	delete [] fileData;
-	fileSize = 0;
-}
-
-bool SoundPC::voiceIsPlaying() {
-	return _mixer->isSoundHandleActive(_vocHandle);
-}
-
 void KyraEngine::snd_playTheme(int file, int track) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_playTheme(%d)", file);
-	assert(file < _xmidiFilesCount);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playTheme(%d)", file);
+	assert(file < _musicFilesCount);
 	_curMusicTheme = _newMusicTheme = file;
-	_sound->playMusic(_xmidiFiles[file]);
+	_sound->playMusic(_musicFiles[file]);
 	_sound->playTrack(track, false);
 }
 
 void KyraEngine::snd_setSoundEffectFile(int file) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_setSoundEffectFile(%d)", file);
-	assert(file < _xmidiFilesCount);
-	_sound->loadSoundEffectFile(_xmidiFiles[file]);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_setSoundEffectFile(%d)", file);
+	assert(file < _musicFilesCount);
+	_sound->loadSoundEffectFile(_musicFiles[file]);
 }
 
 void KyraEngine::snd_playSoundEffect(int track) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_playSoundEffect(%d)", track);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playSoundEffect(%d)", track);
 	if (track == 49) {
 		snd_playWanderScoreViaMap(56, 1);
 	} else {
@@ -399,7 +412,7 @@
 }
 
 void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart);
 	static const int8 soundTable[] = {
 		-1,   0,  -1,   1,   0,   3,   0,   2,
 		 0,   4,   1,   2,   1,   3,   1,   4,
@@ -441,7 +454,7 @@
 }
 
 void KyraEngine::snd_playVoiceFile(int id) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_playVoiceFile(%d)", id);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playVoiceFile(%d)", id);
 	char vocFile[9];
 	assert(id >= 0 && id < 9999);
 	sprintf(vocFile, "%03d", id);
@@ -449,7 +462,7 @@
 }
 
 void KyraEngine::snd_voiceWaitForFinish(bool ingame) {
-	debugC(9, kDebugLevelMain, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame);
+	debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame);
 	while (_sound->voiceIsPlaying() && !_skipFlag) {
 		if (ingame) {
 			delay(10, true);
@@ -461,7 +474,7 @@
 
 // static res
 
-const SoundPC::SpeechCodecs SoundPC::_supportedCodes[] = {
+const Sound::SpeechCodecs Sound::_supportedCodes[] = {
 #ifdef USE_MAD
 	{ ".VO3", makeMP3Stream },
 #endif // USE_MAD

Modified: scummvm/trunk/engines/kyra/sound.h
===================================================================
--- scummvm/trunk/engines/kyra/sound.h	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/sound.h	2006-02-27 22:39:55 UTC (rev 20960)
@@ -41,14 +41,15 @@
 
 class Sound {
 public:
-	Sound() {}
-	virtual ~Sound() {}
+	Sound(KyraEngine *engine, Audio::Mixer *mixer);
+	virtual ~Sound();
+
+	virtual bool init() = 0;
 	
 	virtual void setVolume(int volume) = 0;
 	virtual int getVolume() = 0;
 	
 	virtual void playMusic(const char *file) = 0;
-	virtual void playMusic(uint8 *data, uint32 size) = 0;
 	virtual void stopMusic() = 0;
 	
 	virtual void playTrack(uint8 track, bool looping = true) = 0;
@@ -56,7 +57,6 @@
 	virtual void startTrack() = 0;
 	
 	virtual void loadSoundEffectFile(const char *file) = 0;
-	virtual void loadSoundEffectFile(uint8 *data, uint32 size) = 0;
 	virtual void stopSoundEffect() = 0;
 	
 	virtual void playSoundEffect(uint8 track) = 0;
@@ -64,18 +64,76 @@
 	virtual void beginFadeOut() = 0;
 	virtual bool fadeOut() = 0;
 	
-	virtual void voicePlay(const char *file) = 0;
-	virtual void voiceUnload() = 0;
-	virtual bool voiceIsPlaying() = 0;
+	void voicePlay(const char *file);
+	void voiceUnload() {}
+	bool voiceIsPlaying();
+
+protected:
+	KyraEngine *_engine;
+	Audio::Mixer *_mixer;
+
+private:
+	AudioStream *_currentVocFile;
+	Audio::SoundHandle _vocHandle;
+	Common::File _compressHandle;
+	
+	struct SpeechCodecs {
+		const char *fileext;
+		AudioStream *(*streamFunc)(Common::File*, uint32);
+	};
+	
+	static const SpeechCodecs _supportedCodes[];
 };
 
-class SoundPC : public MidiDriver, public Sound {
+class AdlibDriver;
+
+class SoundAdlibPC : public Sound {
 public:
+	SoundAdlibPC(Audio::Mixer *mixer, KyraEngine *engine);
+	~SoundAdlibPC();
 
-	SoundPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine);
-	~SoundPC();
+	bool init();
 
 	void setVolume(int volume);
+	int getVolume();
+	
+	void playMusic(const char *file);
+	void stopMusic();
+	
+	void playTrack(uint8 track, bool looping);
+	void haltTrack();
+	void startTrack();
+	
+	void loadSoundEffectFile(const char *file);
+	void stopSoundEffect();
+	
+	void playSoundEffect(uint8 track);
+	
+	void beginFadeOut();
+	bool fadeOut();
+private:
+	void loadSoundFile(const char *file);
+
+	AdlibDriver *_driver;
+
+	uint8 _trackEntries[120];
+	uint8 *_soundDataPtr;
+	int _sfxPlayingSound;
+	Common::String _soundFileLoaded;
+
+	uint8 _sfxSecondByteOfSong;
+	uint8 _sfxFourthByteOfSong;
+};
+
+class SoundMidiPC : public MidiDriver, public Sound {
+public:
+
+	SoundMidiPC(MidiDriver *driver, Audio::Mixer *mixer, KyraEngine *engine);
+	~SoundMidiPC();
+
+	bool init() { return true; }
+
+	void setVolume(int volume);
 	int getVolume() { return _volume; }
 
 	void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
@@ -98,10 +156,6 @@
 
 	void beginFadeOut();
 	bool fadeOut() { return _fadeMusicOut; }
-	
-	void voicePlay(const char *file);
-	void voiceUnload() {};
-	bool voiceIsPlaying();
 
 	//MidiDriver interface implementation
 	int open();
@@ -116,7 +170,7 @@
 	MidiChannel *allocateChannel()		{ return 0; }
 	MidiChannel *getPercussionChannel()	{ return 0; }
 
-protected:
+private:
 
 	static void onTimer(void *data);
 
@@ -137,19 +191,6 @@
 	byte *_parserSource;
 	MidiParser *_soundEffect;
 	byte *_soundEffectSource;
-	KyraEngine *_engine;
-	
-	Audio::Mixer *_mixer;
-	AudioStream *_currentVocFile;
-	Audio::SoundHandle _vocHandle;
-	Common::File _compressHandle;
-	
-	struct SpeechCodecs {
-		const char *fileext;
-		AudioStream *(*streamFunc)(Common::File*, uint32);
-	};
-	
-	static const SpeechCodecs _supportedCodes[];
 };
 } // end of namespace Kyra
 

Added: scummvm/trunk/engines/kyra/sound_adlib.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sound_adlib.cpp	                        (rev 0)
+++ scummvm/trunk/engines/kyra/sound_adlib.cpp	2006-02-27 22:39:55 UTC (rev 20960)
@@ -0,0 +1,1908 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "common/stdafx.h"
+#include "common/system.h"
+#include "common/mutex.h"
+#include "common/timer.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "sound/mixer.h"
+#include "sound/fmopl.h"
+#include "sound/audiostream.h"
+
+// TODO:
+//   - check how the sounds are stopped (doesn't work atm whyever)
+//   - implement music pausing + stop and fadeing
+//   - check why the sfx sounds strange sometimes
+//   - implement stateCallback1_1
+
+namespace Kyra {
+
+class AdlibDriver : public AudioStream {
+public:
+	AdlibDriver(Audio::Mixer *mixer);
+	~AdlibDriver();
+
+	int callback(int opcode, ...);
+	void callback();
+
+	// AudioStream API
+	int readBuffer(int16 *buffer, const int numSamples) {
+		memset(buffer, 0, sizeof(int16)*numSamples);
+		lock();
+		YM3812UpdateOne(_adlib, buffer, numSamples);
+		unlock();
+		return numSamples;
+	}
+
+	bool isStereo() const { return false; }
+	bool endOfData() const { return false; }
+	int getRate() const { return 22050; }
+
+private:
+	struct OpcodeEntry {
+		typedef int (AdlibDriver::*DriverOpcode)(va_list &list);
+		DriverOpcode function;
+		const char *name;
+	};
+
+	static const OpcodeEntry _opcodeList[];
+	static const int _opcodesEntries;
+
+	int snd_ret0x100(va_list &list);
+	int snd_ret0x1983(va_list &list);
+	int snd_initDriver(va_list &list);
+	int snd_deinitDriver(va_list &list);
+	int snd_setSoundData(va_list &list);
+	int snd_unkOpcode1(va_list &list);
+	int snd_startSong(va_list &list);
+	int snd_unkOpcode2(va_list &list);
+	int snd_unkOpcode3(va_list &list);
+	int snd_readByte(va_list &list);
+	int snd_writeByte(va_list &list);
+	int snd_setUnk5(va_list &list);
+	int snd_unkOpcode4(va_list &list);
+	int snd_dummy(va_list &list);
+	int snd_getNullvar4(va_list &list);
+	int snd_setNullvar3(va_list &list);
+	int snd_setFlag(va_list &list);
+	int snd_clearFlag(va_list &list);
+
+	struct OutputState {
+		uint8 unk27;
+		uint8 *dataptr;
+		uint8 unk5;
+		uint8 unk9;
+		uint8 unk10;
+		int8 unk2;
+		uint8 dataptrStackPos;
+		uint8 *dataptrStack[4];
+		uint8 unk14;
+		uint8 unk29;
+		int8 unk31;
+		uint16 unk30;
+		uint16 unk37;
+		uint8 unk33;
+		uint8 unk34;
+		uint8 unk35;
+		uint8 unk36;
+		uint8 unk32;
+		uint8 unk41;
+		uint8 unk38;
+		uint8 unk26;
+		uint8 unk7;
+		uint8 unk15;
+		int8 unk1;
+		int8 unk4;
+		uint8 unk17;
+		uint8 unkOutputValue1;
+		typedef void (AdlibDriver::*Callback)(OutputState&);
+		Callback callback1;
+		Callback callback2;
+		uint8 unk12;
+		uint8 unk24;
+		uint8 unk25;
+		uint8 unk28;
+		uint8 unk23;
+		uint8 unk39;	
+		uint8 unk40;
+		uint8 unk3;
+		uint8 unk11;
+		uint8 unk19;
+		uint8 unk18;
+		uint8 unk20;
+		uint8 unk21;
+		uint8 unk22;
+		uint16 offset;
+		uint8 unk6;
+		uint8 unk13;
+		int8 unk16;
+	};
+
+	void stateCallback1_1(OutputState &state);
+	void stateCallback1_2(OutputState &state);
+	void stateCallback2_1(OutputState& state);
+
+	void resetAdlibState();
+	void output0x388(uint16 word);
+	void waitLoops(int count);
+	void initTable(OutputState &table);
+	void unkOutput1(OutputState &table);
+	void unkOutput2(uint8 num);
+
+	uint16 updateUnk6Value();
+	void update1(uint8 unk1, OutputState &state);
+
+	void updateAndOutput1(uint8 unk1, OutputState &state);
+	void updateAndOutput2(uint8 unk1, uint8 *dataptr, OutputState &state);
+	void updateAndOutput3(OutputState &state);
+
+	void output1(OutputState &state);
+
+	uint8 calculateLowByte1(OutputState &state);
+	uint8 calculateLowByte2(OutputState &state);
+
+	uint16 checkValue(int16 val) {
+		if (val < 0)
+			val = 0;
+		if (val > 0x3F)
+			val = 0x3F;
+		return val;
+	}
+
+	void callbackOutput();
+	void callbackProcess();
+
+	struct ParserOpcode {
+		typedef int (AdlibDriver::*POpcode)(uint8 *&dataptr, OutputState &state, uint8 value);
+		POpcode function;
+		const char *name;
+	};
+	static const ParserOpcode _parserOpcodeTable[];
+	static const int _parserOpcodeTableSize;
+
+	int updateCallback1(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback2(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback3(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback4(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback5(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallbackPushDataPtr(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallbackPopDataPtr(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback8(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback9(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback10(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback11(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback12(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback13(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback14(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback15(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback16(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback17(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback18(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback19(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback20(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback21(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback22(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback23(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback24(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback25(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback26(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback27(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback28(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback29(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback30(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback31(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback32(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback33(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback34(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback35(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback36(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback37(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback38(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback39(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback40(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback41(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback42(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback43(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback44(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback45(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback46(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback47(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback48(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback49(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback50(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback51(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback52(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback53(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback54(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback55(uint8 *&dataptr, OutputState &state, uint8 value);
+	int updateCallback56(uint8 *&dataptr, OutputState &state, uint8 value);
+private:
+	int _lastProcessed;
+	uint8 _flagTrigger;
+	int _curTable;
+	uint8 _unk4;
+	uint8 _unk5;
+	int _soundsPlaying;
+
+	uint16 _unk6;
+	uint8 _continueFlag;
+
+	uint8 _unkValue1;
+	uint8 _unkValue2;
+	uint8 _unkValue3;
+	uint8 _unkValue4;
+	uint8 _unkValue5;
+	uint8 _unkValue6;
+	uint8 _unkValue7;
+	uint8 _unkValue8;
+	uint8 _unkValue9;
+	uint8 _unkValue10;
+	uint8 _unkValue11;
+	uint8 _unkValue12;
+	uint8 _unkValue13;
+	uint8 _unkValue14;
+	uint8 _unkValue15;
+	uint8 _unkValue16;
+	uint8 _unkValue17;
+	uint8 _unkValue18;
+	uint8 _unkValue19;
+	uint8 _unkValue20;
+
+	int _flags;
+	FM_OPL *_adlib;
+
+	uint8 *_soundData;
+
+	uint8 _soundIdTable[0x10];
+	OutputState _outputTables[10];
+
+	uint8 _unkOutputByte2;
+	uint8 _unkOutputByte1;
+	uint8 _unkTableByte1;
+
+	const uint8 *_tablePtr1;
+	const uint8 *_tablePtr2;
+
+	static const uint8 _outputTable[];
+	static const uint16 _unkTable[];
+	static const uint8 *_unkTable2[];
+	static const uint8 _unkTable2_1[];
+	static const uint8 _unkTable2_2[];
+	static const uint8 _unkTable2_3[];
+	static const uint8 _unkTables[][32];
+
+	Common::Mutex _mutex;
+	Audio::Mixer *_mixer;
+
+	void lock() { _mutex.lock(); }
+	void unlock() { _mutex.unlock(); }
+};
+
+void AdlibTimerCall(void *refCon) {
+	AdlibDriver *driver = (AdlibDriver*)refCon;
+	driver->callback();
+}
+
+AdlibDriver::AdlibDriver(Audio::Mixer *mixer) {
+	_mixer = mixer;
+
+	_flags = 0;
+	// TODO: use mixer sample rate
+	_adlib = makeAdlibOPL(22050);
+	assert(_adlib);
+
+	memset(_outputTables, 0, sizeof(_outputTables));
+	_soundData = 0;
+
+	_unkOutputByte2 = _unkOutputByte1 = 0;
+
+	_lastProcessed = _flagTrigger = _curTable = _unk4 = 0;
+	_unk6 = 0x1234;
+	_continueFlag = 0;
+
+	_unkTableByte1 = 0;
+
+	_unkValue3 = 0xFF;
+	_unkValue1 = _unkValue2 = _unkValue4 = _unkValue5 = 0;
+	_unkValue6 = _unkValue7 = _unkValue8 = _unkValue9 = _unkValue10 = 0;
+	_unkValue11 = _unkValue12 = _unkValue13 = _unkValue14 = _unkValue15 =
+	_unkValue16 = _unkValue17 = _unkValue18 = _unkValue19 = _unkValue20 = 0;
+
+	_tablePtr1 = _tablePtr2 = 0;
+
+	_mixer->setupPremix(this);
+
+	// the interval should be around 13000 to 20000
+	Common::g_timer->installTimerProc(&AdlibTimerCall, 15000, this);
+}
+
+AdlibDriver::~AdlibDriver() {
+	Common::g_timer->removeTimerProc(&AdlibTimerCall);
+	_mixer->setupPremix(0);
+	OPLDestroy(_adlib);
+	_adlib = 0;
+}
+
+int AdlibDriver::callback(int opcode, ...) {
+	lock();
+	if (opcode >= _opcodesEntries || opcode < 0) {
+		warning("AdlibDriver: calling unknown opcode '%d'", opcode);
+		return 0;
+	}
+
+	debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d)", _opcodeList[opcode].name, opcode);
+
+	va_list args;
+	va_start(args, opcode);
+	int returnValue = (this->*(_opcodeList[opcode].function))(args);
+	va_end(args);
+	unlock();
+	return returnValue;
+}
+
+// Opcodes
+
+int AdlibDriver::snd_ret0x100(va_list &list) {
+	return 0x100;
+}
+
+int AdlibDriver::snd_ret0x1983(va_list &list) {
+	return 0x1983;
+}
+
+int AdlibDriver::snd_initDriver(va_list &list) {
+	_lastProcessed = _soundsPlaying = 0;
+	resetAdlibState();
+	return 0;
+}
+
+int AdlibDriver::snd_deinitDriver(va_list &list) {
+	resetAdlibState();
+	return 0;
+}
+
+int AdlibDriver::snd_setSoundData(va_list &list) {
+	if (_soundData) {
+		delete [] _soundData;
+		_soundData = 0;
+	}
+	_soundData = va_arg(list, uint8*);
+	return 0;
+}
+
+int AdlibDriver::snd_unkOpcode1(va_list &list) {
+	warning("unimplemented snd_unkOpcode1");
+	return 0;
+}
+
+int AdlibDriver::snd_startSong(va_list &list) {
+	int songId = va_arg(list, int);
+	_flags |= 8;
+	uint16 offset = READ_LE_UINT16(&_soundData[songId << 1]);
+	uint8 firstByte = *(_soundData + offset);
+
+	if ((songId << 1) != 0) {
+		if (firstByte == 9) {
+			if (_flags & 2)
+				return 0;
+		} else {
+			if (_flags & 1)
+				return 0;
+		}
+	}
+
+	_soundIdTable[_soundsPlaying] = songId;
+	++_soundsPlaying;
+	_soundsPlaying &= 0x0F;
+
+	return 0;
+}
+
+int AdlibDriver::snd_unkOpcode2(va_list &list) {
+	warning("unimplemented snd_unkOpcode2");
+	return 0;
+}
+
+int AdlibDriver::snd_unkOpcode3(va_list &list) {
+	int value = va_arg(list, int);
+	int loop = value;
+	if (value < 0) {
+		value = 0;
+		loop = 9;
+	}
+	loop -= value;
+	++loop;
+
+	while (loop--) {
+		_curTable = value;
+		OutputState &table = _outputTables[_curTable];
+		table.unk2 = 0;
+		table.dataptr = 0;
+		if (value != 9) {
+			unkOutput1(table);
+		}
+		++value;
+	}
+
+	return 0;
+}
+
+int AdlibDriver::snd_readByte(va_list &list) {
+	uint8 *ptr = _soundData + READ_LE_UINT16(&_soundData[va_arg(list, int) << 1]) + va_arg(list, int);
+	return *ptr;
+}
+
+int AdlibDriver::snd_writeByte(va_list &list) {
+	uint8 *ptr = _soundData + READ_LE_UINT16(&_soundData[va_arg(list, int) << 1]) + va_arg(list, int);
+	uint8 oldValue = *ptr;
+	*ptr = (uint8)va_arg(list, int);
+	return oldValue;
+}
+
+int AdlibDriver::snd_setUnk5(va_list &list) {
+	warning("unimplemented snd_setUnk5");
+	return 0;
+}
+
+int AdlibDriver::snd_unkOpcode4(va_list &list) {
+	warning("unimplemented snd_unkOpcode4");
+	return 0;
+}
+
+int AdlibDriver::snd_dummy(va_list &list) {
+	return 0;
+}
+
+int AdlibDriver::snd_getNullvar4(va_list &list) {
+	warning("unimplemented snd_getNullvar4");
+	return 0;
+}
+
+int AdlibDriver::snd_setNullvar3(va_list &list) {
+	warning("unimplemented snd_setNullvar3");
+	return 0;
+}
+
+int AdlibDriver::snd_setFlag(va_list &list) {
+	int oldFlags = _flags;
+	_flags |= va_arg(list, int);
+	return oldFlags;
+}
+
+int AdlibDriver::snd_clearFlag(va_list &list) {
+	int oldFlags = _flags;
+	_flags &= ~(va_arg(list, int));
+	return oldFlags;
+}
+
+// timer callback
+
+void AdlibDriver::callback() {
+	lock();
+	//--_flagTrigger;
+	//if ((int8)_flagTrigger < 0)
+		_flags &= 0xFFF7;
+	callbackOutput();
+	callbackProcess();
+
+	_unkValue3 += _unkTableByte1;
+	if ((int8)_unkValue3 < 0) {
+		if (!(--_unkValue2)) {
+			_unkValue2 = _unkValue1;
+			++_unkValue4;
+		}
+	}
+	unlock();
+}
+
+void AdlibDriver::callbackOutput() {
+	while (_lastProcessed != _soundsPlaying) {
+		uint8 *ptr = _soundData;
+
+		ptr += READ_LE_UINT16(&ptr[_soundIdTable[_lastProcessed] << 1]);
+		uint8 index = *ptr++; // set nullvar
+
+		OutputState &table = _outputTables[index];
+
+		int8 unk2 = *ptr++;
+		if (unk2 >= table.unk2) {
+			initTable(table);
+			table.unk2 = unk2;
+			table.dataptr = ptr;
+			table.unk1 = -1;
+			table.unk4 = -1;
+			table.unk5 = 1;
+			if (index != 9) {
+				unkOutput2(index);
+			}
+		}
+
+		++_lastProcessed;
+		_lastProcessed &= 0x0F;
+	}
+}
+
+void AdlibDriver::callbackProcess() {
+	_curTable = 9;
+	for (_curTable = 9; _curTable >= 0; --_curTable) {
+		if (!_outputTables[_curTable].dataptr) {
+			continue;
+		}
+	
+		OutputState &table = _outputTables[_curTable];
+		_unkOutputByte1 = _outputTable[_curTable];
+
+		if (table.unk6) {
+			table.unk1 = _unkTableByte1;
+		}
+
+		table.unk4 += table.unk1;
+		if (table.unk4 < 0) {
+			if (--table.unk5) {
+				if (table.unk5 == table.unk7)
+					unkOutput1(table);
+				if (table.unk5 == table.unk3 && _curTable != 9)
+					unkOutput1(table);
+			} else {
+				int8 opcode = 0;
+				while (1 && table.dataptr) {
+					uint16 command = READ_LE_UINT16(table.dataptr);
+					table.dataptr += 2;
+					if (command & 0x0080) {
+						opcode = command & 0x7F;
+						if (opcode > 0x4A)
+							opcode = 0x4A;
+						//debug("'%s' (%d) (%d)", _parserOpcodeTable[opcode].name, opcode, _curTable);
+						opcode = (this->*(_parserOpcodeTable[opcode].function))(table.dataptr, table, (command & 0xFF00) >> 8);
+						--opcode;
+						if (opcode >= 0)
+							break;
+						continue;
+					} else {
+						opcode = 0;
+						updateAndOutput1(command & 0xFF, table);
+						updateAndOutput3(table);
+						update1((command & 0xFF00) >> 8, table);
+						if (!_continueFlag)
+							continue;
+						break;
+					}
+				}
+				if (opcode)
+					continue;
+			}
+		}
+
+		if (table.callback1)
+			(this->*(table.callback1))(table);
+		if (table.callback2)
+			(this->*(table.callback2))(table);
+	}
+}
+
+// 
+
+void AdlibDriver::resetAdlibState() {
+	_unk6 = 0x1234;
+	output0x388(0x120);
+	output0x388(0x800);
+	output0x388(0xBD00);
+	int loop = 10;
+	while (loop--) {
+		if (loop != 9) {
+			output0x388(((_outputTable[loop] + 0x40) << 8) | 0x3F);
+			output0x388(((_outputTable[loop] + 0x43) << 8) | 0x3F);
+		}
+		initTable(_outputTables[loop]);
+	}
+}
+
+void AdlibDriver::output0x388(uint16 word) {
+	OPLWrite(_adlib, 0x388, (word >> 8) & 0xFF);
+	waitLoops(4);
+	OPLWrite(_adlib, 0x389, word & 0xFF);
+	waitLoops(23);	
+}
+
+void AdlibDriver::waitLoops(int count) {
+	while (count--) {
+		OPLRead(_adlib, 0x388);
+	}
+}
+
+void AdlibDriver::initTable(OutputState &table) {
+	uint8 unk27BackUp = table.unk27;
+
+	memset(&table, 0, sizeof(OutputState));
+
+	table.unk27 = unk27BackUp;
+
+	table.unk1 = -1;
+	table.unk2 = 0;
+	// normally here are nullfuncs but we set 0 for now
+	table.callback1 = 0;
+	table.callback2 = 0;
+	table.unk3 = 0x01;
+}
+
+void AdlibDriver::unkOutput1(OutputState &table) {
+	if (_curTable == 9)
+		return;
+	if (_unk4 && _curTable >= 6)
+		return;
+	uint16 output = (_curTable + 0xB0) << 8;
+	table.unkOutputValue1 &= 0xDF;
+	output |= table.unkOutputValue1;
+	output0x388(output);
+}
+
+void AdlibDriver::unkOutput2(uint8 num) {
+	if (_unk4)
+		if (num >= 6)
+			return;
+
+	uint8 value = _outputTable[num];
+	output0x388(((value + 0x60) << 8) | 0xFF);
+	output0x388(((value + 0x63) << 8) | 0xFF);
+	output0x388(((value + 0x80) << 8) | 0xFF);
+	output0x388(((value + 0x83) << 8) | 0xFF);
+
+	output0x388(((num + 0xB0) << 8) | 0x00);
+	output0x388(((num + 0xB0) << 8) | 0x20);
+}
+
+uint16 AdlibDriver::updateUnk6Value() {
+	_unk6 += 0x9248;
+	uint16 lowBits = _unk6 & 7;
+	_unk6 >>= 3;
+	_unk6 |= lowBits << 12;
+	return _unk6;
+}
+
+void AdlibDriver::update1(uint8 unk1, OutputState &state) {
+	_continueFlag = unk1;
+	if (state.unk11) {
+		state.unk5 = (updateUnk6Value() & 0xFF) + (unk1 & state.unk11);
+		return;
+	}
+	uint8 value = unk1;
+	if (state.unk12) {
+		uint8 value2 = value;
+		uint8 add = value >> 3;
+		int loops = state.unk12;
+		while (loops--) {
+			value2 += add;
+		}
+		state.unk7 = value2;
+	}
+	state.unk5 = value;
+}
+
+void AdlibDriver::updateAndOutput1(uint8 unk1, OutputState &state) {
+	state.unk13 = unk1;
+	uint8 unk2 = unk1 & 0xF0;
+	unk2 += state.unk10;
+	unk1 &= 0x0F;
+	unk1 += state.unk14;
+
+	if ((int8)unk1 >= 0x0C) {
+		unk1 -= 0x0C;
+		unk2 += 0x10;
+	} else if ((int8)unk1 < 0) {
+		unk1 += 0x0C;
+		unk2 -= 0x10;
+	}
+
+	uint16 value = _unkTable[unk1] + state.unk15;
+
+	unk2 >>= 2;
+	unk2 &= 0x1C;
+	unk2 |= (value & 0xFF00) >> 8;
+	value = (value & 0xFF) | (unk2 << 8);
+
+	if (state.unk16 != 0) {
+		if (state.unk16 >= 0) {
+			const uint8 *table = _unkTables[(state.unk13 & 0x0F) + 2];
+			value += table[state.unk16];
+		} else {
+			const uint8 *table = _unkTables[state.unk13 & 0x0F];
+			value -= table[(state.unk16 ^ 0xFF) + 1];
+		}
+	}
+
+	state.unkOutputValue1 = (state.unkOutputValue1 & 0x20) | ((value & 0xFF00) >> 8);
+	state.unk17 = value & 0xFF;
+
+	output0x388(((0xA0 + _curTable) << 8) | state.unk17);
+	output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+}
+
+void AdlibDriver::updateAndOutput2(uint8 unk1, uint8 *dataptr, OutputState &state) {
+	output0x388(((0x20 + unk1) << 8) | *dataptr++);
+	output0x388(((0x23 + unk1) << 8) | *dataptr++);
+
+	uint8 temp = *dataptr++;
+	output0x388(((0xC0 + _curTable) << 8) | temp);
+	state.unk23 = temp & 1;
+
+	output0x388(((0xE0 + unk1) << 8) | *dataptr++);
+	output0x388(((0xE3 + unk1) << 8) | *dataptr++);
+
+	state.unk24 = *dataptr++;
+	output0x388(((0x40 + unk1) << 8) | calculateLowByte1(state));
+
+	state.unk25 = *dataptr++;
+	output0x388(((0x43 + unk1) << 8) | calculateLowByte2(state));
+
+	output0x388(((0x60 + unk1) << 8) | *dataptr++);
+	output0x388(((0x63 + unk1) << 8) | *dataptr++);
+
+	output0x388(((0x80 + unk1) << 8) | *dataptr++);
+	output0x388(((0x83 + unk1) << 8) | *dataptr++);
+}
+
+void AdlibDriver::updateAndOutput3(OutputState &state) {
+	state.unkOutputValue1 |= 0x20;
+	output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+	int8 shift = 9 - state.unk33;
+	uint16 temp = state.unk17 | (state.unkOutputValue1 << 8);
+	state.unk37 = ((temp & 0x3FF) >> shift) & 0xFF;
+	state.unk38 = state.unk36;
+}
+
+void AdlibDriver::output1(OutputState &state) {
+	uint8 lowByte = calculateLowByte2(state);
+	output0x388(((0x43 + _outputTable[_curTable]) << 8) | lowByte);
+	if (state.unk23) {
+		lowByte = calculateLowByte1(state);
+		output0x388(((0x40 + _outputTable[_curTable]) << 8) | lowByte);
+	}
+}
+
+void AdlibDriver::stateCallback1_1(OutputState &state) {
+	state.unk31 += state.unk29;
+	if ((int8)state.unk31 < 0)
+		return;
+	warning("stateCallback1_1 unimplemented");
+}
+
+void AdlibDriver::stateCallback1_2(OutputState &state) {
+	if (state.unk38) {
+		--state.unk38;
+		return;
+	}
+
+	state.unk41 += state.unk32;
+	if ((int8)state.unk41 < 0) {
+		uint16 temp2 = state.unk37;
+		if (!(--state.unk34)) {
+			temp2 ^= 0xFFFF;
+			++temp2;
+			state.unk37 = temp2;
+			state.unk34 = state.unk35;
+		}
+
+		uint16 temp3 = state.unk17 | (state.unkOutputValue1 << 8);
+		temp2 += temp3 & 0x3FF;
+		state.unk17 = temp2 & 0xFF;
+
+		state.unkOutputValue1 = (state.unkOutputValue1 & 0xFC) | (temp3 >> 8);
+
+		output0x388(((0xA0 + _curTable) << 8) | state.unkOutputValue1);
+		output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+	}
+}
+
+void AdlibDriver::stateCallback2_1(OutputState &state) {
+	state.unk18 += state.unk19;
+	if ((int8)state.unk18 < 0) {
+		if ((--state.unk21) & 0x80) {
+			state.unk21 = state.unk20;
+		}
+		uint16 value = (state.unk22 + _unkOutputByte1) << 8;
+		value |= (_soundData/*state.dataptr:segment*/ + state.offset)[state.unk21];
+		output0x388(value);
+	}
+}
+
+uint8 AdlibDriver::calculateLowByte1(OutputState &state) {
+	int8 value = state.unk24 & 0x3F;
+	if (state.unk23) {
+		value += state.unk26;
+		value += state.unk27;
+		value += state.unk28;
+	}
+
+	if (value > 0x3F) {
+		if (value < 0)
+			value = 0;
+		else
+			value = 0x3F;
+	}
+
+	return value | (state.unk24 & 0xC0);
+}
+
+uint8 AdlibDriver::calculateLowByte2(OutputState &state) {
+	int8 value = state.unk25 & 0x3F;
+	value += state.unk26;
+	value += state.unk27;
+	value += state.unk28;
+
+	if (value > 0x3F) {
+		if (value < 0)
+			value = 0;
+		else
+			value = 0x3F;
+	}
+
+	return value | (state.unk25 & 0xC0);
+}
+
+// parser opcodes
+
+int AdlibDriver::updateCallback1(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk9 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback2(uint8 *&dataptr, OutputState &state, uint8 value) {
+	++dataptr;
+	if (--state.unk9) {
+		--dataptr;
+		--dataptr;
+		uint16 add = READ_LE_UINT16(dataptr);
+		dataptr += 2;
+		dataptr += add;
+	}
+	return 0;
+}
+
+int AdlibDriver::updateCallback3(uint8 *&dataptr, OutputState &state, uint8 value) {
+	if (value >= 0xFF)
+		return 0;
+
+	uint16 add = value << 1;
+	uint8 *ptr = _soundData + READ_LE_UINT16(_soundData + add);
+	uint8 table = *ptr++;
+	OutputState &state2 = _outputTables[table];
+	int8 temp = *((int8*)ptr); ++ptr;
+	if (temp >= (int8)state2.unk2) {
+		_flagTrigger = 1;
+		_flags |= 8;
+		initTable(state2);
+		state2.unk2 = temp;
+		state2.dataptr = ptr;
+		state2.unk1 = -1;
+		state2.unk4 = -1;
+		state2.unk5 = 1;
+		unkOutput2(table);
+	}
+	return 0;
+}
+
+int AdlibDriver::updateCallback4(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk3 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback5(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	uint16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+	dataptr += add;
+	return 0;
+}
+
+int AdlibDriver::updateCallbackPushDataPtr(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	uint16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+	state.dataptrStack[state.dataptrStackPos++] = dataptr;
+	dataptr += add;
+	return 0;
+}
+
+int AdlibDriver::updateCallbackPopDataPtr(uint8 *&dataptr, OutputState &state, uint8 value) {
+	dataptr = state.dataptrStack[--state.dataptrStackPos];
+	return 0;
+}
+
+int AdlibDriver::updateCallback8(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk10 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback9(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk2 = 0;
+	if (_curTable != 9) {
+		unkOutput1(state);
+	}
+	dataptr = 0;
+	return 2;
+}
+
+int AdlibDriver::updateCallback10(uint8 *&dataptr, OutputState &state, uint8 value) {
+	update1(value, state);
+	unkOutput1(state);
+	return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback11(uint8 *&dataptr, OutputState &state, uint8 value) {
+	output0x388(*dataptr++);
+	return 0;
+}
+
+int AdlibDriver::updateCallback12(uint8 *&dataptr, OutputState &state, uint8 value) {
+	updateAndOutput1(value, state);
+	value = *dataptr++;
+	update1(value, state);
+	return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback13(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk14 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback14(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk18 = value;
+	state.unk19 = value;
+	state.unk20 = state.unk21 = *dataptr++;
+	state.unk22 = *dataptr++;
+	state.offset = READ_LE_UINT16(dataptr); dataptr += 2;
+	state.callback2 = &AdlibDriver::stateCallback2_1;
+	return 0;
+}
+
+int AdlibDriver::updateCallback15(uint8 *&dataptr, OutputState &state, uint8 value) {
+	OutputState &state2 = _outputTables[_curTable];
+	state2.unk5 = 0;
+	state2.unk2 = 0;
+	state2.dataptr = 0;
+	return 0;
+}
+
+int AdlibDriver::updateCallback16(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint8 *ptr = _soundData;
+	ptr += READ_LE_UINT16(&_soundData[value << 1]);
+	OutputState &state2 = _outputTables[*ptr];
+	if (!state2.dataptr) {
+		return 0;
+	}
+	dataptr -= 2;
+	return 2;
+}
+
+int AdlibDriver::updateCallback17(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint8 *ptr = _soundData;
+	ptr += READ_LE_UINT16(_soundData + value * 2 + 0x1F4);
+	updateAndOutput2(_unkOutputByte1, ptr, state);
+	return 0;
+}
+
+int AdlibDriver::updateCallback18(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk29 = value;
+	state.unk30 = READ_BE_UINT16(dataptr); dataptr += 2;
+	state.callback1 = &AdlibDriver::stateCallback1_1;
+	state.unk31 = -1;
+	return 0;
+}
+
+int AdlibDriver::updateCallback19(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	state.callback1 = 0;
+	state.unk30 = 0;
+	return 0;
+}
+
+int AdlibDriver::updateCallback20(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk15 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback21(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk32 = value;
+	state.unk33 = *dataptr++;
+	uint8 temp = *dataptr++;
+	state.unk34 = temp + 1;
+	state.unk35 = temp << 1;
+	state.unk36 = *dataptr++;
+	state.callback1 = &AdlibDriver::stateCallback1_2;
+	return 0;
+}
+
+int AdlibDriver::updateCallback22(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk2 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback23(uint8 *&dataptr, OutputState &state, uint8 value) {
+	value >>= 1;
+	_unkValue1 = _unkValue2 = value;
+	_unkValue3 = 0xFF;
+	_unkValue4 = _unkValue5 = 0;
+	return 0;
+}
+
+int AdlibDriver::updateCallback24(uint8 *&dataptr, OutputState &state, uint8 value) {
+	if (_unkValue5) {
+		if (_unkValue4 & value) {
+			_unkValue5 = 0;
+			return 0;
+		}
+	}
+
+	if (!(value & _unkValue4)) {
+		++_unkValue5;
+	}
+
+	dataptr -= 2;
+	state.unk5 = 1;
+	return 2;
+}
+
+int AdlibDriver::updateCallback25(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk26 = value;
+	output1(state);
+	return 0;
+}
+
+int AdlibDriver::updateCallback26(uint8 *&dataptr, OutputState &state, uint8 value) {
+	update1(value, state);
+	return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback27(uint8 *&dataptr, OutputState &state, uint8 value) {
+	update1(value, state);
+	updateAndOutput3(state);
+	return (_continueFlag != 0);
+}
+
+int AdlibDriver::updateCallback28(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk12 = value & 7;
+	return 0;
+}
+
+int AdlibDriver::updateCallback29(uint8 *&dataptr, OutputState &state, uint8 value) {
+	_unkTableByte1 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback30(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	state.callback2 = 0;
+	return 0;
+}
+
+int AdlibDriver::updateCallback31(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk1 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback32(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk28 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback33(uint8 *&dataptr, OutputState &state, uint8 value) {
+	int tableBackup = _curTable;
+
+	_curTable = value;
+	OutputState &state2 = _outputTables[value];
+	state2.unk27 = *dataptr++;
+	output1(state2);
+
+	_curTable = tableBackup;
+	return 0;
+}
+
+int AdlibDriver::updateCallback34(uint8 *&dataptr, OutputState &state, uint8 value) {
+	int tableBackup = _curTable;
+
+	_curTable = value;
+	OutputState &state2 = _outputTables[value];
+	state2.unk27 += *dataptr++;
+	output1(state2);
+
+	_curTable = tableBackup;
+	return 0;
+}
+
+int AdlibDriver::updateCallback35(uint8 *&dataptr, OutputState &state, uint8 value) {
+	value &= 1;
+	value <<= 7;
+	_unkOutputByte2 = (_unkOutputByte2 & 0x7F) | value;
+	output0x388(0xBD00 | _unkOutputByte2);
+	return 0;
+}
+
+int AdlibDriver::updateCallback36(uint8 *&dataptr, OutputState &state, uint8 value) {
+	value &= 1;
+	value <<= 6;
+	_unkOutputByte2 = (_unkOutputByte2 & 0xBF) | value;
+	output0x388(0xBD00 | _unkOutputByte2);
+	return 0;
+}
+
+int AdlibDriver::updateCallback37(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk26 += value;
+	output1(state);
+	return 0;
+}
+
+int AdlibDriver::updateCallback38(uint8 *&dataptr, OutputState &state, uint8 value) {
+	int tableBackUp = _curTable;
+
+	_curTable = value;
+	OutputState &state2 = _outputTables[value];
+	state2.unk5 = state2.unk2 = 0;
+	state2.dataptr = 0;
+	state2.unk27 = 0;
+
+	if (value != 9) {
+		uint8 outValue = _outputTable[value];
+		output0x388((0xC0 + _curTable) << 8);
+		output0x388(((0x43 + outValue) << 8) | 0x3F);
+		output0x388(((0x83 + outValue) << 8) | 0xFF);
+		output0x388((0xB0 + _curTable) << 8);
+	}
+
+	_curTable = tableBackUp;
+	return 0;
+}
+
+int AdlibDriver::updateCallback39(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint16 unk = *dataptr++;
+	unk |= value << 8;
+	unk &= updateUnk6Value();
+
+	uint16 unk2 = ((state.unkOutputValue1 & 0x1F) << 8) | state.unk17;
+	unk2 += unk;
+	unk2 |= ((state.unkOutputValue1 & 0x20) << 8);
+
+	output0x388(((0xA0 + _curTable) << 8) | (unk2 & 0xFF));
+	output0x388(((0xB0 + _curTable) << 8) | ((unk2 & 0xFF00) >> 8));
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback40(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	state.callback1 = 0;
+	return 0;
+}
+
+int AdlibDriver::updateCallback41(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk16 = value;
+	int8 unk1 = 0, unk2 = 0;
+
+	unk1 = state.unk13 & 0xF0;
+	unk1 += state.unk10;
+
+	unk2 = state.unk13 & 0x0F;
+	unk2 += state.unk14;
+
+	if (unk2 >= 12) {
+		unk2 -= 12;
+		unk1 += 16;
+	} else if (unk2 < 0) {
+		unk2 += 12;
+		unk1 -= 16;
+	}
+
+	uint16 unk3 = _unkTable[unk2] + state.unk15;
+	unk1 >>= 1; unk1 &= 0x1C;
+	unk2 |= (unk3 >> 8);
+
+	uint16 unk4 = (unk2 << 8) | (unk3 & 0xFF);
+	if (state.unk16 >= 0) {
+		const uint8 *ptr = _unkTables[(state.unk13 & 0x0F) + 2];
+		unk4 += ptr[state.unk16];
+	} else {
+		const uint8 *ptr = _unkTables[state.unk13 & 0x0F];
+		unk4 += ptr[(state.unk16 ^ 0xFF) + 1];
+	}
+
+	unk2 = unk4 >> 8;
+	unk1 = unk4 & 0xFF;
+
+	state.unkOutputValue1 = unk2 | (state.unkOutputValue1 & 0x20);
+	state.unk17 = unk1;
+
+	output0x388(((0xA0 + _curTable) << 8) | unk1);
+	output0x388(((0xB0 + _curTable) << 8) | state.unkOutputValue1);
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback42(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	state.unk1 = _unkTableByte1;
+	return 0;
+}
+
+int AdlibDriver::updateCallback43(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	return 0;
+}
+
+int AdlibDriver::updateCallback44(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk11 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback45(uint8 *&dataptr, OutputState &state, uint8 value) {
+	if (value & 0x80) {
+		value += state.unk1;
+		if ((int8)value >= (int8)state.unk1)
+			value = 1;
+	} else {
+		value += state.unk1;
+		if ((int8)value < 0)
+			value = (uint8)-1;
+	}
+	state.unk1 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback46(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint8 entry = *dataptr++;
+	_tablePtr1 = _unkTable2[entry++];
+	_tablePtr2 = _unkTable2[entry];
+	if (value == 2) {
+		output0x388(0xA000 | _tablePtr2[0]);
+	}
+	return 0;
+}
+
+int AdlibDriver::updateCallback47(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	return 0;
+}
+
+int AdlibDriver::updateCallback48(uint8 *&dataptr, OutputState &state, uint8 value) {
+	int tableBackUp = _curTable;
+	int outputByteBackUp = _unkOutputByte1;
+
+	uint8 entry = value * 2;
+
+	uint8 *ptr = _soundData;
+	_curTable = 6;
+	_unkOutputByte1 = _outputTable[6];
+
+	ptr += READ_LE_UINT16(_soundData + entry + 0x1F4);
+
+	_unkValue6 = *(ptr + 6);
+	updateAndOutput2(_unkOutputByte1, ptr, state);
+
+	entry = *ptr++ * 2;
+
+	ptr = _soundData;
+	_curTable = 7;
+	_unkOutputByte1 = _outputTable[7];
+
+	_unkValue7 = entry = *(ptr + 5);
+	_unkValue8 = entry = *(ptr + 6);
+	updateAndOutput2(_unkOutputByte1, ptr, state);
+
+	entry = *ptr++ * 2;
+
+	ptr = _soundData;
+	_curTable = 8;
+	_unkOutputByte1 = _outputTable[8];
+
+	_unkValue9 = entry = *(ptr + 5);
+	_unkValue10 = entry = *(ptr + 6);
+	updateAndOutput2(_unkOutputByte1, ptr, state);
+
+	_outputTables[6].unkOutputValue1 = *ptr++ & 0x2F;
+	output0x388(0xB600 | _outputTables[6].unkOutputValue1);
+	output0x388(0xA600 | *ptr++);
+
+	_outputTables[7].unkOutputValue1 = *ptr++ & 0x2F;
+	output0x388(0xB700 | _outputTables[7].unkOutputValue1);
+	output0x388(0xA700 | *ptr++);
+
+	_outputTables[8].unkOutputValue1 = *ptr++ & 0x2F;
+	output0x388(0xB800 | _outputTables[8].unkOutputValue1);
+	output0x388(0xA800 | *ptr++);
+
+	_unk4 = 0x20;
+
+	_unkOutputByte1 = outputByteBackUp;
+	_curTable = tableBackUp;
+	return 0;
+}
+
+int AdlibDriver::updateCallback49(uint8 *&dataptr, OutputState &state, uint8 value) {
+	OPLWrite(_adlib, 0x388, (value << 8) | 0xBD);
+	waitLoops(4);
+
+	OPLWrite(_adlib, 0x389, 0xBD00 | (((value & 0x1F) ^ 0xFF) & _unk4) | 0x20);
+	waitLoops(23);
+
+	value |= _unk4;
+	_unk4 = value;
+
+	value |= _unkOutputByte2;
+	value |= 0x20;
+	OPLWrite(_adlib, 0x389, 0xBD00 | value);
+	waitLoops(23);
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback50(uint8 *&dataptr, OutputState &state, uint8 value) {
+	--dataptr;
+	_unk4 = 0;
+	output0x388(0xBD00 | (value & _unkOutputByte2));
+	return 0;
+}
+
+int AdlibDriver::updateCallback51(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint16 temp = (value << 8) | *dataptr++;
+
+	if (value & 1) {
+		uint8 val = temp & 0xFF;
+		_unkValue12 = val;
+		val += _unkValue7;
+		val += _unkValue11;
+		val += _unkValue12;
+		output0x388(0x5100 | checkValue(val));
+	}
+
+	if (value & 2) {
+		uint8 val = temp & 0xFF;
+		_unkValue14 = val;
+		val += _unkValue10;
+		val += _unkValue13;
+		val += _unkValue14;
+		output0x388(0x5500 | checkValue(val));
+	}
+
+	if (value & 4) {
+		uint8 val = temp & 0xFF;
+		_unkValue15 = val;
+		val += _unkValue9;
+		val += _unkValue16;
+		val += _unkValue15;
+		output0x388(0x5200 | checkValue(val));
+	}
+
+	if (value & 8) {
+		uint8 val = temp & 0xFF;
+		_unkValue18 = val;
+		val += _unkValue8;
+		val += _unkValue17;
+		val += _unkValue18;
+		output0x388(0x5400 | checkValue(val));
+	}
+
+	if (value & 16) {
+		uint8 val = temp & 0xFF;
+		_unkValue20 = val;
+		val += _unkValue6;
+		val += _unkValue19;
+		val += _unkValue20;
+		output0x388(0x5300 | checkValue(val));
+	}
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback52(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint16 temp = (value << 8) | *dataptr++;
+
+	if (value & 1) {
+		uint8 val = temp & 0xFF;
+		val += _unkValue7;
+		val += _unkValue11;
+		val += _unkValue12;
+		output0x388(0x5100 | checkValue(val));
+	}
+
+	if (value & 2) {
+		uint8 val = temp & 0xFF;
+		val += _unkValue10;
+		val += _unkValue13;
+		val += _unkValue14;
+		output0x388(0x5500 | checkValue(val));
+	}
+
+	if (value & 4) {
+		uint8 val = temp & 0xFF;
+		val += _unkValue9;
+		val += _unkValue16;
+		val += _unkValue15;
+		output0x388(0x5200 | checkValue(val));
+	}
+
+	if (value & 8) {
+		uint8 val = temp & 0xFF;
+		val += _unkValue8;
+		val += _unkValue17;
+		val += _unkValue18;
+		output0x388(0x5400 | checkValue(val));
+	}
+
+	if (value & 16) {
+		uint8 val = temp & 0xFF;
+		val += _unkValue6;
+		val += _unkValue19;
+		val += _unkValue20;
+		output0x388(0x5300 | checkValue(val));
+	}
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback53(uint8 *&dataptr, OutputState &state, uint8 value) {
+	uint16 temp = (value << 8) | *dataptr++;
+
+	if (value & 1) {
+		uint8 val = temp & 0xFF;
+		_unkValue11 = val;
+		val += _unkValue7;
+		val += _unkValue12;
+		output0x388(0x5100 | checkValue(val));
+	}
+
+	if (value & 2) {
+		uint8 val = temp & 0xFF;
+		_unkValue13 = val;
+		val += _unkValue10;
+		val += _unkValue14;
+		output0x388(0x5500 | checkValue(val));
+	}
+
+	if (value & 4) {
+		uint8 val = temp & 0xFF;
+		_unkValue16 = val;
+		val += _unkValue9;
+		val += _unkValue15;
+		output0x388(0x5200 | checkValue(val));
+	}
+
+	if (value & 8) {
+		uint8 val = temp & 0xFF;
+		_unkValue17 = val;
+		val += _unkValue8;
+		val += _unkValue18;
+		output0x388(0x5400 | checkValue(val));
+	}
+
+	if (value & 16) {
+		uint8 val = temp & 0xFF;
+		_unkValue19 = val;
+		val += _unkValue6;
+		val += _unkValue20;
+		output0x388(0x5300 | checkValue(val));
+	}
+
+	return 0;
+}
+
+int AdlibDriver::updateCallback54(uint8 *&dataptr, OutputState &state, uint8 value) {
+	_unk5 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback55(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk6 = value;
+	return 0;
+}
+
+int AdlibDriver::updateCallback56(uint8 *&dataptr, OutputState &state, uint8 value) {
+	state.unk39 = value;
+	state.unk40 = *dataptr++;
+	return 0;
+}
+
+// static res
+
+#define COMMAND(x) { &AdlibDriver::x, #x }
+const AdlibDriver::OpcodeEntry AdlibDriver::_opcodeList[] = {
+	COMMAND(snd_ret0x100),
+	COMMAND(snd_ret0x1983),
+	COMMAND(snd_initDriver),
+	COMMAND(snd_deinitDriver),
+	COMMAND(snd_setSoundData),
+	COMMAND(snd_unkOpcode1),
+	COMMAND(snd_startSong),
+	COMMAND(snd_unkOpcode2),
+	COMMAND(snd_unkOpcode3),
+	COMMAND(snd_readByte),
+	COMMAND(snd_writeByte),
+	COMMAND(snd_setUnk5),
+	COMMAND(snd_unkOpcode4),
+	COMMAND(snd_dummy),
+	COMMAND(snd_getNullvar4),
+	COMMAND(snd_setNullvar3),
+	COMMAND(snd_setFlag),
+	COMMAND(snd_clearFlag)
+};
+
+const AdlibDriver::ParserOpcode AdlibDriver::_parserOpcodeTable[] = {
+	COMMAND(updateCallback1),
+	COMMAND(updateCallback2),
+	COMMAND(updateCallback3),
+	COMMAND(updateCallback4),
+	COMMAND(updateCallback5),
+	COMMAND(updateCallbackPushDataPtr),
+	COMMAND(updateCallbackPopDataPtr),
+	COMMAND(updateCallback8),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback10),
+	COMMAND(updateCallback11),
+	COMMAND(updateCallback12),
+	COMMAND(updateCallback13),
+	COMMAND(updateCallback14),
+	COMMAND(updateCallback15),
+	COMMAND(updateCallback16),
+	COMMAND(updateCallback17),
+	COMMAND(updateCallback18),
+	COMMAND(updateCallback19),
+	COMMAND(updateCallback20),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback21),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback22),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback23),
+	COMMAND(updateCallback24),
+	COMMAND(updateCallback25),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback26),
+	COMMAND(updateCallback27),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback28),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback29),
+	COMMAND(updateCallback30),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback31),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback32),
+	COMMAND(updateCallback33),
+	COMMAND(updateCallback34),
+	COMMAND(updateCallback35),
+	COMMAND(updateCallback36),
+	COMMAND(updateCallback37),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback38),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback39),
+	COMMAND(updateCallback40),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback41),
+	COMMAND(updateCallback42),
+	COMMAND(updateCallback43),
+	COMMAND(updateCallback44),
+	COMMAND(updateCallback45),
+	COMMAND(updateCallback9),
+	COMMAND(updateCallback46),
+	COMMAND(updateCallback47),
+	COMMAND(updateCallback48),
+	COMMAND(updateCallback49),
+	COMMAND(updateCallback50),
+	COMMAND(updateCallback51),
+	COMMAND(updateCallback52),
+	COMMAND(updateCallback53),
+	COMMAND(updateCallback54),
+	COMMAND(updateCallback55),
+	COMMAND(updateCallback56),
+	COMMAND(updateCallback9)
+};
+#undef COMMAND
+
+const int AdlibDriver::_opcodesEntries = ARRAYSIZE(AdlibDriver::_opcodeList);
+const int AdlibDriver::_parserOpcodeTableSize = ARRAYSIZE(AdlibDriver::_parserOpcodeTable);
+
+const uint8 AdlibDriver::_outputTable[] = {
+	0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11,
+	0x12
+};
+
+const uint16 AdlibDriver::_unkTable[] = {
+	0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9,
+	0x0207, 0x0225, 0x0246
+};
+
+const uint8 *AdlibDriver::_unkTable2[] = {
+	AdlibDriver::_unkTable2_1,
+	AdlibDriver::_unkTable2_2,
+	AdlibDriver::_unkTable2_1,
+	AdlibDriver::_unkTable2_2,
+	AdlibDriver::_unkTable2_3,
+	AdlibDriver::_unkTable2_2
+};
+
+const uint8 AdlibDriver::_unkTable2_1[] = {
+	0x50, 0x50, 0x4F, 0x4F, 0x4E, 0x4E, 0x4D, 0x4D,
+	0x4C, 0x4C, 0x4B, 0x4B, 0x4A, 0x4A, 0x49, 0x49,
+	0x48, 0x48, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45,
+	0x44, 0x44, 0x43, 0x43, 0x42, 0x42, 0x41, 0x41,
+	0x40, 0x40, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D,
+	0x3C, 0x3C, 0x3B, 0x3B, 0x3A, 0x3A, 0x39, 0x39,
+	0x38, 0x38, 0x37, 0x37, 0x36, 0x36, 0x35, 0x35,
+	0x34, 0x34, 0x33, 0x33, 0x32, 0x32, 0x31, 0x31,
+	0x30, 0x30, 0x2F, 0x2F, 0x2E, 0x2E, 0x2D, 0x2D,
+	0x2C, 0x2C, 0x2B, 0x2B, 0x2A, 0x2A, 0x29, 0x29,
+	0x28, 0x28, 0x27, 0x27, 0x26, 0x26, 0x25, 0x25,
+	0x24, 0x24, 0x23, 0x23, 0x22, 0x22, 0x21, 0x21,
+	0x20, 0x20, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D,
+	0x1C, 0x1C, 0x1B, 0x1B, 0x1A, 0x1A, 0x19, 0x19,
+	0x18, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15,
+	0x14, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
+	0x10, 0x10
+};
+
+// no don't ask me WHY this table exsits!
+const uint8 AdlibDriver::_unkTable2_2[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x6F,
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
+};
+
+const uint8 AdlibDriver::_unkTable2_3[] = {
+	0x40, 0x40, 0x40, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E,
+	0x3E, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B,
+	0x3B, 0x3B, 0x3A, 0x3A, 0x3A, 0x39, 0x39, 0x39,
+	0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x36, 0x36,
+	0x36, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x33,
+	0x33, 0x33, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31,
+	0x30, 0x30, 0x30, 0x2F, 0x2F, 0x2F, 0x2E, 0x2E,
+	0x2E, 0x2D, 0x2D, 0x2D, 0x2C, 0x2C, 0x2C, 0x2B,
+	0x2B, 0x2B, 0x2A, 0x2A, 0x2A, 0x29, 0x29, 0x29,
+	0x28, 0x28, 0x28, 0x27, 0x27, 0x27, 0x26, 0x26,
+	0x26, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x23,
+	0x23, 0x23, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21,
+	0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E,
+	0x1E, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B,
+	0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19,
+	0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x16, 0x16,
+	0x16, 0x15
+};
+
+// TODO: format this
+const uint8 AdlibDriver::_unkTables[][32] = {
+	{    0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x08,
+	     0x09,  0x0A,  0x0B,  0x0C,  0x0D,  0x0E,  0x0F,  0x10,
+	     0x11,  0x12,  0x13,  0x14,  0x15,  0x16,  0x17,  0x19,
+	     0x1A,  0x1B,  0x1C,  0x1D,  0x1E,  0x1F,  0x20,  0x21 },
+	{    0x00,  0x01,  0x02,  0x03,  0x04,  0x06,  0x07,  0x09,
+	     0x0A,  0x0B,  0x0C,  0x0D,  0x0E,  0x0F,  0x10,  0x11,
+	     0x12,  0x13,  0x14,  0x15,  0x16,  0x17,  0x18,  0x1A,
+	     0x1B,  0x1C,  0x1D,  0x1E,  0x1F,  0x20,  0x22,  0x24 },
+	{    0x00,  0x01,  0x02,  0x03,  0x04,  0x06,  0x08,  0x09,
+	     0x0A,  0x0C,  0x0D,  0x0E,  0x0F,  0x11,  0x12,  0x13,
+	     0x14,  0x15,  0x16,  0x17,  0x19,  0x1A,  0x1C,  0x1D,
+	     0x1E,  0x1F,  0x20,  0x21,  0x22,  0x24,  0x25,  0x26 },
+	{    0x00,  0x01,  0x02,  0x03,  0x04,  0x06,  0x08,  0x0A,
+	     0x0B,  0x0C,  0x0D,  0x0E,  0x0F,  0x11,  0x12,  0x13,
+	     0x14,  0x15,  0x16,  0x17,  0x18,  0x1A,  0x1C,  0x1D,
+	     0x1E,  0x1F,  0x20,  0x21,  0x23,  0x25,  0x27,  0x28 },
+	{    0x00,  0x01,  0x02,  0x03,  0x04,  0x06,  0x08,  0x0A,
+	     0x0B,  0x0C,  0x0D,  0x0E,  0x0F,  0x11,  0x13,  0x15,
+	     0x16,  0x17,  0x18,  0x19,  0x1B,  0x1D,  0x1F,  0x20,
+	     0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x28,  0x2A },
+	{    0x00,  0x01,  0x02,  0x03,  0x05,  0x07,  0x09,  0x0B,
+	     0x0C,  0x0D,  0x0E,  0x0F,  0x10,  0x11,  0x13,  0x15,
+	     0x16,  0x17,  0x18,  0x19,  0x1B,  0x1D,  0x1F,  0x20,
+	     0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x28,  0x2A },
+	{    0x00,  0x01,  0x02,  0x03,  0x05,  0x07,  0x09,  0x0B,
+	     0x0C,  0x0D,  0x0E,  0x0F,  0x10,  0x11,  0x13,  0x15,
+	     0x16,  0x17,  0x18,  0x19,  0x1B,  0x1D,  0x1F,  0x20,
+	     0x21,  0x22,  0x23,  0x25,  0x27,  0x29,  0x2B,  0x2D },
+	{    0x00,  0x01,  0x02,  0x03,  0x05,  0x07,  0x09,  0x0B,
+	     0x0C,  0x0D,  0x0E,  0x0F,  0x10,  0x11,  0x13,  0x15,
+	     0x16,  0x17,  0x18,  0x1A,  0x1C,  0x1E,  0x21,  0x24,
+	     0x25,  0x26,  0x27,  0x29,  0x2B,  0x2D,  0x2F,  0x30 },
+	{    0x00,  0x01,  0x02,  0x04,  0x06,  0x08,  0x0A,  0x0C,
+	     0x0D,  0x0E,  0x0F,  0x10,  0x11,  0x13,  0x15,  0x18,
+	     0x19,  0x1A,  0x1C,  0x1D,  0x1F,  0x21,  0x23,  0x25,
+	     0x26,  0x27,  0x29,  0x2B,  0x2D,  0x2F,  0x30,  0x32 },
+	{    0x00,  0x01,  0x02,  0x04,  0x06,  0x08,  0x0A,  0x0D,
+	     0x0E,  0x0F,  0x10,  0x11,  0x12,  0x14,  0x17,  0x1A,
+	     0x19,  0x1A,  0x1C,  0x1E,  0x20,  0x22,  0x25,  0x28,
+	     0x29,  0x2A,  0x2B,  0x2D,  0x2F,  0x31,  0x33,  0x35 },
+	{    0x00,  0x01,  0x03,  0x05,  0x07,  0x09,  0x0B,  0x0E,
+	     0x0F,  0x10,  0x12,  0x14,  0x16,  0x18,  0x1A,  0x1B,
+	     0x1C,  0x1D,  0x1E,  0x20,  0x22,  0x24,  0x26,  0x29,
+	     0x2A,  0x2C,  0x2E,  0x30,  0x32,  0x34,  0x36,  0x39 },
+	{    0x00,  0x01,  0x03,  0x05,  0x07,  0x09,  0x0B,  0x0E,
+	     0x0F,  0x10,  0x12,  0x14,  0x16,  0x19,  0x1B,  0x1E,
+	     0x1F,  0x21,  0x23,  0x25,  0x27,  0x29,  0x2B,  0x2D,
+	     0x2E,  0x2F,  0x31,  0x32,  0x34,  0x36,  0x39,  0x3C },
+	{    0x00,  0x01,  0x03,  0x05,  0x07,  0x0A,  0x0C,  0x0F,
+	     0x10,  0x11,  0x13,  0x15,  0x17,  0x19,  0x1B,  0x1E,
+	     0x1F,  0x20,  0x22,  0x24,  0x26,  0x28,  0x2B,  0x2E,
+	     0x2F,  0x30,  0x32,  0x34,  0x36,  0x39,  0x3C,  0x3F },
+	{    0x00,  0x02,  0x04,  0x06,  0x08,  0x0B,  0x0D,  0x10,
+	     0x11,  0x12,  0x14,  0x16,  0x18,  0x1B,  0x1E,  0x21,
+	     0x22,  0x23,  0x25,  0x27,  0x29,  0x2C,  0x2F,  0x32,
+	     0x33,  0x34,  0x36,  0x38,  0x3B,  0x34,  0x41,  0x44 },
+	{    0x00,  0x02,  0x04,  0x06,  0x08,  0x0B,  0x0D,  0x11,
+	     0x12,  0x13,  0x15,  0x17,  0x1A,  0x1D,  0x20,  0x23,
+	     0x24,  0x25,  0x27,  0x29,  0x2C,  0x2F,  0x32,  0x35,
+	     0x36,  0x37,  0x39,  0x3B,  0x3E,  0x41,  0x44,  0x47 }
+};
+
+#pragma mark -
+
+SoundAdlibPC::SoundAdlibPC(Audio::Mixer *mixer, KyraEngine *engine)
+	: Sound(engine, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
+	memset(_trackEntries, 0, sizeof(_trackEntries));
+	_driver = new AdlibDriver(mixer);
+	assert(_driver);
+
+	_sfxPlayingSound = -1;
+	_soundFileLoaded = "";
+}
+
+SoundAdlibPC::~SoundAdlibPC() {
+	delete [] _soundDataPtr;
+	delete _driver;
+}
+
+bool SoundAdlibPC::init() {
+	_driver->callback(2);
+	_driver->callback(16, int(4));
+	return true;
+}
+
+void SoundAdlibPC::setVolume(int volume) {
+}
+
+int SoundAdlibPC::getVolume() {
+	return 0;
+}
+
+void SoundAdlibPC::playMusic(const char *file) {
+	loadSoundFile(file);
+}
+
+void SoundAdlibPC::stopMusic() {
+	playSoundEffect(0);
+}
+
+void SoundAdlibPC::playTrack(uint8 track, bool looping) {
+	// snd_stopSound();
+	// snd_unk1();
+	playSoundEffect(track);
+}
+
+void SoundAdlibPC::haltTrack() {
+}
+
+void SoundAdlibPC::startTrack() {
+}
+
+void SoundAdlibPC::loadSoundEffectFile(const char *file) {
+	loadSoundFile(file);
+}
+
+void SoundAdlibPC::stopSoundEffect() {
+}
+
+void SoundAdlibPC::playSoundEffect(uint8 track) {
+	uint8 soundId = _trackEntries[track];
+	if ((int8)soundId == -1 || !_soundDataPtr)
+		return;
+	soundId &= 0xFF;
+	while ((_driver->callback(16, 0) & 8)) {
+		_engine->delay(10);
+	}
+	if (_sfxPlayingSound != -1) {
+		_driver->callback(10, _sfxPlayingSound, int(1), int(_sfxSecondByteOfSong));
+		_driver->callback(10, _sfxPlayingSound, int(3), int(_sfxFourthByteOfSong));
+		_sfxPlayingSound = -1;
+	}
+
+	int firstByteOfSong = _driver->callback(9, soundId, int(0));
+
+	if (firstByteOfSong != 9) {
+		_sfxPlayingSound = soundId;
+		_sfxSecondByteOfSong = _driver->callback(9, soundId, int(1));
+		_sfxFourthByteOfSong = _driver->callback(9, soundId, int(3));
+
+		int newVal = ((((-_sfxFourthByteOfSong) + 63) * 0xFF) >> 8) & 0xFF;
+		newVal = -newVal + 63;
+		_driver->callback(10, soundId, int(3), newVal);
+		newVal = ((_sfxSecondByteOfSong * 0xFF) >> 8) & 0xFF;
+		_driver->callback(10, soundId, int(1), newVal);
+	}
+
+	_driver->callback(6, soundId);
+}
+
+void SoundAdlibPC::beginFadeOut() {
+}
+
+bool SoundAdlibPC::fadeOut() {
+	return false;
+}
+
+void SoundAdlibPC::loadSoundFile(const char *file) {
+	if (_soundFileLoaded == file)
+		return;
+
+	uint8 *file_data = 0; uint32 file_size = 0;
+
+	char filename[25];
+	sprintf(filename, "%s.ADL", file);
+
+	file_data = _engine->resource()->fileData(filename, &file_size);
+	if (!file_data) {
+		warning("Couldn't find music file: '%s'", filename);
+		return;
+	}
+
+	// snd_stopSound();
+	// snd_unk1();
+
+	_driver->callback(8, int(-1));
+	_soundDataPtr = 0;
+
+	uint8 *p = file_data;
+	memcpy(_trackEntries, p, 120*sizeof(uint8));
+	p += 120;
+
+	int soundDataSize = file_size - 120;
+
+	_soundDataPtr = new uint8[soundDataSize];
+	assert(_soundDataPtr);
+
+	memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8));
+
+	delete [] file_data;
+	file_data = p = 0;
+	file_size = 0;
+
+	_driver->callback(4, _soundDataPtr);
+
+	_soundFileLoaded = file;
+}
+
+} // end of namespace Kyra
+


Property changes on: scummvm/trunk/engines/kyra/sound_adlib.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-
   + 
Name: svn:eol-style
   + native

Modified: scummvm/trunk/engines/kyra/staticres.cpp
===================================================================
--- scummvm/trunk/engines/kyra/staticres.cpp	2006-02-27 22:15:21 UTC (rev 20959)
+++ scummvm/trunk/engines/kyra/staticres.cpp	2006-02-27 22:39:55 UTC (rev 20960)
@@ -814,20 +814,20 @@
 
 const int KyraEngine::_opcodeTableSize = ARRAYSIZE(_opcodeTable);
 
-const char *KyraEngine::_xmidiFiles[] = {
-	"INTRO.XMI",
-	"KYRA1A.XMI",
-	"KYRA1B.XMI",
-	"KYRA2A.XMI",
-	"KYRA3A.XMI",
-	"KYRA4A.XMI",
-	"KYRA4B.XMI",
-	"KYRA5A.XMI",
-	"KYRA5B.XMI",
-	"KYRAMISC.XMI"
+const char *KyraEngine::_musicFiles[] = {
+	"INTRO",
+	"KYRA1A",
+	"KYRA1B",
+	"KYRA2A",
+	"KYRA3A",
+	"KYRA4A",
+	"KYRA4B",
+	"KYRA5A",
+	"KYRA5B",
+	"KYRAMISC"
 };
 
-const int KyraEngine::_xmidiFilesCount = ARRAYSIZE(_xmidiFiles);
+const int KyraEngine::_musicFilesCount = ARRAYSIZE(_musicFiles);
 
 const int8 KyraEngine::_charXPosTable[] = {
 	 0,  4,  4,  4,  0, -4, -4, -4







More information about the Scummvm-git-logs mailing list