Added midi.c for SMF decoding.
[cantaveria.git] / midi.c
blob82fc5c38cbd052aeee91550129b623a3dd4ba143
1 /*
2 Cantaveria - action adventure platform game
3 Copyright (C) 2009 2010 Evan Rinehart
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to
18 The Free Software Foundation, Inc.
19 51 Franklin Street, Fifth Floor
20 Boston, MA 02110-1301, USA
22 evanrinehart@gmail.com
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include <list.h>
30 #include <loader.h>
31 #include <seq.h>
34 event* make_event(int tick, int type, int chan, int val1, int val2){
35 event* e = malloc(sizeof(event));
36 /* FIXME */
37 return e;
40 int get_delta(reader* f){
41 int a = read_byte(f);
42 if(a<0x80){return a;}
44 int b = read_byte(f);
45 if(b<0x80){return ((a&0x7f)<<7) | b;}
47 int c = read_byte(f);
48 if(c<0x80){return ((a&0x7f)<<14) | ((b&0x7f)<<7) | c;}
50 int d = read_byte(f);
51 return ((a&0x7f)<<21) | ((b&0x7f)<<14) | ((c&0x7f)<<7) | d;
54 list* midi_load(char* filename){
56 int i;
57 reader* f = data_open("music", filename);
58 list* events = empty();
60 char buf[16];
61 char string[64];
63 int uspq;
64 int bpm;
66 /*MThd*/
67 loader_read(f,buf,4);
69 /*0x00000006*/
70 read_int(f);
72 /*format type: 0x0000 0x0001 or 0x0002*/
73 read_short(f);
75 /*number of tracks*/
76 short track_count = read_short(f);
78 /* time division */
79 loader_read(f,buf,2);
80 //code to figure out time division
82 for(i=0; i<track_count; i++){
84 /*MTrk*/
85 loader_read(f,buf,4);
87 /* chunk size */
88 int chunk_size = read_int(f);
89 printf("%d\n",chunk_size);
91 int tick = 0;
92 int end_of_track = 0;
93 int last_type = 0x80;
94 int last_chan = 0;
95 while(1){
96 int delta = get_delta(f);
98 if(delta < 0) return NULL;
99 tick += delta;
101 //type and channel
102 buf[0] = read_byte(f);
104 int type = buf[0] & 0xf0;
105 if(type >= 0x80 && type <= 0xe0){//normal event
106 last_type = type;
107 int chan = buf[0] & 0x0f;
108 last_chan = chan;
109 loader_read(f,buf,2);
110 int val1 = buf[0];
111 int val2 = buf[1];
112 append(events, make_event(tick, type, chan, val1, val2));
114 else if(type < 0x80){//running status
115 int val1 = buf[0];
116 buf[0] = read_byte(f);
117 int val2 = buf[0];
118 append(events, make_event(tick, last_type, last_chan, val1, val2));
120 else if(type == 0xff){//meta event
121 buf[0] = read_byte(f);
122 type = buf[0];
124 int len = get_delta(f);
126 switch(type){
127 case 0x2f: printf("end of track\n");
128 end_of_track = 1;
129 break;
130 case 0x51:printf("tempo change\n"); /*tempo*/
131 loader_read(f,buf,3);
132 uspq = (buf[0]<<16) | (buf[1]<<8) | buf[2];
133 bpm = 120;/*FIXME*/
134 break;
135 case 0x01: printf("text\n");/*text*/
136 if(len >= 64){/*too big, skip ahead*/
137 loader_read(f, NULL, len);
139 else{
140 loader_read(f,string,len);
141 string[len] = '\0';
142 if(strncmp(string,"LoopStart",len)==0){
143 push(events, make_event(tick, 0x100, 0, 1, 0));
145 else if(strncmp(string,"LoopEnd",len)==0){
146 push(events, make_event(tick, 0x100, 0, 0, 0));
149 break;
150 default: /*skip*/
151 loader_read(f,NULL,len);
152 break;
155 else{ //sysex and such...
156 int len = get_delta(f);
157 loader_read(f, NULL, len);
160 if(end_of_track) break;
166 //qsort(s->e, s->len, sizeof(event), event_cmp);
167 //synth_setbpm(bpm);
168 /* FIXME tempo change needs to be an event */
170 return events;