int (*Mf_getc) (); int (*Mf_putc) (); int (*Mf_error) (char *msg); int (*Mf_header) (int format, int ntrks, int division); int (*Mf_trackstart) (); int (*Mf_trackend) (); int (*Mf_noteon) (int chan, int pitch, int vol); int (*Mf_noteoff) (int chan, int pitch, int vol); int (*Mf_pressure) (int chan, int pitch, int pressure); int (*Mf_parameter) (int chan, int control, int value); int (*Mf_pitchbend) (int chan, int msb, int lsb); int (*Mf_program) (int chan, int program); int (*Mf_chanpressure) (int chan, int pressure); int (*Mf_sysex) (int leng, char *msg); int (*Mf_metamisc) (int type, int leng, int msg); int (*Mf_seqspecific) (int type, int leng, int msg); int (*Mf_seqnum) (int num); int (*Mf_text) (int type, int leng, int msg); int (*Mf_eot) (); int (*Mf_timesig) (int numer, int denom, int clocks, int qnotes); int (*Mf_smpte) (int hour, int min, int sec, int frame, int fract); int (*Mf_tempo) (int microsecs); int (*Mf_keysig) (int sharpflat, int minor); int (*Mf_arbitrary) (int leng, int msg); int Mf_nomerge; long Mf_currtime;
mfwrite(int format, int ntracks, int division, FILE *fp)
int (*Mf_writetrack)(int track); int (*Mf_writetempotrack)(); void mf_write_midi_event(delta, type, chan, data, size) unsigned long delta; unsigned int type,chan,size; char *data; void mf_write_meta_event(delta, type, data, size) unsigned long delta; unsigned int type,chan,size; char *data; void mf_write_tempo(tempo) unsigned long tempo; unsigned long mf_sec2ticks(float seconds, int division, int tempo) float seconds; int division; unsigned int tempo; float mf_ticks2sec(ticks, division, tempo) unsigned long ticks; int division; unsigned int tempo;
#include <stdio.h> #include "midifile.h" mygetc() { /* use standard input */ return(getchar()); } main() { Mf_getc = mygetc; mfread(); exit(0); }This takes advantage of the default action when an error is detected, which is to exit silently with a return code of 1. An error function of your own can be used by giving a value to Mf_error; the function will be called with the error message as an argument. The other Mf_* variables can similarly be used to call arbitrary functions while parsing the MIDI file. The descriptions below of the information passed to these functions is sparse; refer to the MIDI file standard for the complete descriptions. Mf_header is the first function to be called, and its arguments contain information from the MIDI file's header; the format (0,1, or 2), the number of tracks, and the division of a quarter-note that defines the times units. Mf_trackstart and Mf_trackend are called at the beginning and end of each track. Once inside a track, each separate message causes a function to be called. For example, each note-on message causes Mf_noteon to be called with the channel, pitch, and volume as arguments. The time at which the message occurred is stored in Mf_currtime - one of the few external variables that isn't a function pointer. The other channel messages are handled in a similar and obvious fashion - Mf_noteoff, Mf_pressure, Mf_parameter, Mf_pitchbend, Mf_program, and Mf_chanpressure. See the declarations above for the arguments that are passed to each. System exclusive messages are handled by calling Mf_sysex, passing as arguments the message length and a pointer to a static buffer containing the entire message. The buffer is expanded when necessary; memory availability is the only limit to its size. Normally, 'continued' system exclusives are automatically merged, and Mf_sysex is only called once. It you want to disable this you can set Mf_nomerge to 1, causing Mf_sysex to be called once for each part of the message. Mf_seqnum is called by the meta message that provides a sequence number, which if present must appear at the beginning of a track. The tempo meta message causes Mf_tempo to be called; its argument is the number of microseconds per MIDI quarter-note (24 MIDI clocks). The end-of-track meta message causes Mf_eot to be called. The key signature meta message causes Mf_keysig to be called; the first argument conveys the number of sharps or flats, the second argument is 1 if the key is minor. The Mf_timesig and Mf_smpte functions are called when the corresponding meta messages are seen. See the MIDI file standard for a description of their arguments. The text messages in the MIDI file standard are of the following types:
0x01 Text Event 0x02 Copyright 0x03 Sequence/Track Name 0x04 Instrument 0x05 Lyric 0x06 Marker 0x07 Cue Point 0x08-0x0F Reserverd but UndefinedMf_text is called for each of these; the arguments are the type number, the message length, and a pointer to the message buffer. Misceallaneous meta messages are handled by Mf_metamisc, sequencer-specific messages are handled by Mf_seqspecific, and arbitrary "escape" messages (started with 0xF7) are handled by Mf_arbitrary.
#include <stdio.h> #include <ctype.h> #include "midifile.h" FILE *F; mygetc() { return(getc(F)); } mytext(type,leng,msg) char *msg; { char *p; char *ep = msg + leng; for ( p=msg; p<ep ; p++ ) putchar( isprint(*p) ? *p : '?' ); putchar('); } main(argc,argv) char **argv; { if ( argc > 1 ) F = fopen(argv[1],"r"); else F = stdin; Mf_getc = mygetc; Mf_text = mytext; mfread(); exit(0); }
#include <stdio.h> #include <ctype.h> #include "midifile.h" FILE *fp; myputc(c) { return(putc(c,fp));} int mywritetrack(track) int track; { int i; char data[2]; /* 120 beats/per/second */ mf_write_tempo((long)500000); for(i = 1 ; i < 128; i++){ data[0] = i; /* note number */ data[1] = 64; /* velocity */ if(!mf_write_midi_event(480,note_on,1,data,2)) return(-1); if(!mf_write_midi_event(480,note_off,1,data,2)) return(-1); } return(1); } /* end of write_track() */ main(argc,argv) char **argv; { if((fp = fopen(argv[1],"w")) == 0L) exit(1); Mf_putc = myputc; Mf_writetrack = mywritetrack; /* write a single track */ mfwrite(0,1,480,fp); }