From 2359103e0277dd92b7e93c4afeb1e22537e21d48 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 17 Jun 2022 03:18:32 +0300 Subject: [PATCH] - running status detection - ignore unknown MIDI messages - implement non-UNIX fallback for map_file/unmap_file --- src/midi.c | 121 +++++++++++++++++++++++++++++++++++++++--------------------- src/midi.h | 27 ++++++++++++-- 2 files changed, 103 insertions(+), 45 deletions(-) diff --git a/src/midi.c b/src/midi.c index 60613d6..f6fc49e 100644 --- a/src/midi.c +++ b/src/midi.c @@ -3,13 +3,10 @@ #include #include #include -#include -#include -#include -#include -#include #include "midi.h" +#define USE_MMAP + #define FMT_SINGLE 0 #define FMT_MULTI_TRACK 1 #define FMT_MULTI_SEQ 2 @@ -31,28 +28,6 @@ #define META_KEYSIG 89 #define META_SPECIFIC 127 -struct midi { - int bpm; - - int num_tracks; - struct midi_track *tracks; -}; - -struct midi_track { - char *name; - struct midi_event *head, *tail; - int num_ev; -}; - -struct midi_event { - long dt; - int type; - int channel; - int arg[2]; - - struct midi_event *next; -}; - #define CHUNK_HDR_SIZE 8 struct chunk_hdr { char id[4]; @@ -185,6 +160,8 @@ static int read_track(struct midi *midi, struct chunk_hdr *chunk) unsigned char *ptr; struct midi_track trk = {0, 0, 0, 0}; unsigned char prev_stat = 0; + int type; + struct midi_event *ev; if(!ischunk(chunk, "MTrk")) { return -1; @@ -195,7 +172,6 @@ static int read_track(struct midi *midi, struct chunk_hdr *chunk) long dt; unsigned char stat; - /* TODO also convert dt to some standard unit */ dt = read_vardata(&ptr); stat = *ptr++; @@ -204,7 +180,20 @@ static int read_track(struct midi *midi, struct chunk_hdr *chunk) } else if(stat == 0xf0) { read_sysex_event(midi, &ptr); } else { - struct midi_event *ev = malloc(sizeof *ev); + if(!(stat & 0x80)) { + /* not a status byte, assume running status */ + stat = prev_stat; + ptr--; + } + type = (stat >> 4) & 0xf; + + if(!IS_VALID_EVTYPE(type) || !(ev = malloc(sizeof *ev))) { + /* unkwown message, skip all data bytes */ + while(ptr < chunk->data + chunk->size && !(*ptr & 0x80)) { + ptr++; + } + continue; + } if(trk.head) { trk.tail->next = ev; @@ -215,18 +204,8 @@ static int read_track(struct midi *midi, struct chunk_hdr *chunk) ev->next = 0; trk.num_ev++; - if(!(stat & 0x80)) { - /* not a status byte, assume running status */ - stat = prev_stat; - ptr--; - } - ev->dt = dt; - ev->type = (stat >> 4) & 0xf; - if(!IS_VALID_EVTYPE(ev->type)) { - fprintf(stderr, "warning, skipping track with unknown event %d\n", ev->type); - return -1; - } + ev->type = type; ev->channel = stat & 0xf; ev->arg[0] = *ptr++; @@ -234,6 +213,10 @@ static int read_track(struct midi *midi, struct chunk_hdr *chunk) ev->arg[1] = *ptr++; } + if(ev->type == MIDI_NOTE_ON && ev->arg[1] == 0) { + ev->type = MIDI_NOTE_OFF; + } + prev_stat = stat; } } @@ -328,13 +311,24 @@ static struct midi_hdr *mkmidi(void *ptr) static void bigend(void *ptr, int sz) { + static unsigned char test[] = {0x12, 0x34}; + uint32_t val32; + uint16_t val16; + + if(sz < 2 || *(uint16_t*)test == 0x1234) { + return; + } + switch(sz) { case 4: - *((uint32_t*)ptr) = ntohl(*(uint32_t*)ptr); + val32 = *(uint32_t*)ptr; + *(uint32_t*)ptr = (val32 << 24) | (val32 >> 24) | ((val32 & 0xff00) << 8) | + ((val32 & 0xff0000) >> 8); break; case 2: - *(uint16_t*)ptr = ntohs(*(uint16_t*)ptr); + val16 = *(uint16_t*)ptr; + *(uint16_t*)ptr = (val16 >> 8) | (val16 << 8); break; case 1: @@ -343,6 +337,12 @@ static void bigend(void *ptr, int sz) } } +#if defined(__unix__) && defined(USE_MMAP) +#include +#include +#include +#include + static void *map_file(const char *fname, int *size) { int fd; @@ -370,3 +370,40 @@ static void unmap_file(void *mem, int size) { munmap(mem, size); } +#else +static void *map_file(const char *fname, int *size) +{ + FILE *fp; + long sz; + void *buf; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open midi file: %s: %s\n", fname, strerror(errno)); + return 0; + } + fseek(fp, 0, SEEK_END); + sz = ftell(fp); + rewind(fp); + + if(!(buf = malloc(sz))) { + fprintf(stderr, "failed to allocate space for %s in memory (%ld bytes)\n", fname, sz); + fclose(fp); + return 0; + } + if(fread(buf, 1, sz, fp) != sz) { + fprintf(stderr, "failed to load midi file: %s: %s\n", fname, strerror(errno)); + free(buf); + fclose(fp); + return 0; + } + fclose(fp); + + *size = sz; + return buf; +} + +static void unmap_file(void *mem, int size) +{ + free(mem); +} +#endif diff --git a/src/midi.h b/src/midi.h index 4ad08a4..96fefa8 100644 --- a/src/midi.h +++ b/src/midi.h @@ -3,9 +3,27 @@ #include -struct midi; -struct midi_track; -struct midi_event; +struct midi { + int bpm; + + int num_tracks; + struct midi_track *tracks; +}; + +struct midi_track { + char *name; + struct midi_event *head, *tail; + int num_ev; +}; + +struct midi_event { + long dt; + int type; + int channel; + int arg[2]; + + struct midi_event *next; +}; #define MIDI_NOTE_OFF 8 #define MIDI_NOTE_ON 9 @@ -15,6 +33,9 @@ struct midi_event; #define MIDI_CHAN_AFTERTOUCH 13 #define MIDI_PITCH_BEND 14 +#define MIDI_NOTE_NUM(ev) ((ev)->arg[0]) +#define MIDI_NOTE_VEL(ev) ((ev)->arg[1]) + #ifdef __cplusplus extern "C" { #endif -- 1.7.10.4