/************************************************************************ * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ************************************************************************/ #include "std.hpp" #include #include #include #include #include #include #define ulong unsigned long #define MakeFirm(a,b,c,d) ((ulong)a+((ulong)b<<8)+((ulong)c<<16)+((ulong)d<<24)) const ulong MThd = MakeFirm('M','T','h','d'), MTrk = MakeFirm('M','T','r','k'); const int Freq4[12] = {277,294,311,330,349,370,392,415,440,466,494,523}; ulong adjustulong(ulong num) { asm { MOV DX, WORD PTR num MOV AX, WORD PTR num[2] XCHG AH, AL XCHG DH, DL } } ulong adjusttribyte(ulong num) { asm { MOV AL, BYTE PTR num[2] MOV AH, BYTE PTR num[1] MOV DL, BYTE PTR num XOR DH, DH } } unsigned adjustint(unsigned num) { asm { MOV AH, BYTE PTR num MOV AL, BYTE PTR num[1] } } char findfirm(int handle, const ulong realfirm) { ulong firm, data = 0l; _read(handle,&firm,4); while (firm != realfirm && !eof(handle)) { _read(handle,&data,1); // !!! firm = (firm<<8) | data; } return (firm == realfirm); } void play(int note, int vel) { if (!vel) nosound(); else { int oct = note/12; if (oct==4) sound(Freq4[note % 12]); else if (oct>4) sound(Freq4[note % 12]*(oct-4)); else sound(Freq4[note % 12]/(4-oct)); } } void parsetrack(int handle) { ulong data; int i; byte event,oldevent, meta, oldmeta, channel; ulong totdelay; byte bdat,bdat2; char car = 0, end = 0; _read(handle,&data,4); data = adjustulong(data); printf(" track size: %lu\n",data); do { totdelay=0l; // read delay _read(handle,&bdat,1); totdelay = bdat & 0x7f; for (i=3;i--;) if (bdat & 0x80) { _read(handle,&bdat,1); totdelay = (totdelay<<7) + (bdat & 0x7f); } else break; printf(" - delay: %6lu ",totdelay); // read event _read(handle,&event,1); if (!(event & 0x80)) { printf("*"); bdat = event; meta = oldmeta; event = oldevent; } else { printf(" "); if ((meta = (event == 0xff)) != 0) _read(handle,&event,1); oldmeta = meta; oldevent = event; if ((event & 0xf0) != 0xf0) _read(handle,&bdat,1); } if (!meta) { channel = event & 0x0f; printf(" e: ch(%2d) ",channel); switch(event & 0xf0) { case 0x80: _read(handle,&bdat2,1); printf("note %d off (vel.%d)\n",bdat,bdat2); play(bdat,0); break; case 0x90: _read(handle,&bdat2,1); printf("note %d on (vel.%d)\n",bdat,bdat2); play(bdat,bdat2); break; case 0xa0: _read(handle,&bdat2,1); printf("note %d after-touch (vel.%d)\n",bdat,bdat2); play(bdat,bdat2); break; case 0xb0: _read(handle,&bdat2,1); printf("controller %d change to %d\n",bdat,bdat2); break; case 0xc0: printf("program change to %d\n",bdat); break; case 0xd0: printf("channel after-touch to %d\n",bdat); break; case 0xe0: _read(handle,&bdat2,1); printf("pitch wheel change of %d\n",(int)bdat+((int)bdat2<<7)); break; case 0xf0: // per tigna switch(event) { case 0xf8: printf("time sync\n"); break; case 0xfa: printf("start sequence\n"); break; case 0xfb: printf("continue sequence\n"); break; case 0xfc: printf("stop sequence\n"); break; } break; default: printf("???\n"); break; } } else { printf(" me: "); switch(event) { case 0x2f: // end of track printf("end of track\n"); end++; break; case 0x51: totdelay = 0l; _read(handle,&totdelay,bdat); if (bdat==3) totdelay = adjusttribyte(totdelay); else if (bdat==4) totdelay = adjustulong(totdelay); else if (bdat==2) totdelay = adjustint(totdelay); printf("set tempo: (%d) %lu\n",bdat,totdelay); break; case 0x58: printf("time signature: (%d) ...\n",bdat); for (i=0;i= 0) { clrscr(); // Find Header if (findfirm(handle,MThd)) { printf("MThd\n"); _read(handle,&data,4); data = adjustulong(data); if (data == 6) { data = 0l; _read(handle,&data,2); data = adjustint(data); if (data <= 1) { _read(handle,&numtracks,2); numtracks = adjustint(numtracks); printf("Number of tracks: %d\n",numtracks); _read(handle,&data,2); data = adjustint(data); printf("Delta-time/tick : %u\n",data); for(i=1;i<=numtracks;i++) { if (findfirm(handle,MTrk)) { printf("MTrk #%d\n",i); parsetrack(handle); } else error("main","no more tracks"); } } else error("main","no synchronized tracks"); } else error("main","non-standard 6 bytes header"); } else error("main","no file header"); close(handle); } else error("main","file not found"); }