/* rdmid.h version 0.21, december 30, 2019. C API headerfile. Include this file in your sourcefile. RDMID, a MIDI file parser. Latest version available at: https://ecomaan.nl/c/rdmid Copyright (c) 2004, 2008, 2019 - Pieter Suurmond Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any person wishing to distribute modifications to the Software is requested to send the modifications to the original developer so that they can be incorporated into the canonical version. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Portable ISO/ANSI C. - Thread-safe because no global variables and no static data. - Endian-safe (no endian-awareness though). - Memory-safe (needs more testing!). - Reads standard MIDI file formats 0, 1 and 2, accept sysex of any length below 2^31. The one and only function that you have to call is rdmid(). As first argument, you may supply anything you like, it will be passed to all your event handlers, whenever they are called. The second argument should be a file pointer. Before calling, you must thus open a standard MIDI file yourself, and, of course, after returning from rdmid() you must close it. When the third argument, no_sysex_merge, is zero, unfinished system exclusive messages will be concatenated before your event handler is called. The remaining 21 arguments are function pointers that may be set to NULL. See example read_a_midifile.c which demonstrates event handlers for note_on and for trackstart. Other event handler examples can found at the top of file rdmid.c. */ int rdmid(void* userdata, FILE* fp, int no_sysex_merge, /* The following 21 arguments are function pointers to your event handlers (or NULL). */ /* 3 handlers for header and tracks: */ int (*eh_header) (void* userdata, int format, /* 0, 1 or 2. */ int tracks, int division), int (*eh_trackstart)(void* userdata, int track), int (*eh_trackend) (void* userdata, int track), /* 7 channel messages: */ /* 0 <= time < 2^31. */ int (*eh_note_off) (void* userdata, long time, int channel, /* 0 <= channel < 16. */ int note, /* 0 <= note < 128. */ int velocity), /* 0 <= velocity < 128. */ int (*eh_note_on) (void* userdata, long time, int channel, int note, int velocity), int (*eh_poly_press)(void* userdata, long time, int channel, int note, int pressure), /* 0 <= pressure < 128. */ int (*eh_controller)(void* userdata, long time, int channel, int number, /* 0 <= number < 128. */ int value), /* 0 <= value < 128. */ int (*eh_program) (void* userdata, long time, int channel, int number), int (*eh_chan_press)(void* userdata, long time, int channel, int pressure), int (*eh_pitchbend) (void* userdata, long time, int channel, int bend), /* -8192 <= bend < 8192.*/ /* 1 system exclusive message: */ int (*eh_sysex) (void* userdata, long time, long length, char* data), /* 10 meta events: */ int (*eh_seqnum) (void* userdata, long time, int number), /* 0 <= number < 65536. */ int (*eh_text) (void* userdata, long time, int type, long length, char* data), int (*eh_eot) (void* userdata, long time), /* End of track. */ int (*eh_tempo) (void* userdata, long time, long tempo), /* 0 <= tempo < 1677716. */ /* microsecs/qrter note. */ int (*eh_smpte) (void* userdata, long time, int hour, int min, int sec, int frame, int frac), int (*eh_timesig) (void* userdata, long time, int numer, int denom, /* 1, 2, 4, 8, etc. */ int mclck, int m32), /* Often 8. */ int (*eh_keysig) (void* userdata, long time, int sharps, /* -7 <= sharps <= +7. */ int minor), /* 0=major; 1=minor. */ int (*eh_seq_spec) (void* userdata, long time, long length, char* data), int (*eh_metamisc) (void* userdata, long time, int type, long length, char* data), int (*eh_arbitrary) (void* userdata, long time, long length, char* data) ); /* Here is what rdmid() returns: */ #define RDMID_OK (0) /* No errors, all went well. */ #define RDMID_USER_TERM (1) /* User's callback stopped parser by returning non-zero. */ #define RDMID_EOF (2) /* Premature end of file. */ #define RDMID_CHUNK_END (3) /* Premature end of chunk. */ #define RDMID_BAD_MT (4) /* Wrong 'MThd' or 'MTrk' in header or track. */ #define RDMID_BAD_BYTE (5) /* Unexpected byte in track. */ #define RDMID_SYSEX_CONT (6) /* Didn't find expected continuation of sysex. */ #define RDMID_RUN_STATUS (7) /* Unexpected running status. */ #define RDMID_TOO_BIG (8) /* When a variable length number exceeds 4 bytes, when current time exceeds 31 bits, or when a sysex or meta message's length exceeds 31 bits. */ #define RDMID_MEM_FAIL (9) /* Memory allocation failure. */ #define RDMID_BAD_INTS (10) /* When sizes of integers are insufficient. */