#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; 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; long tmpo,tmpo1; int keyf,pitch; int tonecnt; printf( "\033v" ); /* screen wrap just in case */ handl = Fopen( argv[1] , 0 ); if( handl < 0 ) return; Fread( handl , 512L , &mushdr ); /* title */ printf( "song:%s\n\n" , mushdr.title ); /* inst. names, noise, tone, octave, ADSR (vert,horiz) 0-15 , Casio octave,(midi?)channel(0=16),preset */ printf( "Atari Casio NTO A A D D S S R R O C \n" ); printf( "instrument instrument ZNV | - | - | - | - v h PR\n\n" ); for( i = 0 ; i < 15 ; i++ ) { printf( "%-10s %-10s " , mushdr.ainam[i] , mushdr.cinam[i] ); if( mushdr.aiset[i][0] & 0x80 ) printf( " " ); else printf( "N" ); if( mushdr.aiset[i][0] & 0x10 ) printf( " " ); else printf( "T" ); printf( "%01d" , mushdr.aiset[i][1] >> 4 ); for( j=0 ; j < 8 ; j++ ) printf( "%3d" , mushdr.aiset[i][j] & 0x0f ); printf( " %2d%3d%3d\n" , mushdr.ciset1[i] >> 4 , mushdr.ciset1[i] & 0x0f , mushdr.ciset2[i] ); } /* displacement to 4(?) lines of lyrics */ for( i = 0 ; i < 5 ; i++ ) { printf( "%08X\n" , mushdr.fptr[i] ); } /* 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 ); /* music */ /* track info - 4 words, lsb enables track, rest select instruments */ for( i = 0 ; i < 4 ; i++ ) { if( tmpbuf[i+i + 1 ] ) printf( "Track %d enabled for " , i+1 ); else printf( "Track %d disabled, " , i+1 ); for( j = 1 ; j < 8 ; j++ ) if( ( tmpbuf[ i+i + 1 ] >> j ) & 1 ) printf( "%d " , j ); for( j = 0 ; j < 8 ; j++ ) if( ( tmpbuf[ i+i ] >> j ) & 1 ) printf( "%d " , j+8 ); printf( "\n" ); } /* NOW, FOR THE SOUNDS */ tempo = 60; tmpo1 = 0; initsnd(); /* 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 */ p_pause( (long)(tmpo1 >> 6) ); /* actually should be for each channel */ quiet(); tonecnt = 0; tmpo1 = 0; printf( "\n" ); break; case 0x80: /* grand staff and key signature, what does [1] do? */ printf( " (%d)key:%s," , tmpbuf[i+1] , keys[tmpbuf[i+2]] ); keyf = tmpbuf[i+2]; i += 2; break; case 0x81: /* tempo (MM) */ printf( " tempo, quarter note = %d," , tmpbuf[i+1] ); tempo = tmpbuf[i+1]; i++; break; case 0x82: /* vertical bar across grand staff */ printf( "|" ); break; case 0x83: /* time signature */ printf( " time:%s," , beat[tmpbuf[i+1]] ); i++; break; case 0x84: /* loudness */ printf( " loud(%d)=%d," , tmpbuf[i+1] , tmpbuf[i+2] ); 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 */ printf( "{%d:%d" , tmpbuf[i] & 15 , tmpbuf[i+2] ); /* 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] & 0x40 ) /* begin tie */ printf( "(" ); if( tmpbuf[i] & 0x20 ) /* end tie (valid to begin too */ printf( ")" ); if( ( tmpbuf[i+1] & 0xc0 ) == 0xc0 ) /* flat */ pitch--, printf( "b" ); if( ( tmpbuf[i+1] & 0xc0 ) == 0x80 ) /* sharp */ pitch++, printf( "#" ); if( ( tmpbuf[i+1] & 0xc0 ) == 0x40 ) /* natural */ printf( "(nat)" ); if( !( tmpbuf[i+1] & 0xc0 ) ) /* adjust note value for key */ pitch += keyfix[keyf][pitch%12]; /* only if no accidental */ if( tmpbuf[i] & 0x10 ) printf( "-" ); else if ( tonecnt < 3 ) /* play it sam (tramiel?:) */ play( tonecnt++ , pitch ); if( tmpbuf[i+1] & 0x20 ) /* accent */ printf( ">" ); k = tmpbuf[i+1] & 31; /* Note duration */ j = 64; /* the player does not yet do differing lengths, should be minimum between 00 records */ tmpo = 37500L; /* for milliseconds, 7500 for 200Hz tics */ tmpo *= ppq[k]; tmpo /= tempo; if( !tmpo1 || tmpo < tmpo1 ) tmpo1 = tmpo; while( k > 2 ) /* type of note */ j >>= 1, k -= 3; /* tempo is period not freq */ if( !(k&1) ) printf( " 1/%d" , j ); /* normal and dotted */ if( k == 1 ) printf( " 1/%d(3)" , j >> 1 ); /* triplet */ if( k == 2 ) printf( "." ); /* dotted */ printf( "}" ); i+=2; break; } } printf( "\n" ); quiet(); /* LYRICS - using the pointers - room for a fourth line? ********************/ if( mushdr.fptr[0] ) { for( i = 0 ; i < 16384 ; i++ ) tmpbuf[i] = 0; Fread( handl , mushdr.fptr[1]-mushdr.fptr[0] , tmpbuf ); printf( "verse 1:\n" ); for( i = 0 ; tmpbuf[i] ; i++ ) { if( !(i & 63 ) ) printf( "\n" ); printf( "%c" , tmpbuf[i] ); } printf( "\n" ); for( i = 0 ; i < 16384 ; i++ ) tmpbuf[i] = 0; Fread( handl , mushdr.fptr[2]-mushdr.fptr[1] , tmpbuf ); printf( "verse 2:\n" ); for( i = 0 ; tmpbuf[i] ; i++ ) { if( !(i & 63 ) ) printf( "\n" ); printf( "%c" , tmpbuf[i] ); } printf( "\n" ); for( i = 0 ; i < 16384 ; i++ ) tmpbuf[i] = 0; Fread( handl , mushdr.fptr[3]-mushdr.fptr[2] , tmpbuf ); printf( "verse 3:\n" ); for( i = 0 ; tmpbuf[i] ; i++ ) { if( !(i & 63 ) ) printf( "\n" ); printf( "%c" , tmpbuf[i] ); } printf( "\n" ); for( i = 0 ; i < 16384 ; i++ ) tmpbuf[i] = 0; Fread( handl , mushdr.fptr[4]-mushdr.fptr[3] , tmpbuf ); /*?*/ } 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() { Giaccess( 0 , 8+128 ); Giaccess( 0 , 9+128 ); Giaccess( 0 , 10+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 ); }