diff options
author | Martin Peach <mrpeach@users.sourceforge.net> | 2007-06-02 01:10:35 +0000 |
---|---|---|
committer | Martin Peach <mrpeach@users.sourceforge.net> | 2007-06-02 01:10:35 +0000 |
commit | 0e9ea7dcd4c094e1356c40051c2faf4eb08bcdf4 (patch) | |
tree | d2c515af377a65370c16b957c5eaf4d84f114d11 /midifile | |
parent | 20f6083ffe23d7fb0b871e37e4223f8d92e7762d (diff) |
cleaned up code to reduce number of warnings
svn path=/trunk/externals/mrpeach/; revision=7742
Diffstat (limited to 'midifile')
-rwxr-xr-x | midifile/midifile.c | 2336 |
1 files changed, 1169 insertions, 1167 deletions
diff --git a/midifile/midifile.c b/midifile/midifile.c index 92482aa..d036bac 100755 --- a/midifile/midifile.c +++ b/midifile/midifile.c @@ -32,8 +32,6 @@ * 20060110 output totaltime before end-bang */ -//#define MSW // useful in m_pd.h if not yet replaced by _MSC_VER - #include "m_pd.h" #include <stdio.h> #include <string.h> @@ -48,50 +46,51 @@ static t_class *midifile_class; #define PATH_BUF_SIZE 256 -#define MAX_TRACKS 128 // track data is allocated as needed but we need to preallocate space for the pointers -#define MAX_TRACK_LEN 1024 // for now... +#define MAX_TRACKS 128 +/* track data is allocated as needed but we need to preallocate space for the pointers */ +#define MAX_TRACK_LEN 1024 +/* MAX_TRACK_LEN 1024 for now...*/ #define ALL_TRACKS MAX_TRACKS typedef enum {mfReset, mfReading, mfWriting} mfstate; typedef struct mf_header_chunk { - char chunk_type[4]; // each chunk begins with a 4-character ASCII type. - size_t chunk_length ; // followed by a 32-bit length - int chunk_format; - int chunk_ntrks; - int chunk_division; + char chunk_type[4]; /* each chunk begins with a 4-character ASCII type.*/ + size_t chunk_length ; /* followed by a 32-bit length */ + int chunk_format; + int chunk_ntrks; + int chunk_division; } mf_header_chunk; typedef struct mf_track_chunk { - char chunk_type[4]; // each chunk begins with a 4-character ASCII type. - size_t chunk_length ; // followed by a 32-bit length - size_t delta_time ; // current delta_time of latest track_data element - size_t total_time ; // sum of delta_times so far - size_t track_index ; // current byte offset to next track_data element - unsigned char running_status; - char *track_data; + char chunk_type[4]; /* each chunk begins with a 4-character ASCII type. */ + size_t chunk_length ; /* followed by a 32-bit length */ + size_t delta_time ; /* current delta_time of latest track_data element */ + size_t total_time ; /* sum of delta_times so far */ + size_t track_index ; /* current byte offset to next track_data element */ + unsigned char running_status; + char *track_data; } mf_track_chunk; typedef struct t_midifile { - t_object x_obj; - size_t total_time; // current time for this MIDI file in delta_time units - t_atom midi_data[3]; // one MIDI packet as a list - t_outlet *midi_list_outlet; - t_outlet *bang_outlet; - //t_outlet *sysex_outlet; // 20060105 use midi_list_outlet instead - t_outlet *total_time_outlet; - FILE *fP; - FILE *tmpFP; - char fPath[PATH_BUF_SIZE]; - size_t offset; // character offset into the file fP - int track; // play this track, or all tracks if negative; - int verbosity; // nonzero for text output to console - int ended; // nonzero if all tracks have finished - mfstate state; // READING or WRITING - mf_header_chunk header_chunk; // First chunk in the midi file - mf_track_chunk track_chunk[MAX_TRACKS]; // Subsequent track chunks. Other kinds of chunk are ignored + t_object x_obj; + size_t total_time; /* current time for this MIDI file in delta_time units */ + t_atom midi_data[3]; /* one MIDI packet as a list */ + t_outlet *midi_list_outlet; + t_outlet *bang_outlet; + t_outlet *total_time_outlet; + FILE *fP; + FILE *tmpFP; + char fPath[PATH_BUF_SIZE]; + size_t offset; /* character offset into the file fP */ + int track; /* play this track, or all tracks if negative; */ + int verbosity; /* nonzero for text output to console */ + int ended; /* nonzero if all tracks have finished */ + mfstate state; /* READING or WRITING */ + mf_header_chunk header_chunk; /* First chunk in the midi file */ + mf_track_chunk track_chunk[MAX_TRACKS]; /* Subsequent track chunks. Other kinds of chunk are ignored. */ } t_midifile; void midifile_skip_next_track_chunk_data(t_midifile *x, int index); @@ -130,111 +129,107 @@ EXPORT_SHARED void midifile_setup(void); EXPORT_SHARED void midifile_setup(void) { - midifile_class = class_new (gensym("midifile"), - (t_newmethod) midifile_new, - (t_method)midifile_free, sizeof(t_midifile), - CLASS_DEFAULT, - A_GIMME, 0); - //CLASS_DEFAULT a normal object with one inlet - class_addbang(midifile_class, midifile_bang); - class_addfloat(midifile_class, midifile_float); - class_addlist(midifile_class, midifile_list); - class_addmethod(midifile_class, (t_method)midifile_read, gensym("read"), A_DEFSYMBOL, 0); - class_addmethod(midifile_class, (t_method)midifile_flush, gensym("flush"), 0); - class_addmethod(midifile_class, (t_method)midifile_write, gensym("write"), A_DEFSYMBOL, 0); - class_addmethod(midifile_class, (t_method)midifile_dump, gensym("dump"), A_DEFFLOAT, 0); - class_addmethod(midifile_class, (t_method)midifile_single_track, gensym("track"), A_DEFFLOAT, 0); - class_addmethod(midifile_class, (t_method)midifile_rewind, gensym("rewind"), 0); - class_addmethod(midifile_class, (t_method)midifile_verbosity, gensym("verbose"), A_DEFFLOAT, 0); - class_sethelpsymbol(midifile_class, gensym("midifile-help")); + midifile_class = class_new (gensym("midifile"), + (t_newmethod) midifile_new, + (t_method)midifile_free, sizeof(t_midifile), + CLASS_DEFAULT, + A_GIMME, 0); + + class_addbang(midifile_class, midifile_bang); + class_addfloat(midifile_class, midifile_float); + class_addlist(midifile_class, midifile_list); + class_addmethod(midifile_class, (t_method)midifile_read, gensym("read"), A_DEFSYMBOL, 0); + class_addmethod(midifile_class, (t_method)midifile_flush, gensym("flush"), 0); + class_addmethod(midifile_class, (t_method)midifile_write, gensym("write"), A_DEFSYMBOL, 0); + class_addmethod(midifile_class, (t_method)midifile_dump, gensym("dump"), A_DEFFLOAT, 0); + class_addmethod(midifile_class, (t_method)midifile_single_track, gensym("track"), A_DEFFLOAT, 0); + class_addmethod(midifile_class, (t_method)midifile_rewind, gensym("rewind"), 0); + class_addmethod(midifile_class, (t_method)midifile_verbosity, gensym("verbose"), A_DEFFLOAT, 0); + class_sethelpsymbol(midifile_class, gensym("midifile-help")); } void *midifile_new(t_symbol *s, int argc, t_atom *argv) { - t_midifile *x = (t_midifile *)pd_new(midifile_class); - t_symbol *pathSymbol; - int i; - - if (x == NULL) - { - error("midifile: Could not create..."); - return x; - } - x->fP = NULL; - x->fPath[0] = '\0'; - x->track = ALL_TRACKS; // startup playing anything - x->midi_data[0].a_type = x->midi_data[1].a_type = x->midi_data[2].a_type = A_FLOAT; - x->state = mfReset; - x->verbosity = 1; // default to posting all - for (i = 0; i < MAX_TRACKS; ++i) - { - x->track_chunk[i].track_data = NULL; - } - // find the first string in the arg list and interpret it as a path to a midi file - for (i = 0; i < argc; ++i) - { - if (argv[i].a_type == A_SYMBOL) - { - pathSymbol = atom_getsymbol(&argv[i]); - if (pathSymbol != NULL) - { - if (midifile_open_path(x, pathSymbol->s_name, "rb")) - { - if (x->verbosity) post("midifile: opened %s", x->fPath); - x->state = mfReading; - if (midifle_read_chunks(x) == 0) midifile_free_file(x); - } - else error("midifile: unable to open %s", pathSymbol->s_name); - break; - } - } - } - x->midi_list_outlet = outlet_new(&x->x_obj, &s_list); - // x->sysex_outlet = outlet_new(&x->x_obj, &s_float); // raw sysex stream (20060105 send a list through midi_list_outlet) - x->total_time_outlet = outlet_new(&x->x_obj, &s_float); // current total_time - x->bang_outlet = outlet_new(&x->x_obj, &s_bang); // bang at end of file - return (void *)x; + t_midifile *x = (t_midifile *)pd_new(midifile_class); + t_symbol *pathSymbol; + int i; + + if (x == NULL) + { + error("midifile: Could not create..."); + return x; + } + x->fP = NULL; + x->fPath[0] = '\0'; + x->track = ALL_TRACKS; /* startup playing anything */ + x->midi_data[0].a_type = x->midi_data[1].a_type = x->midi_data[2].a_type = A_FLOAT; + x->state = mfReset; + x->verbosity = 1; /* default to posting all */ + for (i = 0; i < MAX_TRACKS; ++i) + { + x->track_chunk[i].track_data = NULL; + } + /* find the first string in the arg list and interpret it as a path to a midi file */ + for (i = 0; i < argc; ++i) + { + if (argv[i].a_type == A_SYMBOL) + { + pathSymbol = atom_getsymbol(&argv[i]); + if (pathSymbol != NULL) + { + if (midifile_open_path(x, pathSymbol->s_name, "rb")) + { + if (x->verbosity) post("midifile: opened %s", x->fPath); + x->state = mfReading; + if (midifle_read_chunks(x) == 0) midifile_free_file(x); + } + else error("midifile: unable to open %s", pathSymbol->s_name); + break; + } + } + } + x->midi_list_outlet = outlet_new(&x->x_obj, &s_list); + x->total_time_outlet = outlet_new(&x->x_obj, &s_float); /* current total_time */ + x->bang_outlet = outlet_new(&x->x_obj, &s_bang); /* bang at end of file */ + return (void *)x; } void midifile_close(t_midifile *x) { - if (x->fP != NULL) - { - fclose (x->fP); - x->fP = NULL; - } - if (x->tmpFP != NULL) - { - fclose(x->tmpFP); - x->tmpFP = NULL; - } - x->fPath[0] = '\0'; - x->state = mfReset; - x->total_time = 0L; - x->offset = 0L; - outlet_float(x->total_time_outlet, x->total_time); + if (x->fP != NULL) + { + fclose (x->fP); + x->fP = NULL; + } + if (x->tmpFP != NULL) + { + fclose(x->tmpFP); + x->tmpFP = NULL; + } + x->fPath[0] = '\0'; + x->state = mfReset; + x->total_time = 0L; + x->offset = 0L; + outlet_float(x->total_time_outlet, x->total_time); } void midifile_free_file(t_midifile *x) { - int i; - - midifile_close(x); - - for (i = 0; i < MAX_TRACKS; ++i) - { - if (x->track_chunk[i].track_data != NULL) - { - freebytes(x->track_chunk[i].track_data, x->track_chunk[i].chunk_length); - //if (x->verbosity) post("midifile_free: freed %lu bytes for track %d", x->track_chunk[i].chunk_length, i); - } - x->track_chunk[i].track_data = NULL; - } + int i; + + midifile_close(x); + + for (i = 0; i < MAX_TRACKS; ++i) + { + if (x->track_chunk[i].track_data != NULL) + freebytes(x->track_chunk[i].track_data, x->track_chunk[i].chunk_length); + x->track_chunk[i].track_data = NULL; + } } void midifile_free(t_midifile *x) { - midifile_free_file(x); + midifile_free_file(x); } int midifile_open_path(t_midifile *x, char *path, char *mode) @@ -244,166 +239,172 @@ int midifile_open_path(t_midifile *x, char *path, char *mode) /* midifile_open_path attempts to open the file for binary mode reading. */ /* Returns 1 if successful, else 0. */ { - FILE *fP; - char tryPath[PATH_BUF_SIZE]; - - strncpy(tryPath, path, PATH_BUF_SIZE-1); // copy path into a length-limited buffer - // ...if it doesn't work we won't mess up x->fPath - tryPath[PATH_BUF_SIZE-1] = '\0'; // just make sure there is a null termination - - fP = fopen(tryPath, mode); - if (fP == NULL) return 0; - x->fP = fP; - strncpy(x->fPath, tryPath, PATH_BUF_SIZE); - return 1; + FILE *fP; + char tryPath[PATH_BUF_SIZE]; + + strncpy(tryPath, path, PATH_BUF_SIZE-1); /* copy path into a length-limited buffer */ + /* ...if it doesn't work we won't mess up x->fPath */ + tryPath[PATH_BUF_SIZE-1] = '\0'; /* just make sure there is a null termination */ + + fP = fopen(tryPath, mode); + if (fP == NULL) return 0; + x->fP = fP; + strncpy(x->fPath, tryPath, PATH_BUF_SIZE); + return 1; } void midifile_flush(t_midifile *x) /* write the header to x->fP, copy x->tmpFP into it, and close both files */ /* flush ends the track */ { - size_t written = 0L; - size_t end_time = x->total_time; - int c; + size_t written = 0L; + size_t end_time = x->total_time; + int c; - if(x->state != mfWriting) return; // only if we're writing + if(x->state != mfWriting) return; /* only if we're writing */ - outlet_bang(x->bang_outlet); // bang so tick count can be saved externally - midifile_write_end_of_track(x, end_time); - written = midifile_write_header(x); + outlet_bang(x->bang_outlet); /* bang so tick count can be saved externally */ + midifile_write_end_of_track(x, end_time); + written = midifile_write_header(x); /* now copy the MIDI data from tmpFP to fP */ - rewind (x->tmpFP); - while ((c = getc(x->tmpFP)) != EOF) - { - putc(c, x->fP); - ++written; - } - if (x->verbosity) post ("midifile: wrote %lu to %s", written, x->fPath); - midifile_close(x); + rewind (x->tmpFP); + while ((c = getc(x->tmpFP)) != EOF) + { + putc(c, x->fP); + ++written; + } + if (x->verbosity) post ("midifile: wrote %lu to %s", written, x->fPath); + midifile_close(x); } size_t midifile_write_header(t_midifile *x) /* write the MThd and MTrk headers to x->fP */ { - size_t j, written = 0L; - int i; - char c; - - rewind (x->fP); - fprintf (x->fP, "MThd"); - j = 6; // length of header data - for (i = 0; i < 4; ++i) - { // msb first - c = (char)((j & 0xFF000000)>>24); - putc(c, x->fP); - j <<= 8; - } - j = 0; // type of file - for (i = 0; i < 2; ++i) - { // msb first - c = (char)((j & 0xFF00)>>8); - putc(c, x->fP); - j <<= 8; - } - j = 1; // number of tracks - for (i = 0; i < 2; ++i) - { // msb first - c = (char)((j & 0xFF00)>>8); - putc(c, x->fP); - j <<= 8; - } - j = x->header_chunk.chunk_division; // ticks per quarter note - for (i = 0; i < 2; ++i) - { // msb first - c = (char)((j & 0xFF00)>>8); - putc(c, x->fP); - j <<= 8; - } - fprintf (x->fP, "MTrk"); - j = x->track_chunk[0].chunk_length; // length of MIDI data -// if (x->verbosity) post ("chunk_length is %lu", j); - for (i = 0; i < 4; ++i) - { // msb first - c = (char)((j & 0xFF000000)>>24); - putc(c, x->fP); -// if (x->verbosity) post ("...%d...", c); - j <<= 8; - } - written = 22L; - return written; + size_t j, written = 0L; + int i; + char c; + + rewind (x->fP); + fprintf (x->fP, "MThd"); + j = 6; /* length of header data */ + for (i = 0; i < 4; ++i) + { /* msb first */ + c = (char)((j & 0xFF000000)>>24); + putc(c, x->fP); + j <<= 8; + } + j = 0; /* type of file */ + for (i = 0; i < 2; ++i) + { /* msb first */ + c = (char)((j & 0xFF00)>>8); + putc(c, x->fP); + j <<= 8; + } + j = 1; /* number of tracks */ + for (i = 0; i < 2; ++i) + { /* msb first */ + c = (char)((j & 0xFF00)>>8); + putc(c, x->fP); + j <<= 8; + } + j = x->header_chunk.chunk_division; /* ticks per quarter note */ + for (i = 0; i < 2; ++i) + { /* msb first */ + c = (char)((j & 0xFF00)>>8); + putc(c, x->fP); + j <<= 8; + } + fprintf (x->fP, "MTrk"); + j = x->track_chunk[0].chunk_length; /* length of MIDI data */ + for (i = 0; i < 4; ++i) + { /* msb first */ + c = (char)((j & 0xFF000000)>>24); + putc(c, x->fP); + j <<= 8; + } + written = 22L; + return written; } void midifile_write(t_midifile *x, t_symbol *path) /* open the file for writing and write the header */ { - midifile_free_file(x); - if (midifile_open_path(x, path->s_name, "wb")) - { - if (x->verbosity) post("midifile: opened %s", x->fPath); - x->state = mfWriting; - x->tmpFP = tmpfile (); // a temporary file for the MIDI data while we don't know how long it is - - strncpy (x->header_chunk.chunk_type, "MThd", 4L);// track header chunk - x->header_chunk.chunk_length = 6L; // 3 ints to follow - x->header_chunk.chunk_format = 0; // single-track file - x->header_chunk.chunk_ntrks = 1; // one track for type 0 file - x->header_chunk.chunk_division = 0; // for now - strncpy (x->track_chunk[0].chunk_type, "MTrk", 4L); - x->track_chunk[0].chunk_length = 0L; // for now - midifile_rewind_tracks(x); - } - else error("midifile: Unable to open %s", path->s_name); + midifile_free_file(x); + if (midifile_open_path(x, path->s_name, "wb")) + { + if (x->verbosity) post("midifile: opened %s", x->fPath); + x->state = mfWriting; + x->tmpFP = tmpfile (); /* a temporary file for the MIDI data while we don't know how long it is */ + + strncpy (x->header_chunk.chunk_type, "MThd", 4L);/* track header chunk */ + x->header_chunk.chunk_length = 6L; /* 3 ints to follow */ + x->header_chunk.chunk_format = 0; /* single-track file */ + x->header_chunk.chunk_ntrks = 1; /* one track for type 0 file */ + x->header_chunk.chunk_division = 0; /* for now */ + strncpy (x->track_chunk[0].chunk_type, "MTrk", 4L); + x->track_chunk[0].chunk_length = 0L; /* for now */ + midifile_rewind_tracks(x); + } + else error("midifile: Unable to open %s", path->s_name); } void midifile_read(t_midifile *x, t_symbol *path) { - midifile_free_file(x); - if (midifile_open_path(x, path->s_name, "rb")) - { - if (x->verbosity) post("midifile: opened %s", x->fPath); - x->state = mfReading; - if (midifle_read_chunks(x) == 0) midifile_free_file(x); - } - else error("midifile: Unable to open %s", path->s_name); + midifile_free_file(x); + if (midifile_open_path(x, path->s_name, "rb")) + { + if (x->verbosity) post("midifile: opened %s", x->fPath); + x->state = mfReading; + if (midifle_read_chunks(x) == 0) midifile_free_file(x); + } + else error("midifile: Unable to open %s", path->s_name); } void midifile_bang(t_midifile *x) /* step forward one tick and process all tracks for that tick */ { - int j, result = 1, ended = 0; - size_t total_time; - - switch (x->state) - { - case mfReading: - if (x->verbosity > 2) post("midifile_bang: total_time %lu", x->total_time); - for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) - { - if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) - { - while ((total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time) == x->total_time) - { - if ((x->track == j) ||(x->track == ALL_TRACKS)) midifile_get_next_track_chunk_data(x, j); - else midifile_skip_next_track_chunk_data(x, j); - } - x->ended = 0; - } - if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; - } - if ((ended == x->header_chunk.chunk_ntrks)&&(x->ended == 0)) - { // set ended flag, only bang once - if (x->verbosity > 1) post ("ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); - outlet_bang(x->bang_outlet); - ++x->ended; - } - // fall through into mfWriting - case mfWriting: - ++x->total_time; - outlet_float(x->total_time_outlet, x->total_time); - break; - default: - break;// don't change time when no files are open - } + int j, result = 1, ended = 0; + size_t total_time; + + switch (x->state) + { + case mfReading: + if (x->verbosity > 2) post("midifile_bang: total_time %lu", x->total_time); + for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) + { + if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) + { + while + ( + ( + total_time = midifile_get_next_track_chunk_delta_time(x, j) + + x->track_chunk[j].total_time + ) + == x->total_time + ) + { + if ((x->track == j) ||(x->track == ALL_TRACKS)) midifile_get_next_track_chunk_data(x, j); + else midifile_skip_next_track_chunk_data(x, j); + } + x->ended = 0; + } + if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; + } + if ((ended == x->header_chunk.chunk_ntrks)&&(x->ended == 0)) + { /* set ended flag, only bang once */ + if (x->verbosity > 1) + post ("ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); + outlet_bang(x->bang_outlet); + ++x->ended; + } + /* fall through into mfWriting */ + case mfWriting: + ++x->total_time; + outlet_float(x->total_time_outlet, x->total_time); + break; + default: + break;/* don't change time when no files are open */ + } } /* The arguments of the ``list''-method @@ -415,383 +416,379 @@ void midifile_bang(t_midifile *x) void midifile_list(t_midifile *x, t_symbol *s, int argc, t_atom *argv) /* add a list containing time and midi packet to the temporary file in MIDI file format */ { - int i, j, k, m, dt_written = 0; - size_t len, written = 0L; - static int warnings = 0; - - if (! x->state == mfWriting) return;// list only works for writing - if (x->tmpFP == NULL) - { - if (0 == warnings++) error ("midifile: no file is open for writing"); - return; - } - for (i = 0; i < argc; ++i) - { - switch (argv[i].a_type) - { - case A_FLOAT: - { - j = atom_getint(&argv[i]); - if (x->verbosity > 2) post ("midifile_list. j[%d] = 0x%lX", i, j); - if (j <= 0x100) - { - if (!dt_written) - { // deltatime - x->track_chunk[0].delta_time = x->total_time - x->track_chunk[0].total_time; - x->track_chunk[0].total_time = x->total_time; - written = midifile_write_variable_length_value(x->tmpFP, x->track_chunk[0].delta_time); - dt_written = 1; - } - if (j == x->track_chunk[0].running_status) break;// don't save redundant status byte - if (j >= 0x80 && j <= 0xEF)x->track_chunk[0].running_status = j;// new running status - else if (j >= 0xF0 && j <= 0xF7) - { - x->track_chunk[0].running_status = 0;// clear running status - if (j == 0xF0) - { // system exclusive: - // find length - for (k = i+1, len = 0L; k < argc; ++k, ++len) - { - if (argv[k].a_type != A_FLOAT) - { - error ("midifile: sysex list must be all floats"); - x->track_chunk[0].chunk_length += written; - return; - } - m = atom_getint(&argv[k]); - if (m & 0x80) break;// take any non-data as end of exclusive - } - if (m != 0xF7) - { - error ("midifile: sysex list terminator is 0x%d", m); - x->track_chunk[0].chunk_length += written; - return; - } - ++len; - if (x->verbosity) post ("midifile: sysex length %lu. j = 0x%X", len, j); - putc (j, x->tmpFP); - ++written; - // write length as variable length - written += midifile_write_variable_length_value (x->tmpFP, len); - // write the rest of the sysex message - for (k = i+1; j != 0xF7; ++k) - { - j = atom_getint(&argv[k]); - putc (j, x->tmpFP); - ++written; - } - x->track_chunk[0].chunk_length += written; - return; - } - } - if (x->verbosity > 1) post ("midifile: j = 0x%X", j); - putc (j, x->tmpFP); - ++written; - } - break; - } - } - } - x->track_chunk[0].chunk_length += written; -// if (x->verbosity) post ("midifile_list"); + int i, j, k, m, dt_written = 0; + size_t len, written = 0L; + static int warnings = 0; + + if (! x->state == mfWriting) return;/* list only works for writing */ + if (x->tmpFP == NULL) + { + if (0 == warnings++) error ("midifile: no file is open for writing"); + return; + } + for (i = 0; i < argc; ++i) + { + if (A_FLOAT == argv[i].a_type) + { + j = atom_getint(&argv[i]); + if (x->verbosity > 2) post ("midifile_list. j[%d] = 0x%lX", i, j); + if (j <= 0x100) + { + if (!dt_written) + { /* deltatime */ + x->track_chunk[0].delta_time = x->total_time - x->track_chunk[0].total_time; + x->track_chunk[0].total_time = x->total_time; + written = midifile_write_variable_length_value(x->tmpFP, x->track_chunk[0].delta_time); + dt_written = 1; + } + if (j == x->track_chunk[0].running_status) break;/* don't save redundant status byte */ + if (j >= 0x80 && j <= 0xEF)x->track_chunk[0].running_status = j;/* new running status */ + else if (j >= 0xF0 && j <= 0xF7) + { + x->track_chunk[0].running_status = 0;/* clear running status */ + if (j == 0xF0) + { /* system exclusive: */ + /* find length */ + for (k = i+1, len = 0L; k < argc; ++k, ++len) + { + if (argv[k].a_type != A_FLOAT) + { + error ("midifile: sysex list must be all floats"); + x->track_chunk[0].chunk_length += written; + return; + } + m = atom_getint(&argv[k]); + if (m & 0x80) break;/* take any non-data as end of exclusive */ + } + if (m != 0xF7) + { + error ("midifile: sysex list terminator is 0x%d", m); + x->track_chunk[0].chunk_length += written; + return; + } + ++len; + if (x->verbosity) post ("midifile: sysex length %lu. j = 0x%X", len, j); + putc (j, x->tmpFP); + ++written; + /* write length as variable length */ + written += midifile_write_variable_length_value (x->tmpFP, len); + /* write the rest of the sysex message */ + for (k = i+1; j != 0xF7; ++k) + { + j = atom_getint(&argv[k]); + putc (j, x->tmpFP); + ++written; + } + x->track_chunk[0].chunk_length += written; + return; + } + } + if (x->verbosity > 1) post ("midifile: j = 0x%X", j); + putc (j, x->tmpFP); + ++written; + } + } + } + x->track_chunk[0].chunk_length += written; } size_t midifile_write_end_of_track(t_midifile *x, size_t end_time) /* write End of Track event to x->tmpFP */ { - size_t written = 0L; - - x->track_chunk[0].delta_time = end_time - x->track_chunk[0].total_time; - x->track_chunk[0].total_time = x->total_time; - written = midifile_write_variable_length_value (x->tmpFP, x->track_chunk[0].delta_time); - putc (0xFF, x->tmpFP); - putc (0x2F, x->tmpFP); - putc (0x00, x->tmpFP); - written += 3L; - x->track_chunk[0].chunk_length += written; - return written; + size_t written = 0L; + + x->track_chunk[0].delta_time = end_time - x->track_chunk[0].total_time; + x->track_chunk[0].total_time = x->total_time; + written = midifile_write_variable_length_value (x->tmpFP, x->track_chunk[0].delta_time); + putc (0xFF, x->tmpFP); + putc (0x2F, x->tmpFP); + putc (0x00, x->tmpFP); + written += 3L; + x->track_chunk[0].chunk_length += written; + return written; } void midifile_float(t_midifile *x, t_float ticks) /* go to a total time of cue_time */ { - size_t cTime = (size_t)ticks; - size_t total_time; - int j, result = 1, ended = 0; - - switch (x->state) - { - case mfReading: // cue to ticks - //if (x->verbosity) post ("midifile_float %d", cTime); - midifile_rewind_tracks(x); - for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) - { - if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) - { - while ((total_time = midifile_get_next_track_chunk_delta_time(x, j) + x->track_chunk[j].total_time) < cTime) - { - midifile_skip_next_track_chunk_data(x, j); - } - } - if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; - } - x->total_time = cTime; - outlet_float(x->total_time_outlet, x->total_time); - if (ended == x->header_chunk.chunk_ntrks) - { - if (x->verbosity) post ("midifile: ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); - outlet_bang(x->bang_outlet); - } - break; - case mfWriting: // add ticks to current time - x->total_time += cTime; - outlet_float(x->total_time_outlet, x->total_time); - break; - case mfReset: // do nothing - break; - } - + size_t cTime = (size_t)ticks; + size_t total_time; + int j, result = 1, ended = 0; + + switch (x->state) + { + case mfReading: /* cue to ticks */ + midifile_rewind_tracks(x); + for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) + { + if (x->track_chunk[j].total_time != NO_MORE_ELEMENTS) + { + while + ( + ( + total_time = midifile_get_next_track_chunk_delta_time(x, j) + + x->track_chunk[j].total_time + ) + < cTime + ) + midifile_skip_next_track_chunk_data(x, j); + } + if (x->track_chunk[j].delta_time == NO_MORE_ELEMENTS) ++ended; + } + x->total_time = cTime; + outlet_float(x->total_time_outlet, x->total_time); + if (ended == x->header_chunk.chunk_ntrks) + { + if (x->verbosity) + post ("midifile: ended = %d x->header_chunk.chunk_ntrks = %d", ended, x->header_chunk.chunk_ntrks); + outlet_bang(x->bang_outlet); + } + break; + case mfWriting: /* add ticks to current time */ + x->total_time += cTime; + outlet_float(x->total_time_outlet, x->total_time); + break; + case mfReset: /* do nothing */ + break; + } } int midifle_read_chunks(t_midifile *x) { - int j, result; -// size_t delta_time; - - result = midifile_read_header_chunk(x); - midifile_rewind_tracks(x); - for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) - midifile_read_track_chunk(x, j); - return result; + int j, result; + + result = midifile_read_header_chunk(x); + midifile_rewind_tracks(x); + for (j = 0; ((j < x->header_chunk.chunk_ntrks)&&(result != 0)); ++j) + midifile_read_track_chunk(x, j); + return result; } int midifile_read_header_chunk(t_midifile *x) { - char *cP = x->header_chunk.chunk_type; - char *sP; - char buf[4]; - size_t n; - int div, smpte, ticks; - - if (x->fP == NULL) - { - error("midifile: no open file"); - return 0;// no open file - } - rewind(x->fP); - x->offset = 0L; - n = fread(cP, 1L, 4L, x->fP); - x->offset += n; - if (n != 4L) - { - error("midifile: read %lu instead of 4", n); - return 0; - } - if (x->verbosity) post("midifile: Header chunk type: %c%c%c%c", cP[0], cP[1], cP[2], cP[3]); - if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'h' && cP[3] == 'd')) - { - error ("midifile: bad file format: bad header chunk type"); - return 0; - } - cP = buf; - n = fread(cP, 1L, 4L, x->fP); - x->offset += n; - if (n != 4L) - { - error("midifile: read %lu instead of 4", n); - return 0; - } - x->header_chunk.chunk_length = midifile_get_multibyte_4(cP); - if (x->verbosity) post("midifile: Header chunk length: %lu", x->header_chunk.chunk_length); - if (x->header_chunk.chunk_length != 6L) - { - error ("midifile: bad file format: bad header chunk length"); - return 0; - } - n = fread(cP, 1L, 2L, x->fP); - x->offset += n; - if (n != 2L) - { - error("midifile: read %lu instead of 2", n); - return 0; - } - x->header_chunk.chunk_format = midifile_get_multibyte_2(cP); - switch (x->header_chunk.chunk_format) - { - case 0: - sP = "Single multichannel track"; - break; - case 1: - sP = "One or more simultaneous tracks"; - break; - case 2: - sP = "One or more sequentially independent single tracks"; - break; - default: - sP = "Unknown format"; - } - if (x->verbosity) post("midifile: Header chunk format: %d (%s)", x->header_chunk.chunk_format, sP); - - n = fread(cP, 1L, 2L, x->fP); - x->offset += n; - if (n != 2L) - { - error("midifile: read %lu instead of 2", n); - return 0; - } - x->header_chunk.chunk_ntrks = midifile_get_multibyte_2(cP); - if (x->verbosity) post("midifile: Header chunk ntrks: %d", x->header_chunk.chunk_ntrks); - if (x->header_chunk.chunk_ntrks > MAX_TRACKS) - { - error ("midifile: Header chunk ntrks (%d) exceeds midifile MAX_TRACKS, set to %d", x->header_chunk.chunk_ntrks, MAX_TRACKS); - x->header_chunk.chunk_ntrks = MAX_TRACKS; - } - - n = fread(cP, 1L, 2L, x->fP); - x->offset += n; - if (n != 2L) - { - error("midifile: read %lu instead of 2", n); - return 0; - } - x->header_chunk.chunk_division = midifile_get_multibyte_2(cP); - div = x->header_chunk.chunk_division; - if(div & 0x8000) - { - smpte = (-(div>>8)) & 0x0FF; - ticks = div & 0x0FF; - if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d frames per second, %d ticks per frame", div, smpte, ticks); - } - else - { - if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div); - } - return 1; + char *cP = x->header_chunk.chunk_type; + char *sP; + char buf[4]; + size_t n; + int div, smpte, ticks; + + if (x->fP == NULL) + { + error("midifile: no open file"); + return 0;/* no open file */ + } + rewind(x->fP); + x->offset = 0L; + n = fread(cP, 1L, 4L, x->fP); + x->offset += n; + if (n != 4L) + { + error("midifile: read %lu instead of 4", n); + return 0; + } + if (x->verbosity) post("midifile: Header chunk type: %c%c%c%c", cP[0], cP[1], cP[2], cP[3]); + if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'h' && cP[3] == 'd')) + { + error ("midifile: bad file format: bad header chunk type"); + return 0; + } + cP = buf; + n = fread(cP, 1L, 4L, x->fP); + x->offset += n; + if (n != 4L) + { + error("midifile: read %lu instead of 4", n); + return 0; + } + x->header_chunk.chunk_length = midifile_get_multibyte_4(cP); + if (x->verbosity) post("midifile: Header chunk length: %lu", x->header_chunk.chunk_length); + if (x->header_chunk.chunk_length != 6L) + { + error ("midifile: bad file format: bad header chunk length"); + return 0; + } + n = fread(cP, 1L, 2L, x->fP); + x->offset += n; + if (n != 2L) + { + error("midifile: read %lu instead of 2", n); + return 0; + } + x->header_chunk.chunk_format = midifile_get_multibyte_2(cP); + switch (x->header_chunk.chunk_format) + { + case 0: + sP = "Single multichannel track"; + break; + case 1: + sP = "One or more simultaneous tracks"; + break; + case 2: + sP = "One or more sequentially independent single tracks"; + break; + default: + sP = "Unknown format"; + } + if (x->verbosity) post("midifile: Header chunk format: %d (%s)", x->header_chunk.chunk_format, sP); + + n = fread(cP, 1L, 2L, x->fP); + x->offset += n; + if (n != 2L) + { + error("midifile: read %lu instead of 2", n); + return 0; + } + x->header_chunk.chunk_ntrks = midifile_get_multibyte_2(cP); + if (x->verbosity) post("midifile: Header chunk ntrks: %d", x->header_chunk.chunk_ntrks); + if (x->header_chunk.chunk_ntrks > MAX_TRACKS) + { + error ("midifile: Header chunk ntrks (%d) exceeds midifile MAX_TRACKS, set to %d", + x->header_chunk.chunk_ntrks, MAX_TRACKS); + x->header_chunk.chunk_ntrks = MAX_TRACKS; + } + n = fread(cP, 1L, 2L, x->fP); + x->offset += n; + if (n != 2L) + { + error("midifile: read %lu instead of 2", n); + return 0; + } + x->header_chunk.chunk_division = midifile_get_multibyte_2(cP); + div = x->header_chunk.chunk_division; + if(div & 0x8000) + { + smpte = (-(div>>8)) & 0x0FF; + ticks = div & 0x0FF; + if (x->verbosity) + post("midifile: Header chunk division: 0x%X: %d frames per second, %d ticks per frame", div, smpte, ticks); + } + else if (x->verbosity) post("midifile: Header chunk division: 0x%X: %d ticks per quarter note", div, div); + return 1; } int midifile_read_track_chunk(t_midifile *x, int index) /* read the data part of a track chunk into track_data */ /* after allocating the space for it */ { - char *cP = x->track_chunk[index].chunk_type; - char buf[4]; - char type[5]; - size_t n, len; - - if (x->fP == NULL) - { - error("midifile: no open file"); - return 0;// no open file - } - n = fread(cP, 1L, 4L, x->fP); - x->offset += n; - if (n != 4L) - { - error("midifile: read %lu instead of 4", n); - return 0; - } - if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'r' && cP[3] == 'k')) - { - error ("midifile: bad file format: bad track chunk type"); - return 0; - } - type[0] = cP[0]; - type[1] = cP[1]; - type[2] = cP[2]; - type[3] = cP[3]; - type[4] = '\0'; - cP = buf; - n = fread(cP, 1L, 4L, x->fP); - x->offset += n; - if (n != 4L) - { - error("midifile: read %lu instead of 4", n); - return 0; - } - len = midifile_get_multibyte_4(cP); - x->track_chunk[index].chunk_length = len; - if (x->verbosity) post("midifile: Track chunk %d type: %s, length %lu", index, type, len); - if ((cP = getbytes(len)) == NULL) - { - error ("midifile: Unable to allocate %lu bytes for track data", len); - return 0; - } - x->track_chunk[index].track_data = cP; - n = fread(cP, 1L, len, x->fP); - - return 1; + char *cP = x->track_chunk[index].chunk_type; + char buf[4]; + char type[5]; + size_t n, len; + + if (x->fP == NULL) + { + error("midifile: no open file"); + return 0;/* no open file */ + } + n = fread(cP, 1L, 4L, x->fP); + x->offset += n; + if (n != 4L) + { + error("midifile: read %lu instead of 4", n); + return 0; + } + if (!(cP[0] == 'M' && cP[1] == 'T' && cP[2] == 'r' && cP[3] == 'k')) + { + error ("midifile: bad file format: bad track chunk type"); + return 0; + } + type[0] = cP[0]; + type[1] = cP[1]; + type[2] = cP[2]; + type[3] = cP[3]; + type[4] = '\0'; + cP = buf; + n = fread(cP, 1L, 4L, x->fP); + x->offset += n; + if (n != 4L) + { + error("midifile: read %lu instead of 4", n); + return 0; + } + len = midifile_get_multibyte_4(cP); + x->track_chunk[index].chunk_length = len; + if (x->verbosity) post("midifile: Track chunk %d type: %s, length %lu", index, type, len); + if ((cP = getbytes(len)) == NULL) + { + error ("midifile: Unable to allocate %lu bytes for track data", len); + return 0; + } + x->track_chunk[index].track_data = cP; + n = fread(cP, 1L, len, x->fP); + + return 1; } unsigned short midifile_combine_bytes(unsigned char data1, unsigned char data2) /* make a short from two 7bit MIDI data bytes */ { /* - unsigned short value = (unsigned short)data2; - value <<= 7; - value |= (unsigned short)data1; - return value; + unsigned short value = (unsigned short)data2; + value <<= 7; + value |= (unsigned short)data1; + return value; */ - return ((((unsigned short)data2)<< 7) | ((unsigned short)data1)); + return ((((unsigned short)data2)<< 7) | ((unsigned short)data1)); } unsigned long midifile_get_multibyte_4(char*n) /* make a long from 4 consecutive bytes in big-endian format */ { - unsigned long a, b, c, d, e; - a = (*(unsigned long *)(&n[0])) & 0x0FF; - b = (*(unsigned long *)(&n[1])) & 0x0FF; - c = (*(unsigned long *)(&n[2])) & 0x0FF; - d = (*(unsigned long *)(&n[3])) &0x0FF; - e = (a<<24) + (b<<16) + (c<<8) + d; - return e; + unsigned long a, b, c, d, e; + a = (*(unsigned long *)(&n[0])) & 0x0FF; + b = (*(unsigned long *)(&n[1])) & 0x0FF; + c = (*(unsigned long *)(&n[2])) & 0x0FF; + d = (*(unsigned long *)(&n[3])) &0x0FF; + e = (a<<24) + (b<<16) + (c<<8) + d; + return e; } unsigned long midifile_get_multibyte_3(char*n) /* make a long from 3 consecutive bytes in big-endian format */ { - unsigned long a, b, c, d; - a = (*(unsigned long *)(&n[0])) & 0x0FF; - b = (*(unsigned long *)(&n[1])) & 0x0FF; - c = (*(unsigned long *)(&n[2])) & 0x0FF; - d = (a<<16) + (b<<8) + c; - return d; + unsigned long a, b, c, d; + a = (*(unsigned long *)(&n[0])) & 0x0FF; + b = (*(unsigned long *)(&n[1])) & 0x0FF; + c = (*(unsigned long *)(&n[2])) & 0x0FF; + d = (a<<16) + (b<<8) + c; + return d; } unsigned short midifile_get_multibyte_2(char*n) /* make a short from 2 consecutive bytes in big-endian format */ { - unsigned short a, b, c; - a = (*(unsigned long *)(&n[0])) & 0x0FF; - b = (*(unsigned long *)(&n[1])) & 0x0FF; - c = (a<<8) + b; - return c; + unsigned short a, b, c; + a = (*(unsigned long *)(&n[0])) & 0x0FF; + b = (*(unsigned long *)(&n[1])) & 0x0FF; + c = (a<<8) + b; + return c; } int midifile_write_variable_length_value (FILE *fP, size_t value) /* return number of characters written to fP */ { - size_t buffer; - int i; - char c; - - buffer = value & 0x07F; - while ((value >>= 7) > 0) - { - buffer <<= 8; - buffer |= 0x80; - buffer += (value & 0x07F); - } - i = 0; - while (1) - { - c = (char)(buffer & (0x0FF)); - putc(c, fP); - ++i; - if (buffer & 0x80) buffer >>= 8; - else break; - } - return i; + size_t buffer; + int i; + char c; + + buffer = value & 0x07F; + while ((value >>= 7) > 0) + { + buffer <<= 8; + buffer |= 0x80; + buffer += (value & 0x07F); + } + i = 0; + while (1) + { + c = (char)(buffer & (0x0FF)); + putc(c, fP); + ++i; + if (buffer & 0x80) buffer >>= 8; + else break; + } + return i; } char *midifile_read_var_len (char *cP, size_t *delta) @@ -800,645 +797,650 @@ char *midifile_read_var_len (char *cP, size_t *delta) /* set delta to deltatime */ /* return pointer to following data */ - unsigned long value; - char c; - - if (((value = *(cP++))) & 0x80) - { - value &= 0x7f; - do - { - value = (value << 7) + ((c = *(cP++)) & 0x7f); - } while (c & 0x80); - } - *delta = value; - return cP; + unsigned long value; + char c; + + if (((value = *(cP++))) & 0x80) + { + value &= 0x7f; + do + { + value = (value << 7) + ((c = *(cP++)) & 0x7f); + } while (c & 0x80); + } + *delta = value; + return cP; } void midifile_verbosity(t_midifile *x, t_floatarg verbosity) /* set verbosity of console output */ { - x->verbosity = verbosity; + x->verbosity = verbosity; } void midifile_single_track(t_midifile *x, t_floatarg track) /* play only this track or all tracks if out of range */ { - if(x->state != mfReading) return; // only if we're reading - if ((track < 0) || (track >= x->header_chunk.chunk_ntrks)) - // anything out of range will be interpreted as all tracks - x->track = ALL_TRACKS; - else x->track = track; + if(x->state != mfReading) return; /* only if we're reading */ + if ((track < 0) || (track >= x->header_chunk.chunk_ntrks)) + /* anything out of range will be interpreted as all tracks */ + x->track = ALL_TRACKS; + else x->track = track; } void midifile_dump(t_midifile *x, t_floatarg track) { - int index = (int)track; - - if(x->state != mfReading) return; // only if we're reading - if ((index < x->header_chunk.chunk_ntrks) && (index >= 0)) - midifile_dump_track_chunk_data(x, index); - else// anything out of range will be interpreted as all tracks - for (index = 0; index < x->header_chunk.chunk_ntrks; ++index) - midifile_dump_track_chunk_data(x, index); + int index = (int)track; + + if(x->state != mfReading) return; /* only if we're reading */ + if ((index < x->header_chunk.chunk_ntrks) && (index >= 0)) + midifile_dump_track_chunk_data(x, index); + else /* anything out of range will be interpreted as all tracks */ + for (index = 0; index < x->header_chunk.chunk_ntrks; ++index) + midifile_dump_track_chunk_data(x, index); } void midifile_rewind (t_midifile *x) { - if(x->state != mfReading) return; // only if we're reading - midifile_rewind_tracks(x); + if(x->state != mfReading) return; /* only if we're reading */ + midifile_rewind_tracks(x); } void midifile_rewind_tracks(t_midifile *x) /* For all tracks, point to start of track_data */ { - int i; - for (i = 0; i < x->header_chunk.chunk_ntrks; ++i) - { - x->track_chunk[i].delta_time = 0L; - x->track_chunk[i].track_index = 0L; - x->track_chunk[i].total_time = 0L; - x->track_chunk[i].running_status = 0; - } - x->total_time = 0L; - x->ended = 0L; - outlet_float(x->total_time_outlet, x->total_time); + int i; + for (i = 0; i < x->header_chunk.chunk_ntrks; ++i) + { + x->track_chunk[i].delta_time = 0L; + x->track_chunk[i].track_index = 0L; + x->track_chunk[i].total_time = 0L; + x->track_chunk[i].running_status = 0; + } + x->total_time = 0L; + x->ended = 0L; + outlet_float(x->total_time_outlet, x->total_time); } size_t midifile_get_next_track_chunk_delta_time(t_midifile *x, int index) /* return the delta_time of the next event in track[index] */ { - unsigned char *cP, *last_cP; - size_t delta_time; + unsigned char *cP, *last_cP; + size_t delta_time; - cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; - last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; + cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; + last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; - delta_time = NO_MORE_ELEMENTS; - if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) cP = midifile_read_var_len(cP, &delta_time); -// if (x->verbosity) post("delta time for track[%d]: %lu", index, delta_time); - return delta_time; + delta_time = NO_MORE_ELEMENTS; + if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) + cP = midifile_read_var_len(cP, &delta_time); + return delta_time; } void midifile_output_long_list (t_outlet *outlet, unsigned char *cP, size_t len, unsigned char first_byte) -{ // ouput a long MIDI message as a list of floats - // first_byte is followed by len bytes at cP - size_t slen; - unsigned int si; - t_atom *slist; - - slen = (len+1L)*sizeof(t_atom); - slist = getbytes (slen); - if (slist == NULL) - { - error ("midifile: no memory for long list"); - return; - } - slist[0].a_type = A_FLOAT; - slist[0].a_w.w_float = 0xF0; - for (si = 0; si < len; ++si) - { - slist[si+1].a_type = A_FLOAT; - slist[si+1].a_w.w_float = cP[si]; - } - outlet_list(outlet, &s_list, len+1L, slist); - freebytes(slist, slen); +{ /* output a long MIDI message as a list of floats */ + /* first_byte is followed by len bytes at cP */ + size_t slen; + unsigned int si; + t_atom *slist; + + slen = (len+1L)*sizeof(t_atom); + slist = getbytes (slen); + if (slist == NULL) + { + error ("midifile: no memory for long list"); + return; + } + slist[0].a_type = A_FLOAT; + slist[0].a_w.w_float = 0xF0; + for (si = 0; si < len; ++si) + { + slist[si+1].a_type = A_FLOAT; + slist[si+1].a_w.w_float = cP[si]; + } + outlet_list(outlet, &s_list, len+1L, slist); + freebytes(slist, slen); } void midifile_dump_track_chunk_data(t_midifile *x, int index) /* parse entire track chunk and output it to the main window */ { - unsigned char *cP, *last_cP, *str; - size_t total_time, delta_time, time_sig, len; - unsigned char status, running_status, c, d, nn, dd, cc, bb, mi, mcp, ch; - char sf; - unsigned short sn; - unsigned char tt[3]; - char *msgPtr; - char msg[256]; - - cP = x->track_chunk[index].track_data; - last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; - total_time = 0L; - - post("midifile: Parsing track[%d]...", index); - while ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) - { - msgPtr = msg; - cP = midifile_read_var_len(cP, &delta_time); - status = *cP++; - total_time += delta_time; - msgPtr += sprintf (msgPtr, "tick %lu delta %lu status %02X ", total_time, delta_time, status); - if ((status & 0xF0) == 0xF0) - { - switch (status) - { - case 0xF0: - case 0xF7: - cP = midifile_read_var_len(cP, &len);// not a time but the same variable length format - msgPtr += sprintf(msgPtr, "Sysex: %02X length %lu ", status, len); - cP += len; - break; - case 0xF3: // song select - c = *cP++; - msgPtr += sprintf(msgPtr, "Song Select: %d ", c); - break; - case 0xF2: // song position - c = *cP++; - d = *cP++; - msgPtr += sprintf(msgPtr, "Song Position %d ", midifile_combine_bytes(c, d)); - break; - case 0xF1: // quarter frame - msgPtr += sprintf(msgPtr, "MIDI Quarter Frame"); - break; - case 0xF6: // tune request - msgPtr += sprintf(msgPtr, "MIDI Tune Request"); - break; - case 0xF8: // MIDI clock - msgPtr += sprintf(msgPtr, "MIDI Clock"); - break; - case 0xF9: // MIDI tick - msgPtr += sprintf(msgPtr, "MIDI Tick"); - break; - case 0xFA: // MIDI start - msgPtr += sprintf(msgPtr, "MIDI Start"); - break; - case 0xFB: // MIDI continue - msgPtr += sprintf(msgPtr, "MIDI Continue"); - break; - case 0xFC: // MIDI stop - msgPtr += sprintf(msgPtr, "MIDI Stop"); - break; - case 0xFE: // active sense - msgPtr += sprintf(msgPtr, "MIDI Active Sense"); - break; - case 0xFF: - c = *cP++; - cP = midifile_read_var_len(cP, &len);// not a time but the same variable length format - msgPtr += sprintf(msgPtr, "Meta 0x%02X length %lu \n", c, len); - switch (c) - { - case 0x58: - nn = *cP++; - dd = *cP++; - dd = 1<<(dd); - cc = *cP++; - bb = *cP++; - msgPtr += sprintf(msgPtr, "Time Signature %d/%d %d clocks per tick, %d 32nd notes per quarter note", nn, dd, cc, bb); - break; - case 0x59: - sf = *(signed char*)cP++; - mi = *cP++; - msgPtr += sprintf(msgPtr, "Key Signature: %d %s, %s", sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); - break; - case 0x51: - tt[0] = *cP++; - tt[1] = *cP++; - tt[2] = *cP++; - time_sig = midifile_get_multibyte_3(tt); - msgPtr += sprintf(msgPtr, "%lu microseconds per MIDI quarter-note", time_sig); - break; - case 0x2F: - msgPtr += sprintf(msgPtr, "========End of Track %d==========", index); - cP += len; - break; - case 0x21: - tt[0] = *cP++; - msgPtr += sprintf(msgPtr, "MIDI port or cable number (unofficial): %d", tt[0]); - break; - case 0x20: - mcp = *cP++; - msgPtr += sprintf(msgPtr, "MIDI Channel Prefix: %d", mcp); - break; - case 0x06: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Marker %s", str); - cP[len] = c; - cP += len; - break; - case 0x05: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Lyric %s", str); - cP[len] = c; - cP += len; - break; - case 0x04: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Instrument Name %s", str); - cP[len] = c; - cP += len; - break; - case 0x03: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Sequence/Track Name %s", str); - cP[len] = c; - cP += len; - break; - case 0x02: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Copyright Notice %s", str); - cP[len] = c; - cP += len; - break; - case 0x01: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - msgPtr += sprintf(msgPtr, "Text %s", str); - cP[len] = c; - cP += len; - break; - case 0x00: - tt[0] = *cP++; - tt[1] = *cP++; - sn = midifile_get_multibyte_2(tt); - msgPtr += sprintf(msgPtr, "Sequence Number %d", sn); - break; - default: - msgPtr += sprintf(msgPtr, "Unknown: 0x%02X", c); - cP += len; - break; - } - break; - default: // 0xF4, 0xF5, 0xF9, 0xFD are not defined - msgPtr += sprintf(msgPtr, "Undefined: 0x%02X", status); - break; - } - } - else - { - if (status & 0x80) - { - running_status = status; - c = *cP++; - } - else - { - c = status; - status = running_status; - } - ch = (status & 0x0F) + 1; // MIDI channel number - switch (status & 0xF0) - { - case 0x80: - d = *cP++; // 2 data bytes - msgPtr += sprintf(msgPtr, "MIDI 0x%02X %02X %02X : channel %d Note %d Off velocity %d", status, c, d, ch, c, d); - break; - case 0x90: - d = *cP++; // 2 data bytes - if (d == 0) - msgPtr += sprintf(msgPtr,"MIDI 0x%02X %02X %02X : channel %d Note %d Off", status, c, d, ch, c); - else - msgPtr += sprintf(msgPtr,"MIDI 0x%02X %02X %02X : channel %d Note %d On velocity %d", status, c, d, ch, c, d); - break; - case 0xA0: - d = *cP++; // 2 data bytes - msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X %02X : channel %d Note %d Aftertouch %d", status, c, d, ch, c, d); - break; - case 0xB0: - d = *cP++; // 2 data bytes - msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X %02X : channel %d Controller %d: %d", status, c, d, ch, c, d); - break; - case 0xC0: // 1 data byte - msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Program Change: %d", status, c, ch, c); - break; - case 0xD0: // 1 data byte - msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Channel Pressure: %d", status, c, ch, c); - break; - case 0xE0: // 2 data bytes - d = *cP++; // 2 data bytes - msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X %02X : channel %d Pitch Wheel %d", status, c, d, ch, midifile_combine_bytes(c, d)); - break; - } - } - post("midifile: %s", msg); - } + unsigned char *cP, *last_cP, *str; + size_t total_time, delta_time, time_sig, len; + unsigned char status, running_status, c, d, nn, dd, cc, bb, mi, mcp, ch; + char sf; + unsigned short sn; + unsigned char tt[3]; + char *msgPtr; + char msg[256]; + + cP = x->track_chunk[index].track_data; + last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; + total_time = 0L; + + post("midifile: Parsing track[%d]...", index); + while ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) + { + msgPtr = msg; + cP = midifile_read_var_len(cP, &delta_time); + status = *cP++; + total_time += delta_time; + msgPtr += sprintf (msgPtr, "tick %lu delta %lu status %02X ", total_time, delta_time, status); + if ((status & 0xF0) == 0xF0) + { + switch (status) + { + case 0xF0: + case 0xF7: + cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ + msgPtr += sprintf(msgPtr, "Sysex: %02X length %lu ", status, len); + cP += len; + break; + case 0xF3: /* song select */ + c = *cP++; + msgPtr += sprintf(msgPtr, "Song Select: %d ", c); + break; + case 0xF2: /* song position */ + c = *cP++; + d = *cP++; + msgPtr += sprintf(msgPtr, "Song Position %d ", midifile_combine_bytes(c, d)); + break; + case 0xF1: /* quarter frame */ + msgPtr += sprintf(msgPtr, "MIDI Quarter Frame"); + break; + case 0xF6: /* tune request */ + msgPtr += sprintf(msgPtr, "MIDI Tune Request"); + break; + case 0xF8: /* MIDI clock */ + msgPtr += sprintf(msgPtr, "MIDI Clock"); + break; + case 0xF9: /* MIDI tick */ + msgPtr += sprintf(msgPtr, "MIDI Tick"); + break; + case 0xFA: /* MIDI start */ + msgPtr += sprintf(msgPtr, "MIDI Start"); + break; + case 0xFB: /* MIDI continue */ + msgPtr += sprintf(msgPtr, "MIDI Continue"); + break; + case 0xFC: /* MIDI stop */ + msgPtr += sprintf(msgPtr, "MIDI Stop"); + break; + case 0xFE: /* active sense */ + msgPtr += sprintf(msgPtr, "MIDI Active Sense"); + break; + case 0xFF: + c = *cP++; + cP = midifile_read_var_len(cP, &len);/* not a time but the same variable length format */ + msgPtr += sprintf(msgPtr, "Meta 0x%02X length %lu \n", c, len); + switch (c) + { + case 0x58: + nn = *cP++; + dd = *cP++; + dd = 1<<(dd); + cc = *cP++; + bb = *cP++; + msgPtr += sprintf( + msgPtr, "Time Signature %d/%d %d clocks per tick, %d 32nd notes per quarter note", + nn, dd, cc, bb); + break; + case 0x59: + sf = *(signed char*)cP++; + mi = *cP++; + msgPtr += sprintf( + msgPtr, "Key Signature: %d %s, %s", + sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); + break; + case 0x51: + tt[0] = *cP++; + tt[1] = *cP++; + tt[2] = *cP++; + time_sig = midifile_get_multibyte_3(tt); + msgPtr += sprintf(msgPtr, "%lu microseconds per MIDI quarter-note", time_sig); + break; + case 0x2F: + msgPtr += sprintf(msgPtr, "========End of Track %d==========", index); + cP += len; + break; + case 0x21: + tt[0] = *cP++; + msgPtr += sprintf(msgPtr, "MIDI port or cable number (unofficial): %d", tt[0]); + break; + case 0x20: + mcp = *cP++; + msgPtr += sprintf(msgPtr, "MIDI Channel Prefix: %d", mcp); + break; + case 0x06: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Marker %s", str); + cP[len] = c; + cP += len; + break; + case 0x05: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Lyric %s", str); + cP[len] = c; + cP += len; + break; + case 0x04: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Instrument Name %s", str); + cP[len] = c; + cP += len; + break; + case 0x03: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Sequence/Track Name %s", str); + cP[len] = c; + cP += len; + break; + case 0x02: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Copyright Notice %s", str); + cP[len] = c; + cP += len; + break; + case 0x01: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + msgPtr += sprintf(msgPtr, "Text %s", str); + cP[len] = c; + cP += len; + break; + case 0x00: + tt[0] = *cP++; + tt[1] = *cP++; + sn = midifile_get_multibyte_2(tt); + msgPtr += sprintf(msgPtr, "Sequence Number %d", sn); + break; + default: + msgPtr += sprintf(msgPtr, "Unknown: 0x%02X", c); + cP += len; + break; + } + break; + default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ + msgPtr += sprintf(msgPtr, "Undefined: 0x%02X", status); + break; + } + } + else + { + if (status & 0x80) + { + running_status = status; + c = *cP++; + } + else + { + c = status; + status = running_status; + } + ch = (status & 0x0F) + 1; /* MIDI channel number */ + switch (status & 0xF0) + { + case 0x80: + d = *cP++; /* 2 data bytes */ + msgPtr += sprintf(msgPtr, + "MIDI 0x%02X %02X %02X : channel %d Note %d Off velocity %d", + status, c, d, ch, c, d); + break; + case 0x90: + d = *cP++; /* 2 data bytes */ + if (d == 0) + msgPtr += sprintf(msgPtr,"MIDI 0x%02X %02X %02X : channel %d Note %d Off", status, c, d, ch, c); + else + msgPtr += sprintf(msgPtr, + "MIDI 0x%02X %02X %02X : channel %d Note %d On velocity %d", status, c, d, ch, c, d); + break; + case 0xA0: + d = *cP++; /* 2 data bytes */ + msgPtr += sprintf(msgPtr, + "MIDI: 0x%02X %02X %02X : channel %d Note %d Aftertouch %d", status, c, d, ch, c, d); + break; + case 0xB0: + d = *cP++; /* 2 data bytes */ + msgPtr += sprintf(msgPtr, + "MIDI: 0x%02X %02X %02X : channel %d Controller %d: %d", status, c, d, ch, c, d); + break; + case 0xC0: /* 1 data byte */ + msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Program Change: %d", status, c, ch, c); + break; + case 0xD0: /* 1 data byte */ + msgPtr += sprintf(msgPtr,"MIDI: 0x%02X %02X: channel %d Channel Pressure: %d", status, c, ch, c); + break; + case 0xE0: /* 2 data bytes */ + d = *cP++; /* 2 data bytes */ + msgPtr += sprintf(msgPtr, + "MIDI: 0x%02X %02X %02X : channel %d Pitch Wheel %d", + status, c, d, ch, midifile_combine_bytes(c, d)); + break; + } + } + post("midifile: %s", msg); + } } void midifile_get_next_track_chunk_data(t_midifile *x, int index) /* parse the next track chunk data element and output via the appropriate outlet or post to main window */ /* Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ { - unsigned char *cP, *last_cP, *str; - size_t delta_time, time_sig, len, i; - unsigned char status, c, d, nn, dd, cc, bb, mi, mcp, n; - char sf; - unsigned short sn; - unsigned char tt[3]; - - cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; - last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; - -// if (x->verbosity) post("Parsing track[%d]: ", index); - delta_time = NO_MORE_ELEMENTS; - if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) - { - cP = midifile_read_var_len(cP, &delta_time); - status = *cP++; -// if (x->verbosity) post ("delta time %lu total_time %lu status %02X", delta_time, x->track_chunk[index].total_time, status); - if ((status & 0xF0) == 0xF0) - { - switch (status) - {// system message - case 0xF0: - case 0xF7: - cP = midifile_read_var_len(cP, &len); // packet length - if (x->verbosity) post("midifile: Sysex: %02X length %lu", status, len); - midifile_output_long_list(x->midi_list_outlet, cP, len, 0xF0); - /* - outlet_float(x->sysex_outlet, 0xF0); // sysex status - for (i = 0; i < len; ++i) outlet_float(x->sysex_outlet, cP[i]); // sysex packet - //if (cP[len-1] != 0xF7)outlet_float(x->sysex_outlet, 0xF0); // sysex terminator - */ - cP += len; - x->track_chunk[index].running_status = 0; - break; - case 0xF1: // quarter frame - x->midi_data[0].a_w.w_float = status; - outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); - x->track_chunk[index].running_status = 0; - break; - case 0xF3: // song select - c = *cP++; - x->midi_data[0].a_w.w_float = status; - x->midi_data[1].a_w.w_float = c; - outlet_list(x->midi_list_outlet, &s_list, 2, x->midi_data); - x->track_chunk[index].running_status = 0; - break; - case 0xF2: // song position - c = *cP++; - x->midi_data[0].a_w.w_float = status; - x->midi_data[1].a_w.w_float = c; - c = *cP++; - x->midi_data[2].a_w.w_float = c; - outlet_list(x->midi_list_outlet, &s_list, 3, x->midi_data); - x->track_chunk[index].running_status = 0; - break; - case 0xF6: // tune request - x->midi_data[0].a_w.w_float = status; - outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); - x->track_chunk[index].running_status = 0; - break; - case 0xF8: // MIDI clock - case 0xF9: // MIDI tick - case 0xFA: // MIDI start - case 0xFB: // MIDI continue - case 0xFC: // MIDI stop - case 0xFE: // active sense - x->midi_data[0].a_w.w_float = status; - outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); - break; - case 0xFF: - c = *cP++; - cP = midifile_read_var_len(cP, &len);// meta length - if (x->verbosity) post("midifile: Track %d Meta: %02X length %lu", index, c, len); - switch (c) - { - case 0x58: - nn = *cP++; - dd = *cP++; - dd = 1<<(dd); - cc = *cP++; - bb = *cP++; - if (x->verbosity) post ("midifile: Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarternote", nn, dd, cc, bb); - break; - case 0x59: - sf = *(signed char *)cP++; - mi = *cP++; - if (x->verbosity) post ("midifile: Key Signature: %d %s, %s", sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); - break; - case 0x51: - tt[0] = *cP++; - tt[1] = *cP++; - tt[2] = *cP++; - time_sig = midifile_get_multibyte_3(tt); - if (x->verbosity) post ("midifile: %lu microseconds per MIDI quarter-note", time_sig); - break; - case 0x2F: - if (x->verbosity) post ("midifile: End of Track %d", index); - delta_time = NO_MORE_ELEMENTS; - cP += len; - break; - case 0x21: - tt[0] = *cP++; - if (x->verbosity) post ("midifile: MIDI port or cable number (unofficial): %d", tt[0]); - break; - case 0x20: - mcp = *cP++; - if (x->verbosity) post ("midifile: MIDI Channel Prefix: %d", mcp); - break; - case 0x06: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Marker: %s", str); - cP[len] = c; - cP += len; - break; - case 0x05: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Lyric: %s", str); - cP[len] = c; - cP += len; - break; - case 0x04: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Instrument Name: %s", str); - cP[len] = c; - cP += len; - break; - case 0x03: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Sequence/Track Name: %s", str); - cP[len] = c; - cP += len; - break; - case 0x02: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Copyright Notice: %s", str); - cP[len] = c; - cP += len; - break; - case 0x01: - str = cP; - c = cP[len]; - cP[len] = '\0'; //null terminate temporarily - if (x->verbosity) post ("midifile: Text Event: %s", str); - cP[len] = c; - cP += len; - break; - case 0x00: - tt[0] = *cP++; - tt[1] = *cP++; - sn = midifile_get_multibyte_2(tt); - if (x->verbosity) post ("midifile: Sequence Number %d", sn); - break; - default: - if (x->verbosity) post ("midifile: Unknown: %02X", c); - cP += len; - break; - } - break; - default: // 0xF4, 0xF5, 0xF9, 0xFD are not defined - break; - } - } - else - { - if (status & 0x80) - { - x->track_chunk[index].running_status = status;// status is true status - c = *cP++; - } - else - { - c = status; // status is actually 1st data byte - status = x->track_chunk[index].running_status;// current status - } - switch (status & 0xF0) - { - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - case 0xE0: - n = 3; - d = *cP++; // 2 data bytes - break; - case 0xC0: // 1 data byte - case 0xD0: - n = 2; - break; - } - x->midi_data[0].a_w.w_float = status; - x->midi_data[1].a_w.w_float = c; - x->midi_data[2].a_w.w_float = (n == 3)?d:0; - if (x->midi_data[0].a_w.w_float != 0) outlet_list(x->midi_list_outlet, &s_list, n, x->midi_data); - //if (x->verbosity) post("MIDI: %02X %d %d", x->track_chunk[index].running_status, c, d); - if (x->track_chunk[index].running_status == 0) - error ("midifile: No running status on track %d at %lu", index, x->track_chunk[index].total_time + delta_time); - } - } - x->track_chunk[index].track_index = (char *)cP - (char *)x->track_chunk[index].track_data; - x->track_chunk[index].delta_time = delta_time; - if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[index].total_time = delta_time; - else x->track_chunk[index].total_time += delta_time; + unsigned char *cP, *last_cP, *str; + size_t delta_time, time_sig, len, i; + unsigned char status, c, d, nn, dd, cc, bb, mi, mcp, n; + char sf; + unsigned short sn; + unsigned char tt[3]; + + cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; + last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; + + delta_time = NO_MORE_ELEMENTS; + if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) + { + cP = midifile_read_var_len(cP, &delta_time); + status = *cP++; + if ((status & 0xF0) == 0xF0) + { + switch (status) + { /* system message */ + case 0xF0: + case 0xF7: + cP = midifile_read_var_len(cP, &len); /* packet length */ + if (x->verbosity) post("midifile: Sysex: %02X length %lu", status, len); + midifile_output_long_list(x->midi_list_outlet, cP, len, 0xF0); + cP += len; + x->track_chunk[index].running_status = 0; + break; + case 0xF1: /* quarter frame */ + x->midi_data[0].a_w.w_float = status; + outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); + x->track_chunk[index].running_status = 0; + break; + case 0xF3: /* song select */ + c = *cP++; + x->midi_data[0].a_w.w_float = status; + x->midi_data[1].a_w.w_float = c; + outlet_list(x->midi_list_outlet, &s_list, 2, x->midi_data); + x->track_chunk[index].running_status = 0; + break; + case 0xF2: /* song position */ + c = *cP++; + x->midi_data[0].a_w.w_float = status; + x->midi_data[1].a_w.w_float = c; + c = *cP++; + x->midi_data[2].a_w.w_float = c; + outlet_list(x->midi_list_outlet, &s_list, 3, x->midi_data); + x->track_chunk[index].running_status = 0; + break; + case 0xF6: /* tune request */ + x->midi_data[0].a_w.w_float = status; + outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); + x->track_chunk[index].running_status = 0; + break; + case 0xF8: /* MIDI clock */ + case 0xF9: /* MIDI tick */ + case 0xFA: /* MIDI start */ + case 0xFB: /* MIDI continue */ + case 0xFC: /* MIDI stop */ + case 0xFE: /* active sense */ + x->midi_data[0].a_w.w_float = status; + outlet_list(x->midi_list_outlet, &s_list, 1, x->midi_data); + break; + case 0xFF: + c = *cP++; + cP = midifile_read_var_len(cP, &len);/* meta length */ + if (x->verbosity) post("midifile: Track %d Meta: %02X length %lu", index, c, len); + switch (c) + { + case 0x58: + nn = *cP++; + dd = *cP++; + dd = 1<<(dd); + cc = *cP++; + bb = *cP++; + if (x->verbosity) + post ("midifile: Time Signature: %d/%d %d clocks per tick, %d 32nd notes per quarternote", + nn, dd, cc, bb); + break; + case 0x59: + sf = *(signed char *)cP++; + mi = *cP++; + if (x->verbosity) + post ("midifile: Key Signature: %d %s, %s", + sf, (sf<0)?"flats":"sharps", (mi)?"minor":"major"); + break; + case 0x51: + tt[0] = *cP++; + tt[1] = *cP++; + tt[2] = *cP++; + time_sig = midifile_get_multibyte_3(tt); + if (x->verbosity) post ("midifile: %lu microseconds per MIDI quarter-note", time_sig); + break; + case 0x2F: + if (x->verbosity) post ("midifile: End of Track %d", index); + delta_time = NO_MORE_ELEMENTS; + cP += len; + break; + case 0x21: + tt[0] = *cP++; + if (x->verbosity) post ("midifile: MIDI port or cable number (unofficial): %d", tt[0]); + break; + case 0x20: + mcp = *cP++; + if (x->verbosity) post ("midifile: MIDI Channel Prefix: %d", mcp); + break; + case 0x06: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Marker: %s", str); + cP[len] = c; + cP += len; + break; + case 0x05: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Lyric: %s", str); + cP[len] = c; + cP += len; + break; + case 0x04: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Instrument Name: %s", str); + cP[len] = c; + cP += len; + break; + case 0x03: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Sequence/Track Name: %s", str); + cP[len] = c; + cP += len; + break; + case 0x02: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Copyright Notice: %s", str); + cP[len] = c; + cP += len; + break; + case 0x01: + str = cP; + c = cP[len]; + cP[len] = '\0'; /* null terminate temporarily */ + if (x->verbosity) post ("midifile: Text Event: %s", str); + cP[len] = c; + cP += len; + break; + case 0x00: + tt[0] = *cP++; + tt[1] = *cP++; + sn = midifile_get_multibyte_2(tt); + if (x->verbosity) post ("midifile: Sequence Number %d", sn); + break; + default: + if (x->verbosity) post ("midifile: Unknown: %02X", c); + cP += len; + break; + } + break; + default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ + break; + } + } + else + { + if (status & 0x80) + { + x->track_chunk[index].running_status = status;/* status is true status */ + c = *cP++; + } + else + { + c = status; /* status is actually 1st data byte */ + status = x->track_chunk[index].running_status; /* current status */ + } + switch (status & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + n = 3; + d = *cP++; /* 2 data bytes */ + break; + case 0xC0: /* 1 data byte */ + case 0xD0: + n = 2; + break; + } + x->midi_data[0].a_w.w_float = status; + x->midi_data[1].a_w.w_float = c; + x->midi_data[2].a_w.w_float = (n == 3)?d:0; + if (x->midi_data[0].a_w.w_float != 0) outlet_list(x->midi_list_outlet, &s_list, n, x->midi_data); + if (x->track_chunk[index].running_status == 0) + error ("midifile: No running status on track %d at %lu", + index, x->track_chunk[index].total_time + delta_time); + } + } + x->track_chunk[index].track_index = (char *)cP - (char *)x->track_chunk[index].track_data; + x->track_chunk[index].delta_time = delta_time; + if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[index].total_time = delta_time; + else x->track_chunk[index].total_time += delta_time; } void midifile_skip_next_track_chunk_data(t_midifile *x, int index) /* parse the next track chunk data element and skip it without any output */ /* Sets the delta_time of the element or NO_MORE_ELEMENTS if no more elements */ { - unsigned char *cP, *last_cP; - size_t delta_time, len; - unsigned char status, c, n; - - cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; - last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; - -// if (x->verbosity) post("Parsing track[%d]: ", index); - delta_time = NO_MORE_ELEMENTS; - - if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) - { - cP = midifile_read_var_len(cP, &delta_time); - status = *cP++; -// if (x->verbosity) post ("delta time %lu total_time %lu status %02X", delta_time, x->track_chunk[index].total_time, status); - if ((status & 0xF0) == 0xF0) - { - switch (status) - {// system message - case 0xF0: - case 0xF7: - cP = midifile_read_var_len(cP, &len); // packet length - cP += len; - break; - case 0xF1: // quarter frame - break; - case 0xF3: // song select - cP += 1; - break; - case 0xF2: // song position - cP += 2; - break; - case 0xF6: // tune request - case 0xF8: // MIDI clock - case 0xF9: // MIDI tick - case 0xFA: // MIDI start - case 0xFB: // MIDI continue - case 0xFC: // MIDI stop - case 0xFE: // active sense - break; - case 0xFF: - c = *cP++; - cP = midifile_read_var_len(cP, &len);// meta length - // if (x->verbosity) post("Meta: %02X length %lu", c, len); - switch (c) - { - case 0x2F: - if (x->verbosity) post ("midifile: End of Track %d", index); - delta_time = NO_MORE_ELEMENTS; - // fall through to default.... - default: - cP += len; - break; - } - break; - default: // 0xF4, 0xF5, 0xF9, 0xFD are not defined - break; - } - } - else - { - if (status & 0x80) - { - x->track_chunk[index].running_status = status; - n = 1; - } - else - { - n = 0; // no status in this message - status = x->track_chunk[index].running_status; - } - switch (status & 0xF0) - { - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - case 0xE0: - n += 1; // data bytes - break; - case 0xC0: - case 0xD0:// only one data byte - break; - } - cP += n; - } - } - x->track_chunk[index].track_index = (char *)cP - (char *)x->track_chunk[index].track_data; - x->track_chunk[index].delta_time = delta_time; - if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[index].total_time = delta_time; - else x->track_chunk[index].total_time += delta_time; + unsigned char *cP, *last_cP; + size_t delta_time, len; + unsigned char status, c, n; + + cP = x->track_chunk[index].track_data + x->track_chunk[index].track_index; + last_cP = x->track_chunk[index].track_data + x->track_chunk[index].chunk_length; + + delta_time = NO_MORE_ELEMENTS; + + if ((cP != NULL) && (cP < last_cP) && (x->track_chunk[index].delta_time != NO_MORE_ELEMENTS)) + { + cP = midifile_read_var_len(cP, &delta_time); + status = *cP++; + if ((status & 0xF0) == 0xF0) + { + switch (status) + { /* system message */ + case 0xF0: + case 0xF7: + cP = midifile_read_var_len(cP, &len); /* packet length */ + cP += len; + break; + case 0xF1: /* quarter frame */ + break; + case 0xF3: /* song select */ + cP += 1; + break; + case 0xF2: /* song position */ + cP += 2; + break; + case 0xF6: /* tune request */ + case 0xF8: /* MIDI clock */ + case 0xF9: /* MIDI tick */ + case 0xFA: /* MIDI start */ + case 0xFB: /* MIDI continue */ + case 0xFC: /* MIDI stop */ + case 0xFE: /* active sense */ + break; + case 0xFF: + c = *cP++; + cP = midifile_read_var_len(cP, &len);/* meta length */ + switch (c) + { + case 0x2F: + if (x->verbosity) post ("midifile: End of Track %d", index); + delta_time = NO_MORE_ELEMENTS; + /* fall through to default....*/ + default: + cP += len; + break; + } + break; + default: /* 0xF4, 0xF5, 0xF9, 0xFD are not defined */ + break; + } + } + else + { + if (status & 0x80) + { + x->track_chunk[index].running_status = status; + n = 1; + } + else + { + n = 0; /* no status in this message */ + status = x->track_chunk[index].running_status; + } + switch (status & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + n += 1; /* data bytes */ + break; + case 0xC0: + case 0xD0: /* only one data byte */ + break; + } + cP += n; + } + } + x->track_chunk[index].track_index = (char *)cP - (char *)x->track_chunk[index].track_data; + x->track_chunk[index].delta_time = delta_time; + if (delta_time == NO_MORE_ELEMENTS) x->track_chunk[index].total_time = delta_time; + else x->track_chunk[index].total_time += delta_time; } /* fin midifile.c */ |