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
35 static event
* make_event(int tick
, int type
, int chan
, int val1
, int val2
){
36 event
* e
= malloc(sizeof(event
));
45 void free_events(list
* events
){
46 list
* ptr
= events
->next
;
54 int value_of_type(int type
){
57 case EVX_LOOPSTART
: return -1;
58 case EVX_LOOPEND
: return 1;
64 int compare_event(void* v1
, void* v2
){
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
);
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]){
86 if(read_byte(r
, &bytes
[i
])) return 0;
87 if(!(bytes
[i
] & 0x80)){
96 error_msg("midi_load: invalid delta encountered\n");
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
){
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
){
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
);
132 *out
= conv_delta(buf
, count
);
139 event
* meta_endoftrack(reader
* r
, int tick
){
141 if(read_delta(r
, &zero
)) return NULL
;
143 error_msg("midi_load: end of track event not followed by zero\n");
146 return make_event(tick
, EVX_ENDOFTRACK
, 0, 0, 0);
149 event
* meta_tempochange(reader
* r
, int tick
){
150 unsigned char bytes
[3];
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");
168 event
* meta_dummy(reader
* r
, int tick
){
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");
187 event
* read_normal(reader
* r
, int tick
, int status
){
188 int type
= status
& 0xf0;
189 int chan
= status
& 0x0f;
193 if(read_byte(r
, &val1
) || read_byte(r
, &val2
))
196 return make_event(tick
, type
, chan
, val1
, val2
);
199 event
* read_running(reader
* r
, int tick
, int val1
){
202 if(read_byte(r
, &val2
))
205 return make_event(tick
, -1, -1, val1
, val2
);
208 event
* read_meta(reader
* r
, int tick
){
212 if(read_byte(r
, &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
);
232 return skip_sys(r
, tick
);
235 int read_track(reader
* r
, list
* events
){
237 int last_type
= 0x90;
240 unsigned char sig
[4];
243 if(read_bytes(r
, sig
, 4) || read_int(r
, (int*)&chunk_size
)){
247 if(memcmp(sig
, "MTrk", 4) != 0){
248 error_msg("midi_load: MTrk not found\n");
255 if(read_delta(r
, &delta
) || read_byte(r
, &byte0
)){
261 event
* e
= read_event(r
, tick
, byte0
);
268 if(e
->type
== -1){ /* running status */
272 else if(e
->type
== EVX_ENDOFTRACK
){ /* end of track */
276 if(e
->type
== 0x90 && e
->val2
== 0){
280 if(e
->type
== 0x80 || e
->type
== 0x90){
288 int read_header(reader
* r
, int* format
, int* track_count
, int* divraw
){
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");
304 error_msg("midi_load: number six not found (%d)\n", six
);
308 if(*format
!= 0 && *format
!= 1){
309 error_msg("midi_load: format not supported (%d)\n", *format
);
316 list
* midi_load(char* path
){
318 list
* events
= empty();
325 r
= loader_open(path
);
330 if(read_header(r
, &format
, &track_count
, &divraw
) < 0){
331 error_msg("midi_load: read error in header\n");
337 push(events
, make_event(
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");
355 sort(events
, compare_event
);