mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Added playmidi1...
This commit is contained in:
parent
fa2745a3c5
commit
53cbbeee14
5 changed files with 2356 additions and 2 deletions
336
test/midifile.3
Normal file
336
test/midifile.3
Normal file
|
|
@ -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 inteprets 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 Reserverd 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.
|
||||
|
||||
Misceallaneous \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 charcter 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
|
||||
similiar 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 separted 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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue