11 #define FMT_MULTI_TRACK 1
12 #define FMT_MULTI_SEQ 2
17 #define META_COPYRIGHT 2
23 #define META_CHANPREFIX 32
24 #define META_END_TRACK 47
26 #define META_SMPTE_OFFS 84
28 #define META_KEYSIG 89
29 #define META_SPECIFIC 127
31 #define CHUNK_HDR_SIZE 8
35 unsigned char data[1];
39 uint16_t fmt; /* 0: single, 1: multi-track, 2: multiple independent */
43 } __attribute__ ((packed));
45 static void destroy_track(struct midi_track *trk);
46 static int read_track(struct midi *midi, struct chunk_hdr *chunk);
47 static long read_vardata(unsigned char **pptr);
48 static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr);
49 static int read_sysex_event(struct midi *midi, unsigned char **pptr);
50 static int ischunk(struct chunk_hdr *chunk, const char *name);
51 static struct chunk_hdr *mkchunk(void *ptr);
52 static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk);
53 static struct midi_hdr *mkmidi(void *ptr);
54 static void bigend(void *ptr, int sz);
55 static void *map_file(const char *fname, int *size);
56 static void unmap_file(void *mem, int size);
58 #define IS_VALID_EVTYPE(x) ((x) >= MIDI_NOTE_OFF && (x) <= MIDI_PITCH_BEND)
60 /* XXX the event arity table must match the MIDI_* defines in midi.h */
61 static int ev_arity[] = {
62 0, 0, 0, 0, 0, 0, 0, 0,
63 2, /* note off (note, velocity)*/
64 2, /* note on (note, velocity)*/
65 2, /* note aftertouch (note, aftertouch value) */
66 2, /* controller (controller number, value) */
67 1, /* prog change (prog number) */
68 1, /* channel aftertouch (aftertouch value) */
69 2 /* pitch bend (pitch LSB, pitch MSB) */
73 struct midi *load_midi(const char *fname)
78 struct chunk_hdr *chunk;
81 if(!(mem = map_file(fname, &size))) {
86 if(!ischunk(chunk, "MThd") || chunk->size != 6) {
87 fprintf(stderr, "invalid or corrupted midi file: %s\n", fname);
90 hdr = mkmidi(chunk->data);
92 printf("format: %d\n", (int)hdr->fmt);
93 printf("tracks: %d\n", (int)hdr->num_tracks);
95 if((hdr->tm_div & 0x8000) == 0) {
96 /* division is in pulses / quarter note */
97 printf("time division: %d ppqn\n", (int)hdr->tm_div);
99 /* division in frames / sec */
100 int fps = (hdr->tm_div & 0x7f00) >> 8;
101 int ticks_per_frame = hdr->tm_div & 0xff;
102 printf("time division: %d fps, %d ticks/frame\n", fps, ticks_per_frame);
105 if(!(midi = malloc(sizeof *midi))) {
106 perror("failed to allocate memory");
109 if(!(midi->tracks = malloc(hdr->num_tracks * sizeof *midi->tracks))) {
110 perror("failed to allocate memory");
113 midi->num_tracks = 0;
115 while((chunk = skip_chunk(chunk)) && ((char*)chunk < mem + size)) {
116 if(ischunk(chunk, "MTrk")) {
117 if(read_track(midi, chunk) == -1) {
118 fprintf(stderr, "failed to read track\n");
121 printf("ignoring chunk: %c%c%c%c\n", chunk->id[0], chunk->id[1], chunk->id[2], chunk->id[3]);
126 unmap_file(mem, size);
134 void free_midi(struct midi *midi)
140 for(i=0; i<midi->num_tracks; i++) {
141 destroy_track(midi->tracks + i);
144 free(midi->tracks); /* TODO free tracks properly */
148 static void destroy_track(struct midi_track *trk)
152 void *tmp = trk->head;
153 trk->head = trk->head->next;
158 static int read_track(struct midi *midi, struct chunk_hdr *chunk)
161 struct midi_track trk = {0, 0, 0, 0};
162 unsigned char prev_stat = 0;
164 struct midi_event *ev;
166 if(!ischunk(chunk, "MTrk")) {
171 while(ptr < chunk->data + chunk->size) {
175 dt = read_vardata(&ptr);
179 read_meta_event(midi, &trk, &ptr);
180 } else if(stat == 0xf0) {
181 read_sysex_event(midi, &ptr);
184 /* not a status byte, assume running status */
188 type = (stat >> 4) & 0xf;
190 if(!IS_VALID_EVTYPE(type) || !(ev = malloc(sizeof *ev))) {
191 /* unkwown message, skip all data bytes */
192 while(ptr < chunk->data + chunk->size && !(*ptr & 0x80)) {
209 ev->channel = stat & 0xf;
212 if(ev_arity[ev->type] > 1) {
216 if(ev->type == MIDI_NOTE_ON && ev->arg[1] == 0) {
217 ev->type = MIDI_NOTE_OFF;
224 /* if we did actually add any events ... */
226 midi->tracks[midi->num_tracks++] = trk;
227 printf("loaded track with %d events\n", trk.num_ev);
232 static long read_vardata(unsigned char **pptr)
236 unsigned char *ptr = *pptr;
239 res |= (long)(*ptr & 0x7f) << (i * 8);
241 /* if first bit is not set we're done */
242 if((*ptr++ & 0x80) == 0)
249 static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr)
251 unsigned char *ptr = *pptr;
256 size = read_vardata(&ptr);
261 trk->name = malloc(size + 1);
262 memcpy(trk->name, ptr, size);
267 /* TODO add a tempo change event to the midi struct */
277 /* ignore sysex events */
278 static int read_sysex_event(struct midi *midi, unsigned char **pptr)
280 long size = read_vardata(pptr);
285 static int ischunk(struct chunk_hdr *chunk, const char *name)
287 return memcmp(chunk->id, name, 4) == 0;
290 static struct chunk_hdr *mkchunk(void *ptr)
292 struct chunk_hdr *chdr = ptr;
293 bigend(&chdr->size, sizeof chdr->size);
297 static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk)
299 return mkchunk((char*)chunk + CHUNK_HDR_SIZE + chunk->size);
302 static struct midi_hdr *mkmidi(void *ptr)
304 struct midi_hdr *midi = ptr;
306 bigend(&midi->fmt, sizeof midi->fmt);
307 bigend(&midi->num_tracks, sizeof midi->num_tracks);
308 bigend(&midi->tm_div, sizeof midi->tm_div);
312 static void bigend(void *ptr, int sz)
314 static unsigned char test[] = {0x12, 0x34};
318 if(sz < 2 || *(uint16_t*)test == 0x1234) {
324 val32 = *(uint32_t*)ptr;
325 *(uint32_t*)ptr = (val32 << 24) | (val32 >> 24) | ((val32 & 0xff00) << 8) |
326 ((val32 & 0xff0000) >> 8);
330 val16 = *(uint16_t*)ptr;
331 *(uint16_t*)ptr = (val16 >> 8) | (val16 << 8);
340 #if defined(__unix__) && defined(USE_MMAP)
343 #include <sys/mman.h>
344 #include <sys/stat.h>
346 static void *map_file(const char *fname, int *size)
352 if((fd = open(fname, O_RDONLY)) == -1) {
353 fprintf(stderr, "failed to open midi file: %s: %s\n", fname, strerror(errno));
358 if((mem = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) == (void*)-1) {
359 fprintf(stderr, "failed to map midi file: %s: %s\n", fname, strerror(errno));
369 static void unmap_file(void *mem, int size)
374 static void *map_file(const char *fname, int *size)
380 if(!(fp = fopen(fname, "rb"))) {
381 fprintf(stderr, "failed to open midi file: %s: %s\n", fname, strerror(errno));
384 fseek(fp, 0, SEEK_END);
388 if(!(buf = malloc(sz))) {
389 fprintf(stderr, "failed to allocate space for %s in memory (%ld bytes)\n", fname, sz);
393 if(fread(buf, 1, sz, fp) != sz) {
394 fprintf(stderr, "failed to load midi file: %s: %s\n", fname, strerror(errno));
405 static void unmap_file(void *mem, int size)