📄 midifile.c
字号:
/* * Read a Standard MIDI File. Externally-assigned function pointers are * called upon recognizing things in the file. See midifile(3). *//****************************************************************************** Change Log* Date | who : Change*-----------+-----------------------------------------------------------------* 2-Mar-92 | GWL : created changelog; MIDIFILE_ERROR to satisfy compiler* 28-Apr-03 | DM : changed #includes and give return types for portability*****************************************************************************/#include "switches.h"#include <stdio.h>#include <stdlib.h>#include "mfmidi.h"#include "midifile.h"#include "cext.h"#include "userio.h"#include "string.h"#define MIDIFILE_ERROR -1#ifdef PROTOTYPES#define NOARGS void#else#define NOARGS#endif/* public stuff */extern int abort_flag;/* Functions to be called while processing the MIDI file. */void (*Mf_starttrack)(NOARGS) = 0;void (*Mf_endtrack)(NOARGS) = 0;int (*Mf_getc)(NOARGS) = 0;void (*Mf_eot)(NOARGS) = 0;#ifdef PROTOTYPESvoid (*Mf_error)(char *) = 0;void (*Mf_header)(int,int,int) = 0;void (*Mf_on)(int,int,int) = 0;void (*Mf_off)(int,int,int) = 0;void (*Mf_pressure)(int,int,int) = 0;void (*Mf_controller)(int,int,int) = 0;void (*Mf_pitchbend)(int,int,int) = 0;void (*Mf_program)(int,int) = 0;void (*Mf_chanpressure)(int,int) = 0;void (*Mf_sysex)(int,char*) = 0;void (*Mf_arbitrary)(int,char*) = 0;void (*Mf_metamisc)(int,int,char*) = 0;void (*Mf_seqnum)(int) = 0;void (*Mf_smpte)(int,int,int,int,int) = 0;void (*Mf_timesig)(int,int,int,int) = 0;void (*Mf_tempo)(int) = 0;void (*Mf_keysig)(int,int) = 0;void (*Mf_sqspecific)(int,char*) = 0;void (*Mf_text)(int,int,char*) = 0;#elsevoid (*Mf_error)() = 0;void (*Mf_header)() = 0;void (*Mf_on)() = 0;void (*Mf_off)() = 0;void (*Mf_pressure)() = 0;void (*Mf_controller)() = 0;void (*Mf_pitchbend)() = 0;void (*Mf_program)() = 0;void (*Mf_chanpressure)() = 0;void (*Mf_sysex)() = 0;void (*Mf_arbitrary)() = 0;void (*Mf_metamisc)() = 0;void (*Mf_seqnum)() = 0;void (*Mf_smpte)() = 0;void (*Mf_tempo)() = 0;void (*Mf_timesig)() = 0;void (*Mf_keysig)() = 0;void (*Mf_sqspecific)() = 0;void (*Mf_text)() = 0;#endifint Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */ /* not collapsed. */long Mf_currtime = 0L; /* current time in delta-time units */int Mf_skipinit = 0; /* 1 if initial garbage should be skipped *//* private stuff */static long Mf_toberead = 0L;static long readvarinum(NOARGS);static long read32bit(NOARGS);static int read16bit(NOARGS);static void msgenlarge(NOARGS);static char *msg(NOARGS);static int readheader(NOARGS);static void readtrack(NOARGS);static void sysex(NOARGS), msginit(NOARGS);static int egetc(NOARGS);static int msgleng(NOARGS);#ifdef PROTOTYPESstatic int readmt(char*,int);static long to32bit(int,int,int,int);static int to16bit(int,int);static void mferror(char *);static void badbyte(int);static void metaevent(int);static void msgadd(int);static void chanmessage(int,int,int);#elsestatic long to32bit();static int to16bit();static void mferror();static void badbyte();static void metaevent();static void msgadd();static void chanmessage();#endifstatic int midifile_error;voidmidifile() /* The only non-static function in this file. */{ int ntrks; midifile_error = 0; if ( Mf_getc == 0 ) { mferror("mf.h() called without setting Mf_getc"); return; } ntrks = readheader(); if (midifile_error) return; if ( ntrks <= 0 ) { mferror("No tracks!"); /* no need to return since midifile_error is set */ } while ( ntrks-- > 0 && !midifile_error && !check_aborted()) readtrack(); if (check_aborted()) { mferror("Midifile read aborted\n\\tthe rest of your file will be ignored.\n"); if (abort_flag == BREAK_LEVEL) abort_flag = 0; }}static intreadmt(s,skip) /* read through the "MThd" or "MTrk" header string */char *s;int skip; /* if 1, we attempt to skip initial garbage. */{ int nread = 0; char b[4]; char buff[32]; int c; char *errmsg = "expecting "; retry: while ( nread<4 ) { c = (*Mf_getc)(); if ( c == EOF ) { errmsg = "EOF while expecting "; goto err; } b[nread++] = c; } /* See if we found the 4 characters we're looking for */ if ( s[0]==b[0] && s[1]==b[1] && s[2]==b[2] && s[3]==b[3] ) return(0); if ( skip ) { /* If we are supposed to skip initial garbage, */ /* try again with the next character. */ b[0]=b[1]; b[1]=b[2]; b[2]=b[3]; nread = 3; goto retry; } err: (void) strcpy(buff,errmsg); (void) strcat(buff,s); mferror(buff); return(0);}static integetc() /* read a single character and abort on EOF */{ int c = (*Mf_getc)(); if ( c == EOF ) { mferror("premature EOF"); return EOF; } Mf_toberead--; return(c);}static intreadheader() /* read a header chunk */{ int format, ntrks, division; if ( readmt("MThd",Mf_skipinit) == EOF ) return(0); Mf_toberead = read32bit(); if (midifile_error) return MIDIFILE_ERROR; format = read16bit(); if (midifile_error) return MIDIFILE_ERROR; ntrks = read16bit(); if (midifile_error) return MIDIFILE_ERROR; division = read16bit(); if (midifile_error) return MIDIFILE_ERROR; if ( Mf_header ) (*Mf_header)(format,ntrks,division); /* flush any extra stuff, in case the length of header is not 6 */ while ( Mf_toberead > 0 && !midifile_error) (void) egetc(); return(ntrks);}static voidreadtrack() /* read a track chunk */{ /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor, lng; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* (possibly running) status byte */ int needed; if ( readmt("MTrk",0) == EOF ) return; Mf_toberead = read32bit(); if (midifile_error) return; Mf_currtime = 0L; if ( Mf_starttrack ){ (*Mf_starttrack)(); } while ( Mf_toberead > 0 ) { Mf_currtime += readvarinum(); /* delta time */ if (midifile_error) return; c = egetc(); if (midifile_error) return; if ( sysexcontinue && c != 0xf7 ) { mferror("didn't find expected continuation of a sysex"); return; } if ( (c & 0x80) == 0 ) { /* running status? */ if ( status == 0 ) { mferror("unexpected running status"); return; } running = 1; } else { status = c; running = 0; } needed = chantype[ (status>>4) & 0xf ]; if ( needed ) { /* ie. is it a channel message? */ if ( running ) c1 = c; else { c1 = egetc(); if (midifile_error) return; } chanmessage( status, c1, (needed>1) ? egetc() : 0 ); if (midifile_error) return; continue;; } switch ( c ) { case 0xff: /* meta event */ type = egetc(); if (midifile_error) return; /* watch out - Don't combine the next 2 statements */ lng = readvarinum(); if (midifile_error) return; lookfor = Mf_toberead - lng; msginit(); while ( Mf_toberead > lookfor ) { char c = egetc(); if (midifile_error) return; msgadd(c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -