www.pudn.com > txt2midifile.zip > MIDIREAD.CPP
// midiread v1.0 written by Gnter Nagler 1995 (gnagler@ihm.tu-graz.ac.at)
#include "midiread.hpp"
unsigned long getlong(FILE* f)
{
unsigned char c[4];
unsigned long n = 0;
if (fread(c, 4, 1, f) != 1)
return 0;
n = c[0];
n = (n << 8) + c[1];
n = (n << 8) + c[2];
n = (n << 8) + c[3];
return n;
}
unsigned long gettri(FILE* f)
{
unsigned char c[3];
unsigned long n = 0;
if (fread(c, 3, 1, f) != 1)
return 0;
n = c[0];
n = (n << 8) + c[1];
n = (n << 8) + c[2];
return n;
}
int getbyte(FILE*f)
{
return fgetc(f);
}
void putbyte(FILE* f, int n)
{
fputc(n, f);
}
unsigned short getword(FILE* f)
{
unsigned char c[2];
unsigned short n = 0;
if (fread(c, 2, 1, f) != 1)
return 0;
n = c[0];
n = (n << 8) + c[1];
return n;
}
void putword(FILE* f, unsigned short n)
{
unsigned char c[2];
c[0] = ((n>>8) & 0xff);
c[1] = n & 0xff;
fwrite(c, 2, 1, f);
}
void putlong(FILE* f, unsigned long n)
{
unsigned char c[4];
c[0] = ((n>>24) & 0xff);
c[1] = ((n>>16) & 0xff);
c[2] = ((n>>8) & 0xff);
c[3] = n & 0xff;
fwrite(c, 4, 1, f);
}
void puttri(FILE* f, unsigned long n)
{
unsigned char c[3];
c[0] = ((n>>16) & 0xff);
c[1] = ((n>>8) & 0xff);
c[2] = n & 0xff;
fwrite(c, 3, 1, f);
}
int get_midihead(FILE* f, MIDIHEAD* h)
{
long tag;
long taglen;
long tagend;
fseek(f, 0L, SEEK_SET);
tag = getlong(f);
if (tag != MThd)
return 0;
taglen = getlong(f);
tagend = ftell(f)+taglen;
h->songs = getword(f);
h->tracks = getword(f);
h->unitsperbeat = getword(f);
fseek(f, tagend, SEEK_SET);
return 1;
}
void skip_tag(FILE* f)
{
getlong(f);
fseek(f, getlong(f), SEEK_CUR);
}
void put_midihead(FILE* f, MIDIHEAD* h)
{
fseek(f, 0L, SEEK_SET);
putlong(f, MThd);
putlong(f, 6l);
putword(f, h->songs);
putword(f, h->tracks);
putword(f, h->unitsperbeat);
}
unsigned long getdelta(FILE* f)
{
unsigned long n = 0;
int i = 0, c;
for (i = 0; i < 4; i++)
{
c = fgetc(f);
if (c == -1)
break;
n = (n << 7) + (c & 0x7f);
if ((c & 0x80) == 0)
break;
}
return n;
}
void putdelta(FILE* f, unsigned long n)
{
unsigned char c[4], v;
int i = 0;
while (i < 4)
{
v = n & 0x7f;
n >>= 7;
c[i++] = v;
if (n == 0)
break;
}
while (i > 0)
{
int v;
v = c[--i];
if (i > 0)
v |= 0x80;
fputc(v, f);
}
}
static long chunkpos;
void open_chunk(FILE* f, char* s)
{
fwrite(s, 1, 4, f);
putlong(f, 0L);
chunkpos = ftell(f);
}
void close_chunk(FILE* f)
{
unsigned long p = ftell(f);
unsigned long len = 0;
len = p - chunkpos;
fseek(f, chunkpos-4, SEEK_SET);
putlong(f, len);
fseek(f, p, SEEK_SET);
}
int scanevent(
FILE* f,
unsigned long* dtime,
unsigned char* ev,
unsigned char lastev,
unsigned long* len)
{
int c;
*dtime = getdelta(f);
c = getbyte(f);
if (c == EOF)
return 0;
if ((c & 0x80) == 0 && (lastev >= 0x80 && lastev <= 0xEF))
{
fseek(f, -1, SEEK_CUR); // event not given, use lastev
c = lastev;
}
*ev = c;
switch(c & 0xf0)
{
case 0xf0:
{
switch(c)
{
case 0xf0: // sysex event
*len = getdelta(f);
break;
case 0xf2: // song position pointer event
*len = 2;
break;
case 0xf3: // song select event
*len = 1;
break;
case 0xf6: // tune request event
case 0xf8: // timing clock event
case 0xfa: // start event
case 0xfb: // continue event
case 0xfc: // stop event
case 0xfe: // active sensing event
*len = 0;
break;
case 0xff: // system reset event
{
long p = ftell(f);
getbyte(f);
*len = getdelta(f);
*len += ftell(f)-p;
fseek(f, p, SEEK_SET);
}
}
}
break;
case 0x90: // notes
case 0x80:
*len = 2;
break;
case 0xC0:
case 0xD0:
*len = 1;
break;
case 0xA0:
case 0xB0:
case 0xE0:
*len = 2;
break;
default:
*len = 0;
return 0;
}
return 1;
}
int seekchannel(FILE* f, unsigned long len)
{
unsigned char lastev = 0xff, ev;
long oldpos = ftell(f);
long endpos = oldpos + len;
unsigned long delta, paramlen;
while (ftell(f) < endpos && scanevent(f, &delta, &ev, lastev, ¶mlen) && !feof(f))
{
if (ev >= 0x80 && ev <= 0xEF)
{
fseek(f, oldpos, SEEK_SET);
return ev & 15;
}
fseek(f, paramlen, SEEK_CUR);
}
fseek(f, oldpos, SEEK_SET);
return -1;
}
static char* GMProg[128] =
{
"Piano", "BritePiano", "HammerPiano", "HonkeyTonk", "NewTines", "DigiPiano", "Harpsicord", "Clav",
"Celesta", "Glocken", "MusicBox", "Vibes", "Marimba", "Xylophon", "Tubular", "Santur",
"FullOrgan", "PercOrgan", "BX-3Organ", "ChurchPipe", "Positive", "Musette", "Harmonica", "Tango",
"ClassicGtr", "A.Guitar", "JazzGuitar", "CleanGtr", "MuteGuitar", "OverDrive", "DistGuitar", "RockMonics",
"JazzBass", "DeepBass", "PickBass", "FretLess", "SlapBass1", "SlapBass2", "SynthBass1", "SynthBass2",
"Violin", "Viola", "Cello", "ContraBass", "TremoloStr", "Pizzicato", "Harp", "Timpani",
"Marcato", "SlowString", "AnalogPad", "StringPad", "Choir", "DooVoice", "Voices", "OrchHit",
"Trumpet", "Trombone", "Tuba", "MutedTrumpet", "FrenchHorn", "Brass", "SynBrass1", "SynBrass2",
"SopranoSax", "AltoSax", "TenorSax", "BariSax", "SweetOboe", "EnglishHorn", "BasoonOboe", "Clarinet",
"Piccolo", "Flute", "Recorder", "PanFlute", "Bottle", "Shakuhachi","Whistle", "Ocarina",
"SquareWave", "SawWave", "SynCalinope", "SynChiff", "Charang", "AirChorus", "Rezzo4ths", "Bass&Lead",
"Fantasia", "WarmPad", "PolyPad", "GhostPad", "BowedGlas", "MetalPad", "HaloPad", "Sweep",
"IceRain", "SoundTrack", "Crystal", "Atmosphere", "Brightness", "Goblin", "EchoDrop", "StarTheme",
"Sitar", "Banjo", "Shamisen", "Koto", "Kalimba","Scotland","Fiddle", "Shanai",
"MetalBell", "Agogo", "SteelDrums", "Woodblock", "Taiko", "Tom", "SynthTom", "RevCymbal",
"FretNoise", "NoiseChiff", "Seashore", "Birds", "Telephone", "Helicopter", "Stadium!!", "GunShot"
};
const char* progname(int n, int channel)
{
static char defname[10] = "";
if (channel == 9) // drum programs
{
switch(n)
{
case 0: return "Dr1";
case 0x10: return "Dr2";
case 0x19: return "Dr3";
case 0x20: return "Dr4";
case 0x28: return "Dr5";
case 0x40: return "Dr6";
case 0x18: return "Dr7";
case 0x30: return "Dr8";
}
}
else if (n >= 0 && n <= 127)
return GMProg[n];
def:
sprintf(defname, "%d", n);
return (const char*)defname;
}