kaos/KaosSrc/testmid.cpp
2024-10-12 20:32:30 -05:00

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");
}