10 #include <arpa/inet.h>
14 #define FMT_MULTI_TRACK 1
15 #define FMT_MULTI_SEQ 2
20 #define META_COPYRIGHT 2
26 #define META_CHANPREFIX 32
27 #define META_END_TRACK 47
29 #define META_SMPTE_OFFS 84
31 #define META_KEYSIG 89
32 #define META_SPECIFIC 127
38 struct midi_track *tracks;
43 struct midi_event *head, *tail;
53 struct midi_event *next;
56 #define CHUNK_HDR_SIZE 8
60 unsigned char data[1];
64 uint16_t fmt; /* 0: single, 1: multi-track, 2: multiple independent */
68 } __attribute__ ((packed));
70 static void destroy_track(struct midi_track *trk);
71 static int read_track(struct midi *midi, struct chunk_hdr *chunk);
72 static long read_vardata(unsigned char **pptr);
73 static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr);
74 static int read_sysex_event(struct midi *midi, unsigned char **pptr);
75 static int ischunk(struct chunk_hdr *chunk, const char *name);
76 static struct chunk_hdr *mkchunk(void *ptr);
77 static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk);
78 static struct midi_hdr *mkmidi(void *ptr);
79 static void bigend(void *ptr, int sz);
80 static void *map_file(const char *fname, int *size);
81 static void unmap_file(void *mem, int size);
83 #define IS_VALID_EVTYPE(x) ((x) >= MIDI_NOTE_OFF && (x) <= MIDI_PITCH_BEND)
85 /* XXX the event arity table must match the MIDI_* defines in midi.h */
86 static int ev_arity[] = {
87 0, 0, 0, 0, 0, 0, 0, 0,
88 2, /* note off (note, velocity)*/
89 2, /* note on (note, velocity)*/
90 2, /* note aftertouch (note, aftertouch value) */
91 2, /* controller (controller number, value) */
92 1, /* prog change (prog number) */
93 1, /* channel aftertouch (aftertouch value) */
94 2 /* pitch bend (pitch LSB, pitch MSB) */
98 struct midi *load_midi(const char *fname)
103 struct chunk_hdr *chunk;
104 struct midi_hdr *hdr;
106 if(!(mem = map_file(fname, &size))) {
109 chunk = mkchunk(mem);
111 if(!ischunk(chunk, "MThd") || chunk->size != 6) {
112 fprintf(stderr, "invalid or corrupted midi file: %s\n", fname);
115 hdr = mkmidi(chunk->data);
117 printf("format: %d\n", (int)hdr->fmt);
118 printf("tracks: %d\n", (int)hdr->num_tracks);
120 if((hdr->tm_div & 0x8000) == 0) {
121 /* division is in pulses / quarter note */
122 printf("time division: %d ppqn\n", (int)hdr->tm_div);
124 /* division in frames / sec */
125 int fps = (hdr->tm_div & 0x7f00) >> 8;
126 int ticks_per_frame = hdr->tm_div & 0xff;
127 printf("time division: %d fps, %d ticks/frame\n", fps, ticks_per_frame);
130 if(!(midi = malloc(sizeof *midi))) {
131 perror("failed to allocate memory");
134 if(!(midi->tracks = malloc(hdr->num_tracks * sizeof *midi->tracks))) {
135 perror("failed to allocate memory");
138 midi->num_tracks = 0;
140 while((chunk = skip_chunk(chunk)) && ((char*)chunk < mem + size)) {
141 if(ischunk(chunk, "MTrk")) {
142 if(read_track(midi, chunk) == -1) {
143 fprintf(stderr, "failed to read track\n");
146 printf("ignoring chunk: %c%c%c%c\n", chunk->id[0], chunk->id[1], chunk->id[2], chunk->id[3]);
151 unmap_file(mem, size);
159 void free_midi(struct midi *midi)
165 for(i=0; i<midi->num_tracks; i++) {
166 destroy_track(midi->tracks + i);
169 free(midi->tracks); /* TODO free tracks properly */
173 static void destroy_track(struct midi_track *trk)
177 void *tmp = trk->head;
178 trk->head = trk->head->next;
183 static int read_track(struct midi *midi, struct chunk_hdr *chunk)
186 struct midi_track trk = {0, 0, 0, 0};
187 unsigned char prev_stat = 0;
189 if(!ischunk(chunk, "MTrk")) {
194 while(ptr < chunk->data + chunk->size) {
198 /* TODO also convert dt to some standard unit */
199 dt = read_vardata(&ptr);
203 read_meta_event(midi, &trk, &ptr);
204 } else if(stat == 0xf0) {
205 read_sysex_event(midi, &ptr);
207 struct midi_event *ev = malloc(sizeof *ev);
219 /* not a status byte, assume running status */
225 ev->type = (stat >> 4) & 0xf;
226 if(!IS_VALID_EVTYPE(ev->type)) {
227 fprintf(stderr, "warning, skipping track with unknown event %d\n", ev->type);
230 ev->channel = stat & 0xf;
233 if(ev_arity[ev->type] > 1) {
241 /* if we did actually add any events ... */
243 midi->tracks[midi->num_tracks++] = trk;
244 printf("loaded track with %d events\n", trk.num_ev);
249 static long read_vardata(unsigned char **pptr)
253 unsigned char *ptr = *pptr;
256 res |= (long)(*ptr & 0x7f) << (i * 8);
258 /* if first bit is not set we're done */
259 if((*ptr++ & 0x80) == 0)
266 static int read_meta_event(struct midi *midi, struct midi_track *trk, unsigned char **pptr)
268 unsigned char *ptr = *pptr;
273 size = read_vardata(&ptr);
278 trk->name = malloc(size + 1);
279 memcpy(trk->name, ptr, size);
284 /* TODO add a tempo change event to the midi struct */
294 /* ignore sysex events */
295 static int read_sysex_event(struct midi *midi, unsigned char **pptr)
297 long size = read_vardata(pptr);
302 static int ischunk(struct chunk_hdr *chunk, const char *name)
304 return memcmp(chunk->id, name, 4) == 0;
307 static struct chunk_hdr *mkchunk(void *ptr)
309 struct chunk_hdr *chdr = ptr;
310 bigend(&chdr->size, sizeof chdr->size);
314 static struct chunk_hdr *skip_chunk(struct chunk_hdr *chunk)
316 return mkchunk((char*)chunk + CHUNK_HDR_SIZE + chunk->size);
319 static struct midi_hdr *mkmidi(void *ptr)
321 struct midi_hdr *midi = ptr;
323 bigend(&midi->fmt, sizeof midi->fmt);
324 bigend(&midi->num_tracks, sizeof midi->num_tracks);
325 bigend(&midi->tm_div, sizeof midi->tm_div);
329 static void bigend(void *ptr, int sz)
333 *((uint32_t*)ptr) = ntohl(*(uint32_t*)ptr);
337 *(uint16_t*)ptr = ntohs(*(uint16_t*)ptr);
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)