Save as dialog, and confirm save dialog.
[cantaveria.git] / midi.c
blobdc68c46e59b967484fbbd269924ff0c08ac9db3c
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 <util.h>
31 #include <loader.h>
32 #include <midi.h>
35 static event* make_event(int tick, int type, int chan, int val1, int val2){
36 event* e = malloc(sizeof(event));
37 e->tick = tick;
38 e->type = type;
39 e->chan = chan;
40 e->val1 = val1;
41 e->val2 = val2;
42 return e;
45 void free_events(list* events){
46 list* ptr = events->next;
48 while(ptr){
49 free(ptr->item);
50 ptr = ptr->next;
54 int value_of_type(int type){
55 switch(type){
56 case 0x80: return -2;
57 case EVX_LOOPSTART: return -1;
58 case EVX_LOOPEND: return 1;
59 case 0x90: return 2;
60 default: return 0;
64 int compare_event(void* v1, void* v2){
65 event* e1 = v1;
66 event* e2 = v2;
67 int d1, d2;
69 if(e1->tick < e2->tick) return 1;
70 if(e1->tick > e2->tick) return -1;
72 d1 = value_of_type(e1->type);
73 d2 = value_of_type(e2->type);
75 return d2 - d1;
78 /* read a midi variable length quantity */
79 /* returns number of bytes read or 0 for error */
80 /* fills in buf with bytes read */
81 int read_deltaenough(reader* r, unsigned char buf[4]){
82 int bytes[4];
83 int i;
85 for(i=0; i<4; i++){
86 if(read_byte(r, &bytes[i])) return 0;
87 if(!(bytes[i] & 0x80)){
88 buf[0] = bytes[0];
89 buf[1] = bytes[1];
90 buf[2] = bytes[2];
91 buf[3] = bytes[3];
92 return i+1;
96 error_msg("midi_load: invalid delta encountered\n");
97 return 0;
100 /* converts midi variable length quantity x int a normal quantity */
101 /* count should be number of bytes of data in x */
102 int conv_delta(unsigned char x[4], int count){
103 switch(count){
104 case 1: return x[0];
105 case 2: return ((x[0] & 0x7f) << 7) | x[1];
106 case 3: return ((x[0] & 0x7f) << 14) | ((x[1] & 0x7f) << 7) | x[2];
107 case 4: return ((x[0] & 0x7f) << 21) | ((x[1] & 0x7f) << 14) | ((x[2] & 0x7f) << 7) | x[3];
108 default: error_msg("conv_delta: wrong count (%d)\n", count); return 0;
112 int conv_divisions(int divraw){
113 if(divraw > 0){
114 return divraw;
116 else{
117 error_msg("midi_load: time division is given in frames per second, expect breakage without further support\n");
118 return abs(divraw>>8);
122 /* read a midi variable length quantity from r */
123 /* 0 for success, -1 for error. out is filled in with quantity */
124 int read_delta(reader* r, int* out){
125 unsigned char buf[4];
126 int count = read_deltaenough(r, buf);
128 if(count == 0){
129 return -1;
131 else{
132 *out = conv_delta(buf, count);
133 return 0;
139 event* meta_endoftrack(reader* r, int tick){
140 int zero;
141 if(read_delta(r, &zero)) return NULL;
142 if(zero != 0){
143 error_msg("midi_load: end of track event not followed by zero\n");
144 return NULL;
146 return make_event(tick, EVX_ENDOFTRACK, 0, 0, 0);
149 event* meta_tempochange(reader* r, int tick){
150 unsigned char bytes[3];
151 int three;
152 int uspqn;
153 int bpm;
155 if(read_delta(r, &three)) return NULL;
156 if(read_bytes(r, bytes, 3)) return NULL;
157 uspqn = (bytes[0] << 16) | (bytes[1] << 8) | bytes[0];
158 bpm = 60000000 / uspqn;
160 return make_event(tick, EVX_TEMPOCHANGE, 0, bpm, 0);
163 event* meta_possibleloop(reader* r, int tick){
164 error_msg("ERR meta_possibleloop not done\n");
165 return NULL;
168 event* meta_dummy(reader* r, int tick){
169 int len;
170 int foo;
172 if(read_delta(r, &len)) return NULL;
174 /* FIXME need a skip routine */
175 for(; len > 0; len--){
176 if(read_byte(r, &foo)) return NULL;
179 return make_event(tick, EVX_META, 0, 0, 0);
182 event* skip_sys(reader* r, int tick){
183 error_msg("ERR skip_sys not done\n");
184 return NULL;
187 event* read_normal(reader* r, int tick, int status){
188 int type = status & 0xf0;
189 int chan = status & 0x0f;
190 int val1;
191 int val2;
193 if(read_byte(r, &val1) || read_byte(r, &val2))
194 return NULL;
195 else
196 return make_event(tick, type, chan, val1, val2);
199 event* read_running(reader* r, int tick, int val1){
200 int val2;
202 if(read_byte(r, &val2))
203 return NULL;
204 else
205 return make_event(tick, -1, -1, val1, val2);
208 event* read_meta(reader* r, int tick){
209 int type;
212 if(read_byte(r, &type))
213 return NULL;
215 switch(type){
216 case 0x2f: return meta_endoftrack(r, tick);
217 case 0x51: return meta_tempochange(r, tick);
218 case 0x01: return meta_possibleloop(r, tick);
219 default: return meta_dummy(r, tick);
224 event* read_event(reader* r, int tick, int byte0){
225 if(byte0 >= 0x80 && byte0 < 0xf0)
226 return read_normal(r, tick, byte0);
227 else if(byte0 < 0x80)
228 return read_running(r, tick, byte0);
229 else if(byte0 == 0xff)
230 return read_meta(r, tick);
231 else
232 return skip_sys(r, tick);
235 int read_track(reader* r, list* events){
236 int tick = 0;
237 int last_type = 0x90;
238 int last_chan = 0;
240 unsigned char sig[4];
241 unsigned chunk_size;
243 if(read_bytes(r, sig, 4) || read_int(r, (int*)&chunk_size)){
244 return -1;
247 if(memcmp(sig, "MTrk", 4) != 0){
248 error_msg("midi_load: MTrk not found\n");
249 return -1;
252 for(;;){
253 int delta;
254 int byte0;
255 if(read_delta(r, &delta) || read_byte(r, &byte0)){
256 return -1;
259 tick += delta;
261 event* e = read_event(r, tick, byte0);
262 if(e == NULL){
263 return -1;
266 append(events, e);
268 if(e->type == -1){ /* running status */
269 e->type = last_type;
270 e->chan = last_chan;
272 else if(e->type == EVX_ENDOFTRACK){ /* end of track */
273 break;
276 if(e->type == 0x90 && e->val2 == 0){
277 e->type = 0x80;
280 if(e->type == 0x80 || e->type == 0x90){
281 e->val1 -= 57;
285 return 0;
288 int read_header(reader* r, int* format, int* track_count, int* divraw){
289 char sig[4];
290 int six;
292 if(read_bytes(r, (unsigned char*)sig, 4)) return -1;
293 if(read_int(r, &six)) return -1;
294 if(read_short(r, format)) return -1;
295 if(read_short(r, track_count)) return -1;
296 if(read_short(r, divraw)) return -1;
298 if(memcmp(sig, "MThd", 4) != 0){
299 error_msg("midi_load: MThd not found\n");
300 return -1;
303 if(six != 6){
304 error_msg("midi_load: number six not found (%d)\n", six);
305 return -1;
308 if(*format != 0 && *format != 1){
309 error_msg("midi_load: format not supported (%d)\n", *format);
310 return -1;
313 return 0;
316 list* midi_load(char* path){
317 reader* r;
318 list* events = empty();
320 int format;
321 int track_count;
322 int divraw;
323 int i;
325 r = loader_open(path);
326 if(r == NULL){
327 return NULL;
330 if(read_header(r, &format, &track_count, &divraw) < 0){
331 error_msg("midi_load: read error in header\n");
332 loader_close(r);
333 recycle(events);
334 return NULL;
337 push(events, make_event(
339 EVX_TICKSPERBEAT,
341 conv_divisions(divraw),
345 for(i=0; i<track_count; i++){
346 if(read_track(r, events) < 0){
347 error_msg("midi_load: read error in track\n");
348 loader_close(r);
349 free_events(events);
350 recycle(events);
351 return NULL;
355 sort(events, compare_event);
356 return events;