changeset 1280:6ad7eb96dd26 trunk

[svn] Sync with upstream. This adds Westwood ADL format support.
author chainsaw
date Sat, 17 Jun 2006 16:17:51 -0700
parents 01d2aa561b53
children 02c2480ca1d5
files ChangeLog Plugins/Input/adplug/core/Makefile.in Plugins/Input/adplug/core/adl.cpp Plugins/Input/adplug/core/adl.h Plugins/Input/adplug/core/adplug.cpp Plugins/Input/adplug/core/amd.cpp Plugins/Input/adplug/core/bmf.cpp Plugins/Input/adplug/core/d00.cpp Plugins/Input/adplug/core/d00.h Plugins/Input/adplug/core/ksm.cpp Plugins/Input/adplug/core/msc.cpp Plugins/Input/adplug/core/protrack.cpp Plugins/Input/adplug/core/rix.cpp Plugins/Input/adplug/core/rix.h Plugins/Input/adplug/core/u6m.cpp Plugins/Input/adplug/core/u6m.h
diffstat 16 files changed, 3072 insertions(+), 572 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Jun 16 20:55:52 2006 -0700
+++ b/ChangeLog	Sat Jun 17 16:17:51 2006 -0700
@@ -1,3 +1,14 @@
+2006-06-17 03:55:52 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [1472]
+  - libaac: use unified fileinfo requester, since functionality is adequate (cannot save data, only read it at present)
+  
+
+  Changes:        Modified:
+  +1 -1           trunk/Plugins/Input/aac/src/Makefile.in  
+  +0 -449         trunk/Plugins/Input/aac/src/fileinfo.c  
+  +1 -1           trunk/Plugins/Input/aac/src/libmp4.c  
+
+
 2006-06-16 13:13:21 +0000  Yoshiki Yazawa <yaz@cc.rim.or.jp>
   revision [1470]
   - fix for alsa_mutex deadlock
--- a/Plugins/Input/adplug/core/Makefile.in	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/Makefile.in	Sat Jun 17 16:17:51 2006 -0700
@@ -8,14 +8,15 @@
 a2m.cpp adtrack.cpp amd.cpp bam.cpp d00.cpp dfm.cpp dmo.cpp hsp.cpp ksm.cpp \
 mad.cpp mid.cpp mkj.cpp cff.cpp dtm.cpp fmc.cpp mtk.cpp rad.cpp raw.cpp \
 sa2.cpp s3m.cpp xad.cpp flash.cpp bmf.cpp hybrid.cpp hyp.cpp psi.cpp rat.cpp \
-u6m.cpp rol.cpp xsm.cpp adlibemu.c dro.cpp lds.cpp temuopl.cpp msc.cpp rix.cpp
+u6m.cpp rol.cpp xsm.cpp adlibemu.c dro.cpp lds.cpp temuopl.cpp msc.cpp rix.cpp \
+adl.cpp
 
 noinst_HEADERS = adplug.h emuopl.h fmopl.h silentopl.h opl.h diskopl.h \
 a2m.h amd.h bam.h d00.h dfm.h hsc.h hsp.h imf.h ksm.h lds.h mid.h mkj.h mtk.h \
 protrack.h rad.h raw.h sa2.h sng.h u6m.h player.h fmc.h mad.h xad.h bmf.h \
 flash.h hyp.h psi.h rat.h hybrid.h rol.h adtrack.h cff.h dtm.h fprovide.h \
 database.h players.h xsm.h adlibemu.h kemuopl.h dro.h dmo.h s3m.h temuopl.h \
-msc.h rix.h
+msc.h rix.h adl.h
 
 CXXFLAGS += -fPIC -DPIC $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp
 CFLAGS += -fPIC -DPIC $(BINIO_CFLAGS) -I../../../../intl -I../../../.. -Dstricmp=strcasecmp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/adplug/core/adl.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -0,0 +1,2422 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * adl.cpp - ADL player adaption by Simon Peter <dn.tlp@gmx.net>
