- running status detection master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 17 Jun 2022 00:18:32 +0000 (03:18 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 17 Jun 2022 00:18:32 +0000 (03:18 +0300)
- ignore unknown MIDI messages
- implement non-UNIX fallback for map_file/unmap_file

src/midi.c
src/midi.h

index 60613d6..f6fc49e 100644 (file)
@@ -3,13 +3,10 @@
 #include <string.h>
 #include <errno.h>
 #include <inttypes.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
 #include "midi.h"
 
+#define USE_MMAP
+
 #define FMT_SINGLE             0
 #define FMT_MULTI_TRACK        1
 #define FMT_MULTI_SEQ  2
 #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 <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
 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
index 4ad08a4..96fefa8 100644 (file)
@@ -3,9 +3,27 @@
 
 #include <stdio.h>
 
-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