www.pudn.com > txt2midifile.zip > MIDIREAD.CPP


// midiread v1.0 written by Gnter 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; 
}