+ *
+ * Original ADL player by Torbjorn Andersson and Johannes Schickel
+ * 'lordhoto' <lordhoto at scummvm dot org> of the ScummVM project.
+ */
+
+/* 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.
+ */
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "adl.h"
+#include "debug.h"
+
+#ifdef ADL_DEBUG
+#	define warning(...)		AdPlug_LogWrite(__VA_ARGS__); \
+AdPlug_LogWrite("\n")
+
+#	define debugC(i1, i2, ...)	AdPlug_LogWrite(__VA_ARGS__); \
+AdPlug_LogWrite("\n")
+#else
+#	define kDebugLevelSound	1
+
+static inline void warning(const char *str, ...)
+{
+}
+
+static inline void debugC(int i1, int i2, const char *str, ...)
+{
+}
+#endif
+
+// #define warning(...)
+// #define debugC(i1, i2, ...)
+
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
+
+// Basic Adlib Programming:
+// http://www.gamedev.net/reference/articles/article446.asp
+
+#define CALLBACKS_PER_SECOND 72
+
+typedef uint8_t	uint8;
+typedef int8_t	int8;
+typedef uint16_t	uint16;
+typedef int16_t	int16;
+typedef uint32_t	uint32;
+typedef int32_t	int32;
+typedef uint8_t	byte;
+
+static inline uint16 READ_LE_UINT16(const void *ptr) {
+  const byte *b = (const byte *)ptr;
+  return (b[1] << 8) + b[0];
+}
+
+static inline uint16 READ_BE_UINT16(const void *ptr) {
+  const byte *b = (const byte *)ptr;
+  return (b[0] << 8) + b[1];
+}
+
+class AdlibDriver {
+public:
+  AdlibDriver(Copl *opl);
+  ~AdlibDriver();
+
+  int callback(int opcode, ...);
+  void callback();
+
+  // AudioStream API
+  // 	int readBuffer(int16 *buffer, const int numSamples) {
+  // 		int32 samplesLeft = numSamples;
+  // 		memset(buffer, 0, sizeof(int16) * numSamples);
+  // 		while (samplesLeft) {
+  // 			if (!_samplesTillCallback) {
+  // 				callback();
+  // 				_samplesTillCallback = _samplesPerCallback;
+  // 				_samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
+  // 				if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) {
+  // 					_samplesTillCallback++;
+  // 					_samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND;
+  // 				}
+  // 			}
+
+  // 			int32 render = MIN(samplesLeft, _samplesTillCallback);
+  // 			samplesLeft -= render;
+  // 			_samplesTillCallback -= render;
+  // 			YM3812UpdateOne(_adlib, buffer, render);
+  // 			buffer += render;
+  // 		}
+  // 		return numSamples;
+  // 	}
+
+  bool isStereo() const { return false; }
+  bool endOfData() const { return false; }
+  // 	int getRate() const { return _mixer->getOutputRate(); }
+
+  struct OpcodeEntry {
+    typedef int (AdlibDriver::*DriverOpcode)(va_list &list);
+    DriverOpcode function;
+    const char *name;
+  };
+
+  void setupOpcodeList();
+  const OpcodeEntry *_opcodeList;
+  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_getSoundTrigger(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);
+
+  // These variables have not yet been named, but some of them are partly
+  // known nevertheless:
+  //
+  // unk16 - Sound-related. Possibly some sort of pitch bend.
+  // unk18 - Sound-effect. Used for secondaryEffect1()
+  // unk19 - Sound-effect. Used for secondaryEffect1()
+  // unk20 - Sound-effect. Used for secondaryEffect1()
+  // unk21 - Sound-effect. Used for secondaryEffect1()
+  // unk22 - Sound-effect. Used for secondaryEffect1()
+  // unk29 - Sound-effect. Used for primaryEffect1()
+  // unk30 - Sound-effect. Used for primaryEffect1()
+  // unk31 - Sound-effect. Used for primaryEffect1()
+  // unk32 - Sound-effect. Used for primaryEffect2()
+  // unk33 - Sound-effect. Used for primaryEffect2()
+  // unk34 - Sound-effect. Used for primaryEffect2()
+  // unk35 - Sound-effect. Used for primaryEffect2()
+  // unk36 - Sound-effect. Used for primaryEffect2()
+  // unk37 - Sound-effect. Used for primaryEffect2()
+  // unk38 - Sound-effect. Used for primaryEffect2()
+  // unk39 - Currently unused, except for updateCallback56()
+  // unk40 - Currently unused, except for updateCallback56()
+  // unk41 - Sound-effect. Used for primaryEffect2()
+
+  struct Channel {
+    uint8 opExtraLevel2;
+    uint8 *dataptr;
+    uint8 duration;
+    uint8 repeatCounter;
+    int8 baseOctave;
+    uint8 priority;
+    uint8 dataptrStackPos;
+    uint8 *dataptrStack[4];
+    int8 baseNote;
+    uint8 unk29;
+    uint8 unk31;
+    uint16 unk30;
+    uint16 unk37;
+    uint8 unk33;
+    uint8 unk34;
+    uint8 unk35;
+    uint8 unk36;
+    uint8 unk32;
+    uint8 unk41;
+    uint8 unk38;
+    uint8 opExtraLevel1;
+    uint8 spacing2;
+    uint8 baseFreq;
+    uint8 tempo;
+    uint8 position;
+    uint8 regAx;
+    uint8 regBx;
+    typedef void (AdlibDriver::*Callback)(Channel&);
+    Callback primaryEffect;
+    Callback secondaryEffect;
+    uint8 fractionalSpacing;
+    uint8 opLevel1;
+    uint8 opLevel2;
+    uint8 opExtraLevel3;
+    uint8 twoChan;
+    uint8 unk39;	
+    uint8 unk40;
+    uint8 spacing1;
+    uint8 durationRandomness;
+    uint8 unk19;
+    uint8 unk18;
+    int8 unk20;
+    int8 unk21;
+    uint8 unk22;
+    uint16 offset;
+    uint8 tempoReset;
+    uint8 rawNote;
+    int8 unk16;
+  };
+
+  void primaryEffect1(Channel &channel);
+  void primaryEffect2(Channel &channel);
+  void secondaryEffect1(Channel &channel);
+
+  void resetAdlibState();
+  void writeOPL(byte reg, byte val);
+  void initChannel(Channel &channel);
+  void noteOff(Channel &channel);
+  void unkOutput2(uint8 num);
+
+  uint16 getRandomNr();
+  void setupDuration(uint8 duration, Channel &channel);
+
+  void setupNote(uint8 rawNote, Channel &channel, bool flag = false);
+  void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel);
+  void noteOn(Channel &channel);
+
+  void adjustVolume(Channel &channel);
+
+  uint8 calculateOpLevel1(Channel &channel);
+  uint8 calculateOpLevel2(Channel &channel);
+
+  uint16 checkValue(int16 val) {
+    if (val < 0)
+      val = 0;
+    else if (val > 0x3F)
+      val = 0x3F;
+    return val;
+  }
+
+  // The sound data has at least two lookup tables:
+  //
+  // * One for programs, starting at offset 0.
+  // * One for instruments, starting at offset 500.
+
+  uint8 *getProgram(int progId) {
+    return _soundData + READ_LE_UINT16(_soundData + 2 * progId);
+  }
+
+  uint8 *getInstrument(int instrumentId) {
+    return _soundData + READ_LE_UINT16(_soundData + 500 + 2 * instrumentId);
+  }
+
+  void setupPrograms();
+  void executePrograms();
+
+  struct ParserOpcode {
+    typedef int (AdlibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value);
+    POpcode function;
+    const char *name;
+  };
+
+  void setupParserOpcodeTable();
+  const ParserOpcode *_parserOpcodeTable;
+  int _parserOpcodeTableSize;
+
+  int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_jump(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_nop1(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_nop2(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value);
+  int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value);
+  int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value);
+
+  // These variables have not yet been named, but some of them are partly
+  // known nevertheless:
+  //
+  // _unkValue1      - Unknown. Used for updating _unkValue2
+  // _unkValue2      - Unknown. Used for updating _unkValue4
+  // _unkValue3      - Unknown. Used for updating _unkValue2
+  // _unkValue4      - Unknown. Used for updating _unkValue5
+  // _unkValue5      - Unknown. Used for controlling updateCallback24().
+  // _unkValue6      - Unknown. Rhythm section volume?
+  // _unkValue7      - Unknown. Rhythm section volume?
+  // _unkValue8      - Unknown. Rhythm section volume?
+  // _unkValue9      - Unknown. Rhythm section volume?
+  // _unkValue10     - Unknown. Rhythm section volume?
+  // _unkValue11     - Unknown. Rhythm section volume?
+  // _unkValue12     - Unknown. Rhythm section volume?
+  // _unkValue13     - Unknown. Rhythm section volume?
+  // _unkValue14     - Unknown. Rhythm section volume?
+  // _unkValue15     - Unknown. Rhythm section volume?
+  // _unkValue16     - Unknown. Rhythm section volume?
+  // _unkValue17     - Unknown. Rhythm section volume?
+  // _unkValue18     - Unknown. Rhythm section volume?
+  // _unkValue19     - Unknown. Rhythm section volume?
+  // _unkValue20     - Unknown. Rhythm section volume?
+  // _unkTable[]     - Probably frequences for the 12-tone scale.
+  // _unkTable2[]    - Unknown. Currently only used by updateCallback46()
+  // _unkTable2_1[]  - One of the tables in _unkTable2[]
+  // _unkTable2_2[]  - One of the tables in _unkTable2[]
+  // _unkTable2_3[]  - One of the tables in _unkTable2[]
+
+  int32 _samplesPerCallback;
+  int32 _samplesPerCallbackRemainder;
+  int32 _samplesTillCallback;
+  int32 _samplesTillCallbackRemainder;
+
+  int _lastProcessed;
+  int8 _flagTrigger;
+  int _curChannel;
+  uint8 _soundTrigger;
+  int _soundsPlaying;
+
+  uint16 _rnd;
+
+  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;
+
+  uint8 *_soundData;
+
+  uint8 _soundIdTable[0x10];
+  Channel _channels[10];
+
+  uint8 _vibratoAndAMDepthBits;
+  uint8 _rhythmSectionBits;
+
+  uint8 _curRegOffset;
+  uint8 _tempo;
+
+  const uint8 *_tablePtr1;
+  const uint8 *_tablePtr2;
+
+  static const uint8 _regOffset[];
+  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];
+
+  Copl *opl;
+};
+
+AdlibDriver::AdlibDriver(Copl *newopl)
+  : opl(newopl)
+{
+  setupOpcodeList();
+  setupParserOpcodeTable();
+
+  // 	_mixer = mixer;
+
+  _flags = 0;
+  // 	_adlib = makeAdlibOPL(getRate());
+  // 	assert(_adlib);
+
+  memset(_channels, 0, sizeof(_channels));
+  _soundData = 0;
+
+  _vibratoAndAMDepthBits = _curRegOffset = 0;
+
+  _lastProcessed = _flagTrigger = _curChannel = _rhythmSectionBits = 0;
+  _soundsPlaying = 0;
+  _rnd = 0x1234;
+
+  _tempo = 0;
+  _soundTrigger = 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);
+
+  // 	_samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
+  // 	_samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
+  _samplesTillCallback = 0;
+  _samplesTillCallbackRemainder = 0;
+}
+
+AdlibDriver::~AdlibDriver() {
+  // 	_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;
+  _flagTrigger = 1;
+
+  uint8 *ptr = getProgram(songId);
+  uint8 chan = *ptr;
+
+  if ((songId << 1) != 0) {
+    if (chan == 9) {
+      if (_flags & 2)
+	return 0;
+    } else {
+      if (_flags & 1)
+	return 0;
+    }
+  }
+
+  _soundIdTable[_soundsPlaying++] = songId;
+  _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--) {
+    _curChannel = value;
+    Channel &channel = _channels[_curChannel];
+    channel.priority = 0;
+    channel.dataptr = 0;
+    if (value != 9) {
+      noteOff(channel);
+    }
+    ++value;
+  }
+
+  return 0;
+}
+
+int AdlibDriver::snd_readByte(va_list &list) {
+  int a = va_arg(list, int);
+  int b = va_arg(list, int);
+  uint8 *ptr = getProgram(a) + b;
+  return *ptr;
+}
+
+int AdlibDriver::snd_writeByte(va_list &list) {
+  int a = va_arg(list, int);
+  int b = va_arg(list, int);
+  int c = va_arg(list, int);
+  uint8 *ptr = getProgram(a) + b;
+  uint8 oldValue = *ptr;
+  *ptr = (uint8)c;
+  return oldValue;
+}
+
+int AdlibDriver::snd_getSoundTrigger(va_list &list) {
+  return _soundTrigger;
+}
+
+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 (_flagTrigger < 0)
+    _flags &= ~8;
+  setupPrograms();
+  executePrograms();
+
+  uint8 temp = _unkValue3;
+  _unkValue3 += _tempo;
+  if (_unkValue3 < temp) {
+    if (!(--_unkValue2)) {
+      _unkValue2 = _unkValue1;
+      ++_unkValue4;
+    }
+  }
+  // 	unlock();
+}
+
+void AdlibDriver::setupPrograms() {
+  while (_lastProcessed != _soundsPlaying) {
+    uint8 *ptr = getProgram(_soundIdTable[_lastProcessed]);
+    uint8 chan = *ptr++;
+    uint8 priority = *ptr++;
+
+    // Only start this sound if its priority is higher than the one
+    // already playing.
+
+    Channel &channel = _channels[chan];
+
+    if (priority >= channel.priority) {
+      initChannel(channel);
+      channel.priority = priority;
+      channel.dataptr = ptr;
+      channel.tempo = 0xFF;
+      channel.position = 0xFF;
+      channel.duration = 1;
+      unkOutput2(chan);
+    }
+
+    ++_lastProcessed;
+    _lastProcessed &= 0x0F;
+  }
+}
+
+// A few words on opcode parsing and timing:
+//
+// First of all, We simulate a timer callback 72 times per second. Each timeout
+// we update each channel that has something to play.
+//
+// Each channel has its own individual tempo, which is added to its position.
+// This will frequently cause the position to "wrap around" but that is
+// intentional. In fact, it's the signal to go ahead and do more stuff with
+// that channel.
+//
+// Each channel also has a duration, indicating how much time is left on the
+// its current task. This duration is decreased by one. As long as it still has
+// not reached zero, the only thing that can happen is that the note is turned
+// off depending on manual or automatic note spacing. Once the duration reaches
+// zero, a new set of musical opcodes are executed.
+//
+// An opcode is one byte, followed by a variable number of parameters. Since
+// most opcodes have at least one one-byte parameter, we read that as well. Any
+// opcode that doesn't have that one parameter is responsible for moving the
+// data pointer back again.
+//
+// If the most significant bit of the opcode is 1, it's a function; call it.
+// The opcode functions return either 0 (continue), 1 (stop) or 2 (stop, and do
+// not run the effects callbacks).
+//
+// If the most significant bit of the opcode is 0, it's a note, and the first
+// parameter is its duration. (There are cases where the duration is modified
+// but that's an exception.) The note opcode is assumed to return 1, and is the
+// last opcode unless its duration is zero.
+//
+// Finally, most of the times that the callback is called, it will invoke the
+// effects callbacks. The final opcode in a set can prevent this, if it's a
+// function and it returns anything other than 1.
+
+void AdlibDriver::executePrograms() {
+  // Each channel runs its own program. There are ten channels: One for
+  // each Adlib channel (0-8), plus one "control channel" (9) which is
+  // the one that tells the other channels what to do. 
+
+  for (_curChannel = 9; _curChannel >= 0; --_curChannel) {
+    int result = 1;
+
+    if (!_channels[_curChannel].dataptr) {
+      continue;
+    }
+	
+    Channel &channel = _channels[_curChannel];
+    _curRegOffset = _regOffset[_curChannel];
+
+    if (channel.tempoReset) {
+      channel.tempo = _tempo;
+    }
+
+    uint8 backup = channel.position;
+    channel.position += channel.tempo;
+    if (channel.position < backup) {
+      if (--channel.duration) {
+	if (channel.duration == channel.spacing2)
+	  noteOff(channel);
+	if (channel.duration == channel.spacing1 && _curChannel != 9)
+	  noteOff(channel);
+      } else {
+	// An opcode is not allowed to modify its own
+	// data pointer except through the 'dataptr'
+	// parameter. To enforce that, we have to work
+	// on a copy of the data pointer.
+	//
+	// This fixes a subtle music bug where the
+	// wrong music would play when getting the
+	// quill in Kyra 1.
+	uint8 *dataptr = channel.dataptr;
+	while (dataptr) {
+	  uint8 opcode = *dataptr++;
+	  uint8 param = *dataptr++;
+
+	  if (opcode & 0x80) {
+	    opcode &= 0x7F;
+	    if (opcode >= _parserOpcodeTableSize)
+	      opcode = _parserOpcodeTableSize - 1;
+	    debugC(9, kDebugLevelSound, "Calling opcode '%s' (%d) (channel: %d)", _parserOpcodeTable[opcode].name, opcode, _curChannel);
+	    result = (this->*(_parserOpcodeTable[opcode].function))(dataptr, channel, param);
+	    channel.dataptr = dataptr;
+	    if (result)
+	      break;
+	  } else {
+	    debugC(9, kDebugLevelSound, "Note on opcode 0x%02X (duration: %d) (channel: %d)", opcode, param, _curChannel);
+	    setupNote(opcode, channel);
+	    noteOn(channel);
+	    setupDuration(param, channel);
+	    if (param) {
+	      channel.dataptr = dataptr;
+	      break;
+	    }
+	  }
+	}
+      }
+    }
+
+    if (result == 1) {
+      if (channel.primaryEffect)
+	(this->*(channel.primaryEffect))(channel);
+      if (channel.secondaryEffect)
+	(this->*(channel.secondaryEffect))(channel);
+    }
+  }
+}
+
+// 
+
+void AdlibDriver::resetAdlibState() {
+  debugC(9, kDebugLevelSound, "resetAdlibState()");
+  _rnd = 0x1234;
+
+  // Authorize the control of the waveforms
+  writeOPL(0x01, 0x20);
+
+  // Select FM music mode
+  writeOPL(0x08, 0x00);
+
+  // I would guess the main purpose of this is to turn off the rhythm,
+  // thus allowing us to use 9 melodic voices instead of 6.
+  writeOPL(0xBD, 0x00);
+
+  int loop = 10;
+  while (loop--) {
+    if (loop != 9) {
+      // Silence the channel
+      writeOPL(0x40 + _regOffset[loop], 0x3F);
+      writeOPL(0x43 + _regOffset[loop], 0x3F);
+    }
+    initChannel(_channels[loop]);
+  }
+}
+
+// Old calling style: output0x388(0xABCD)
+// New calling style: writeOPL(0xAB, 0xCD)
+
+void AdlibDriver::writeOPL(byte reg, byte val) {
+  opl->write(reg, val);
+}
+
+void AdlibDriver::initChannel(Channel &channel) {
+  debugC(9, kDebugLevelSound, "initChannel(%lu)", (long)(&channel - _channels));
+  memset(&channel.dataptr, 0, sizeof(Channel) - ((char*)&channel.dataptr - (char*)&channel));
+
+  channel.tempo = 0xFF;
+  channel.priority = 0;
+  // normally here are nullfuncs but we set 0 for now
+  channel.primaryEffect = 0;
+  channel.secondaryEffect = 0;
+  channel.spacing1 = 1;
+}
+
+void AdlibDriver::noteOff(Channel &channel) {
+  debugC(9, kDebugLevelSound, "noteOff(%lu)", (long)(&channel - _channels));
+
+  // The control channel has no corresponding Adlib channel
+
+  if (_curChannel >= 9)
+    return;
+
+  // When the rhythm section is enabled, channels 6, 7 and 8 are special.
+
+  if (_rhythmSectionBits && _curChannel >= 6)
+    return;
+
+  // This means the "Key On" bit will always be 0
+  channel.regBx &= 0xDF;
+
+  // Octave / F-Number / Key-On
+  writeOPL(0xB0 + _curChannel, channel.regBx);
+}
+
+void AdlibDriver::unkOutput2(uint8 chan) {
+  debugC(9, kDebugLevelSound, "unkOutput2(%d)", chan);
+
+  // The control channel has no corresponding Adlib channel
+
+  if (chan >= 9)
+    return;
+
+  // I believe this has to do with channels 6, 7, and 8 being special
+  // when Adlib's rhythm section is enabled.
+
+  if (_rhythmSectionBits && chan >= 6)
+    return;
+
+  uint8 offset = _regOffset[chan];
+
+  // The channel is cleared: First the attack/delay rate, then the
+  // sustain level/release rate, and finally the note is turned off.
+
+  writeOPL(0x60 + offset, 0xFF);
+  writeOPL(0x63 + offset, 0xFF);
+
+  writeOPL(0x80 + offset, 0xFF);
+  writeOPL(0x83 + offset, 0xFF);
+
+  writeOPL(0xB0 + chan, 0x00);
+
+  // ...and then the note is turned on again, with whatever value is
+  // still lurking in the A0 + chan register, but everything else -
+  // including the two most significant frequency bit, and the octave -
+  // set to zero.
+  //
+  // This is very strange behaviour, and causes problems with the ancient
+  // FMOPL code we borrowed from AdPlug. I've added a workaround. See
+  // fmopl.cpp for more details.
+  //
+  // More recent versions of the MAME FMOPL don't seem to have this
+  // problem, but cannot currently be used because of licensing and
+  // performance issues.
+  //
+  // Ken Silverman's Adlib emulator (which can be found on his Web page -
+  // http://www.advsys.net/ken - and as part of AdPlug) also seems to be
+  // immune, but is apparently not as feature complete as MAME's.
+
+  writeOPL(0xB0 + chan, 0x20);
+}
+
+// I believe this is a random number generator. It actually does seem to
+// generate an even distribution of almost all numbers from 0 through 65535,
+// though in my tests some numbers were never generated.
+
+uint16 AdlibDriver::getRandomNr() {
+  _rnd += 0x9248;
+  uint16 lowBits = _rnd & 7;
+  _rnd >>= 3;
+  _rnd |= (lowBits << 13);
+  return _rnd;
+}
+
+void AdlibDriver::setupDuration(uint8 duration, Channel &channel) {
+  debugC(9, kDebugLevelSound, "setupDuration(%d, %lu)", duration, (long)(&channel - _channels));
+  if (channel.durationRandomness) {
+    channel.duration = duration + (getRandomNr() & channel.durationRandomness);
+    return;
+  }
+  if (channel.fractionalSpacing) {
+    channel.spacing2 = (duration >> 3) * channel.fractionalSpacing;
+  }
+  channel.duration = duration;
+}
+
+// This function may or may not play the note. It's usually followed by a call
+// to noteOn(), which will always play the current note.
+
+void AdlibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) {
+  debugC(9, kDebugLevelSound, "setupNote(%d, %lu)", rawNote, (long)(&channel - _channels));
+
+  channel.rawNote = rawNote;
+
+  int8 note = (rawNote & 0x0F) + channel.baseNote;
+  int8 octave = ((rawNote + channel.baseOctave) >> 4) & 0x0F;
+
+  // There are only twelve notes. If we go outside that, we have to
+  // adjust the note and octave.
+
+  if (note >= 12) {
+    note -= 12;
+    octave++;
+  } else if (note < 0) {
+    note += 12;
+    octave--;
+  }
+
+  // The calculation of frequency looks quite different from the original
+  // disassembly at a first glance, but when you consider that the
+  // largest possible value would be 0x0246 + 0xFF + 0x47 (and that's if
+  // baseFreq is unsigned), freq is still a 10-bit value, just as it
+  // should be to fit in the Ax and Bx registers.
+  //
+  // If it were larger than that, it could have overflowed into the
+  // octave bits, and that could possibly have been used in some sound.
+  // But as it is now, I can't see any way it would happen.
+
+  uint16 freq = _unkTable[note] + channel.baseFreq;
+
+  // When called from callback 41, the behaviour is slightly different:
+  // We adjust the frequency, even when channel.unk16 is 0.
+
+  if (channel.unk16 || flag) {
+    const uint8 *table;
+
+    if (channel.unk16 >= 0) {
+      table = _unkTables[(channel.rawNote & 0x0F) + 2];
+      freq += table[channel.unk16];
+    } else {
+      table = _unkTables[channel.rawNote & 0x0F];
+      freq -= table[-channel.unk16];
+    }
+  }
+
+  channel.regAx = freq & 0xFF;
+  channel.regBx = (channel.regBx & 0x20) | (octave << 2) | ((freq >> 8) & 0x03);
+
+  // Keep the note on or off
+  writeOPL(0xA0 + _curChannel, channel.regAx);
+  writeOPL(0xB0 + _curChannel, channel.regBx);
+}
+
+void AdlibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) {
+  debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels));
+  // Amplitude Modulation / Vibrato / Envelope Generator Type /
+  // Keyboard Scaling Rate / Modulator Frequency Multiple
+  writeOPL(0x20 + regOffset, *dataptr++);
+  writeOPL(0x23 + regOffset, *dataptr++);
+
+  uint8 temp = *dataptr++;
+
+  // Feedback / Algorithm
+
+  // It is very likely that _curChannel really does refer to the same
+  // channel as regOffset, but there's only one Cx register per channel.
+
+  writeOPL(0xC0 + _curChannel, temp);
+
+  // The algorithm bit. I don't pretend to understand this fully, but
+  // "If set to 0, operator 1 modulates operator 2. In this case,
+  // operator 2 is the only one producing sound. If set to 1, both
+  // operators produce sound directly. Complex sounds are more easily
+  // created if the algorithm is set to 0."
+
+  channel.twoChan = temp & 1;
+
+  // Waveform Select
+  writeOPL(0xE0 + regOffset, *dataptr++);
+  writeOPL(0xE3 + regOffset, *dataptr++);
+
+  channel.opLevel1 = *dataptr++;
+  channel.opLevel2 = *dataptr++;
+
+  // Level Key Scaling / Total Level
+  writeOPL(0x40 + regOffset, calculateOpLevel1(channel));
+  writeOPL(0x43 + regOffset, calculateOpLevel2(channel));
+
+  // Attack Rate / Decay Rate
+  writeOPL(0x60 + regOffset, *dataptr++);
+  writeOPL(0x63 + regOffset, *dataptr++);
+
+  // Sustain Level / Release Rate
+  writeOPL(0x80 + regOffset, *dataptr++);
+  writeOPL(0x83 + regOffset, *dataptr++);
+}
+
+// Apart from playing the note, this function also updates the variables for
+// primary effect 2.
+
+void AdlibDriver::noteOn(Channel &channel) {
+  debugC(9, kDebugLevelSound, "noteOn(%lu)", (long)(&channel - _channels));
+
+  // The "note on" bit is set, and the current note is played.
+
+  channel.regBx |= 0x20;
+  writeOPL(0xB0 + _curChannel, channel.regBx);
+
+  int8 shift = 9 - channel.unk33;
+  uint16 temp = channel.regAx | (channel.regBx << 8);
+  channel.unk37 = ((temp & 0x3FF) >> shift) & 0xFF;
+  channel.unk38 = channel.unk36;
+}
+
+void AdlibDriver::adjustVolume(Channel &channel) {
+  debugC(9, kDebugLevelSound, "adjustVolume(%lu)", (long)(&channel - _channels));
+  // Level Key Scaling / Total Level
+
+  writeOPL(0x43 + _regOffset[_curChannel], calculateOpLevel2(channel));
+  if (channel.twoChan)
+    writeOPL(0x40 + _regOffset[_curChannel], calculateOpLevel1(channel));
+}
+
+// This is presumably only used for some sound effects, e.g. Malcolm blowing up
+// the trees in the intro (but not the effect where he "booby-traps" the big
+// tree) and turning Kallak to stone. Related functions and variables:
+//
+// update_setupPrimaryEffect1()
+//    - Initialises unk29, unk30 and unk31
+//    - unk29 is not further modified
+//    - unk30 is not further modified, except by update_removePrimaryEffect1()
+//
+// update_removePrimaryEffect1()
+//    - Deinitialises unk30
+//
+// unk29 - determines how often the notes are played
+// unk30 - modifies the frequency
+// unk31 - determines how often the notes are played
+
+void AdlibDriver::primaryEffect1(Channel &channel) {
+  debugC(9, kDebugLevelSound, "Calling primaryEffect1 (channel: %d)", _curChannel);
+  uint8 temp = channel.unk31;
+  channel.unk31 += channel.unk29;
+  if (channel.unk31 >= temp)
+    return;
+
+  // Initialise unk1 to the current frequency
+  uint16 unk1 = ((channel.regBx & 3) << 8) | channel.regAx;
+
+  // This is presumably to shift the "note on" bit so far to the left
+  // that it won't be affected by any of the calculations below.
+  uint16 unk2 = ((channel.regBx & 0x20) << 8) | (channel.regBx & 0x1C);
+
+  int16 unk3 = (int16)channel.unk30;
+
+  if (unk3 >= 0) {
+    unk1 += unk3;
+    if (unk1 >= 734) {
+      // The new frequency is too high. Shift it down and go
+      // up one octave.
+      unk1 >>= 1;
+      if (!(unk1 & 0x3FF))
+	++unk1;
+      unk2 = (unk2 & 0xFF00) | ((unk2 + 4) & 0xFF);
+      unk2 &= 0xFF1C;
+    }
+  } else {
+    unk1 += unk3;
+    if (unk1 < 388) {
+      // The new frequency is too low. Shift it up and go
+      // down one octave.
+      unk1 <<= 1;
+      if (!(unk1 & 0x3FF))
+	--unk1;
+      unk2 = (unk2 & 0xFF00) | ((unk2 - 4) & 0xFF);
+      unk2 &= 0xFF1C;
+    }
+  }
+
+  // Make sure that the new frequency is still a 10-bit value.
+  unk1 &= 0x3FF;
+
+  writeOPL(0xA0 + _curChannel, unk1 & 0xFF);
+  channel.regAx = unk1 & 0xFF;
+
+  // Shift down the "note on" bit again.
+  uint8 value = unk1 >> 8;
+  value |= (unk2 >> 8) & 0xFF;
+  value |= unk2 & 0xFF;
+
+  writeOPL(0xB0 + _curChannel, value);
+  channel.regBx = value;
+}
+
+// This is presumably only used for some sound effects, e.g. Malcolm entering
+// and leaving Kallak's hut. Related functions and variables:
+//
+// update_setupPrimaryEffect2()
+//    - Initialises unk32, unk33, unk34, unk35 and unk36
+//    - unk32 is not further modified
+//    - unk33 is not further modified
+//    - unk34 is a countdown that gets reinitialised to unk35 on zero
+//    - unk35 is based on unk34 and not further modified
+//    - unk36 is not further modified
+//
+// noteOn()
+//    - Plays the current note
+//    - Updates unk37 with a new (lower?) frequency
+//    - Copies unk36 to unk38. The unk38 variable is a countdown.
+//
+// unk32 - determines how often the notes are played
+// unk33 - modifies the frequency
+// unk34 - countdown, updates frequency on zero
+// unk35 - initialiser for unk34 countdown
+// unk36 - initialiser for unk38 countdown
+// unk37 - frequency
+// unk38 - countdown, begins playing on zero
+// unk41 - determines how often the notes are played
+//
+// Note that unk41 is never initialised. Not that it should matter much, but it
+// is a bit sloppy.
+
+void AdlibDriver::primaryEffect2(Channel &channel) {
+  debugC(9, kDebugLevelSound, "Calling primaryEffect2 (channel: %d)", _curChannel);
+  if (channel.unk38) {
+    --channel.unk38;
+    return;
+  }
+
+  uint8 temp = channel.unk41;
+  channel.unk41 += channel.unk32;
+  if (channel.unk41 < temp) {
+    uint16 unk1 = channel.unk37;
+    if (!(--channel.unk34)) {
+      unk1 ^= 0xFFFF;
+      ++unk1;
+      channel.unk37 = unk1;
+      channel.unk34 = channel.unk35;
+    }
+
+    uint16 unk2 = (channel.regAx | (channel.regBx << 8)) & 0x3FF;
+    unk2 += unk1;
+		
+    channel.regAx = unk2 & 0xFF;
+    channel.regBx = (channel.regBx & 0xFC) | (unk2 >> 8);
+
+    // Octave / F-Number / Key-On
+    writeOPL(0xA0 + _curChannel, channel.regAx);
+    writeOPL(0xB0 + _curChannel, channel.regBx);
+  }
+}
+
+// I don't know where this is used. The same operation is performed several
+// times on the current channel, using a chunk of the _soundData[] buffer for
+// parameters. The parameters are used starting at the end of the chunk.
+//
+// Since we use _curRegOffset to specify the final register, it's quite
+// unlikely that this function is ever used to play notes. It's probably only
+// used to modify the sound. Another thing that supports this idea is that it
+// can be combined with any of the effects callbacks above.
+//
+// Related functions and variables:
+//
+// update_setupSecondaryEffect1()
+//    - Initialies unk18, unk19, unk20, unk21, unk22 and offset
+//    - unk19 is not further modified
+//    - unk20 is not further modified
+//    - unk22 is not further modified
+//    - offset is not further modified
+//
+// unk18 -  determines how often the operation is performed
+// unk19 -  determines how often the operation is performed
+// unk20 -  the start index into the data chunk
+// unk21 -  the current index into the data chunk
+// unk22 -  the operation to perform
+// offset - the offset to the data chunk
+
+void AdlibDriver::secondaryEffect1(Channel &channel) {
+  debugC(9, kDebugLevelSound, "Calling secondaryEffect1 (channel: %d)", _curChannel);
+  uint8 temp = channel.unk18;
+  channel.unk18 += channel.unk19;
+  if (channel.unk18 < temp) {
+    if (--channel.unk21 < 0) {
+      channel.unk21 = channel.unk20;
+    }
+    writeOPL(channel.unk22 + _curRegOffset, _soundData[channel.offset + channel.unk21]);
+  }
+}
+
+uint8 AdlibDriver::calculateOpLevel1(Channel &channel) {
+  int8 value = channel.opLevel1 & 0x3F;
+
+  if (channel.twoChan) {
+    value += channel.opExtraLevel1;
+    value += channel.opExtraLevel2;
+    value += channel.opExtraLevel3;
+  }
+
+  // Preserve the scaling level bits from opLevel1
+
+  return checkValue(value) | (channel.opLevel1 & 0xC0);
+}
+
+uint8 AdlibDriver::calculateOpLevel2(Channel &channel) {
+  int8 value = channel.opLevel2 & 0x3F;
+
+  value += channel.opExtraLevel1;
+  value += channel.opExtraLevel2;
+  value += channel.opExtraLevel3;
+
+  // Preserve the scaling level bits from opLevel2
+
+  return checkValue(value) | (channel.opLevel2 & 0xC0);
+}
+
+// parser opcodes
+
+int AdlibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.repeatCounter = value;
+  return 0;
+}
+
+int AdlibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) {
+  ++dataptr;
+  if (--channel.repeatCounter) {
+    int16 add = READ_LE_UINT16(dataptr - 2);
+    dataptr += add;
+  }
+  return 0;
+}
+
+int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
+  if (value == 0xFF)
+    return 0;
+
+  uint8 *ptr = getProgram(value);
+  uint8 chan = *ptr++;
+  uint8 priority = *ptr++;
+
+  Channel &channel2 = _channels[chan];
+
+  if (priority >= channel2.priority) {
+    _flagTrigger = 1;
+    _flags |= 8;
+    initChannel(channel2);
+    channel2.priority = priority;
+    channel2.dataptr = ptr;
+    channel2.tempo = 0xFF;
+    channel2.position = 0xFF;
+    channel2.duration = 1;
+    unkOutput2(chan);
+  }
+
+  return 0;
+}
+
+int AdlibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.spacing1 = value;
+  return 0;
+}
+
+int AdlibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+  dataptr += add;
+  return 0;
+}
+
+int AdlibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
+  channel.dataptrStack[channel.dataptrStackPos++] = dataptr;
+  dataptr += add;
+  return 0;
+}
+
+int AdlibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) {
+  dataptr = channel.dataptrStack[--channel.dataptrStackPos];
+  return 0;
+}
+
+int AdlibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.baseOctave = value;
+  return 0;
+}
+
+int AdlibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.priority = 0;
+  if (_curChannel != 9) {
+    noteOff(channel);
+  }
+  dataptr = 0;
+  return 2;
+}
+
+int AdlibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) {
+  setupDuration(value, channel);
+  noteOff(channel);
+  return (value != 0);
+}
+
+int AdlibDriver::update_writeAdlib(uint8 *&dataptr, Channel &channel, uint8 value) {
+  writeOPL(value, *dataptr++);
+  return 0;
+}
+
+int AdlibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+  setupNote(value, channel);
+  value = *dataptr++;
+  setupDuration(value, channel);
+  return (value != 0);
+}
+
+int AdlibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.baseNote = value;
+  return 0;
+}
+
+int AdlibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.unk18 = value;
+  channel.unk19 = value;
+  channel.unk20 = channel.unk21 = *dataptr++;
+  channel.unk22 = *dataptr++;
+  channel.offset = READ_LE_UINT16(dataptr); dataptr += 2;
+  channel.secondaryEffect = &AdlibDriver::secondaryEffect1;
+  return 0;
+}
+
+int AdlibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) {
+  Channel &channel2 = _channels[value];
+  channel2.duration = 0;
+  channel2.priority = 0;
+  channel2.dataptr = 0;
+  return 0;
+}
+
+int AdlibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint8 *ptr = getProgram(value);
+  uint8 chan = *ptr;
+
+  if (!_channels[chan].dataptr) {
+    return 0;
+  }
+
+  dataptr -= 2;
+  return 2;
+}
+
+int AdlibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) {
+  setupInstrument(_curRegOffset, getInstrument(value), channel);
+  return 0;
+}
+
+int AdlibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.unk29 = value;
+  channel.unk30 = READ_BE_UINT16(dataptr);
+  dataptr += 2;
+  channel.primaryEffect = &AdlibDriver::primaryEffect1;
+  channel.unk31 = 0xFF;
+  return 0;
+}
+
+int AdlibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  channel.primaryEffect = 0;
+  channel.unk30 = 0;
+  return 0;
+}
+
+int AdlibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.baseFreq = value;
+  return 0;
+}
+
+int AdlibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.unk32 = value;
+  channel.unk33 = *dataptr++;
+  uint8 temp = *dataptr++;
+  channel.unk34 = temp + 1;
+  channel.unk35 = temp << 1;
+  channel.unk36 = *dataptr++;
+  channel.primaryEffect = &AdlibDriver::primaryEffect2;
+  return 0;
+}
+
+int AdlibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.priority = value;
+  return 0;
+}
+
+int AdlibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) {
+  value >>= 1;
+  _unkValue1 = _unkValue2 = value;
+  _unkValue3 = 0xFF;
+  _unkValue4 = _unkValue5 = 0;
+  return 0;
+}
+
+int AdlibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) {
+  if (_unkValue5) {
+    if (_unkValue4 & value) {
+      _unkValue5 = 0;
+      return 0;
+    }
+  }
+
+  if (!(value & _unkValue4)) {
+    ++_unkValue5;
+  }
+
+  dataptr -= 2;
+  channel.duration = 1;
+  return 2;
+}
+
+int AdlibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.opExtraLevel1 = value;
+  adjustVolume(channel);
+  return 0;
+}
+
+int AdlibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) {
+  setupDuration(value, channel);
+  return (value != 0);
+}
+
+int AdlibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) {
+  setupDuration(value, channel);
+  noteOn(channel);
+  return (value != 0);
+}
+
+int AdlibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.fractionalSpacing = value & 7;
+  return 0;
+}
+
+int AdlibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+  _tempo = value;
+  return 0;
+}
+
+int AdlibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  channel.secondaryEffect = 0;
+  return 0;
+}
+
+int AdlibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.tempo = value;
+  return 0;
+}
+
+int AdlibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.opExtraLevel3 = value;
+  return 0;
+}
+
+int AdlibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+  int channelBackUp = _curChannel;
+
+  _curChannel = value;
+  Channel &channel2 = _channels[value];
+  channel2.opExtraLevel2 = *dataptr++;
+  adjustVolume(channel2);
+
+  _curChannel = channelBackUp;
+  return 0;
+}
+
+int AdlibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) {
+  int channelBackUp = _curChannel;
+
+  _curChannel = value;
+  Channel &channel2 = _channels[value];
+  channel2.opExtraLevel2 += *dataptr++;
+  adjustVolume(channel2);
+
+  _curChannel = channelBackUp;
+  return 0;
+}
+
+// Apart from initialising to zero, these two functions are the only ones that
+// modify _vibratoAndAMDepthBits.
+
+int AdlibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+  if (value & 1)
+    _vibratoAndAMDepthBits |= 0x80;
+  else
+    _vibratoAndAMDepthBits &= 0x7F;
+
+  writeOPL(0xBD, _vibratoAndAMDepthBits);
+  return 0;
+}
+
+int AdlibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) {
+  if (value & 1)
+    _vibratoAndAMDepthBits |= 0x40;
+  else
+    _vibratoAndAMDepthBits &= 0xBF;
+
+  writeOPL(0xBD, _vibratoAndAMDepthBits);
+  return 0;
+}
+
+int AdlibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.opExtraLevel1 += value;
+  adjustVolume(channel);
+  return 0;
+}
+
+int AdlibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) {
+  int channelBackUp = _curChannel;
+
+  _curChannel = value;
+  Channel &channel2 = _channels[value];
+  channel2.duration = channel2.priority = 0;
+  channel2.dataptr = 0;
+  channel2.opExtraLevel2 = 0;
+
+  if (value != 9) {
+    uint8 outValue = _regOffset[value];
+
+    // Feedback strength / Connection type
+    writeOPL(0xC0 + _curChannel, 0x00);
+
+    // Key scaling level / Operator output level
+    writeOPL(0x43 + outValue, 0x3F);
+
+    // Sustain Level / Release Rate
+    writeOPL(0x83 + outValue, 0xFF);
+
+    // Key On / Octave / Frequency
+    writeOPL(0xB0 + _curChannel, 0x00);
+  }
+
+  _curChannel = channelBackUp;
+  return 0;
+}
+
+int AdlibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint16 unk = *dataptr++;
+  unk |= value << 8;
+  unk &= getRandomNr();
+
+  uint16 unk2 = ((channel.regBx & 0x1F) << 8) | channel.regAx;
+  unk2 += unk;
+  unk2 |= ((channel.regBx & 0x20) << 8);
+
+  // Frequency
+  writeOPL(0xA0 + _curChannel, unk2 & 0xFF);
+
+  // Key On / Octave / Frequency
+  writeOPL(0xB0 + _curChannel, (unk2 & 0xFF00) >> 8);
+
+  return 0;
+}
+
+int AdlibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  channel.primaryEffect = 0;
+  return 0;
+}
+
+int AdlibDriver::updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.unk16 = value;
+  setupNote(channel.rawNote, channel, true);
+  return 0;
+}
+
+int AdlibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  channel.tempo = _tempo;
+  return 0;
+}
+
+int AdlibDriver::update_nop1(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  return 0;
+}
+
+int AdlibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.durationRandomness = value;
+  return 0;
+}
+
+int AdlibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) {
+  int tempo = channel.tempo + (int8)value;
+
+  if (tempo <= 0)
+    tempo = 1;
+  else if (tempo > 255)
+    tempo = 255;
+
+  channel.tempo = tempo;
+  return 0;
+}
+
+int AdlibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint8 entry = *dataptr++;
+  _tablePtr1 = _unkTable2[entry++];
+  _tablePtr2 = _unkTable2[entry];
+  if (value == 2) {
+    // Frequency
+    writeOPL(0xA0, _tablePtr2[0]);
+  }
+  return 0;
+}
+
+// TODO: This is really the same as update_nop1(), so they should be combined
+//       into one single update_nop().
+
+int AdlibDriver::update_nop2(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  return 0;
+}
+
+int AdlibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+  int channelBackUp = _curChannel;
+  int regOffsetBackUp = _curRegOffset;
+
+  _curChannel = 6;
+  _curRegOffset = _regOffset[6];
+
+  setupInstrument(_curRegOffset, getInstrument(value), channel);
+  _unkValue6 = channel.opLevel2;
+
+  _curChannel = 7;
+  _curRegOffset = _regOffset[7];
+
+  setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+  _unkValue7 = channel.opLevel1;
+  _unkValue8 = channel.opLevel2;
+
+  _curChannel = 8;
+  _curRegOffset = _regOffset[8];
+
+  setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel);
+  _unkValue9 = channel.opLevel1;
+  _unkValue10 = channel.opLevel2;
+
+  // Octave / F-Number / Key-On for channels 6, 7 and 8
+
+  _channels[6].regBx = *dataptr++ & 0x2F;
+  writeOPL(0xB6, _channels[6].regBx);
+  writeOPL(0xA6, *dataptr++);
+
+  _channels[7].regBx = *dataptr++ & 0x2F;
+  writeOPL(0xB7, _channels[7].regBx);
+  writeOPL(0xA7, *dataptr++);
+
+  _channels[8].regBx = *dataptr++ & 0x2F;
+  writeOPL(0xB8, _channels[8].regBx);
+  writeOPL(0xA8, *dataptr++);
+
+  _rhythmSectionBits = 0x20;
+
+  _curRegOffset = regOffsetBackUp;
+  _curChannel = channelBackUp;
+  return 0;
+}
+
+int AdlibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+  // Any instrument that we want to play, and which was already playing,
+  // is temporarily keyed off. Instruments that were off already, or
+  // which we don't want to play, retain their old on/off status. This is
+  // probably so that the instrument's envelope is played from its
+  // beginning again...
+
+  writeOPL(0xBD, (_rhythmSectionBits & ~(value & 0x1F)) | 0x20);
+
+  // ...but since we only set the rhythm instrument bits, and never clear
+  // them (until the entire rhythm section is disabled), I'm not sure how
+  // useful the cleverness above is. We could perhaps simply turn off all
+  // the rhythm instruments instead.
+
+  _rhythmSectionBits |= value;
+
+  writeOPL(0xBD, _vibratoAndAMDepthBits | 0x20 | _rhythmSectionBits);
+  return 0;
+}
+
+int AdlibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) {
+  --dataptr;
+  _rhythmSectionBits = 0;
+
+  // All the rhythm bits are cleared. The AM and Vibrato depth bits
+  // remain unchanged.
+
+  writeOPL(0xBD, _vibratoAndAMDepthBits);
+  return 0;
+}
+
+int AdlibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint8 value2 = *dataptr++;
+
+  if (value & 1) {
+    _unkValue12 = value2;
+
+    // Channel 7, op1: Level Key Scaling / Total Level
+    writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12));
+  }
+
+  if (value & 2) {
+    _unkValue14 = value2;
+
+    // Channel 8, op2: Level Key Scaling / Total Level
+    writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14));
+  }
+
+  if (value & 4) {
+    _unkValue15 = value2;
+
+    // Channel 8, op1: Level Key Scaling / Total Level
+    writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15));
+  }
+
+  if (value & 8) {
+    _unkValue18 = value2;
+
+    // Channel 7, op2: Level Key Scaling / Total Level
+    writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18));
+  }
+
+  if (value & 16) {
+    _unkValue20 = value2;
+
+    // Channel 6, op2: Level Key Scaling / Total Level
+    writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20));
+  }
+
+  return 0;
+}
+
+int AdlibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint8 value2 = *dataptr++;
+
+  if (value & 1) {
+    _unkValue11 = checkValue(value2 + _unkValue7 + _unkValue11 + _unkValue12);
+
+    // Channel 7, op1: Level Key Scaling / Total Level
+    writeOPL(0x51, _unkValue11);
+  }
+
+  if (value & 2) {
+    _unkValue13 = checkValue(value2 + _unkValue10 + _unkValue13 + _unkValue14);
+
+    // Channel 8, op2: Level Key Scaling / Total Level
+    writeOPL(0x55, _unkValue13);
+  }
+
+  if (value & 4) {
+    _unkValue16 = checkValue(value2 + _unkValue9 + _unkValue16 + _unkValue15);
+
+    // Channel 8, op1: Level Key Scaling / Total Level
+    writeOPL(0x52, _unkValue16);
+  }
+
+  if (value & 8) {
+    _unkValue17 = checkValue(value2 + _unkValue8 + _unkValue17 + _unkValue18);
+
+    // Channel 7, op2: Level Key Scaling / Total Level
+    writeOPL(0x54, _unkValue17);
+  }
+
+  if (value & 16) {
+    _unkValue19 = checkValue(value2 + _unkValue6 + _unkValue19 + _unkValue20);
+
+    // Channel 6, op2: Level Key Scaling / Total Level
+    writeOPL(0x53, _unkValue19);
+  }
+
+  return 0;
+}
+
+int AdlibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) {
+  uint8 value2 = *dataptr++;
+
+  if (value & 1) {
+    _unkValue11 = value2;
+
+    // Channel 7, op1: Level Key Scaling / Total Level
+    writeOPL(0x51, checkValue(value2 + _unkValue7 + _unkValue12));
+  }
+
+  if (value & 2) {
+    _unkValue13 = value2;
+
+    // Channel 8, op2: Level Key Scaling / Total Level
+    writeOPL(0x55, checkValue(value2 + _unkValue10 + _unkValue14));
+  }
+
+  if (value & 4) {
+    _unkValue16 = value2;
+
+    // Channel 8, op1: Level Key Scaling / Total Level
+    writeOPL(0x52, checkValue(value2 + _unkValue9 + _unkValue15));
+  }
+
+  if (value & 8) {
+    _unkValue17 = value2;
+
+    // Channel 7, op2: Level Key Scaling / Total Level
+    writeOPL(0x54, checkValue(value2 + _unkValue8 + _unkValue18));
+  }
+
+  if (value & 16) {
+    _unkValue19 = value2;
+
+    // Channel 6, op2: Level Key Scaling / Total Level
+    writeOPL(0x53, checkValue(value2 + _unkValue6 + _unkValue20));
+  }
+
+  return 0;
+}
+
+int AdlibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) {
+  _soundTrigger = value;
+  return 0;
+}
+
+int AdlibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.tempoReset = value;
+  return 0;
+}
+
+int AdlibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) {
+  channel.unk39 = value;
+  channel.unk40 = *dataptr++;
+  return 0;
+}
+
+// static res
+
+#define COMMAND(x) { &AdlibDriver::x, #x }
+
+void AdlibDriver::setupOpcodeList() {
+  static const OpcodeEntry 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_getSoundTrigger),
+    COMMAND(snd_unkOpcode4),
+    COMMAND(snd_dummy),
+    COMMAND(snd_getNullvar4),
+    COMMAND(snd_setNullvar3),
+    COMMAND(snd_setFlag),
+    COMMAND(snd_clearFlag)
+  };
+
+  _opcodeList = opcodeList;
+  _opcodesEntries = ARRAYSIZE(opcodeList);
+}
+
+void AdlibDriver::setupParserOpcodeTable() {
+  static const ParserOpcode parserOpcodeTable[] = {
+    // 0
+    COMMAND(update_setRepeat),
+    COMMAND(update_checkRepeat),
+    COMMAND(update_setupProgram),
+    COMMAND(update_setNoteSpacing),
+
+    // 4
+    COMMAND(update_jump),
+    COMMAND(update_jumpToSubroutine),
+    COMMAND(update_returnFromSubroutine),
+    COMMAND(update_setBaseOctave),
+
+    // 8
+    COMMAND(update_stopChannel),
+    COMMAND(update_playRest),
+    COMMAND(update_writeAdlib),
+    COMMAND(update_setupNoteAndDuration),
+
+    // 12
+    COMMAND(update_setBaseNote),
+    COMMAND(update_setupSecondaryEffect1),
+    COMMAND(update_stopOtherChannel),
+    COMMAND(update_waitForEndOfProgram),
+
+    // 16
+    COMMAND(update_setupInstrument),
+    COMMAND(update_setupPrimaryEffect1),
+    COMMAND(update_removePrimaryEffect1),
+    COMMAND(update_setBaseFreq),
+
+    // 20
+    COMMAND(update_stopChannel),
+    COMMAND(update_setupPrimaryEffect2),
+    COMMAND(update_stopChannel),
+    COMMAND(update_stopChannel),
+
+    // 24
+    COMMAND(update_stopChannel),
+    COMMAND(update_stopChannel),
+    COMMAND(update_setPriority),
+    COMMAND(update_stopChannel),
+
+    // 28
+    COMMAND(updateCallback23),
+    COMMAND(updateCallback24),
+    COMMAND(update_setExtraLevel1),
+    COMMAND(update_stopChannel),
+
+    // 32
+    COMMAND(update_setupDuration),
+    COMMAND(update_playNote),
+    COMMAND(update_stopChannel),
+    COMMAND(update_stopChannel),
+
+    // 36
+    COMMAND(update_setFractionalNoteSpacing),
+    COMMAND(update_stopChannel),
+    COMMAND(update_setTempo),
+    COMMAND(update_removeSecondaryEffect1),
+
+    // 40
+    COMMAND(update_stopChannel),
+    COMMAND(update_setChannelTempo),
+    COMMAND(update_stopChannel),
+    COMMAND(update_setExtraLevel3),
+
+    // 44
+    COMMAND(update_setExtraLevel2),
+    COMMAND(update_changeExtraLevel2),
+    COMMAND(update_setAMDepth),
+    COMMAND(update_setVibratoDepth),
+
+    // 48
+    COMMAND(update_changeExtraLevel1),
+    COMMAND(update_stopChannel),
+    COMMAND(update_stopChannel),
+    COMMAND(updateCallback38),
+
+    // 52
+    COMMAND(update_stopChannel),
+    COMMAND(updateCallback39),
+    COMMAND(update_removePrimaryEffect2),
+    COMMAND(update_stopChannel),
+
+    // 56
+    COMMAND(update_stopChannel),
+    COMMAND(updateCallback41),
+    COMMAND(update_resetToGlobalTempo),
+    COMMAND(update_nop1),
+
+    // 60
+    COMMAND(update_setDurationRandomness),
+    COMMAND(update_changeChannelTempo),
+    COMMAND(update_stopChannel),
+    COMMAND(updateCallback46),
+
+    // 64
+    COMMAND(update_nop2),
+    COMMAND(update_setupRhythmSection),
+    COMMAND(update_playRhythmSection),
+    COMMAND(update_removeRhythmSection),
+
+    // 68
+    COMMAND(updateCallback51),
+    COMMAND(updateCallback52),
+    COMMAND(updateCallback53),
+    COMMAND(update_setSoundTrigger),
+
+    // 72
+    COMMAND(update_setTempoReset),
+    COMMAND(updateCallback56),
+    COMMAND(update_stopChannel)
+  };
+
+  _parserOpcodeTable = parserOpcodeTable;
+  _parserOpcodeTableSize = ARRAYSIZE(parserOpcodeTable);
+}
+#undef COMMAND
+
+// This table holds the register offset for operator 1 for each of the nine
+// channels. To get the register offset for operator 2, simply add 3.
+
+const uint8 AdlibDriver::_regOffset[] = {
+  0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11,
+  0x12
+};
+
+// Given the size of this table, and the range of its values, it's probably the
+// F-Numbers (10 bits) for the notes of the 12-tone scale. However, it does not
+// match the table in the Adlib documentation I've seen.
+
+const uint16 AdlibDriver::_unkTable[] = {
+  0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9,
+  0x0207, 0x0225, 0x0246
+};
+
+// These tables are currently only used by updateCallback46(), which only ever
+// uses the first element of one of the sub-tables.
+
+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
+};
+
+// This table is used to modify the frequency of the notes, depending on the
+// note value and unk16. In theory, we could very well try to access memory
+// outside this table, but in reality that probably won't happen.
+//
+// This could be some sort of pitch bend, but I have yet to see it used for
+// anything so it's hard to say.
+
+const uint8 AdlibDriver::_unkTables[][32] = {
+  // 0
+  { 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 },
+  // 1
+  { 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 },
+  // 2
+  { 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 },
+  // 3
+  { 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 },
+  // 4
+  { 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 },
+  // 5
+  { 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 },
+  // 6
+  { 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 },
+  // 7
+  { 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 },
+  // 8
+  { 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 },
+  // 9
+  { 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 },
+  // 10
+  { 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 },
+  // 11
+  { 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 },
+  // 12
+  { 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 },
+  // 13
+  { 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 -
+
+// At the time of writing, the only known case where Kyra 1 uses sound triggers
+// is in the castle, to cycle between three different songs.
+
+const int CadlPlayer::_kyra1SoundTriggers[] = {
+  0, 4, 5, 3
+};
+
+const int CadlPlayer::_kyra1NumSoundTriggers = ARRAYSIZE(CadlPlayer::_kyra1SoundTriggers);
+
+CadlPlayer::CadlPlayer(Copl *newopl)
+  : CPlayer(newopl), numsubsongs(0), _trackEntries(), _soundDataPtr(0)
+{
+  memset(_trackEntries, 0, sizeof(_trackEntries));
+  _driver = new AdlibDriver(newopl);
+  assert(_driver);
+
+  _sfxPlayingSound = -1;
+  // 	_soundFileLoaded = "";
+
+  _soundTriggers = _kyra1SoundTriggers;
+  _numSoundTriggers = _kyra1NumSoundTriggers;
+
+  init();
+}
+
+CadlPlayer::~CadlPlayer() {
+  delete [] _soundDataPtr;
+  delete _driver;
+}
+
+bool CadlPlayer::init() {
+  _driver->callback(2);
+  _driver->callback(16, int(4));
+  return true;
+}
+
+void CadlPlayer::process() {
+  uint8 trigger = _driver->callback(11);
+
+  if (trigger < _numSoundTriggers) {
+    int soundId = _soundTriggers[trigger];
+
+    if (soundId) {
+      playTrack(soundId);
+    }
+  } else {
+    warning("Unknown sound trigger %d", trigger);
+    // TODO: At this point, we really want to clear the trigger...
+  }
+}
+
+// void CadlPlayer::setVolume(int volume) {
+// }
+
+// int CadlPlayer::getVolume() {
+// 	return 0;
+// }
+
+// void CadlPlayer::loadMusicFile(const char *file) {
+// 	loadSoundFile(file);
+// }
+
+void CadlPlayer::playTrack(uint8 track) {
+  play(track);
+}
+
+// void CadlPlayer::haltTrack() {
+// 	unk1();
+// 	unk2();
+// 	//_engine->_system->delayMillis(3 * 60);
+// }
+
+void CadlPlayer::playSoundEffect(uint8_t track) {
+  play(track);
+}
+
+void CadlPlayer::play(uint8_t track) {
+  uint8 soundId = _trackEntries[track];
+  if ((int8)soundId == -1 || !_soundDataPtr)
+    return;
+  soundId &= 0xFF;
+  _driver->callback(16, 0);
+  // 	while ((_driver->callback(16, 0) & 8)) {
+  // We call the system delay and not the game delay to avoid concurrency issues.
+  // 		_engine->_system->delayMillis(10);
+  // 	}
+  if (_sfxPlayingSound != -1) {
+    // Restore the sounds's normal values.
+    _driver->callback(10, _sfxPlayingSound, int(1), int(_sfxPriority));
+    _driver->callback(10, _sfxPlayingSound, int(3), int(_sfxFourthByteOfSong));
+    _sfxPlayingSound = -1;
+  }
+
+  int chan = _driver->callback(9, soundId, int(0));
+
+  if (chan != 9) {
+    _sfxPlayingSound = soundId;
+    _sfxPriority = _driver->callback(9, soundId, int(1));
+    _sfxFourthByteOfSong = _driver->callback(9, soundId, int(3));
+
+    // In the cases I've seen, the mysterious fourth byte has been
+    // the parameter for the update_setExtraLevel3() callback.
+    //
+    // The extra level is part of the channels "total level", which
+    // is a six-bit value where larger values means softer volume.
+    //
+    // So what seems to be happening here is that sounds which are
+    // started by this function are given a slightly lower priority
+    // and a slightly higher (i.e. softer) extra level 3 than they
+    // would have if they were started from anywhere else. Strange.
+
+    int newVal = ((((-_sfxFourthByteOfSong) + 63) * 0xFF) >> 8) & 0xFF;
+    newVal = -newVal + 63;
+    _driver->callback(10, soundId, int(3), newVal);
+    newVal = ((_sfxPriority * 0xFF) >> 8) & 0xFF;
+    _driver->callback(10, soundId, int(1), newVal);
+  }
+
+  _driver->callback(6, soundId);
+}
+
+// void CadlPlayer::beginFadeOut() {
+// 	playSoundEffect(1);
+// }
+
+bool CadlPlayer::load(const std::string &filename, const CFileProvider &fp)
+{
+  binistream	*f = fp.open(filename);
+
+  // file validation section
+  if(!f || !fp.extension(filename, ".adl")) {
+    fp.close(f);
+    return false;
+  }
+
+  // 	if (_soundFileLoaded == file)
+  // 		return;
+
+  // 	if (_soundDataPtr) {
+  // 		haltTrack();
+  // 	}
+
+  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;
+  // 	}
+
+  unk2();
+  unk1();
+
+  file_size = fp.filesize(f);
+  file_data = new uint8 [file_size];
+  f->readString((char *)file_data, file_size);
+
+  _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;
+
+  for(int i = 0; i < 200; i++)
+    if(_trackEntries[i] != 0xff)
+      numsubsongs = i + 1;
+
+  fp.close(f);
+  return true;
+}
+
+void CadlPlayer::rewind(int subsong)
+{
+  opl->init();
+  opl->write(1,32);
+  playSoundEffect(subsong);
+  cursubsong = subsong;
+  update();
+}
+
+unsigned int CadlPlayer::getsubsongs()
+{
+  return numsubsongs;
+}
+
+bool CadlPlayer::update()
+{
+  bool songend = true;
+
+//   if(_trackEntries[cursubsong] == 0xff)
+//     return false;
+
+  _driver->callback();
+
+  for(int i = 0; i < 10; i++)
+    if(_driver->_channels[i].dataptr != NULL)
+      songend = false;
+
+  return !songend;
+}
+
+void CadlPlayer::unk1() {
+  playSoundEffect(0);
+  //_engine->_system->delayMillis(5 * 60);
+}
+
+void CadlPlayer::unk2() {
+  playSoundEffect(0);
+}
+
+CPlayer *CadlPlayer::factory(Copl *newopl)
+{
+  return new CadlPlayer(newopl);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/adplug/core/adl.h	Sat Jun 17 16:17:51 2006 -0700
@@ -0,0 +1,79 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * adl.h - ADL player adaption by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_ADPLUG_ADLPLAYER
+#define H_ADPLUG_ADLPLAYER
+
+#include <inttypes.h>
+
+#include "player.h"
+
+class AdlibDriver;
+
+class CadlPlayer: public CPlayer
+{
+ public:
+  static CPlayer *factory(Copl *newopl);
+
+  CadlPlayer(Copl *newopl);
+  ~CadlPlayer();
+
+  bool load(const std::string &filename, const CFileProvider &fp);
+  bool update();
+  void rewind(int subsong);
+
+  // refresh rate is fixed at 72Hz
+  float getrefresh()
+    {
+      return 72.0f;
+    }
+
+  unsigned int getsubsongs();
+  std::string gettype() { return std::string("Westwood ADL"); }
+
+ private:
+  int numsubsongs, cursubsong;
+
+  AdlibDriver *_driver;
+
+  uint8_t _trackEntries[120];
+  uint8_t *_soundDataPtr;
+  int _sfxPlayingSound;
+
+  uint8_t _sfxPriority;
+  uint8_t _sfxFourthByteOfSong;
+
+  int _numSoundTriggers;
+  const int *_soundTriggers;
+
+  static const int _kyra1NumSoundTriggers;
+  static const int _kyra1SoundTriggers[];
+
+  bool init();
+  void process();
+  void playTrack(uint8_t track);
+  void playSoundEffect(uint8_t track);
+  void play(uint8_t track);
+  void unk1();
+  void unk2();
+};
+
+#endif
--- a/Plugins/Input/adplug/core/adplug.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/adplug.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -63,6 +63,7 @@
 #include "dro.h"
 #include "msc.h"
 #include "rix.h"
+#include "adl.h"
 
 /***** Defines *****/
 
@@ -108,6 +109,7 @@
   CPlayerDesc(CdroPlayer::factory, "DOSBox Raw OPL", ".dro\0"),
   CPlayerDesc(CmscPlayer::factory, "Adlib MSC Player", ".msc\0"),
   CPlayerDesc(CrixPlayer::factory, "Softstar RIX OPL Music", ".rix\0"),
+  CPlayerDesc(CadlPlayer::factory, "Westwood ADL", ".adl\0"),
   CPlayerDesc()
 };
 
--- a/Plugins/Input/adplug/core/amd.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/amd.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -36,7 +36,7 @@
 		char id[9];
 		unsigned char version;
 	} header;
-	int i, j, k, t, numtrax;
+	int i, j, k, t, numtrax, maxi = 0;
 	unsigned char buf, buf2, buf3;
 	const unsigned char convfx[10] = {0,1,2,9,17,11,13,18,3,14};
 
@@ -60,6 +60,7 @@
 	for(i=0;i<128;i++) order[i] = f->readInt(1);
 	f->seek(10, binio::Add);
 	if(header.version == 0x10) {	// unpacked module
+	maxi = nop * 9;
 		for(i=0;i<64*9;i++)
 			trackord[i/9][i%9] = i+1;
 		t = 0;
@@ -89,6 +90,7 @@
 		for(k=0;k<numtrax;k++) {
 			i = f->readInt(2);
 			if(i > 575) i = 575;	// fix corrupted modules
+			maxi = (i + 1 > maxi ? i + 1 : maxi);
 			j = 0;
 			do {
 				buf = f->readInt(1);
@@ -144,15 +146,17 @@
 			if(instname[i][j] == '\xff')
 				instname[i][j] = '\x20';
 	}
-	for(i=0;i<nop*9;i++)	// convert patterns
+  for(i=0;i<maxi;i++)	// convert patterns
 		for(j=0;j<64;j++) {
 			tracks[i][j].command = convfx[tracks[i][j].command];
+			// extended command
 			if(tracks[i][j].command == 14) {
 				if(tracks[i][j].param1 == 2) {
 					tracks[i][j].command = 10;
 					tracks[i][j].param1 = tracks[i][j].param2;
 					tracks[i][j].param2 = 0;
 				}
+
 				if(tracks[i][j].param1 == 3) {
 					tracks[i][j].command = 10;
 					tracks[i][j].param1 = 0;
--- a/Plugins/Input/adplug/core/bmf.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/bmf.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2003, 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -251,7 +251,9 @@
 	  {
         memcpy(&event, &bmf.streams[i][bmf.channel[i].stream_position], sizeof(bmf_event));
 #ifdef DEBUG
-   AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X\n",event.note,event.delay,event.volume,event.instrument,event.cmd,event.cmd_data );
+   AdPlug_LogWrite("%02X %02X %02X %02X %02X %02X\n",
+		   event.note,event.delay,event.volume,event.instrument,
+		   event.cmd,event.cmd_data);
 #endif
 
         if (event.cmd == 0xFF)
--- a/Plugins/Input/adplug/core/d00.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/d00.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,7 @@
 
 #include <string.h>
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "debug.h"
 #include "d00.h"
@@ -37,7 +38,13 @@
 #define LOBYTE(val)	(val & 0xff)
 
 static const unsigned short notetable[12] =	// D00 note table
-			{340,363,385,408,432,458,485,514,544,577,611,647};
+  {340,363,385,408,432,458,485,514,544,577,611,647};
+
+static inline uint16_t LE_WORD(const uint16_t *val)
+{
+  const uint8_t *b = (const uint8_t *)val;
+  return (b[1] << 8) + b[0];
+}
 
 /*** public methods *************************************/
 
@@ -48,480 +55,484 @@
 
 bool Cd00Player::load(const std::string &filename, const CFileProvider &fp)
 {
-        binistream	*f = fp.open(filename); if(!f) return false;
-	d00header	*checkhead;
-	d00header1	*ch;
-	unsigned long	filesize;
-	int		i,ver1=0;
-	char		*str;
+  binistream	*f = fp.open(filename); if(!f) return false;
+  d00header	*checkhead;
+  d00header1	*ch;
+  unsigned long	filesize;
+  int		i,ver1=0;
+  char		*str;
 
-	// file validation section
-	checkhead = new d00header;
-	f->readString((char *)checkhead, sizeof(d00header));
+  // file validation section
+  checkhead = new d00header;
+  f->readString((char *)checkhead, sizeof(d00header));
 
-	// Check for version 2-4 header
-	if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type ||
-	   !checkhead->subsongs || checkhead->soundcard) {
-	  // Check for version 0 or 1 header (and .d00 file extension)
-		delete checkhead;
-		if(!fp.extension(filename, ".d00")) { fp.close(f); return false; }
-		ch = new d00header1;
-		f->seek(0); f->readString((char *)ch, sizeof(d00header1));
-		if(ch->version > 1 || !ch->subsongs)
-		  { delete ch; fp.close(f); return false; }
-		delete ch;
-		ver1 = 1;
-	} else
-		delete checkhead;
+  // Check for version 2-4 header
+  if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type ||
+     !checkhead->subsongs || checkhead->soundcard) {
+    // Check for version 0 or 1 header (and .d00 file extension)
+    delete checkhead;
+    if(!fp.extension(filename, ".d00")) { fp.close(f); return false; }
+    ch = new d00header1;
+    f->seek(0); f->readString((char *)ch, sizeof(d00header1));
+    if(ch->version > 1 || !ch->subsongs)
+      { delete ch; fp.close(f); return false; }
+    delete ch;
+    ver1 = 1;
+  } else
+    delete checkhead;
 
-	AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n",
-			filename.c_str(), ver1 ? "Old" : "New");
+  AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n",
+		  filename.c_str(), ver1 ? "Old" : "New");
 
-	// load section
-	filesize = fp.filesize(f); f->seek(0);
-	filedata = new char [filesize + 1];			// 1 byte is needed for old-style DataInfo block
-	f->readString((char *)filedata, filesize);
-	fp.close(f);
-	if(!ver1) {	// version 2 and above
-		header = (struct d00header *)filedata;
-		version = header->version;
-		datainfo = (char *)filedata + header->infoptr;
-		inst = (struct Sinsts *)((char *)filedata + header->instptr);
-		seqptr = (unsigned short *)((char *)filedata + header->seqptr);
-		for(i=31;i>=0;i--)	// erase whitespace
-			if(header->songname[i] == ' ')
-				header->songname[i] = '\0';
-			else
-				break;
-		for(i=31;i>=0;i--)
-			if(header->author[i] == ' ')
-				header->author[i] = '\0';
-			else
-				break;
-	} else {	// version 1
-		header1 = (struct d00header1 *)filedata;
-		version = header1->version;
-		datainfo = (char *)filedata + header1->infoptr;
-		inst = (struct Sinsts *)((char *)filedata + header1->instptr);
-		seqptr = (unsigned short *)((char *)filedata + header1->seqptr);
-	}
-	switch(version) {
-	case 0:
-		levpuls = 0;
-		spfx = 0;
-		header1->speed = 70;		// v0 files default to 70Hz
-		break;
-	case 1:
-		levpuls = (struct Slevpuls *)((char *)filedata + header1->lpulptr);
-		spfx = 0;
-		break;
-	case 2:
-		levpuls = (struct Slevpuls *)((char *)filedata + header->spfxptr);
-		spfx = 0;
-		break;
-	case 3:
-		spfx = 0;
-		levpuls = 0;
-		break;
-	case 4:
-		spfx = (struct Sspfx *)((char *)filedata + header->spfxptr);
-		levpuls = 0;
-		break;
-	}
-	if((str = strstr(datainfo,"\xff\xff")))
-		while((*str == '\xff' || *str == ' ') && str >= datainfo) {
-			*str = '\0'; str--;
-		}
-	else	// old-style block
-		memset((char *)filedata+filesize,0,1);
+  // load section
+  filesize = fp.filesize(f); f->seek(0);
+  filedata = new char [filesize + 1];			// 1 byte is needed for old-style DataInfo block
+  f->readString((char *)filedata, filesize);
+  fp.close(f);
+  if(!ver1) {	// version 2 and above
+    header = (struct d00header *)filedata;
+    version = header->version;
+    datainfo = (char *)filedata + LE_WORD(&header->infoptr);
+    inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header->instptr));
+    seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header->seqptr));
+    for(i=31;i>=0;i--)	// erase whitespace
+      if(header->songname[i] == ' ')
+	header->songname[i] = '\0';
+      else
+	break;
+    for(i=31;i>=0;i--)
+      if(header->author[i] == ' ')
+	header->author[i] = '\0';
+      else
+	break;
+  } else {	// version 1
+    header1 = (struct d00header1 *)filedata;
+    version = header1->version;
+    datainfo = (char *)filedata + LE_WORD(&header1->infoptr);
+    inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header1->instptr));
+    seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header1->seqptr));
+  }
+  switch(version) {
+  case 0:
+    levpuls = 0;
+    spfx = 0;
+    header1->speed = 70;		// v0 files default to 70Hz
+    break;
+  case 1:
+    levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header1->lpulptr));
+    spfx = 0;
+    break;
+  case 2:
+    levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header->spfxptr));
+    spfx = 0;
+    break;
+  case 3:
+    spfx = 0;
+    levpuls = 0;
+    break;
+  case 4:
+    spfx = (struct Sspfx *)((char *)filedata + LE_WORD(&header->spfxptr));
+    levpuls = 0;
+    break;
+  }
+  if((str = strstr(datainfo,"\xff\xff")))
+    while((*str == '\xff' || *str == ' ') && str >= datainfo) {
+      *str = '\0'; str--;
+    }
+  else	// old-style block
+    memset((char *)filedata+filesize,0,1);
 
-	rewind(0);
-	return true;
+  rewind(0);
+  return true;
 }
 
 bool Cd00Player::update()
 {
-	unsigned char	c,cnt,trackend=0,fx,note;
-	unsigned short	ord,*patt,buf,fxop;
+  unsigned char	c,cnt,trackend=0,fx,note;
+  unsigned short ord,*patt,buf,fxop,pattpos;
 
-	// effect handling (timer dependant)
-	for(c=0;c<9;c++) {
-		channel[c].slideval += channel[c].slide; setfreq(c);	// sliding
-		vibrato(c);	// vibrato
+  // effect handling (timer dependant)
+  for(c=0;c<9;c++) {
+    channel[c].slideval += channel[c].slide; setfreq(c);	// sliding
+    vibrato(c);	// vibrato
 
-		if(channel[c].spfx != 0xffff) {	// SpFX
-			if(channel[c].fxdel)
-				channel[c].fxdel--;
-			else {
-				channel[c].spfx = spfx[channel[c].spfx].ptr;
-				channel[c].fxdel = spfx[channel[c].spfx].duration;
-				channel[c].inst = spfx[channel[c].spfx].instnr & 0xfff;
-				if(spfx[channel[c].spfx].modlev != 0xff)
-					channel[c].modvol = spfx[channel[c].spfx].modlev;
-				setinst(c);
-				if(spfx[channel[c].spfx].instnr & 0x8000)	// locked frequency
-					note = spfx[channel[c].spfx].halfnote;
-				else												// unlocked frequency
-					note = spfx[channel[c].spfx].halfnote + channel[c].note;
-				channel[c].freq = notetable[note%12] + ((note/12) << 10);
-				setfreq(c);
-			}
-			channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63;
-			setvolume(c);
-		}
+    if(channel[c].spfx != 0xffff) {	// SpFX
+      if(channel[c].fxdel)
+	channel[c].fxdel--;
+      else {
+	channel[c].spfx = LE_WORD(&spfx[channel[c].spfx].ptr);
+	channel[c].fxdel = spfx[channel[c].spfx].duration;
+	channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff;
+	if(spfx[channel[c].spfx].modlev != 0xff)
+	  channel[c].modvol = spfx[channel[c].spfx].modlev;
+	setinst(c);
+	if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000)	// locked frequency
+	  note = spfx[channel[c].spfx].halfnote;
+	else							// unlocked frequency
+	  note = spfx[channel[c].spfx].halfnote + channel[c].note;
+	channel[c].freq = notetable[note%12] + ((note/12) << 10);
+	setfreq(c);
+      }
+      channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63;
+      setvolume(c);
+    }
 
-		if(channel[c].levpuls != 0xff)	// Levelpuls
-			if(channel[c].frameskip)
-				channel[c].frameskip--;
-			else {
-				channel[c].frameskip = inst[channel[c].inst].timer;
-				if(channel[c].fxdel)
-					channel[c].fxdel--;
-				else {
-					channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1;
-					channel[c].fxdel = levpuls[channel[c].levpuls].duration;
-					if(levpuls[channel[c].levpuls].level != 0xff)
-						channel[c].modvol = levpuls[channel[c].levpuls].level;
-				}
-				channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63;
-				setvolume(c);
-			}
+    if(channel[c].levpuls != 0xff)	// Levelpuls
+      if(channel[c].frameskip)
+	channel[c].frameskip--;
+      else {
+	channel[c].frameskip = inst[channel[c].inst].timer;
+	if(channel[c].fxdel)
+	  channel[c].fxdel--;
+	else {
+	  channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1;
+	  channel[c].fxdel = levpuls[channel[c].levpuls].duration;
+	  if(levpuls[channel[c].levpuls].level != 0xff)
+	    channel[c].modvol = levpuls[channel[c].levpuls].level;
 	}
+	channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63;
+	setvolume(c);
+      }
+  }
 
-	// song handling
-	for(c=0;c<9;c++)
-		if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) {
-			if(version == 4)	// v4: hard restart SR
-				if(channel[c].del == inst[channel[c].inst].timer)
-					if(channel[c].nextnote)
-						opl->write(0x83 + op_table[c], inst[channel[c].inst].sr);
-			if(version < 3)
-				channel[c].del--;
-			else
-				if(channel[c].speed)
-					channel[c].del += channel[c].speed;
-				else {
-					channel[c].seqend = 1;
-					continue;
-				}
-		} else {
-			if(channel[c].speed) {
-				if(version < 3)
-					channel[c].del = channel[c].speed;
-				else {
-					channel[c].del &= 0x7f;
-					channel[c].del += channel[c].speed;
-				}
-			} else {
-				channel[c].seqend = 1;
-				continue;
-			}
-			if(channel[c].rhcnt) {	// process pending REST/HOLD events
-				channel[c].rhcnt--;
-				continue;
-			}
-readorder:	// process arrangement (orderlist)
-			ord = channel[c].order[channel[c].ordpos];
-			switch(ord) {
-			case 0xfffe: channel[c].seqend = 1; continue;	// end of arrangement stream
-			case 0xffff:										// jump to order
-				channel[c].ordpos = channel[c].order[channel[c].ordpos+1];
-				channel[c].seqend = 1;
-				goto readorder;
-			default:
-				if(ord >= 0x9000) {		// set speed
-					channel[c].speed = ord & 0xff;
-					ord = channel[c].order[channel[c].ordpos - 1];
-					channel[c].ordpos++;
-				} else
-					if(ord >= 0x8000) {	// transpose track
-						channel[c].transpose = ord & 0xff;
-						if(ord & 0x100)
-							channel[c].transpose = -channel[c].transpose;
-						ord = channel[c].order[++channel[c].ordpos];
-					}
-				patt = (unsigned short *)((char *)filedata + seqptr[ord]);
-				break;
-			}
-readseq:	// process sequence (pattern)
-			if(!version)	// v0: always initialize rhcnt
-				channel[c].rhcnt = channel[c].irhcnt;
-			if(patt[channel[c].pattpos] == 0xffff) {	// pattern ended?
-				channel[c].pattpos = 0;
-				channel[c].ordpos++;
-				goto readorder;
-			}
-			cnt = HIBYTE(patt[channel[c].pattpos]);
-			note = LOBYTE(patt[channel[c].pattpos]);
-			fx = patt[channel[c].pattpos] >> 12;
-			fxop = patt[channel[c].pattpos] & 0x0fff;
-			channel[c].pattpos++;
-			channel[c].nextnote = LOBYTE(patt[channel[c].pattpos]) & 0x7f;
-			if(version ? cnt < 0x40 : !fx) {	// note event
-				switch(note) {
-				case 0:						// REST event
-				case 0x80:
-					if(!note || version) {
-						channel[c].key = 0;
-						setfreq(c);
-					}
-					// fall through...
-				case 0x7e:					// HOLD event
-					if(version)
-						channel[c].rhcnt = cnt;
-					channel[c].nextnote = 0;
-					break;
-				default:					// play note
-					channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0;	// restart fx
+  // song handling
+  for(c=0;c<9;c++)
+    if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) {
+      if(version == 4)	// v4: hard restart SR
+	if(channel[c].del == inst[channel[c].inst].timer)
+	  if(channel[c].nextnote)
+	    opl->write(0x83 + op_table[c], inst[channel[c].inst].sr);
+      if(version < 3)
+	channel[c].del--;
+      else
+	if(channel[c].speed)
+	  channel[c].del += channel[c].speed;
+	else {
+	  channel[c].seqend = 1;
+	  continue;
+	}
+    } else {
+      if(channel[c].speed) {
+	if(version < 3)
+	  channel[c].del = channel[c].speed;
+	else {
+	  channel[c].del &= 0x7f;
+	  channel[c].del += channel[c].speed;
+	}
+      } else {
+	channel[c].seqend = 1;
+	continue;
+      }
+      if(channel[c].rhcnt) {	// process pending REST/HOLD events
+	channel[c].rhcnt--;
+	continue;
+      }
+    readorder:	// process arrangement (orderlist)
+      ord = LE_WORD(&channel[c].order[channel[c].ordpos]);
+      switch(ord) {
+      case 0xfffe: channel[c].seqend = 1; continue;	// end of arrangement stream
+      case 0xffff:		// jump to order
+	channel[c].ordpos = LE_WORD(&channel[c].order[channel[c].ordpos + 1]);
+	channel[c].seqend = 1;
+	goto readorder;
+      default:
+	if(ord >= 0x9000) {	// set speed
+	  channel[c].speed = ord & 0xff;
+	  ord = LE_WORD(&channel[c].order[channel[c].ordpos - 1]);
+	  channel[c].ordpos++;
+	} else
+	  if(ord >= 0x8000) {	// transpose track
+	    channel[c].transpose = ord & 0xff;
+	    if(ord & 0x100)
+	      channel[c].transpose = -channel[c].transpose;
+	    ord = LE_WORD(&channel[c].order[++channel[c].ordpos]);
+	  }
+	patt = (unsigned short *)((char *)filedata + LE_WORD(&seqptr[ord]));
+	break;
+      }
+    readseq:	// process sequence (pattern)
+      if(!version)	// v0: always initialize rhcnt
+	channel[c].rhcnt = channel[c].irhcnt;
+      pattpos = LE_WORD(&patt[channel[c].pattpos]);
+      if(pattpos == 0xffff) {	// pattern ended?
+	channel[c].pattpos = 0;
+	channel[c].ordpos++;
+	goto readorder;
+      }
+      cnt = HIBYTE(pattpos);
+      note = LOBYTE(pattpos);
+      fx = pattpos >> 12;
+      fxop = pattpos & 0x0fff;
+      channel[c].pattpos++; pattpos = LE_WORD(&patt[channel[c].pattpos]);
+      channel[c].nextnote = LOBYTE(pattpos) & 0x7f;
+      if(version ? cnt < 0x40 : !fx) {	// note event
+	switch(note) {
+	case 0:						// REST event
+	case 0x80:
+	  if(!note || version) {
+	    channel[c].key = 0;
+	    setfreq(c);
+	  }
+	  // fall through...
+	case 0x7e:					// HOLD event
+	  if(version)
+	    channel[c].rhcnt = cnt;
+	  channel[c].nextnote = 0;
+	  break;
+	default:					// play note
+	  // restart fx
+	  channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0;
 
-					if(version) {	// note handling for v1 and above
-						if(note > 0x80)	// locked note (no channel transpose)
-							note -= 0x80;
-						else			// unlocked note
-							note += channel[c].transpose;
-						channel[c].note = note;	// remember note for SpFX
+	  if(version) {	// note handling for v1 and above
+	    if(note > 0x80)	// locked note (no channel transpose)
+	      note -= 0x80;
+	    else			// unlocked note
+	      note += channel[c].transpose;
+	    channel[c].note = note;	// remember note for SpFX
 
-						if(channel[c].ispfx != 0xffff && cnt < 0x20) {	// reset SpFX
-							channel[c].spfx = channel[c].ispfx;
-							if(spfx[channel[c].spfx].instnr & 0x8000)	// locked frequency
-								note = spfx[channel[c].spfx].halfnote;
-							else												// unlocked frequency
-								note += spfx[channel[c].spfx].halfnote;
-							channel[c].inst = spfx[channel[c].spfx].instnr & 0xfff;
-							channel[c].fxdel = spfx[channel[c].spfx].duration;
-							if(spfx[channel[c].spfx].modlev != 0xff)
-								channel[c].modvol = spfx[channel[c].spfx].modlev;
-							else
-								channel[c].modvol = inst[channel[c].inst].data[7] & 63;
-						}
+	    if(channel[c].ispfx != 0xffff && cnt < 0x20) {	// reset SpFX
+	      channel[c].spfx = channel[c].ispfx;
+	      if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000)	// locked frequency
+		note = spfx[channel[c].spfx].halfnote;
+	      else												// unlocked frequency
+		note += spfx[channel[c].spfx].halfnote;
+	      channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff;
+	      channel[c].fxdel = spfx[channel[c].spfx].duration;
+	      if(spfx[channel[c].spfx].modlev != 0xff)
+		channel[c].modvol = spfx[channel[c].spfx].modlev;
+	      else
+		channel[c].modvol = inst[channel[c].inst].data[7] & 63;
+	    }
 
-						if(channel[c].ilevpuls != 0xff && cnt < 0x20) {	// reset LevelPuls
-							channel[c].levpuls = channel[c].ilevpuls;
-							channel[c].fxdel = levpuls[channel[c].levpuls].duration;
-							channel[c].frameskip = inst[channel[c].inst].timer;
-							if(levpuls[channel[c].levpuls].level != 0xff)
-								channel[c].modvol = levpuls[channel[c].levpuls].level;
-							else
-								channel[c].modvol = inst[channel[c].inst].data[7] & 63;
-						}
+	    if(channel[c].ilevpuls != 0xff && cnt < 0x20) {	// reset LevelPuls
+	      channel[c].levpuls = channel[c].ilevpuls;
+	      channel[c].fxdel = levpuls[channel[c].levpuls].duration;
+	      channel[c].frameskip = inst[channel[c].inst].timer;
+	      if(levpuls[channel[c].levpuls].level != 0xff)
+		channel[c].modvol = levpuls[channel[c].levpuls].level;
+	      else
+		channel[c].modvol = inst[channel[c].inst].data[7] & 63;
+	    }
 
-						channel[c].freq = notetable[note%12] + ((note/12) << 10);
-						if(cnt < 0x20)	// normal note
-							playnote(c);
-						else {			// tienote
-							setfreq(c);
-							cnt -= 0x20;	// make count proper
-						}
-						channel[c].rhcnt = cnt;
-					} else {	// note handling for v0
-						if(cnt < 2)	// unlocked note
-							note += channel[c].transpose;
-						channel[c].note = note;
+	    channel[c].freq = notetable[note%12] + ((note/12) << 10);
+	    if(cnt < 0x20)	// normal note
+	      playnote(c);
+	    else {			// tienote
+	      setfreq(c);
+	      cnt -= 0x20;	// make count proper
+	    }
+	    channel[c].rhcnt = cnt;
+	  } else {	// note handling for v0
+	    if(cnt < 2)	// unlocked note
+	      note += channel[c].transpose;
+	    channel[c].note = note;
 
-						channel[c].freq = notetable[note%12] + ((note/12) << 10);
-						if(cnt == 1)	// tienote
-							setfreq(c);
-						else			// normal note
-							playnote(c);
-					}
-					break;
-				}
-				continue;	// event is complete
-			} else {		// effect event
-				switch(fx) {
-				case 6:		// Cut/Stop Voice
-					buf = channel[c].inst;
-					channel[c].inst = 0;
-					playnote(c);
-					channel[c].inst = buf;
-					channel[c].rhcnt = fxop;
-					continue;	// no note follows this event
-				case 7:		// Vibrato
-					channel[c].vibspeed = fxop & 0xff;
-					channel[c].vibdepth = fxop >> 8;
-					channel[c].trigger = fxop >> 9;
-					break;
-				case 8:		// v0: Duration
-					if(!version)
-						channel[c].irhcnt = fxop;
-					break;
-				case 9:		// New Level
-					channel[c].vol = fxop & 63;
-					if(channel[c].vol + channel[c].cvol < 63)	// apply channel volume
-						channel[c].vol += channel[c].cvol;
-					else
-						channel[c].vol = 63;
-					setvolume(c);
-					break;
-				case 0xb:	// v4: Set SpFX
-					if(version == 4)
-						channel[c].ispfx = fxop;
-					break;
-				case 0xc:	// Set Instrument
-					channel[c].ispfx = 0xffff;
-					channel[c].spfx = 0xffff;
-					channel[c].inst = fxop;
-					channel[c].modvol = inst[fxop].data[7] & 63;
-					if(version < 3 && version && inst[fxop].tunelev)	// Set LevelPuls
-						channel[c].ilevpuls = inst[fxop].tunelev - 1;
-					else {
-						channel[c].ilevpuls = 0xff;
-						channel[c].levpuls = 0xff;
-					}
-					break;
-				case 0xd:	// Slide up
-					channel[c].slide = fxop;
-					break;
-				case 0xe:	// Slide down
-					channel[c].slide = -fxop;
-					break;
-				}
-				goto readseq;	// event is incomplete, note follows
-			}
-		}
+	    channel[c].freq = notetable[note%12] + ((note/12) << 10);
+	    if(cnt == 1)	// tienote
+	      setfreq(c);
+	    else			// normal note
+	      playnote(c);
+	  }
+	  break;
+	}
+	continue;	// event is complete
+      } else {		// effect event
+	switch(fx) {
+	case 6:		// Cut/Stop Voice
+	  buf = channel[c].inst;
+	  channel[c].inst = 0;
+	  playnote(c);
+	  channel[c].inst = buf;
+	  channel[c].rhcnt = fxop;
+	  continue;	// no note follows this event
+	case 7:		// Vibrato
+	  channel[c].vibspeed = fxop & 0xff;
+	  channel[c].vibdepth = fxop >> 8;
+	  channel[c].trigger = fxop >> 9;
+	  break;
+	case 8:		// v0: Duration
+	  if(!version)
+	    channel[c].irhcnt = fxop;
+	  break;
+	case 9:		// New Level
+	  channel[c].vol = fxop & 63;
+	  if(channel[c].vol + channel[c].cvol < 63)	// apply channel volume
+	    channel[c].vol += channel[c].cvol;
+	  else
+	    channel[c].vol = 63;
+	  setvolume(c);
+	  break;
+	case 0xb:	// v4: Set SpFX
+	  if(version == 4)
+	    channel[c].ispfx = fxop;
+	  break;
+	case 0xc:	// Set Instrument
+	  channel[c].ispfx = 0xffff;
+	  channel[c].spfx = 0xffff;
+	  channel[c].inst = fxop;
+	  channel[c].modvol = inst[fxop].data[7] & 63;
+	  if(version < 3 && version && inst[fxop].tunelev)	// Set LevelPuls
+	    channel[c].ilevpuls = inst[fxop].tunelev - 1;
+	  else {
+	    channel[c].ilevpuls = 0xff;
+	    channel[c].levpuls = 0xff;
+	  }
+	  break;
+	case 0xd:	// Slide up
+	  channel[c].slide = fxop;
+	  break;
+	case 0xe:	// Slide down
+	  channel[c].slide = -fxop;
+	  break;
+	}
+	goto readseq;	// event is incomplete, note follows
+      }
+    }
 
