242 lines
No EOL
5.8 KiB
C++
242 lines
No EOL
5.8 KiB
C++
/************************************************************************
|
|
* 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 <io.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <conio.h>
|
|
#include <dos.h>
|
|
|
|
#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<bdat;i++) _read(handle,&bdat2,1);
|
|
break;
|
|
case 0x59:
|
|
printf("key signature: (%d) ...\n",bdat);
|
|
for (i=0;i<bdat;i++) _read(handle,&bdat2,1);
|
|
break;
|
|
case 0x7f:
|
|
printf("sequencer info: (%d) ...\n",bdat);
|
|
for (i=0;i<bdat;i++) _read(handle,&bdat2,1);
|
|
break;
|
|
default:
|
|
printf("%u\n",event);
|
|
for (i=0;i<bdat;i++) _read(handle,&bdat2,1);
|
|
}
|
|
}
|
|
if (car != 'q') {
|
|
car = getch();
|
|
if (car == 27) {
|
|
close(handle);
|
|
nosound();
|
|
exit(0);
|
|
}
|
|
}
|
|
} while (!end);
|
|
printf(" ----\n");
|
|
nosound();
|
|
}
|
|
|
|
void main() {
|
|
int handle, i, numtracks;
|
|
ulong data;
|
|
|
|
if ((handle = _open("c:\\music\\mid\\furelise2.mid",O_RDONLY|O_BINARY)) >= 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");
|
|
} |