Mercurial > audlegacy-plugins
view src/adplug/core/mid.cxx @ 3085:ac0af6b39272
Introduce new GIO plugin to buildsystem. stdio is now deprecated.
Thoughts:
- getc()/ungetc() should be moved to VFS core now
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Wed, 29 Apr 2009 20:58:36 -0500 |
parents | a31410f560cf |
children |
line wrap: on
line source
/* * Adplug - Replayer for many OPL2/OPL3 audio file formats. * Copyright (C) 1999 - 2005 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 * .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/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. * * 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 }; // dunno const int CmidPlayer::ops[] = { 0x20, 0x20, 0x40, 0x40, 0x60, 0x60, 0x80, 0x80, 0xe0, 0xe0, 0xc0 }; // 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"); VFSFile *instfd = aud_vfs_fopen (pfilename, "rb"); f = fp.open (instfd); free (pfilename); if (!f) { aud_vfs_fclose (instfd); 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); aud_vfs_fclose (instfd); 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; } bool CmidPlayer::load (VFSFile * fd, const CFileProvider & fp) { binistream *f = fp.open (fd); if (!f) return false; int good; unsigned char s[6]; std::string filename (fd->uri); 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; } 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_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]); midi_write_adlib (0xc0 + opadd, 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 << 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 ("[%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 (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) midi_fm_instrument (on, ch[c].ins); else midi_fm_percussion (c, ch[c].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; if (adlib_mode == ADLIB_RYTHM && c >= 11) { midi_write_adlib (0xbd, adlib_data[0xbd] & ~(0x10 >> (c - 11))); midi_write_adlib (0xbd, adlib_data[0xbd] | (0x10 >> (c - 11))); } } 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; 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 ("{%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; 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"); } }