-	for(c=0;c<9;c++)
-		if(channel[c].seqend)
-			trackend++;
-	if(trackend == 9)
-		songend = 1;
+  for(c=0;c<9;c++)
+    if(channel[c].seqend)
+      trackend++;
+  if(trackend == 9)
+    songend = 1;
 
-	return !songend;
+  return !songend;
 }
 
 void Cd00Player::rewind(int subsong)
 {
-	struct Stpoin {
-		unsigned short ptr[9];
-		unsigned char volume[9],dummy[5];
-	} *tpoin;
-	int i;
+  struct Stpoin {
+    unsigned short ptr[9];
+    unsigned char volume[9],dummy[5];
+  } *tpoin;
+  int i;
 
-	if(version > 1) {	// do nothing if subsong > number of subsongs
-		if(subsong >= header->subsongs)
-			return;
-	} else
-		if(subsong >= header1->subsongs)
-			return;
+  if(version > 1) {	// do nothing if subsong > number of subsongs
+    if(subsong >= header->subsongs)
+      return;
+  } else
+    if(subsong >= header1->subsongs)
+      return;
 
-	memset(channel,0,sizeof(channel));
-	if(version > 1)
-		tpoin = (struct Stpoin *)((char *)filedata + header->tpoin);
-	else
-		tpoin = (struct Stpoin *)((char *)filedata + header1->tpoin);
-	for(i=0;i<9;i++) {
-		if(tpoin[subsong].ptr[i]) {	// track enabled
-			channel[i].speed = *((unsigned short *)((char *)filedata + tpoin[subsong].ptr[i]));
-			channel[i].order = (unsigned short *)((char *)filedata + tpoin[subsong].ptr[i] + 2);
-		} else {					// track disabled
-			channel[i].speed = 0;
-			channel[i].order = 0;
-		}
-		channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff;	// no SpFX
-		channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff;	// no LevelPuls
-		channel[i].cvol = tpoin[subsong].volume[i] & 0x7f;			// our player may savely ignore bit 7
-		channel[i].vol = channel[i].cvol;						// initialize volume
-	}
-	songend = 0;
-	opl->init(); opl->write(1,32);	// reset OPL chip
+  memset(channel,0,sizeof(channel));
+  if(version > 1)
+    tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header->tpoin));
+  else
+    tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header1->tpoin));
+  for(i=0;i<9;i++) {
+    if(LE_WORD(&tpoin[subsong].ptr[i])) {	// track enabled
+      channel[i].speed = LE_WORD((unsigned short *)
+				 ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i])));
+      channel[i].order = (unsigned short *)
+	((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]) + 2);
+    } else {					// track disabled
+      channel[i].speed = 0;
+      channel[i].order = 0;
+    }
+    channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff;	// no SpFX
+    channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff;	// no LevelPuls
+    channel[i].cvol = tpoin[subsong].volume[i] & 0x7f;	// our player may savely ignore bit 7
+    channel[i].vol = channel[i].cvol;			// initialize volume
+  }
+  songend = 0;
+  opl->init(); opl->write(1,32);	// reset OPL chip
 }
 
 std::string Cd00Player::gettype()
 {
-	char	tmpstr[40];
+  char	tmpstr[40];
 
-	sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version);
-	return std::string(tmpstr);
+  sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version);
+  return std::string(tmpstr);
 }
 
 float Cd00Player::getrefresh()
 {
-	if(version > 1)
-		return header->speed;
-	else
-		return header1->speed;
+  if(version > 1)
+    return header->speed;
+  else
+    return header1->speed;
 }
 
 unsigned int Cd00Player::getsubsongs()
 {
-	if(version <= 1)	// return number of subsongs
-		return header1->subsongs;
-	else
-		return header->subsongs;
+  if(version <= 1)	// return number of subsongs
+    return header1->subsongs;
+  else
+    return header->subsongs;
 }
 
 /*** private methods *************************************/
 
 void Cd00Player::setvolume(unsigned char chan)
 {
-	unsigned char	op = op_table[chan];
-	unsigned short	insnr = channel[chan].inst;
+  unsigned char	op = op_table[chan];
+  unsigned short	insnr = channel[chan].inst;
 
-	opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) +
-		(inst[insnr].data[2] & 192));
-	if(inst[insnr].data[10] & 1)
-		opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) +
-			(inst[insnr].data[7] & 192));
-	else
-		opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192));
+  opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) +
+	     (inst[insnr].data[2] & 192));
+  if(inst[insnr].data[10] & 1)
+    opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) +
+	       (inst[insnr].data[7] & 192));
+  else
+    opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192));
 }
 
 void Cd00Player::setfreq(unsigned char chan)
 {
-	unsigned short freq = channel[chan].freq;
+  unsigned short freq = channel[chan].freq;
 
-	if(version == 4)	// v4: apply instrument finetune
-		freq += inst[channel[chan].inst].tunelev;
+  if(version == 4)	// v4: apply instrument finetune
+    freq += inst[channel[chan].inst].tunelev;
 
-	freq += channel[chan].slideval;
-	opl->write(0xa0 + chan, freq & 255);
-	if(channel[chan].key)
-		opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32);
-	else
-		opl->write(0xb0 + chan, (freq >> 8) & 31);
+  freq += channel[chan].slideval;
+  opl->write(0xa0 + chan, freq & 255);
+  if(channel[chan].key)
+    opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32);
+  else
+    opl->write(0xb0 + chan, (freq >> 8) & 31);
 }
 
 void Cd00Player::setinst(unsigned char chan)
 {
-	unsigned char	op = op_table[chan];
-	unsigned short	insnr = channel[chan].inst;
+  unsigned char	op = op_table[chan];
+  unsigned short	insnr = channel[chan].inst;
 
-	// set instrument data
-	opl->write(0x63 + op, inst[insnr].data[0]);
-	opl->write(0x83 + op, inst[insnr].data[1]);
-	opl->write(0x23 + op, inst[insnr].data[3]);
-	opl->write(0xe3 + op, inst[insnr].data[4]);
-	opl->write(0x60 + op, inst[insnr].data[5]);
-	opl->write(0x80 + op, inst[insnr].data[6]);
-	opl->write(0x20 + op, inst[insnr].data[8]);
-	opl->write(0xe0 + op, inst[insnr].data[9]);
-	if(version)
-		opl->write(0xc0 + chan, inst[insnr].data[10]);
-	else
-		opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1));
+  // set instrument data
+  opl->write(0x63 + op, inst[insnr].data[0]);
+  opl->write(0x83 + op, inst[insnr].data[1]);
+  opl->write(0x23 + op, inst[insnr].data[3]);
+  opl->write(0xe3 + op, inst[insnr].data[4]);
+  opl->write(0x60 + op, inst[insnr].data[5]);
+  opl->write(0x80 + op, inst[insnr].data[6]);
+  opl->write(0x20 + op, inst[insnr].data[8]);
+  opl->write(0xe0 + op, inst[insnr].data[9]);
+  if(version)
+    opl->write(0xc0 + chan, inst[insnr].data[10]);
+  else
+    opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1));
 }
 
 void Cd00Player::playnote(unsigned char chan)
 {
-	// set misc vars & play
-	opl->write(0xb0 + chan, 0);	// stop old note
-	setinst(chan);
-	channel[chan].key = 1;
-	setfreq(chan);
-	setvolume(chan);
+  // set misc vars & play
+  opl->write(0xb0 + chan, 0);	// stop old note
+  setinst(chan);
+  channel[chan].key = 1;
+  setfreq(chan);
+  setvolume(chan);
 }
 
 void Cd00Player::vibrato(unsigned char chan)
 {
-	if(!channel[chan].vibdepth)
-		return;
+  if(!channel[chan].vibdepth)
+    return;
 
-	if(channel[chan].trigger)
-		channel[chan].trigger--;
-	else {
-		channel[chan].trigger = channel[chan].vibdepth;
-		channel[chan].vibspeed = -channel[chan].vibspeed;
-	}
-	channel[chan].freq += channel[chan].vibspeed;
-	setfreq(chan);
+  if(channel[chan].trigger)
+    channel[chan].trigger--;
+  else {
+    channel[chan].trigger = channel[chan].vibdepth;
+    channel[chan].vibspeed = -channel[chan].vibspeed;
+  }
+  channel[chan].freq += channel[chan].vibspeed;
+  setfreq(chan);
 }
