changeset 412:451d2dc68ba8 trunk

[svn] Support .cmf .sci & .laa without stealing .mid from timidity.
author chainsaw
date Mon, 09 Jan 2006 13:15:02 -0800
parents b13e87374f73
children 97ba91ee699e
files Plugins/Input/adplug/core/Makefile.am Plugins/Input/adplug/core/adplug.cpp Plugins/Input/adplug/core/mid.cpp Plugins/Input/adplug/core/mid.h Plugins/Input/adplug/core/mididata.h
diffstat 5 files changed, 1333 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Input/adplug/core/Makefile.am	Mon Jan 09 12:30:26 2006 -0800
+++ b/Plugins/Input/adplug/core/Makefile.am	Mon Jan 09 13:15:02 2006 -0800
@@ -3,9 +3,9 @@
 libadplugcore_la_SOURCES = adplug.cpp emuopl.cpp fmopl.c diskopl.cpp debug.c \
 debug.h fprovide.cpp player.cpp database.cpp hsc.cpp sng.cpp imf.cpp \
 players.cpp protrack.cpp a2m.cpp adtrack.cpp amd.cpp bam.cpp d00.cpp dfm.cpp dmo.cpp \
-hsp.cpp ksm.cpp mad.cpp mkj.cpp cff.cpp dtm.cpp fmc.cpp mtk.cpp rad.cpp raw.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
+rol.cpp xsm.cpp adlibemu.c dro.cpp lds.cpp middata.h
 
 # This is a hack. Throughout AdPlug, stricmp() is used to do caseless string
 # comparations. UNIX libc's don't support stricmp(), but do support the BSD
@@ -14,7 +14,7 @@
 AM_CPPFLAGS = -Dstricmp=strcasecmp
 
 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 mkj.h mtk.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
--- a/Plugins/Input/adplug/core/adplug.cpp	Mon Jan 09 12:30:26 2006 -0800
+++ b/Plugins/Input/adplug/core/adplug.cpp	Mon Jan 09 13:15:02 2006 -0800
@@ -39,6 +39,7 @@
 #include "hsp.h"
 #include "ksm.h"
 #include "mad.h"
+#include "mid.h"
 #include "mkj.h"
 #include "cff.h"
 #include "dmo.h" 	 
@@ -81,6 +82,7 @@
   CPlayerDesc(ChspLoader::factory, "HSC Packed", ".hsp\0"),
   CPlayerDesc(CksmPlayer::factory, "Ken Silverman Music", ".ksm\0"),
   CPlayerDesc(CmadLoader::factory, "Mlat Adlib Tracker", ".mad\0"),
+  CPlayerDesc(CmidPlayer::factory, "MIDI", ".cmf\0.sci\0.laa\0"),
   CPlayerDesc(CmkjPlayer::factory, "MKJamz", ".mkj\0"),
   CPlayerDesc(CcffLoader::factory, "Boomtracker", ".cff\0"),
   CPlayerDesc(CdmoLoader::factory, "TwinTeam", ".dmo\0"),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/adplug/core/mid.cpp	Mon Jan 09 13:15:02 2006 -0800
