summaryrefslogtreecommitdiff
path: root/src/adplug/core/mid.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/adplug/core/mid.cc')
-rw-r--r--src/adplug/core/mid.cc1110
1 files changed, 0 insertions, 1110 deletions
diff --git a/src/adplug/core/mid.cc b/src/adplug/core/mid.cc
deleted file mode 100644
index 9ff191f..0000000
--- a/src/adplug/core/mid.cc
+++ /dev/null
@@ -1,1110 +0,0 @@
-/*
- * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * MIDI & MIDI-like file player - Last Update: 10/15/2005
- * 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
- * .MID - a "midi" save of a Lucas Arts Adlib music
- * - or general MIDI files
- * .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.)
- *
- * 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/2000:
- * Status: LAA: now EGA and VGA lucas games work pretty well
- *
- * 10/15/2005: Changes by Simon Peter
- * Added rhythm mode support for CMF format.
- *
- * 09/13/2008: Changes by Adam Nielsen (malvineous@shikadi.net)
- * Fixed a couple of CMF rhythm mode bugs
- * Disabled note velocity for CMF files
- * Added support for nonstandard CMF AM+VIB controller (for VGFM CMFs)
- *
- * 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"
-
-/*#define TESTING*/
-#ifdef TESTING
-#define midiprintf printf
-#else
-void CmidPlayer::midiprintf(const char *format, ...)
- {
- }
-#endif
-
-#define LUCAS_STYLE 1
-#define CMF_STYLE 2
-#define MIDI_STYLE 4
-#define SIERRA_STYLE 8
-
-// AdLib melodic and rhythm mode defines
-#define ADLIB_MELODIC 0
-#define ADLIB_RYTHM 1
-
-// File types
-#define FILE_LUCAS 1
-#define FILE_MIDI 2
-#define FILE_CMF 3
-#define FILE_SIERRA 4
-#define FILE_ADVSIERRA 5
-#define FILE_OLDLUCAS 6
-
-// AdLib standard operator table
-const unsigned char CmidPlayer::adlib_opadd[] = {0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12};
-
-// map CMF drum channels 12 - 15 to corresponding AdLib drum operators
-// bass drum (channel 11) not mapped, cause it's handled like a normal instrument
-const int CmidPlayer::map_chan[] = { 0x14, 0x12, 0x15, 0x11 };
-
-// Standard AdLib frequency table
-const int CmidPlayer::fnums[] = { 0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae };
-
-// Map CMF drum channels 11 - 15 to corresponding AdLib drum channels
-const int CmidPlayer::percussion_map[] = { 6, 7, 8, 8, 7 };
-
-CPlayer *CmidPlayer::factory(Copl *newopl)
-{
- return new CmidPlayer(newopl);
-}
-
-CmidPlayer::CmidPlayer(Copl *newopl)
- : CPlayer(newopl), author(&emptystr), title(&emptystr), remarks(&emptystr),
- emptystr('\0'), flen(0), data(0)
-{
-}
-
-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);
-}
-
-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%2ld: ",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 %u 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;
-}
-
-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 'M':
- if (s[1]=='T' && s[2]=='h' && s[3]=='d') good=FILE_MIDI;
- 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;
-}
-
-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) {
- 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) || (adlib_style & CMF_STYLE)) {
- 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_percussion(int ch, unsigned char *inst)
-{
- int opadd = map_chan[ch - 12];
-
- midi_write_adlib(0x20 + opadd, inst[0]);
- midi_write_adlib(0x40 + opadd, inst[2]);
- midi_write_adlib(0x60 + opadd, inst[4]);
- midi_write_adlib(0x80 + opadd, inst[6]);
- midi_write_adlib(0xe0 + opadd, inst[8]);
- if (opadd < 0x13) // only output this for the modulator, not the carrier, as it affects the entire channel
- midi_write_adlib(0xc0 + percussion_map[ch - 11], 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)));
- }
- }
-}
-
-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&7)<<2) + (adlib_mode == ADLIB_MELODIC || voice < 6 ? (1<<5) : 0);
- 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;
-
- opl->init();
-
- 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,numchan;
- 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 ("[%2lX]",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(adlib_mode == ADLIB_RYTHM)
- numchan = 6;
- else
- numchan = 9;
-
- if (ch[c].on!=0)
- {
- for (i=0; i<18; i++)
- chp[i][2]++;
-
- if(c < 11 || adlib_mode == ADLIB_MELODIC) {
- j=0;
- on=-1;onl=0;
- for (i=0; i<numchan; 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<numchan; i++)
- if (chp[i][2]>onl)
- { onl=chp[i][2]; on=i; }
- }
-
- if (j==0)
- midi_fm_endnote(on);
- } else
- on = percussion_map[c - 11];
-
- if (vel!=0 && ch[c].inum>=0 && ch[c].inum<128) {
- if (adlib_mode == ADLIB_MELODIC || c < 12) // 11 == bass drum, handled like a normal instrument, on == channel 6 thanks to percussion_map[] above
- midi_fm_instrument(on,ch[c].ins);
- else
- midi_fm_percussion(c, ch[c].ins);
-
- if (adlib_style & MIDI_STYLE) {
- 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 if (adlib_style & CMF_STYLE) {
- // CMF doesn't support note velocity (even though some files have them!)
- nv = 127;
- } else {
- nv=vel;
- }
-
- midi_fm_playnote(on,note+ch[c].nshift,nv*2); // sets freq in rhythm mode
- chp[on][0]=c;
- chp[on][1]=note;
- chp[on][2]=0;
-
- if(adlib_mode == ADLIB_RYTHM && c >= 11) {
- // Still need to turn off the perc instrument before playing it again,
- // as not all songs send a noteoff.
- midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11)));
- // Play the perc instrument
- midi_write_adlib(0xbd, adlib_data[0xbd] | (0x10 >> (c - 11)));
- }
-
- } else {
- if (vel==0) { //same code as end note
- if (adlib_mode == ADLIB_RYTHM && c >= 11) {
- // Turn off the percussion instrument
- midi_write_adlib(0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11)));
- //midi_fm_endnote(percussion_map[c]);
- chp[percussion_map[c - 11]][0]=-1;
- } else {
- 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:%ld:%ld]\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: %ld %ld)",c,ctrl,vel);
- ch[c].vol=vel;
- midiprintf("vol");
- break;
- case 0x63:
- if (adlib_style & CMF_STYLE) {
- // Custom extension to allow CMF files to switch the
- // AM+VIB depth on and off (officially this is on,
- // and there's no way to switch it off.) Controller
- // values:
- // 0 == AM+VIB off
- // 1 == VIB on
- // 2 == AM on
- // 3 == AM+VIB on
- midi_write_adlib(0xbd, (adlib_data[0xbd] & ~0xC0) | (vel << 6));
- midiprintf(" AM+VIB depth change - AM %s, VIB %s\n",
- (adlib_data[0xbd] & 0x80) ? "on" : "off",
- (adlib_data[0xbd] & 0x40) ? "on" : "off"
- );
- }
- break;
- case 0x67:
- midiprintf("Rhythm mode: %ld\n", vel);
- if ((adlib_style&CMF_STYLE)!=0) {
- adlib_mode=vel;
- if(adlib_mode == ADLIB_RYTHM)
- midi_write_adlib(0xbd, adlib_data[0xbd] | (1 << 5));
- else
- midi_write_adlib(0xbd, adlib_data[0xbd] & ~(1 << 5));
- }
- 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("{%ld}",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 ("%2lX ",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: %lu -- %lx\n",pos,pos);
- }
- break;
- case 0xfe:
- break;
- case 0xfd:
- break;
- case 0xff:
- v=getnext(1);
- l=getval();
- midiprintf ("\n");
- midiprintf("{%lX_%lX}",v,l);
- if (v==0x51)
- {
- lnum=getnext(l);
- msqtr=lnum; /*set tempo*/
- midiprintf ("(qtr=%ld)",msqtr);
- }
- else
- {
- for (i=0; i<l; i++)
- midiprintf ("%2lX ",getnext(1));
- }
- break;
- }
- break;
- default: midiprintf("%lX!",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 ("<%lu>",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:%lu\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:%ld\nmoff%ld\ndeltas:%ld\nmsqtr:%ld\nnumi:%ld\n",
- n,m,deltas,msqtr,i);
- pos=n; // jump to instruments
- tins=i;
- for (j=0; j<i; j++)
- {
- midiprintf ("\n%ld: ",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%ld: ",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;
- midi_fm_reset();
-}
-
-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");
- }
-}