diff Plugins/Input/adplug/core/mid.cpp @ 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
children 15ca2ea93a30
line wrap: on
line diff
--- /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");
+	}
+}