diff options
Diffstat (limited to 'alsa-lib/test/midifile.3')
-rw-r--r-- | alsa-lib/test/midifile.3 | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/alsa-lib/test/midifile.3 b/alsa-lib/test/midifile.3 new file mode 100644 index 0000000..3aadb6d --- /dev/null +++ b/alsa-lib/test/midifile.3 @@ -0,0 +1,336 @@ +.TH MIDIFILE 3 +.SH NAME +mfread,mfwrite \- read and write a standard MIDI file +.SH SYNOPSIS +\fC#include "mfread.h" + +mfread () + +.nf +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; +.fi +.sp 1 +mfwrite(int format, int ntracks, int division, FILE *fp) +.sp 1 +.nf +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; +.fi + +.SH DESCRIPTION +The \fCmfread\fR function reads and interprets a standard MIDI file. +To use it you need to understand the general form of a +MIDI file and the type of information it contains, but you don't +need to know much, if anything, about the detailed format of the file +and the mechanics of reading it reliably and portably. + +The \fCmfwrite\fR function writes a standard MIDI file making +use of user-defined functions that access the program's +data structure. To use it you need to define your own Mf_writetrack +routine and then make use of the write_* family of routines to +write out the MIDI data. The \fCmfwrite\fR routine takes +care of the file format and writing the file and track chunk headers. + +.SH READING STANDARD MIDI FILES +A single call to \fCmfread\fR will read an entire MIDI file. +The interface to \fCmfread\fR is a set of external variables +named \fCMf_*\fR, most of which are function pointers to be called +from within \fCmfread\fR during the process of parsing the MIDI file. +Before calling \fCmfread\fR, the only +requirement is that you assign a value +to \fCMf_getc\fR - a pointer to a function that will return +characters from the MIDI file, using \-1 to indicate EOF. +All the rest of the function +pointers are initialized to NULL, and the default action for each +is to do nothing. The following is a complete program using \fCmfread\fR +that could serve as a 'syntax checker' for MIDI files: + +.in +1i +.ft C +.nf +#include <stdio.h> +#include "midifile.h" + +mygetc() +{ + /* use standard input */ + return(getchar()); +} + +main() +{ + Mf_getc = mygetc; + mfread(); + exit(0); +} +.fi +.ft R +.in -1i + +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 \fCMf_error\fR; the function will be +called with the error message as an argument. +The other \fCMf_* 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. + +\fCMf_header\fR 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. +\fCMf_trackstart\fR and +\fCMf_trackend\fR 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 \fCMf_noteon\fR to be called +with the channel, pitch, and volume as arguments. The time at which +the message occurred is stored in \fCMf_currtime\fR - one of the few +external variables that isn't a function pointer. The other channel messages +are handled in a similar and obvious fashion - +\fCMf_noteoff\fR, +\fCMf_pressure\fR, +\fCMf_parameter\fR, +\fCMf_pitchbend\fR, +\fCMf_program\fR, +and \fCMf_chanpressure\fR. See the declarations above for the arguments +that are passed to each. + +System exclusive messages are handled by calling \fCMf_sysex\fR, 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 \fCMf_sysex\fR is only called once. It you want to disable this +you can set \fCMf_nomerge\fR to 1, causing \fCMf_sysex\fR to be called +once for each part of the message. + +\fCMf_seqnum\fR is called by the \fImeta\fR message that provides +a sequence number, +which if present must appear at the beginning of a track. +The tempo \fImeta\fR message causes \fCMf_tempo\fR to be called; its +argument is the number of microseconds per MIDI quarter-note (24 MIDI clocks). +The end-of-track \fImeta\fR message causes \fCMf_eot\fR to be called. +The key signature \fImeta\fR message causes \fCMf_keysig\fR to be called; +the first argument conveys the number of sharps or flats, the second +argument is 1 if the key is minor. + +The \fCMf_timesig\fR and \fCMf_smpte\fR functions are called when the +corresponding \fImeta\fR messages are seen. See the MIDI file standard +for a description of their arguments. + +The \fItext\fR messages in the MIDI file standard are of the following +types: + +.in +1i +.nf +0x01 Text Event +0x02 Copyright +0x03 Sequence/Track Name +0x04 Instrument +0x05 Lyric +0x06 Marker +0x07 Cue Point +0x08-0x0F Reserved but Undefined +.fi +.in -1i + +\fCMf_text\fR is called for each of these; the arguments are +the type number, the message length, and a pointer to the message buffer. + +Miscellaneous \fImeta\fR messages are handled by \fCMf_metamisc\fR, +sequencer-specific messages are handled by \fCMf_seqspecific\fR, and +arbitrary "escape" messages (started with 0xF7) are handled by +\fCMf_arbitrary\fR. +.SH READING EXAMPLE +The following is a \fCstrings\fR-like program for MIDI files: + +.in +1i +.ft C +.nf +#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('\n'); +} + +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); +} +.fi +.ft R +.in -1i +.sp +.SH WRITING STANDARD MIDI FILES +A single call to \fCmfwrite\fR will write an entire MIDI file. Before +calling \fCmfwrite\fR, you must assign values to function pointers +\fCMf_writetrack\fR and \fCMf_putc\fR. The first is a routine to +access your MIDI data structure, which can make use of other library +routines to write the actual MIDI data. The routine +\fCMf_writetrack\fR will be passed a single parameter which is the +number of the track to be written. The pointer \fCMf_putc\fR should be +set to point to a routine that accepts a character as input, writes that +character to a file, and returns the value that was written. In the +case of a format 1 file, a routine has to be written to write a tempo +map, and assigned to the function pointer \fCMf_writetempotrack\fR. +This is because format 1 files assume the first track written is a +tempo track. + +\fCmf_write_midi_event\fR and \fCmf_write_meta_event\fR are routines +that should be called from your \fCMf_writetrack\fR routine to write +out MIDI events. The delta time param is the number of ticks since the +last event. The int "type" is the type of MIDI message. The int "chan" +is the MIDI channel, which can be between 1 and 16. The char pointer +"data" points to an array containing the data bytes, if any exist. The +int "size" is the number of data bytes. + +\fCmf_sec2ticks\fR and \fCmf_ticks2sec\fR are utility routines +to help you convert between the MIDI file parameter of ticks +and the more standard seconds. The int "division" is the same +division parameter from the file header, and tempo is expressed +in microseconds per MIDI quarter-note, or "24ths of a microsecond +per MIDI clock". The division has two meanings, depending on +whether bit 15 is set or not. If bit 15 of division is zero, +bits 14 through 0 represent the number of delta-time "ticks" +which make up a quarter note. If bit 15 of division is a one, +delta-times in a file correspond to subdivisions of a second +similar to SMPTE and MIDI time code. In this format bits +14 through 8 contain one of four values \-24, \-25, \-29, or \-30, +corresponding to the four standard SMPTE and MIDI time code +frame per second formats, where \-29 represents 30 drop frame. +The second byte consisting of bits 7 through 0 corresponds +the the resolution within a frame. Refer the Standard MIDI Files +1.0 spec for more details. + +.SH WRITING EXAMPLE +The following is a simple program to demonstrate writing MIDI files. +The track would consist of a series of quarter notes from lowest to +highest in pitch at constant velocity, each separated by a quarter-note +rest. +.sp +.in +1i +.ft C +.nf +#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); +} +.sp +.fi +.ft R +.in -1i +.sp +.SH AUTHOR +Tim Thompson (att!twitch!glimmer!tjt) +.SH CONTRIBUTORS +Michael Czeiszperger (mike@pan.com) |