#include struct { unsigned char ident[10]; unsigned char ainam[15][10]; unsigned char aiset[15][8]; unsigned char cinam[15][10]; unsigned char ciset1[15]; unsigned char ciset2[15]; long fptr[5]; unsigned char title[32]; } mushdr; struct muevnt { long rltime; long deltime; char etype; char inst; char frq; char fill; } evnt[2500]; unsigned char tmpbuf[16384]; char *keys[] = { "none","C","G","D","A","E","B","F#","C#","F","Bb","Eb","Ab", "Db","Gb","Cb" }; char *beat[] = { "none","2/2","3/2","2/4","3/4","4/4","5/4","6/8" }; /* sharping and flatting for key: c d e f g a b */ int keyfix[16][12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0, 0,-1, 0,-1, 0, 0,-1, 0,-1, 0, 0, 0, 0,-1, 0,-1, 0, 0,-1, 0,-1, 0, 0,-1, 0,-1, 0,-1, -1, 0,-1, 0,-1, 0, 0,-1, 0,-1, 0,-1, -1, 0,-1, 0,-1,-1, 0,-1, 0,-1, 0,-1 }; /* 96 pulses per quarter note timing */ int ppq[] = { /* 1/32 1/16 1/8 (3)---1/4-----(.) 1/2 1 2*/ 6,8,9, 12,16,18, 24,32,36, 48,64,72, 96,128,144, 192,256,288, 384,512,576, 768, 1024,1152, 1536,2048,2304, 3072,4096,4608, 6144,8192 }; /*************************/ main( argc , argv ) int argc; char *argv[]; { int handl; int i,j,k; int tempo; int evntptr; long tmpo,tmpo1; register int keyf,pitch; register long realtime; int noteplay[3]; handl = Fopen( argv[1] , 0 ); if( handl < 0 ) return; Fread( handl , 512L , &mushdr ); /* NOTES **********************/ for( i = 0 ; i < 16384 ; i++ ) tmpbuf[i] = 0; if( mushdr.fptr[0] ) Fread( handl , (unsigned long)(mushdr.fptr[0] - 512L) , tmpbuf ); else Fread( handl , 16384L , tmpbuf ); /* NOW, FOR THE SOUNDS */ tempo = 60; tmpo1 = 0; realtime = 0; evntptr = 0; printf( "PROCESSING\n" ); /* for each byte, but may jump for variable record lengths */ for( i = 8 ; tmpbuf[i] != 0xff ; i++ ) { switch( tmpbuf[i] ) { case 0x00: /* begin/end record delimiter */ realtime += tmpo1; tmpo1 = 0; break; case 0x80: /* grand staff and key signature, what does [1] do? */ keyf = tmpbuf[i+2]; i += 2; break; case 0x81: /* tempo (MM) */ tempo = tmpbuf[i+1]; i++; break; case 0x82: /* vertical bar across grand staff */ break; case 0x83: /* time signature */ i++; break; case 0x84: /* loudness */ i+=2; break; case 0x85: /* repeat (n times) marker ||: */ /* printf( " %d*[" , tmpbuf[i+1] ); */ i++; break; case 0x86: /* repeat ends here :|| */ /* printf( "]" ); */ break; default: /* note subrecord, 3 bytes, instr:note */ /* the printed value is the base note, pitch is the actual to play */ pitch = tmpbuf[i+2]; /* should be +/-12 per octave (oct2=0) offset for instrument */ if( ( tmpbuf[i+1] & 0xc0 ) == 0xc0 ) /* flat */ pitch--; if( ( tmpbuf[i+1] & 0xc0 ) == 0x80 ) /* sharp */ pitch++; /* if( ( tmpbuf[i+1] & 0xc0 ) == 0x40 ) natural */ if( !( tmpbuf[i+1] & 0xc0 ) ) /* adjust note value for key */ pitch += keyfix[keyf][pitch%12]; /* only if no accidental */ /* Note duration */ /* the player does not yet do differing lengths, should be minimum between 00 records */ tmpo = 1250L; /* for .5 milliseconds, 125 for 200Hz tics */ tmpo = ppq[ tmpbuf[i+1] & 31 ]; /* *= */ /* tmpo /= tempo; */ if( !tmpo1 || tmpo < tmpo1 ) tmpo1 = tmpo; k = 0; if( tmpbuf[i] & 0x40 ) /* begin tie */ k |= 4; if( tmpbuf[i] & 0x20 ) /* end tie (valid to begin too */ k |= 2; if( tmpbuf[i+1] & 0x20 ) /* accent */ k |= 8; if( !( tmpbuf[i] & 0x10 ) ) { /* rest */ evnt[ evntptr ].rltime = realtime; evnt[ evntptr+1 ].rltime = realtime + tmpo; evnt[ evntptr ].deltime = tmpo; evnt[ evntptr+1 ].deltime = tmpo; evnt[ evntptr ].etype = k; evnt[ evntptr+1 ].etype = k|1; evnt[ evntptr ].inst = tmpbuf[i]&15; evnt[ evntptr+1 ].inst = tmpbuf[i]&15; evnt[ evntptr ].frq = pitch; evnt[ evntptr+1 ].frq = pitch; evntptr += 2; } i+=2; break; } } /* unfold event table */ printf( "SORTING\n" ); heapsort( evnt , evntptr ); evnt[ evntptr ].rltime = 0x7fffffffL; printf( "UNFOLDING-\n" ); /* look for end of tie/beginning of tie pairs, and expand first note */ printf( "RESULTS:\n" ); initsnd(); tmpo1 = 0; k = 0; noteplay[0]=0; noteplay[1]=0; noteplay[2]=0; for( i = 0 ; i < evntptr ; i++ ) { if( tmpo1 < evnt[i].rltime ) { printf( "%10D\n" , evnt[i].rltime ); while( k < i ) { if( !( evnt[k].etype & 1 ) ) { if( !noteplay[0] )play(0,evnt[k].frq),noteplay[0]=evnt[k].frq; else if( !noteplay[1] )play(1,evnt[k].frq),noteplay[1]=evnt[k].frq; else if( !noteplay[2] )play(2,evnt[k].frq),noteplay[2]=evnt[k].frq; } k++; } p_pause( (long)( (evnt[i].rltime - tmpo1) * 625L / tempo ) ); tmpo1 = evnt[i].rltime; } /* printf( "%10D %6D %2d %2d %3d\n" , evnt[i].rltime, evnt[i].deltime, evnt[i].etype, evnt[i].inst, evnt[i].frq ); */ if( evnt[i].etype & 1 ) { /* if( !( evnt[i].etype & 4 ) ) { only if matching &2*/ if( noteplay[0] == evnt[i].frq )quiet(0),noteplay[0]=0; else if( noteplay[1] == evnt[i].frq )quiet(1),noteplay[1]=0; else if( noteplay[2] == evnt[i].frq )quiet(2),noteplay[2]=0; /* }*/ } } printf( "\n" ); Fclose( handl ); } /*** HOW TO PLAY NOTES ***/ int notedivs[12] = { 3822, 3608, 3405, 3214, 3034, 2863, 2703, 2551, 2408, 2273, 2145, 2025 }; /*****/ initsnd() { int val; Giaccess( 0 , 8+128 ); Giaccess( 0 , 9+128 ); Giaccess( 0 , 10+128 ); val = Giaccess( 0 , 7 ); val &= 0xc0; val |= 0x38; Giaccess( val , 7+128 ); } /*****/ quiet( channel ) register int channel; { Giaccess( 0 , channel + 8+128 ); } /*****/ play( channel , note ) register int channel,note; { register int val; note -= 24; if( note < 0 ) return; val = notedivs[ note % 12 ] >> (note / 12); Giaccess( 0x08 , channel + 8+128 ); Giaccess( val & 0xff , channel + channel + 0+128 ); Giaccess( val >> 8 , channel + channel + 1+128 ); } /*************************/ heapsort( tbl , len ) struct muevnt *tbl; int len; { int l; int r; int i,j; struct muevnt ktbl; /*1*/ l = len/2 + 1; r = len; while( 1 ) { /*2*/ if( l > 1 ) { l--; ktbl = tbl[ l ]; } else { ktbl = tbl[ r ]; tbl[ r ] = tbl[ 1 ]; r--; if( r == 1 ) { tbl[ 1 ] = ktbl; break; } } /*3*/ j = l; while( 1 ) { /*4*/ i = j; j = j+j; if( j > r ) break; if( j < r && tbl[ j ].rltime < tbl[ j+1 ].rltime ) j++; /*6*/ if( ktbl.rltime >= tbl[ j ].rltime ) break; /*7*/ tbl[i] = tbl[j]; } /*8*/ tbl[i] = ktbl; } }