@@ -0,0 +1,1043 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2003 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
+ *
+ *
+ * MIDI & MIDI-like file player - Last Update: 8/16/2000
+ *                  by Phil Hassey - www.imitationpickles.org
+ *                                   philhassey@hotmail.com
+ *
+ * Can play the following
+ *      .LAA - a raw save of a Lucas Arts Adlib music
+ *             or
+ *             a raw save of a LucasFilm Adlib music
+ *      .CMF - Creative Music Format
+ *      .SCI - the sierra "midi" format.
+ *             Files must be in the form
+ *             xxxNAME.sci
+ *             So that the loader can load the right patch file:
+ *             xxxPATCH.003  (patch.003 must be saved from the
+ *                            sierra resource from each game.)
+ *
+ * 1/9/2006: audacious libadplug
+ *      Status:  MID not as fine as originally thought. Removing general MIDI detector so timidity handles these files instead.
+ *      
+ * 6/2/2000:  v1.0 relased by phil hassey
+ *      Status:  LAA is almost perfect
+ *                      - some volumes are a bit off (intrument too quiet)
+ *               MID is fine (who wants to listen to MIDI vid adlib anyway)
+ *               CMF is okay (still needs the adlib rythm mode implemented
+ *                            for real)
+ * 6/6/2000:
+ *      Status:  SCI:  there are two SCI formats, orginal and advanced.
+ *                    original:  (Found in SCI/EGA Sierra Adventures)
+ *                               played almost perfectly, I believe
+ *                               there is one mistake in the instrument
+ *                               loader that causes some sounds to
+ *                               not be quite right.  Most sounds are fine.
+ *                    advanced:  (Found in SCI/VGA Sierra Adventures)
+ *                               These are multi-track files.  (Thus the
+ *                               player had to be modified to work with
+ *                               them.)  This works fine.
+ *                               There are also multiple tunes in each file.
+ *                               I think some of them are supposed to be
+ *                               played at the same time, but I'm not sure
+ *                               when.
+ *  8/16/200:
+ *      Status:  LAA: now EGA and VGA lucas games work pretty well
+ *
+ * Other acknowledgements:
+ *  Allegro - for the midi instruments and the midi volume table
+ *  SCUMM Revisited - for getting the .LAA / .MIDs out of those
+ *                    LucasArts files.
+ *  FreeSCI - for some information on the sci music files
+ *  SD - the SCI Decoder (to get all .sci out of the Sierra files)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "mid.h"
+#include "mididata.h"
+
+void CmidPlayer::midiprintf(char *format, ...)
+    {
+    }
+
+CPlayer *CmidPlayer::factory(Copl *newopl)
+{
+  return new CmidPlayer(newopl);
+}
+
+unsigned char CmidPlayer::datalook(long pos)
+{
+    if (pos<0 || pos >= flen) return(0);
+    return(data[pos]);
+}
+
+unsigned long CmidPlayer::getnexti(unsigned long num)
+{
+	unsigned long v=0;
+	unsigned long i;
+
+    for (i=0; i<num; i++)
+        {
+        v+=(datalook(pos)<<(8*i)); pos++;
+        }
+    return(v);
+}
+
+unsigned long CmidPlayer::getnext(unsigned long num)
+{
+	unsigned long v=0;
+	unsigned long i;
+
+    for (i=0; i<num; i++)
+        {
+        v<<=8;
+        v+=datalook(pos); pos++;
+        }
+    return(v);
+}
+
+unsigned long CmidPlayer::getval()
+{
+    int v=0;
+	unsigned char b;
+
+    b=(unsigned char)getnext(1);
+	v=b&0x7f;
+	while ((b&0x80) !=0)
+		{
+        b=(unsigned char)getnext(1);
+        v = (v << 7) + (b & 0x7F);
+		}
+	return(v);
+}
+
+#define LUCAS_STYLE   1
+#define CMF_STYLE     2
+#define MIDI_STYLE    4
+#define SIERRA_STYLE  8
+
+#define ADLIB_MELODIC	0
+#define ADLIB_RYTHM	1
+
+bool CmidPlayer::load_sierra_ins(const std::string &fname, const CFileProvider &fp)
+{
+    long i,j,k,l;
+    unsigned char ins[28];
+    char *pfilename;
+    binistream *f;
+
+    pfilename = (char *)malloc(fname.length()+9);
+    strcpy(pfilename,fname.c_str());
+    j=0;
+    for(i=strlen(pfilename)-1; i >= 0; i--)
+      if(pfilename[i] == '/' || pfilename[i] == '\\') {
+	j = i+1;
+	break;
+      }
+    sprintf(pfilename+j+3,"patch.003");
+
+    f = fp.open(pfilename);
+    free(pfilename);
+    if(!f) return false;
+
+    f->ignore(2);
+    stins = 0;
+    for (i=0; i<2; i++)
+        {
+        for (k=0; k<48; k++)
+            {
+            l=i*48+k;
+            midiprintf ("\n%2d: ",l);
+            for (j=0; j<28; j++)
+                ins[j] = f->readInt(1);
+
+            myinsbank[l][0]=
+                (ins[9]*0x80) + (ins[10]*0x40) +
+                (ins[5]*0x20) + (ins[11]*0x10) +
+                ins[1];   //1=ins5
+            myinsbank[l][1]=
+                (ins[22]*0x80) + (ins[23]*0x40) +
+                (ins[18]*0x20) + (ins[24]*0x10) +
+                ins[14];  //1=ins18
+
+            myinsbank[l][2]=(ins[0]<<6)+ins[8];
+            myinsbank[l][3]=(ins[13]<<6)+ins[21];
+
+            myinsbank[l][4]=(ins[3]<<4)+ins[6];
+            myinsbank[l][5]=(ins[16]<<4)+ins[19];
+            myinsbank[l][6]=(ins[4]<<4)+ins[7];
+            myinsbank[l][7]=(ins[17]<<4)+ins[20];
+
+            myinsbank[l][8]=ins[26];
+            myinsbank[l][9]=ins[27];
+
+            myinsbank[l][10]=((ins[2]<<1))+(1-(ins[12]&1));
+            //(ins[12] ? 0:1)+((ins[2]<<1));
+
+            for (j=0; j<11; j++)
+                midiprintf ("%02X ",myinsbank[l][j]);
+			stins++;
+            }
+		f->ignore(2);
+        }
+
+    fp.close(f);
+    memcpy(smyinsbank, myinsbank, 128 * 16);
+    return true;
+}
+
+void CmidPlayer::sierra_next_section()
+{
+    int i,j;
+
+    for (i=0; i<16; i++)
+        track[i].on=0;
+
+    midiprintf("\n\nnext adv sierra section:\n");
+
+    pos=sierra_pos;
+    i=0;j=0;
+    while (i!=0xff)
+       {
+       getnext(1);
+       curtrack=j; j++;
+       track[curtrack].on=1;
+	   track[curtrack].spos = getnext(1);
+	   track[curtrack].spos += (getnext(1) << 8) + 4;	//4 best usually +3? not 0,1,2 or 5
+//       track[curtrack].spos=getnext(1)+(getnext(1)<<8)+4;		// dynamite!: doesn't optimize correctly!!
+       track[curtrack].tend=flen; //0xFC will kill it
+       track[curtrack].iwait=0;
+       track[curtrack].pv=0;
+       midiprintf ("track %d starts at %lx\n",curtrack,track[curtrack].spos);
+
+       getnext(2);
+       i=getnext(1);
+       }
+    getnext(2);
+    deltas=0x20;
+    sierra_pos=pos;
+    //getch();
+
+    fwait=0;
+    doing=1;
+}
+
+#define FILE_LUCAS      1
+#define FILE_MIDI       2
+#define FILE_CMF        3
+#define FILE_SIERRA     4
+#define FILE_ADVSIERRA  5
+#define FILE_OLDLUCAS   6
+
+bool CmidPlayer::load(const std::string &filename, const CFileProvider &fp)
+{
+    binistream *f = fp.open(filename); if(!f) return false;
+    int good;
+    unsigned char s[6];
+
+    f->readString((char *)s, 6);
+    good=0;
+    subsongs=0;
+    switch(s[0])
+        {
+        case 'A':
+            if (s[1]=='D' && s[2]=='L') good=FILE_LUCAS;
+            break;
+        case 'C':
+            if (s[1]=='T' && s[2]=='M' && s[3]=='F') good=FILE_CMF;
+            break;
+        case 0x84:
+            if (s[1]==0x00 && load_sierra_ins(filename, fp))
+                if (s[2]==0xf0)
+                    good=FILE_ADVSIERRA;
+                    else
+                    good=FILE_SIERRA;
+            break;
+        default:
+            if (s[4]=='A' && s[5]=='D') good=FILE_OLDLUCAS;
+            break;
+        }
+
+    if (good!=0)
+		subsongs=1;
+    else {
+      fp.close(f);
+      return false;
+    }
+
+    type=good;
+    f->seek(0);
+    flen = fp.filesize(f);
+    data = new unsigned char [flen];
+    f->readString((char *)data, flen);
+
+    fp.close(f);
+    rewind(0);
+    return true;
+}
+
+void CmidPlayer::midi_write_adlib(unsigned int r, unsigned char v)
+{
+	opl->write(r,v);
+    adlib_data[r]=v;
+}
+
+unsigned char adlib_opadd[] = {0x00  ,0x01 ,0x02  ,0x08  ,0x09  ,0x0A  ,0x10 ,0x11  ,0x12};
+int ops[] = {0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0};
+
+void CmidPlayer::midi_fm_instrument(int voice, unsigned char *inst)
+{
+    if ((adlib_style&SIERRA_STYLE)!=0)
+        midi_write_adlib(0xbd,0);  //just gotta make sure this happens..
+                                      //'cause who knows when it'll be
+                                      //reset otherwise.
+
+
+    midi_write_adlib(0x20+adlib_opadd[voice],inst[0]);
+    midi_write_adlib(0x23+adlib_opadd[voice],inst[1]);
+
+    if ((adlib_style&LUCAS_STYLE)!=0)
+        {
+        midi_write_adlib(0x43+adlib_opadd[voice],0x3f);
+        if ((inst[10] & 1)==0)
+            midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+            else
+            midi_write_adlib(0x40+adlib_opadd[voice],0x3f);
+        }
+        else
+        {
+        if ((adlib_style&SIERRA_STYLE)!=0)
+            {
+            midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+            midi_write_adlib(0x43+adlib_opadd[voice],inst[3]);
+            }
+            else
+            {
+            midi_write_adlib(0x40+adlib_opadd[voice],inst[2]);
+            if ((inst[10] & 1)==0)
+                midi_write_adlib(0x43+adlib_opadd[voice],inst[3]);
+                else
+                midi_write_adlib(0x43+adlib_opadd[voice],0);
+            }
+        }
+
+    midi_write_adlib(0x60+adlib_opadd[voice],inst[4]);
+    midi_write_adlib(0x63+adlib_opadd[voice],inst[5]);
+    midi_write_adlib(0x80+adlib_opadd[voice],inst[6]);
+    midi_write_adlib(0x83+adlib_opadd[voice],inst[7]);
+    midi_write_adlib(0xe0+adlib_opadd[voice],inst[8]);
+    midi_write_adlib(0xe3+adlib_opadd[voice],inst[9]);
+
+    midi_write_adlib(0xc0+voice,inst[10]);
+}
+
+void CmidPlayer::midi_fm_volume(int voice, int volume)
+{
+    int vol;
+
+    if ((adlib_style&SIERRA_STYLE)==0)  //sierra likes it loud!
+    {
+    vol=volume>>2;
+
+    if ((adlib_style&LUCAS_STYLE)!=0)
+        {
+        if ((adlib_data[0xc0+voice]&1)==1)
+            midi_write_adlib(0x40+adlib_opadd[voice], (unsigned 
+char)((63-vol) |
+            (adlib_data[0x40+adlib_opadd[voice]]&0xc0)));
+        midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) |
+            (adlib_data[0x43+adlib_opadd[voice]]&0xc0)));
+        }
+        else
+        {
+        if ((adlib_data[0xc0+voice]&1)==1)
+            midi_write_adlib(0x40+adlib_opadd[voice], (unsigned 
+char)((63-vol) |
+            (adlib_data[0x40+adlib_opadd[voice]]&0xc0)));
+        midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) |
+           (adlib_data[0x43+adlib_opadd[voice]]&0xc0)));
+        }
+    }
+}
+
+
+int fnums[] = {
+0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae
+		  };
+
+void CmidPlayer::midi_fm_playnote(int voice, int note, int volume)
+{
+    int freq=fnums[note%12];
+    int oct=note/12;
+	int c;
+
+    midi_fm_volume(voice,volume);
+    midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff));
+
+	c=((freq&0x300) >> 8)+(oct<<2) + (1<<5);
+    midi_write_adlib(0xb0+voice,(unsigned char)c);
+}
+
+void CmidPlayer::midi_fm_endnote(int voice)
+{
+    //midi_fm_volume(voice,0);
+    //midi_write_adlib(0xb0+voice,0);
+
+    midi_write_adlib(0xb0+voice,(unsigned char)(adlib_data[0xb0+voice]&(255-32)));
+}
+
+void CmidPlayer::midi_fm_reset()
+{
+    int i;
+    for (i=0; i<256; i++)
+        midi_write_adlib(i,0);
+
+    midi_write_adlib(0x01, 0x20);
+    midi_write_adlib(0xBD,0xc0);
+}
+
+bool CmidPlayer::update()
+{
+    long w,v,note,vel,ctrl,nv,x,l,lnum;
+    int i=0,j,c;
+    int on,onl;
+    unsigned char ins[11];
+    int ret;
+
+    if (doing == 1)
+        {
+        // just get the first wait and ignore it :>
+        for (curtrack=0; curtrack<16; curtrack++)
+            if (track[curtrack].on)
+                {
+                pos=track[curtrack].pos;
+                if (type != FILE_SIERRA && type !=FILE_ADVSIERRA)
+                    track[curtrack].iwait+=getval();
+                    else
+                    track[curtrack].iwait+=getnext(1);
+                track[curtrack].pos=pos;
+                }
+        doing=0;
+        }
+
+    iwait=0;
+    ret=1;
+
+    while (iwait==0 && ret==1)
+        {
+        for (curtrack=0; curtrack<16; curtrack++)
+        if (track[curtrack].on && track[curtrack].iwait==0 &&
+            track[curtrack].pos < track[curtrack].tend)
+        {
+        pos=track[curtrack].pos;
+
+		v=getnext(1);
+
+        //  This is to do implied MIDI events.
+        if (v<0x80) {v=track[curtrack].pv; pos--;}
+        track[curtrack].pv=(unsigned char)v;
+
+		c=v&0x0f;
+        midiprintf ("[%2X]",v);
+        switch(v&0xf0)
+            {
+			case 0x80: /*note off*/
+				note=getnext(1); vel=getnext(1);
+                for (i=0; i<9; i++)
+                    if (chp[i][0]==c && chp[i][1]==note)
+                        {
+                        midi_fm_endnote(i);
+                        chp[i][0]=-1;
+                        }
+                break;
+            case 0x90: /*note on*/
+              //  doing=0;
+                note=getnext(1); vel=getnext(1);
+
+                if (ch[c].on!=0)
+                {
+                for (i=0; i<9; i++)
+                    chp[i][2]++;
+
+                j=0;
+                on=-1;onl=0;
+                for (i=0; i<9; i++)
+                    if (chp[i][0]==-1 && chp[i][2]>onl)
+                        { onl=chp[i][2]; on=i; j=1; }
+
+                if (on==-1)
+                    {
+                    onl=0;
+                    for (i=0; i<9; i++)
+                        if (chp[i][2]>onl)
+                            { onl=chp[i][2]; on=i; }
+                    }
+
+                 if (j==0)
+                    midi_fm_endnote(on);
+
+                 if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128)
+                    {
+                    if (adlib_mode == ADLIB_MELODIC || c < 12)
+                        midi_fm_instrument(on,ch[c].ins);
+                        else
+                        {
+                        //the following fails to be effective
+                        //at doing rythm sounds .. (cmf blah)
+                        ins[0]=ins[1]=ch[c].ins[0];
+                        ins[2]=ins[3]=ch[c].ins[2];
+                        ins[4]=ins[5]=ch[c].ins[4];
+                        ins[6]=ins[7]=ch[c].ins[6];
+                        ins[8]=ins[9]=ch[c].ins[8];
+                        ins[10]=ch[c].ins[10]|1;
+                        midi_fm_instrument(on,ins);
+                        }
+
+                    if ((adlib_style&MIDI_STYLE)!=0)
+                        {
+                        nv=((ch[c].vol*vel)/128);
+                        if ((adlib_style&LUCAS_STYLE)!=0)
+                            nv*=2;
+                        if (nv>127) nv=127;
+                        nv=my_midi_fm_vol_table[nv];
+                        if ((adlib_style&LUCAS_STYLE)!=0)
+                            nv=(int)((float)sqrt((float)nv)*11);
+                        }
+                        else
+                        {
+                        nv=vel;
+                        }
+
+                    midi_fm_playnote(on,note+ch[c].nshift,nv*2);
+                    chp[on][0]=c;
+                    chp[on][1]=note;
+                    chp[on][2]=0;
+                    }
+                    else
+                    {
+                    if (vel==0)  //same code as end note
+                        {
+                        for (i=0; i<9; i++)
+                            if (chp[i][0]==c && chp[i][1]==note)
+                                {
+                               // midi_fm_volume(i,0);  // really end the note
+                                midi_fm_endnote(i);
+                                chp[i][0]=-1;
+                                }
+                        }
+                        else
+                        {        // i forget what this is for.
+                        chp[on][0]=-1;
+                        chp[on][2]=0;
+                        }
+                    }
+                midiprintf(" [%d:%d:%d:%d]\n",c,ch[c].inum,note,vel);
+                }
+                else
+                midiprintf ("off");
+                break;
+            case 0xa0: /*key after touch */
+                note=getnext(1); vel=getnext(1);
+                /*  //this might all be good
+                for (i=0; i<9; i++)
+                    if (chp[i][0]==c & chp[i][1]==note)
+                        
+midi_fm_playnote(i,note+cnote[c],my_midi_fm_vol_table[(cvols[c]*vel)/128]*2);
+                */
+                break;
+            case 0xb0: /*control change .. pitch bend? */
+                ctrl=getnext(1); vel=getnext(1);
+
+                switch(ctrl)
+                    {
+                    case 0x07:
+                        midiprintf ("(pb:%d: %d %d)",c,ctrl,vel);
+                        ch[c].vol=vel;
+                        midiprintf("vol");
+                        break;
+                    case 0x67:
+                        midiprintf ("\n\nhere:%d\n\n",vel);
+                        if ((adlib_style&CMF_STYLE)!=0)
+                            adlib_mode=vel;  // this gets faked - no mode change
+                        break;
+                    }
+                break;
+            case 0xc0: /*patch change*/
+				x=getnext(1);
+                ch[c].inum=x;
+                for (j=0; j<11; j++)
+                    ch[c].ins[j]=myinsbank[ch[c].inum][j];
+                break;
+            case 0xd0: /*chanel touch*/
+                x=getnext(1);
+                break;
+            case 0xe0: /*pitch wheel*/
+                x=getnext(1);
+                x=getnext(1);
+                break;
+            case 0xf0:
+                switch(v)
+                    {
+                    case 0xf0:
+                    case 0xf7: /*sysex*/
+						l=getval();
+                        if (datalook(pos+l)==0xf7)
+							i=1;
+                        midiprintf("{%d}",l);
+                        midiprintf("\n");
+
+                        if (datalook(pos)==0x7d &&
+                            datalook(pos+1)==0x10 &&
+                            datalook(pos+2)<16)
+							{
+                            adlib_style=LUCAS_STYLE|MIDI_STYLE;
+							for (i=0; i<l; i++)
+								{
+                                midiprintf ("%x ",datalook(pos+i));
+                                if ((i-3)%10 == 0) midiprintf("\n");
+								}
+                            midiprintf ("\n");
+                            getnext(1);
+                            getnext(1);
+							c=getnext(1);
+							getnext(1);
+
+                          //  getnext(22); //temp
+                            ch[c].ins[0]=(unsigned char)((getnext(1)<<4)+getnext(1));
+                            ch[c].ins[2]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f));
+                            ch[c].ins[4]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1)));
+                            ch[c].ins[6]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1)));
+                            ch[c].ins[8]=(unsigned char)((getnext(1)<<4)+getnext(1));
+
+                            ch[c].ins[1]=(unsigned char)((getnext(1)<<4)+getnext(1));
+                            ch[c].ins[3]=(unsigned char)(0xff-(((getnext(1)<<4)+getnext(1))&0x3f));
+                            ch[c].ins[5]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1)));
+                            ch[c].ins[7]=(unsigned char)(0xff-((getnext(1)<<4)+getnext(1)));
+                            ch[c].ins[9]=(unsigned char)((getnext(1)<<4)+getnext(1));
+
+                            i=(getnext(1)<<4)+getnext(1);
+                            ch[c].ins[10]=i;
+
+                            //if ((i&1)==1) ch[c].ins[10]=1;
+
+                            midiprintf ("\n%d: ",c);
+							for (i=0; i<11; i++)
+                                midiprintf ("%2X ",ch[c].ins[i]);
+                            getnext(l-26);
+							}
+                            else
+                            {
+                            midiprintf("\n");
+                            for (j=0; j<l; j++)
+                                midiprintf ("%2X ",getnext(1));
+                            }
+
+                        midiprintf("\n");
+						if(i==1)
+							getnext(1);
+                        break;
+                    case 0xf1:
+                        break;
+                    case 0xf2:
+                        getnext(2);
+                        break;
+                    case 0xf3:
+                        getnext(1);
+                        break;
+                    case 0xf4:
+                        break;
+                    case 0xf5:
+                        break;
+                    case 0xf6: /*something*/
+                    case 0xf8:
+                    case 0xfa:
+                    case 0xfb:
+                    case 0xfc:
+                        //this ends the track for sierra.
+                        if (type == FILE_SIERRA ||
+                            type == FILE_ADVSIERRA)
+                            {
+                            track[curtrack].tend=pos;
+                            midiprintf ("endmark: %ld -- %lx\n",pos,pos);
+                            }
+                        break;
+                    case 0xfe:
+                        break;
+                    case 0xfd:
+                        break;
+                    case 0xff:
+                        v=getnext(1);
+                        l=getval();
+                        midiprintf ("\n");
+                        midiprintf("{%X_%X}",v,l);
+                        if (v==0x51)
+                            {
+                            lnum=getnext(l);
+                            msqtr=lnum; /*set tempo*/
+                            midiprintf ("(qtr=%ld)",msqtr);
+                            }
+                            else
+                            {
+                            for (i=0; i<l; i++)
+                                midiprintf ("%2X ",getnext(1));
+                            }
+                        break;
+					}
+                break;
+            default: midiprintf("!",v); /* if we get down here, a error occurred */
+			break;
+            }
+
+        if (pos < track[curtrack].tend)
+            {
+            if (type != FILE_SIERRA && type !=FILE_ADVSIERRA)
+                w=getval();
+                else
+                w=getnext(1);
+            track[curtrack].iwait=w;
+            /*
+            if (w!=0)
+                {
+                midiprintf("\n<%d>",w);
+                f = 
+((float)w/(float)deltas)*((float)msqtr/(float)1000000);
+                if (doing==1) f=0; //not playing yet. don't wait yet
+                }
+                */
+            }
+            else
+            track[curtrack].iwait=0;
+
+        track[curtrack].pos=pos;
+        }
+
+
+        ret=0; //end of song.
+        iwait=0;
+        for (curtrack=0; curtrack<16; curtrack++)
+            if (track[curtrack].on == 1 &&
+                track[curtrack].pos < track[curtrack].tend)
+                ret=1;  //not yet..
+
+        if (ret==1)
+            {
+            iwait=0xffffff;  // bigger than any wait can be!
+            for (curtrack=0; curtrack<16; curtrack++)
+               if (track[curtrack].on == 1 &&
+                   track[curtrack].pos < track[curtrack].tend &&
+                   track[curtrack].iwait < iwait)
+                   iwait=track[curtrack].iwait;
+            }
+        }
+
+
+    if (iwait !=0 && ret==1)
+        {
+        for (curtrack=0; curtrack<16; curtrack++)
+            if (track[curtrack].on)
+                track[curtrack].iwait-=iwait;
+
+        
+fwait=1.0f/(((float)iwait/(float)deltas)*((float)msqtr/(float)1000000));
+        }
+        else
+        fwait=50;  // 1/50th of a second
+
+    midiprintf ("\n");
+    for (i=0; i<16; i++)
+        if (track[i].on)
+            if (track[i].pos < track[i].tend)
+                midiprintf ("<%d>",track[i].iwait);
+                else
+                midiprintf("stop");
+
+    /*
+    if (ret==0 && type==FILE_ADVSIERRA)
+        if (datalook(sierra_pos-2)!=0xff)
+            {
+            midiprintf ("next sectoin!");
+            sierra_next_section(p);
+            fwait=50;
+            ret=1;
+            }
+    */
+
+	if(ret)
+		return true;
+	else
+		return false;
+}
+
+float CmidPlayer::getrefresh()
+{
+    return (fwait > 0.01f ? fwait : 0.01f);
+}
+
+void CmidPlayer::rewind(int subsong)
+{
+    long i,j,n,m,l;
+    long o_sierra_pos;
+    unsigned char ins[16];
+
+    pos=0; tins=0;
+    adlib_style=MIDI_STYLE|CMF_STYLE;
+    adlib_mode=ADLIB_MELODIC;
+    for (i=0; i<128; i++)
+        for (j=0; j<16; j++)
+            myinsbank[i][j]=midi_fm_instruments[i][j];
+	for (i=0; i<16; i++)
+        {
+        ch[i].inum=0;
+        for (j=0; j<11; j++)
+            ch[i].ins[j]=myinsbank[ch[i].inum][j];
+        ch[i].vol=127;
+        ch[i].nshift=-25;
+        ch[i].on=1;
+        }
+
+    /* General init */
+    for (i=0; i<9; i++)
+        {
+        chp[i][0]=-1;
+        chp[i][2]=0;
+        }
+
+    deltas=250;  // just a number,  not a standard
+    msqtr=500000;
+    fwait=123; // gotta be a small thing.. sorta like nothing
+    iwait=0;
+
+    subsongs=1;
+
+    for (i=0; i<16; i++)
+        {
+        track[i].tend=0;
+        track[i].spos=0;
+        track[i].pos=0;
+        track[i].iwait=0;
+        track[i].on=0;
+        track[i].pv=0;
+        }
+    curtrack=0;
+
+    /* specific to file-type init */
+
+        pos=0;
+        i=getnext(1);
+        switch(type)
+            {
+            case FILE_LUCAS:
+                getnext(24);  //skip junk and get to the midi.
+                adlib_style=LUCAS_STYLE|MIDI_STYLE;
+                //note: no break, we go right into midi headers...
+            case FILE_MIDI:
+                if (type != FILE_LUCAS)
+                    tins=128;
+                getnext(11);  /*skip header*/
+                deltas=getnext(2);
+                midiprintf ("deltas:%ld\n",deltas);
+                getnext(4);
+
+                curtrack=0;
+                track[curtrack].on=1;
+                track[curtrack].tend=getnext(4);
+                track[curtrack].spos=pos;
+                midiprintf ("tracklen:%ld\n",track[curtrack].tend);
+                break;
+            case FILE_CMF:
+                getnext(3);  // ctmf
+                getnexti(2); //version
+                n=getnexti(2); // instrument offset
+                m=getnexti(2); // music offset
+                deltas=getnexti(2); //ticks/qtr note
+                msqtr=1000000/getnexti(2)*deltas;
+                   //the stuff in the cmf is click ticks per second..
+
+                i=getnexti(2);
+				if(i) title = (char *)data+i;
+                i=getnexti(2);
+				if(i) author = (char *)data+i;
+                i=getnexti(2);
+				if(i) remarks = (char *)data+i;
+
+                getnext(16); // channel in use table ..
+                i=getnexti(2); // num instr
+                if (i>128) i=128; // to ward of bad numbers...
+                getnexti(2); //basic tempo
+
+                midiprintf("\nioff:%d\nmoff%d\ndeltas:%ld\nmsqtr:%ld\nnumi:%d\n",
+                    n,m,deltas,msqtr,i);
+                pos=n;  // jump to instruments
+                tins=i;
+                for (j=0; j<i; j++)
+                    {
+                    midiprintf ("\n%d: ",j);
+                    for (l=0; l<16; l++)
+                        {
+                        myinsbank[j][l]=(unsigned char)getnext(1);
+                        midiprintf ("%2X ",myinsbank[j][l]);
+                        }
+                    }
+
+                for (i=0; i<16; i++)
+                    ch[i].nshift=-13;
+
+                adlib_style=CMF_STYLE;
+
+                curtrack=0;
+                track[curtrack].on=1;
+                track[curtrack].tend=flen;  // music until the end of the file
+                track[curtrack].spos=m;  //jump to midi music
+                break;
+            case FILE_OLDLUCAS:
+                msqtr=250000;
+                pos=9;
+                deltas=getnext(1);
+
+                i=8;
+                pos=0x19;  // jump to instruments
+                tins=i;
+                for (j=0; j<i; j++)
+                    {
+                    midiprintf ("\n%d: ",j);
+                    for (l=0; l<16; l++)
+                        ins[l]=(unsigned char)getnext(1);
+
+                    myinsbank[j][10]=ins[2];
+                    myinsbank[j][0]=ins[3];
+                    myinsbank[j][2]=ins[4];
+                    myinsbank[j][4]=ins[5];
+                    myinsbank[j][6]=ins[6];
+                    myinsbank[j][8]=ins[7];
+                    myinsbank[j][1]=ins[8];
+                    myinsbank[j][3]=ins[9];
+                    myinsbank[j][5]=ins[10];
+                    myinsbank[j][7]=ins[11];
+                    myinsbank[j][9]=ins[12];
+
+                    for (l=0; l<11; l++)
+                        midiprintf ("%2X ",myinsbank[j][l]);
+                    }
+
+                for (i=0; i<16; i++)
+                    {
+                    if (i<tins)
+                        {
+                        ch[i].inum=i;
+                        for (j=0; j<11; j++)
+                            ch[i].ins[j]=myinsbank[ch[i].inum][j];
+                        }
+                    }
+
+                adlib_style=LUCAS_STYLE|MIDI_STYLE;
+
+                curtrack=0;
+                track[curtrack].on=1;
+                track[curtrack].tend=flen;  // music until the end of the file
+                track[curtrack].spos=0x98;  //jump to midi music
+                break;
+            case FILE_ADVSIERRA:
+	      memcpy(myinsbank, smyinsbank, 128 * 16);
+	      tins = stins;
+                deltas=0x20;
+                getnext(11); //worthless empty space and "stuff" :)
+
+                o_sierra_pos=sierra_pos=pos;
+                sierra_next_section();
+                while (datalook(sierra_pos-2)!=0xff)
+                    {
+                    sierra_next_section();
+                    subsongs++;
+                    }
+
+                if (subsong < 0 || subsong >= subsongs) subsong=0;
+
+                sierra_pos=o_sierra_pos;
+                sierra_next_section();
+                i=0;
+                while (i != subsong)
+                    {
+                    sierra_next_section();
+                    i++;
+                    }
+
+                adlib_style=SIERRA_STYLE|MIDI_STYLE;  //advanced sierra tunes use volume
+                break;
+            case FILE_SIERRA:
+	      memcpy(myinsbank, smyinsbank, 128 * 16);
+	      tins = stins;
+                getnext(2);
+                deltas=0x20;
+
+                curtrack=0;
+                track[curtrack].on=1;
+                track[curtrack].tend=flen;  // music until the end of the file
+
+                for (i=0; i<16; i++)
+                    {
+                    ch[i].nshift=-13;
+                    ch[i].on=getnext(1);
+                    ch[i].inum=getnext(1);
+                    for (j=0; j<11; j++)
+                        ch[i].ins[j]=myinsbank[ch[i].inum][j];
+                    }
+
+                track[curtrack].spos=pos;
+                adlib_style=SIERRA_STYLE|MIDI_STYLE;
+                break;
+            }
+
+
+/*        sprintf(info,"%s\r\nTicks/Quarter Note: %ld\r\n",info,deltas);
+        sprintf(info,"%sms/Quarter Note: %ld",info,msqtr); */
+
+        for (i=0; i<16; i++)
+            if (track[i].on)
+                {
+                track[i].pos=track[i].spos;
+                track[i].pv=0;
+                track[i].iwait=0;
+                }
+
+    doing=1;
+	opl->init();
+}
+
+std::string CmidPlayer::gettype()
+{
+	switch(type) {
+	case FILE_LUCAS:
+		return std::string("LucasArts AdLib MIDI");
+	case FILE_MIDI:
+		return std::string("General MIDI");
+	case FILE_CMF:
+		return std::string("Creative Music Format (CMF MIDI)");
+	case FILE_OLDLUCAS:
+		return std::string("Lucasfilm Adlib MIDI");
+	case FILE_ADVSIERRA:
+		return std::string("Sierra On-Line VGA MIDI");
+	case FILE_SIERRA:
+		return std::string("Sierra On-Line EGA MIDI");
+	default:
+		return std::string("MIDI unknown");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/adplug/core/mid.h	Mon Jan 09 13:15:02 2006 -0800
@@ -0,0 +1,111 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2003 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
+ *
+ * mid.h - LAA, SCI, MID & CMF Player by Philip Hassey <philhassey@hotmail.com>
+ */
+
+#include "player.h"
+
+class CmidPlayer: public CPlayer
+{
+public:
+  static CPlayer *factory(Copl *newopl);
+
+	CmidPlayer(Copl *newopl)
+		: CPlayer(newopl), author(&emptystr), title(&emptystr),
+	  remarks(&emptystr), emptystr('\0'), flen(0), data(0)
+	{ };
+	~CmidPlayer()
+	{ if(data) delete [] data; };
+
+	bool load(const std::string &filename, const CFileProvider &fp);
+	bool update();
+	void rewind(int subsong);
+	float getrefresh();
+
+	std::string gettype();
+	std::string gettitle()
+	{ return std::string(title); };
+	std::string getauthor()
+	{ return std::string(author); };
+	std::string getdesc()
+	{ return std::string(remarks); };
+	unsigned int getinstruments()
+	{ return tins; };
+	unsigned int getsubsongs()
+	{ return subsongs; };
+
+protected:
+	struct midi_channel {
+		int inum;
+		unsigned char ins[11];
+		int vol;
+		int nshift;
+		int on;
+	};
+
+	struct midi_track {
+		unsigned long tend;
+		unsigned long spos;
+		unsigned long pos;
+		unsigned long iwait;
+		int on;
+		unsigned char pv;
+	};
+
+    char *author,*title,*remarks,emptystr;
+    long flen;
+    unsigned long pos;
+    unsigned long sierra_pos; //sierras gotta be special.. :>
+    int subsongs;
+    unsigned char *data;
+
+    unsigned char adlib_data[256];
+    int adlib_style;
+    int adlib_mode;
+    unsigned char myinsbank[128][16], smyinsbank[128][16];
+    midi_channel ch[16];
+    int chp[9][3];
+
+    long deltas;
+    long msqtr;
+
+    midi_track track[16];
+    unsigned int curtrack;
+
+    float fwait;
+    unsigned long iwait;
+    int doing;
+
+    int type,tins,stins;
+
+private:
+	bool load_sierra_ins(const std::string &fname, const CFileProvider &fp);
+	void midiprintf(char *format, ...);
+	unsigned char datalook(long pos);
+	unsigned long getnexti(unsigned long num);
+	unsigned long getnext(unsigned long num);
+	unsigned long getval();
+	void sierra_next_section();
+	void midi_write_adlib(unsigned int r, unsigned char v);
+	void midi_fm_instrument(int voice, unsigned char *inst);
+	void midi_fm_volume(int voice, int volume);
+	void midi_fm_playnote(int voice, int note, int volume);
+	void midi_fm_endnote(int voice);
+	void midi_fm_reset();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/adplug/core/mididata.h	Mon Jan 09 13:15:02 2006 -0800
@@ -0,0 +1,174 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999, 2000, 2001 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
+ *
+ *
+ * FM instrument definitions below borrowed from the Allegro library by
+ * Phil Hassey, <philhassey@hotmail.com> - see "adplug/players/mid.cpp"
+ * for further acknowledgements.
+ */
+ 
+unsigned char midi_fm_instruments[128][14] =
+{
+
+   /* This set of GM instrument patches was provided by Jorrit Rouwe...
+    */
+
+   { 0x21, 0x21, 0x8f, 0x0c, 0xf2, 0xf2, 0x45, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Acoustic Grand */
+   { 0x31, 0x21, 0x4b, 0x09, 0xf2, 0xf2, 0x54, 0x56, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Bright Acoustic */
+   { 0x31, 0x21, 0x49, 0x09, 0xf2, 0xf2, 0x55, 0x76, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Electric Grand */
+   { 0xb1, 0x61, 0x0e, 0x09, 0xf2, 0xf3, 0x3b, 0x0b, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Honky-Tonk */
+   { 0x01, 0x21, 0x57, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 1 */
+   { 0x01, 0x21, 0x93, 0x09, 0xf1, 0xf1, 0x38, 0x28, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Piano 2 */
+   { 0x21, 0x36, 0x80, 0x17, 0xa2, 0xf1, 0x01, 0xd5, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Harpsichord */
+   { 0x01, 0x01, 0x92, 0x09, 0xc2, 0xc2, 0xa8, 0x58, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Clav */
+   { 0x0c, 0x81, 0x5c, 0x09, 0xf6, 0xf3, 0x54, 0xb5, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Celesta */
+   { 0x07, 0x11, 0x97, 0x89, 0xf6, 0xf5, 0x32, 0x11, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Glockenspiel */
+   { 0x17, 0x01, 0x21, 0x09, 0x56, 0xf6, 0x04, 0x04, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Music Box */
+   { 0x18, 0x81, 0x62, 0x09, 0xf3, 0xf2, 0xe6, 0xf6, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Vibraphone */
+   { 0x18, 0x21, 0x23, 0x09, 0xf7, 0xe5, 0x55, 0xd8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Marimba */
+   { 0x15, 0x01, 0x91, 0x09, 0xf6, 0xf6, 0xa6, 0xe6, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Xylophone */
+   { 0x45, 0x81, 0x59, 0x89, 0xd3, 0xa3, 0x82, 0xe3, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tubular Bells */
+   { 0x03, 0x81, 0x49, 0x89, 0x74, 0xb3, 0x55, 0x05, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Dulcimer */
+   { 0x71, 0x31, 0x92, 0x09, 0xf6, 0xf1, 0x14, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Drawbar Organ */
+   { 0x72, 0x30, 0x14, 0x09, 0xc7, 0xc7, 0x58, 0x08, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Percussive Organ */
+   { 0x70, 0xb1, 0x44, 0x09, 0xaa, 0x8a, 0x18, 0x08, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Rock Organ */
+   { 0x23, 0xb1, 0x93, 0x09, 0x97, 0x55, 0x23, 0x14, 0x01, 0x00, 0x04, 0, 0, 0 }, /* Church Organ */
+   { 0x61, 0xb1, 0x13, 0x89, 0x97, 0x55, 0x04, 0x04, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Reed Organ */
+   { 0x24, 0xb1, 0x48, 0x09, 0x98, 0x46, 0x2a, 0x1a, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Accoridan */
+   { 0x61, 0x21, 0x13, 0x09, 0x91, 0x61, 0x06, 0x07, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Harmonica */
+   { 0x21, 0xa1, 0x13, 0x92, 0x71, 0x61, 0x06, 0x07, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tango Accordian */
+   { 0x02, 0x41, 0x9c, 0x89, 0xf3, 0xf3, 0x94, 0xc8, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(nylon) */
+   { 0x03, 0x11, 0x54, 0x09, 0xf3, 0xf1, 0x9a, 0xe7, 0x01, 0x00, 0x0c, 0, 0, 0 }, /* Acoustic Guitar(steel) */
+   { 0x23, 0x21, 0x5f, 0x09, 0xf1, 0xf2, 0x3a, 0xf8, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(jazz) */
+   { 0x03, 0x21, 0x87, 0x89, 0xf6, 0xf3, 0x22, 0xf8, 0x01, 0x00, 0x06, 0, 0, 0 }, /* Electric Guitar(clean) */
+   { 0x03, 0x21, 0x47, 0x09, 0xf9, 0xf6, 0x54, 0x3a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Electric Guitar(muted) */
+   { 0x23, 0x21, 0x4a, 0x0e, 0x91, 0x84, 0x41, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Overdriven Guitar */
+   { 0x23, 0x21, 0x4a, 0x09, 0x95, 0x94, 0x19, 0x19, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Distortion Guitar */
+   { 0x09, 0x84, 0xa1, 0x89, 0x20, 0xd1, 0x4f, 0xf8, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Guitar Harmonics */
+   { 0x21, 0xa2, 0x1e, 0x09, 0x94, 0xc3, 0x06, 0xa6, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Acoustic Bass */
+   { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(finger) */
+   { 0x31, 0x31, 0x8d, 0x09, 0xf1, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Electric Bass(pick) */
+   { 0x31, 0x32, 0x5b, 0x09, 0x51, 0x71, 0x28, 0x48, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Fretless Bass */
+   { 0x01, 0x21, 0x8b, 0x49, 0xa1, 0xf2, 0x9a, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 1 */
+   { 0x21, 0x21, 0x8b, 0x11, 0xa2, 0xa1, 0x16, 0xdf, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Slap Bass 2 */
+   { 0x31, 0x31, 0x8b, 0x09, 0xf4, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 1 */
+   { 0x31, 0x31, 0x12, 0x09, 0xf1, 0xf1, 0x28, 0x18, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Synth Bass 2 */
+   { 0x31, 0x21, 0x15, 0x09, 0xdd, 0x56, 0x13, 0x26, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Violin */
+   { 0x31, 0x21, 0x16, 0x09, 0xdd, 0x66, 0x13, 0x06, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Viola */
+   { 0x71, 0x31, 0x49, 0x09, 0xd1, 0x61, 0x1c, 0x0c, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Cello */
+   { 0x21, 0x23, 0x4d, 0x89, 0x71, 0x72, 0x12, 0x06, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Contrabass */
+   { 0xf1, 0xe1, 0x40, 0x09, 0xf1, 0x6f, 0x21, 0x16, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Tremolo Strings */
+   { 0x02, 0x01, 0x1a, 0x89, 0xf5, 0x85, 0x75, 0x35, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pizzicato Strings */
+   { 0x02, 0x01, 0x1d, 0x89, 0xf5, 0xf3, 0x75, 0xf4, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Orchestral Strings */
+   { 0x10, 0x11, 0x41, 0x09, 0xf5, 0xf2, 0x05, 0xc3, 0x01, 0x00, 0x02, 0, 0, 0 }, /* Timpani */
+   { 0x21, 0xa2, 0x9b, 0x0a, 0xb1, 0x72, 0x25, 0x08, 0x01, 0x00, 0x0e, 0, 0, 0 }, /* String Ensemble 1 */
+   { 0xa1, 0x21, 0x98, 0x09, 0x7f, 0x3f, 0x03, 0x07, 0x01, 0x01, 0x00, 0, 0, 0 }, /* String Ensemble 2 */
+   { 0xa1, 0x61, 0x93, 0x09, 0xc1, 0x4f, 0x12, 0x05, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* SynthStrings 1 */
+   { 0x21, 0x61, 0x18, 0x09, 0xc1, 0x4f, 0x22, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* SynthStrings 2 */
+   { 0x31, 0x72, 0x5b, 0x8c, 0xf4, 0x8a, 0x15, 0x05, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Choir Aahs */
+   { 0xa1, 0x61, 0x90, 0x09, 0x74, 0x71, 0x39, 0x67, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Voice Oohs */
+   { 0x71, 0x72, 0x57, 0x09, 0x54, 0x7a, 0x05, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Synth Voice */
+   { 0x90, 0x41, 0x00, 0x09, 0x54, 0xa5, 0x63, 0x45, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Orchestra Hit */
+   { 0x21, 0x21, 0x92, 0x0a, 0x85, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trumpet */
+   { 0x21, 0x21, 0x94, 0x0e, 0x75, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Trombone */
+   { 0x21, 0x61, 0x94, 0x09, 0x76, 0x82, 0x15, 0x37, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Tuba */
+   { 0x31, 0x21, 0x43, 0x09, 0x9e, 0x62, 0x17, 0x2c, 0x01, 0x01, 0x02, 0, 0, 0 }, /* Muted Trumpet */
+   { 0x21, 0x21, 0x9b, 0x09, 0x61, 0x7f, 0x6a, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* French Horn */
+   { 0x61, 0x22, 0x8a, 0x0f, 0x75, 0x74, 0x1f, 0x0f, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Brass Section */
+   { 0xa1, 0x21, 0x86, 0x8c, 0x72, 0x71, 0x55, 0x18, 0x01, 0x00, 0x00, 0, 0, 0 }, /* SynthBrass 1 */
+   { 0x21, 0x21, 0x4d, 0x09, 0x54, 0xa6, 0x3c, 0x1c, 0x00, 0x00, 0x08, 0, 0, 0 }, /* SynthBrass 2 */
+   { 0x31, 0x61, 0x8f, 0x09, 0x93, 0x72, 0x02, 0x0b, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Soprano Sax */
+   { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x03, 0x09, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Alto Sax */
+   { 0x31, 0x61, 0x91, 0x09, 0x93, 0x82, 0x03, 0x09, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Tenor Sax */
+   { 0x31, 0x61, 0x8e, 0x09, 0x93, 0x72, 0x0f, 0x0f, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Baritone Sax */
+   { 0x21, 0x21, 0x4b, 0x09, 0xaa, 0x8f, 0x16, 0x0a, 0x01, 0x00, 0x08, 0, 0, 0 }, /* Oboe */
+   { 0x31, 0x21, 0x90, 0x09, 0x7e, 0x8b, 0x17, 0x0c, 0x01, 0x01, 0x06, 0, 0, 0 }, /* English Horn */
+   { 0x31, 0x32, 0x81, 0x09, 0x75, 0x61, 0x19, 0x19, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Bassoon */
+   { 0x32, 0x21, 0x90, 0x09, 0x9b, 0x72, 0x21, 0x17, 0x00, 0x00, 0x04, 0, 0, 0 }, /* Clarinet */
+   { 0xe1, 0xe1, 0x1f, 0x09, 0x85, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Piccolo */
+   { 0xe1, 0xe1, 0x46, 0x09, 0x88, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Flute */
+   { 0xa1, 0x21, 0x9c, 0x09, 0x75, 0x75, 0x1f, 0x0a, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Recorder */
+   { 0x31, 0x21, 0x8b, 0x09, 0x84, 0x65, 0x58, 0x1a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pan Flute */
+   { 0xe1, 0xa1, 0x4c, 0x09, 0x66, 0x65, 0x56, 0x26, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Blown Bottle */
+   { 0x62, 0xa1, 0xcb, 0x09, 0x76, 0x55, 0x46, 0x36, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Skakuhachi */
+   { 0x62, 0xa1, 0xa2, 0x09, 0x57, 0x56, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Whistle */
+   { 0x62, 0xa1, 0x9c, 0x09, 0x77, 0x76, 0x07, 0x07, 0x00, 0x00, 0x0b, 0, 0, 0 }, /* Ocarina */
+   { 0x22, 0x21, 0x59, 0x09, 0xff, 0xff, 0x03, 0x0f, 0x02, 0x00, 0x00, 0, 0, 0 }, /* Lead 1 (square) */
+   { 0x21, 0x21, 0x0e, 0x09, 0xff, 0xff, 0x0f, 0x0f, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Lead 2 (sawtooth) */
+   { 0x22, 0x21, 0x46, 0x89, 0x86, 0x64, 0x55, 0x18, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 3 (calliope) */
+   { 0x21, 0xa1, 0x45, 0x09, 0x66, 0x96, 0x12, 0x0a, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Lead 4 (chiff) */
+   { 0x21, 0x22, 0x8b, 0x09, 0x92, 0x91, 0x2a, 0x2a, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Lead 5 (charang) */
+   { 0xa2, 0x61, 0x9e, 0x49, 0xdf, 0x6f, 0x05, 0x07, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Lead 6 (voice) */
+   { 0x20, 0x60, 0x1a, 0x09, 0xef, 0x8f, 0x01, 0x06, 0x00, 0x02, 0x00, 0, 0, 0 }, /* Lead 7 (fifths) */
+   { 0x21, 0x21, 0x8f, 0x86, 0xf1, 0xf4, 0x29, 0x09, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Lead 8 (bass+lead) */
+   { 0x77, 0xa1, 0xa5, 0x09, 0x53, 0xa0, 0x94, 0x05, 0x00, 0x00, 0x02, 0, 0, 0 }, /* Pad 1 (new age) */
+   { 0x61, 0xb1, 0x1f, 0x89, 0xa8, 0x25, 0x11, 0x03, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 2 (warm) */
+   { 0x61, 0x61, 0x17, 0x09, 0x91, 0x55, 0x34, 0x16, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Pad 3 (polysynth) */
+   { 0x71, 0x72, 0x5d, 0x09, 0x54, 0x6a, 0x01, 0x03, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Pad 4 (choir) */
+   { 0x21, 0xa2, 0x97, 0x09, 0x21, 0x42, 0x43, 0x35, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Pad 5 (bowed) */
+   { 0xa1, 0x21, 0x1c, 0x09, 0xa1, 0x31, 0x77, 0x47, 0x01, 0x01, 0x00, 0, 0, 0 }, /* Pad 6 (metallic) */
+   { 0x21, 0x61, 0x89, 0x0c, 0x11, 0x42, 0x33, 0x25, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Pad 7 (halo) */
+   { 0xa1, 0x21, 0x15, 0x09, 0x11, 0xcf, 0x47, 0x07, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Pad 8 (sweep) */
+   { 0x3a, 0x51, 0xce, 0x09, 0xf8, 0x86, 0xf6, 0x02, 0x00, 0x00, 0x02, 0, 0, 0 }, /* FX 1 (rain) */
+   { 0x21, 0x21, 0x15, 0x09, 0x21, 0x41, 0x23, 0x13, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 2 (soundtrack) */
+   { 0x06, 0x01, 0x5b, 0x09, 0x74, 0xa5, 0x95, 0x72, 0x00, 0x00, 0x00, 0, 0, 0 }, /* FX 3 (crystal) */
+   { 0x22, 0x61, 0x92, 0x8c, 0xb1, 0xf2, 0x81, 0x26, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* FX 4 (atmosphere) */
+   { 0x41, 0x42, 0x4d, 0x09, 0xf1, 0xf2, 0x51, 0xf5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* FX 5 (brightness) */
+   { 0x61, 0xa3, 0x94, 0x89, 0x11, 0x11, 0x51, 0x13, 0x01, 0x00, 0x06, 0, 0, 0 }, /* FX 6 (goblins) */
+   { 0x61, 0xa1, 0x8c, 0x89, 0x11, 0x1d, 0x31, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* FX 7 (echoes) */
+   { 0xa4, 0x61, 0x4c, 0x09, 0xf3, 0x81, 0x73, 0x23, 0x01, 0x00, 0x04, 0, 0, 0 }, /* FX 8 (sci-fi) */
+   { 0x02, 0x07, 0x85, 0x0c, 0xd2, 0xf2, 0x53, 0xf6, 0x00, 0x01, 0x00, 0, 0, 0 }, /* Sitar */
+   { 0x11, 0x13, 0x0c, 0x89, 0xa3, 0xa2, 0x11, 0xe5, 0x01, 0x00, 0x00, 0, 0, 0 }, /* Banjo */
+   { 0x11, 0x11, 0x06, 0x09, 0xf6, 0xf2, 0x41, 0xe6, 0x01, 0x02, 0x04, 0, 0, 0 }, /* Shamisen */
+   { 0x93, 0x91, 0x91, 0x09, 0xd4, 0xeb, 0x32, 0x11, 0x00, 0x01, 0x08, 0, 0, 0 }, /* Koto */
+   { 0x04, 0x01, 0x4f, 0x09, 0xfa, 0xc2, 0x56, 0x05, 0x00, 0x00, 0x0c, 0, 0, 0 }, /* Kalimba */
+   { 0x21, 0x22, 0x49, 0x09, 0x7c, 0x6f, 0x20, 0x0c, 0x00, 0x01, 0x06, 0, 0, 0 }, /* Bagpipe */
+   { 0x31, 0x21, 0x85, 0x09, 0xdd, 0x56, 0x33, 0x16, 0x01, 0x00, 0x0a, 0, 0, 0 }, /* Fiddle */
+   { 0x20, 0x21, 0x04, 0x8a, 0xda, 0x8f, 0x05, 0x0b, 0x02, 0x00, 0x06, 0, 0, 0 }, /* Shanai */
+   { 0x05, 0x03, 0x6a, 0x89, 0xf1, 0xc3, 0xe5, 0xe5, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Tinkle Bell */
+   { 0x07, 0x02, 0x15, 0x09, 0xec, 0xf8, 0x26, 0x16, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Agogo */
+   { 0x05, 0x01, 0x9d, 0x09, 0x67, 0xdf, 0x35, 0x05, 0x00, 0x00, 0x08, 0, 0, 0 }, /* Steel Drums */
+   { 0x18, 0x12, 0x96, 0x09, 0xfa, 0xf8, 0x28, 0xe5, 0x00, 0x00, 0x0a, 0, 0, 0 }, /* Woodblock */
+   { 0x10, 0x00, 0x86, 0x0c, 0xa8, 0xfa, 0x07, 0x03, 0x00, 0x00, 0x06, 0, 0, 0 }, /* Taiko Drum */
+   { 0x11, 0x10, 0x41, 0x0c, 0xf8, 0xf3, 0x47, 0x03, 0x02, 0x00, 0x04, 0, 0, 0 }, /* Melodic Tom */
+   { 0x01, 0x10, 0x8e, 0x09, 0xf1, 0xf3, 0x06, 0x02, 0x02, 0x00, 0x0e, 0, 0, 0 }, /* Synth Drum */
+   { 0x0e, 0xc0, 0x00, 0x09, 0x1f, 0x1f, 0x00, 0xff, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Reverse Cymbal */
+   { 0x06, 0x03, 0x80, 0x91, 0xf8, 0x56, 0x24, 0x84, 0x00, 0x02, 0x0e, 0, 0, 0 }, /* Guitar Fret Noise */
+   { 0x0e, 0xd0, 0x00, 0x0e, 0xf8, 0x34, 0x00, 0x04, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Breath Noise */
+   { 0x0e, 0xc0, 0x00, 0x09, 0xf6, 0x1f, 0x00, 0x02, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Seashore */
+   { 0xd5, 0xda, 0x95, 0x49, 0x37, 0x56, 0xa3, 0x37, 0x00, 0x00, 0x00, 0, 0, 0 }, /* Bird Tweet */
+   { 0x35, 0x14, 0x5c, 0x11, 0xb2, 0xf4, 0x61, 0x15, 0x02, 0x00, 0x0a, 0, 0, 0 }, /* Telephone ring */
+   { 0x0e, 0xd0, 0x00, 0x09, 0xf6, 0x4f, 0x00, 0xf5, 0x00, 0x03, 0x0e, 0, 0, 0 }, /* Helicopter */
+   { 0x26, 0xe4, 0x00, 0x09, 0xff, 0x12, 0x01, 0x16, 0x00, 0x01, 0x0e, 0, 0, 0 }, /* Applause */
+   { 0x00, 0x00, 0x00, 0x09, 0xf3, 0xf6, 0xf0, 0xc9, 0x00, 0x02, 0x0e, 0, 0, 0 }  /* Gunshot */
+
+};
+
+/* logarithmic relationship between midi and FM volumes */
+static int my_midi_fm_vol_table[128] = {
+   0,  11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43,
+   45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+   64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77,
+   78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89,
+   90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100,
+   101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108,
+   109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115,
+   116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122,
+   123, 123, 124, 124, 125, 125, 126, 126, 127
+};
+