Mercurial > audlegacy
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"); + } +}