#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];
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;
long dt;
unsigned char stat;
- /* TODO also convert dt to some standard unit */
dt = read_vardata(&ptr);
stat = *ptr++;
} 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;
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++;
ev->arg[1] = *ptr++;
}
+ if(ev->type == MIDI_NOTE_ON && ev->arg[1] == 0) {
+ ev->type = MIDI_NOTE_OFF;
+ }
+
prev_stat = stat;
}
}
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:
}
}
+#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;
{
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