--- a/Plugins/Input/adplug/core/d00.h	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/d00.h	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * AdPlug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,7 +26,7 @@
 
 class Cd00Player: public CPlayer
 {
-public:
+ public:
   static CPlayer *factory(Copl *newopl);
 
 	Cd00Player(Copl *newopl)
@@ -49,7 +49,7 @@
 	{ if(*datainfo) return std::string(datainfo); else return std::string(); };
 	unsigned int getsubsongs();
 
-protected:
+ protected:
 #pragma pack(1)
 	struct d00header {
 		char id[6];
@@ -96,7 +96,7 @@
 	d00header1 *header1;
 	char *filedata;
 
-private:
+ private:
 	void setvolume(unsigned char chan);
 	void setfreq(unsigned char chan);
 	void setinst(unsigned char chan);
--- a/Plugins/Input/adplug/core/ksm.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/ksm.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -50,7 +50,6 @@
   if(!fp.extension(filename, ".ksm")) {
     AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' "
 		    "extension! Rejected!\n", filename.c_str());
-    delete [] fn;
     return false;
   }
   AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str());
@@ -98,7 +97,7 @@
 
 bool CksmPlayer::update()
 {
-	int quanter,chan=0,drumnum=0,freq,track,volevel,volval;
+  int quanter,chan,drumnum,freq,track,volevel,volval;
 	unsigned int i,j,bufnum;
 	unsigned long temp,templong;
 
@@ -113,7 +112,10 @@
 			if ((templong&192) == 0)
 			{
 				i = 0;
-				while (((chanfreq[i] != (templong&63)) || (chantrack[i] != ((templong>>8)&15))) && (i < numchans))
+
+	      while ((i < numchans) &&
+		     ((chanfreq[i] != (templong&63)) ||
+		      (chantrack[i] != ((templong>>8)&15))))
 					i++;
 				if (i < numchans)
 				{
--- a/Plugins/Input/adplug/core/msc.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/msc.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,30 +22,28 @@
 #include <stdio.h>
 
 #include "msc.h"
+#include "debug.h"
 
 const unsigned char CmscPlayer::msc_signature [MSC_SIGN_LEN] = {
 	'C', 'e', 'r', 'e', 's', ' ', '\x13', ' ',
 	'M', 'S', 'C', 'p', 'l', 'a', 'y', ' ' };
 
-
 /*** public methods *************************************/
 
-CPlayer *
-CmscPlayer::factory (Copl * newopl)
+CPlayer *CmscPlayer::factory (Copl * newopl)
 {
 	return new CmscPlayer (newopl);
 }
 
-	
-CmscPlayer::CmscPlayer (Copl * newopl) : CPlayer (newopl) {
+CmscPlayer::CmscPlayer(Copl * newopl) : CPlayer (newopl)
+{
 	desc = NULL;
 	msc_data = NULL;
 	raw_data = NULL;
 	nr_blocks = 0;
 }
 
-
-CmscPlayer::~CmscPlayer ()
+CmscPlayer::~CmscPlayer()
 {
 	if (raw_data != NULL)
 		delete [] raw_data;
@@ -64,9 +62,7 @@
 		delete [] desc;
 }
 
-
-bool 
-CmscPlayer::load (const std::string & filename, const CFileProvider & fp)
+bool CmscPlayer::load(const std::string & filename, const CFileProvider & fp)
 {
 	binistream * 	bf;
 	msc_header	hdr;
@@ -115,9 +111,7 @@
 	return true;	
 }
 
-
-bool 
-CmscPlayer::update ()
+bool CmscPlayer::update()
 {
 	// output data
 	while (! delay) {
@@ -156,9 +150,7 @@
 	return true;
 }
 
-
-void 
-CmscPlayer::rewind (int subsong)
+void CmscPlayer::rewind(int subsong)
 {
 	// reset state
 	dec_prefix = 0;
@@ -169,32 +161,27 @@
 	delay = 0;
 	
 	// init the OPL chip and go to OPL2 mode
-	opl->init (); 
-	opl->write (1, 32);
+  opl->init();
+  opl->write(1, 32);
 }
 
-
-float 
-CmscPlayer::getrefresh ()
+float CmscPlayer::getrefresh()
 {
 	// PC timer oscillator frequency / wait register
 	return 1193180 / (float) (timer_div ? timer_div : 0xffff);
 }
 
-std::string
-CmscPlayer::gettype ()
+std::string CmscPlayer::gettype()
 {
 	char vstr [40];
 	
-	snprintf (vstr, sizeof (vstr), "AdLib MSCplay (version %d)", version);
+  sprintf(vstr, "AdLib MSCplay (version %d)", version);
 	return std::string (vstr);
 }
 
-
 /*** private methods *************************************/
 
-bool 
-CmscPlayer::load_header (binistream * bf, msc_header * hdr)
+bool CmscPlayer::load_header(binistream * bf, msc_header * hdr)
 {
 	// check signature
 	bf->readString ((char *) hdr->mh_sign, sizeof (hdr->mh_sign));
@@ -213,9 +200,7 @@
 	return true;
 }
 
-
-bool
-CmscPlayer::decode_octet (u8 * output)
+bool CmscPlayer::decode_octet(u8 * output)
 {
 	msc_block blk;			// compressed data block
 	
@@ -225,7 +210,7 @@
 	blk = msc_data [block_num];
 	while (1) {
 		u8 	octet;		// decoded octet
-		u8	len_corr = 0;	// length correction
+    u8	len_corr;	// length correction
 		
 		// advance to next block if necessary
 		if (block_pos >= blk.mb_length && dec_len == 0) {
@@ -288,7 +273,12 @@
 			
 		// prefix copy mode
 		case 255:
+      if((int)raw_pos >= dec_dist)
 			octet = raw_data [raw_pos - dec_dist];
+      else {
+	AdPlug_LogWrite("error! read before raw_data buffer.\n");
+	octet = 0;
+      }
 			
 			dec_len--;
 			if (dec_len == 0) {
--- a/Plugins/Input/adplug/core/protrack.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/protrack.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2002 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,16 +17,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * protrack.cpp - Generic Protracker Player
- * Copyright (C) 2000 - 2002 Simon Peter <dn.tlp@gmx.net>
  *
  * NOTES:
  * This is a generic Protracker-based formats player. It offers all Protracker
  * features, plus a good set of extensions to be compatible to other Protracker
  * derivatives. It is derived from the original SA2 player by me. If you got a
  * Protracker-like format, this is most certainly the player you want to use.
- *
- * USAGE:
- * Read the file 'Protracker.txt' in the 'doc' subdirectory.
  */
 
 #include "protrack.h"
@@ -37,11 +33,11 @@
 
 // SA2 compatible adlib note table
 const unsigned short CmodPlayer::sa2_notetable[12] =
-{340,363,385,408,432,458,485,514,544,577,611,647};
+  {340,363,385,408,432,458,485,514,544,577,611,647};
 
 // SA2 compatible vibrato rate table
 const unsigned char CmodPlayer::vibratotab[32] =
-{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
+  {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
 
 /*** public methods *************************************/
 
@@ -337,6 +333,7 @@
 	 			if(channel[chan].vol2 > 63)
 					channel[chan].vol2 = 63;
 			}
+
 			setvolume(chan);
 			break;
 		case 18: // AMD set speed
--- a/Plugins/Input/adplug/core/rix.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/rix.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -21,7 +21,7 @@
  */
 
 #include "rix.h"
-#include <binfile.h>
+#include "debug.h"
 
 const unsigned char CrixPlayer::adflag[] = {0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1};
 const unsigned char CrixPlayer::reg_data[] = {0,1,2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21};
@@ -53,12 +53,62 @@
 }
 
 CrixPlayer::CrixPlayer(Copl *newopl)
-  : CPlayer(newopl),I(0),T(0),mus_block(0),ins_block(0),rhythm(0),mutex(0),
-    music_on(0),pause_flag(0),band(0),band_low(0),e0_reg_flag(0),bd_modify(0),
-    sustain(0),dro_end(0), mstotal(0), opl3_mode(0)
+  : CPlayer(newopl), buf_addr(0)
+{
+}
+
+CrixPlayer::~CrixPlayer()
+{
+  if(buf_addr)
+    delete [] buf_addr;
+}
+
+bool CrixPlayer::load(const std::string &filename, const CFileProvider &fp)
 {
-  memset(dro, 0, 128000);
-  memset(buf_addr, 0, 327680);
+  binistream *f = fp.open(filename); if(!f) return false;
+  unsigned long i=0;
+
+  if(f->readInt(2)!=0x55aa) { fp.close(f);return false; }
+  buf_addr = new unsigned char [fp.filesize(f) + 1];
+  buf_addr[i++]=0xaa;buf_addr[i++]=0x55;
+  while(!f->eof())
+    buf_addr[i++]=f->readInt(1);
+  length=i;
+  fp.close(f);
+
+  rewind(0);
+  return true;
+}
+
+bool CrixPlayer::update()
+{
+	if (delay>100) {
+		delay-=100;   
+    return true;
+  } else delay=1;
+
+	int_08h_entry();
+	return !dro_end;
+}
+
+void CrixPlayer::rewind(int subsong)
+{
+  I = 0; T = 0;
+  mus_block = 0;
+  ins_block = 0;
+  rhythm = 0;
+  mutex = 0;
+  music_on = 0;
+  pause_flag = 0;
+  band = 0;
+  band_low = 0;
+  e0_reg_flag = 0;
+  bd_modify = 0;
+  delay = 1;
+  sustain = 0;
+  dro_end = 0;
+  pos = index = 0; 
+
   memset(buffer, 0, sizeof(unsigned short) * 300);
   memset(a0b0_data2, 0, sizeof(unsigned short) * 11);
   memset(a0b0_data3, 0, 18);
@@ -68,93 +118,17 @@
   memset(insbuf, 0, 28 * sizeof(unsigned short));
   memset(displace, 0, 11 * sizeof(unsigned short));
   memset(reg_bufs, 0, 18 * sizeof(ADDT));
-  memset(for40reg, 0, 18);
 
-  if(opl->gettype() == Copl::TYPE_OPL2)
-    opl3_mode = 0;
-  else
-    opl3_mode = 1;
-};
-
-bool CrixPlayer::load(const std::string &filename, const CFileProvider &fp)
-{
-  binistream *f = fp.open(filename); if(!f) return false;
-  unsigned long i=0;
-
-  if(f->readInt(2)!=0x55aa)	{fp.close(f);return false;	}
-  buf_addr[i++]=0xaa;buf_addr[i++]=0x55;
-  while(!f->eof())
-    buf_addr[i++]=f->readInt(1);
-  length=i;
-  fp.close(f);
+  opl->init(); 
+  opl->write(1,32);	// go to OPL2 mode
   set_new_int();
   data_initial();
-  while(!dro_end)
-    int_08h_entry();
-
-  length=T;
-  mode = (OplMode)1;		// Type of opl data this can contain
-	
-  //	binofstream *g=new binofstream(filename+string(".dro"));
-  //	g->writeString("DBRAWOPL",8);
-  //	g->writeInt(mstotal,4);
-  //	g->writeInt(length+1,4);
-  //	g->writeInt(1,1);
-  //	for(int t=0;t<length;t++)
-  //		g->writeInt(dro[t],1);
-  //	g->close();
-  //	delete g;
-
-  rewind(0);
-  return true;
-}
-
-bool CrixPlayer::update()
-{
-  if (delay>500) {
-    delay-=500;
-    return true;
-  } else delay=1;
-  while (pos < length) 
-    {	
-      unsigned char cmd = dro[pos++];
-      switch(cmd) {
-      case 0: 
-	delay = 1 + dro[pos++];
-	return true;
-      case 1: 
-	delay = 1 + dro[pos] + (dro[pos+1]<<8);
-	pos+=2;
-	return true;
-      case 2:
-	index = 0;
-	opl->setchip(0);
-	break;
-      case 3:
-	index = 1;
-	opl->setchip(1);
-	break;
-      default:
-	if(index == 0 || opl3_mode)
-	  opl->write(cmd,dro[pos++]);
-	break;
-      }
-    }
-  return pos<length;
-}
-
-void CrixPlayer::rewind(int subsong)
-{
-  delay=1;
-  pos = index = 0; 
-  opl->init(); 
-  opl->write(1,32);	// go to OPL2 mode
 }
 
 float CrixPlayer::getrefresh()
 {
-  if (delay > 500) return 1000 / 500;
-  else return 1000 / (double)delay;
+  if (delay > 100) return 1000 / 100;
+  else return 1000.0 / (double)delay;
 }
 
 /*------------------Implemention----------------------------*/
@@ -239,7 +213,9 @@
 /*----------------------------------------------------------*/
 inline void CrixPlayer::ad_bop(unsigned short reg,unsigned short value)
 {
-  dro[T++]=reg;dro[T++]=value;
+  if(reg == 2 || reg == 3)
+    AdPlug_LogWrite("switch OPL2/3 mode!\n");
+  opl->write(reg & 0xff, value & 0xff);
 }
 /*------------------------------------------------------*/
 inline unsigned short CrixPlayer::ad_test()   /* Test the SoundCard */
@@ -254,7 +230,7 @@
 }
 /*--------------------------------------------------------------*/
 inline void CrixPlayer::int_08h_entry()
-{
+  {   
   unsigned short band_sus = 1;
   while(band_sus)
     {
@@ -263,11 +239,7 @@
 	  mutex++;
 	  band_sus = rix_proc();
 	  if(band_sus) sustain += band_sus;
-	  mstotal+=sustain;
-	  dro[T++]=(sustain>=0x100?1:0);
-	  dro[T++]=sustain&0xff;
-	  if(sustain>=0x100)
-	    dro[T++]=(sustain>>8)&0xff;
+			delay=sustain;
 	  mutex--;
 	  if(band_sus == 0)
 	    {
@@ -277,11 +249,11 @@
 	}
       else
 	{
-	  if(band_sus) sustain -= 1; /* aging */
+            if(band_sus) sustain -= 9; /* aging */   
 	  break;
 	}
     }
-}
+  }   
 /*--------------------------------------------------------------*/
 inline unsigned short CrixPlayer::rix_proc()
 {
@@ -312,7 +284,13 @@
 /*--------------------------------------------------------------*/
 inline void CrixPlayer::rix_get_ins()
 {
-  memcpy(insbuf,(&buf_addr[ins_block])+(band_low<<6),56);
+  int		i;
+  unsigned char	*baddr = (&buf_addr[ins_block])+(band_low<<6);
+
+  for(i = 0; i < 28; i++)
+    insbuf[i] = (baddr[i * 2 + 1] << 8) + baddr[i * 2];
+
+//   memcpy(insbuf,(&buf_addr[ins_block])+(band_low<<6),56);
 }
 /*--------------------------------------------------------------*/
 inline void CrixPlayer::rix_90_pro(unsigned short ctrl_l)
--- a/Plugins/Input/adplug/core/rix.h	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/rix.h	Sat Jun 17 16:17:51 2006 -0700
@@ -28,7 +28,7 @@
   static CPlayer *factory(Copl *newopl);
 
   CrixPlayer(Copl *newopl);
-  ~CrixPlayer() {};
+  ~CrixPlayer();
 
   bool load(const std::string &filename, const CFileProvider &fp);
   bool update();
@@ -57,7 +57,7 @@
   unsigned char bd_modify;
   int sustain;
   int dro_end;
-  unsigned char buf_addr[327680];  /* rix files' buffer */
+  unsigned char *buf_addr;  /* rix files' buffer */
   unsigned short buffer[300];
   unsigned short a0b0_data2[11];
   unsigned char a0b0_data3[18];
@@ -68,12 +68,8 @@
   unsigned short displace[11];
   ADDT reg_bufs[18];
   unsigned long pos,length;
-  unsigned long msdone,mstotal;
+  unsigned char index;
   unsigned short delay;
-  unsigned char index, opl3_mode;
-  enum OplMode {
-    ModeOPL2,ModeOPL3,ModeDUALOPL2
-  } mode;
 
   static const unsigned char adflag[18];
   static const unsigned char reg_data[18];
--- a/Plugins/Input/adplug/core/u6m.cpp	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/u6m.cpp	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -60,7 +60,7 @@
 
     // load section
     song_data = new unsigned char[decompressed_filesize];
-    unsigned char* compressed_song_data = new unsigned char[filesize-4];
+    unsigned char* compressed_song_data = new unsigned char[filesize-3];
 
     f->seek(4);
     f->readString((char *)compressed_song_data, filesize - 4);
@@ -891,6 +891,11 @@
 }
 
 
+Cu6mPlayer::MyDict::~MyDict()
+{
+  delete [] dictionary;
+}
+
 // re-initializes the dictionary
 void Cu6mPlayer::MyDict::reset()
 {
--- a/Plugins/Input/adplug/core/u6m.h	Fri Jun 16 20:55:52 2006 -0700
+++ b/Plugins/Input/adplug/core/u6m.h	Sat Jun 17 16:17:51 2006 -0700
@@ -1,6 +1,6 @@
 /*
  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -52,7 +52,6 @@
         return std::string("Ultima 6 Music");
     };
 
-
     protected:
 
     struct byte_pair
@@ -93,6 +92,7 @@
         public:
         MyDict(); // use dictionary size of 4096
         MyDict(int); // let the caller specify a dictionary size
+      ~MyDict();
         void reset(); // re-initializes the dictionary
         void add(unsigned char, int);
         unsigned char get_root(int);