Mercurial > audlegacy
comparison Plugins/Input/timidity/libtimidity/readmidi.c @ 285:d1762728ea4b trunk
[svn] Timidity support, via external contractor dai+audacious@cdr.jp.
author | nenolod |
---|---|
date | Wed, 14 Dec 2005 08:51:51 -0800 |
parents | |
children | 0235eaed75fe |
comparison
equal
deleted
inserted
replaced
284:763afa52f416 | 285:d1762728ea4b |
---|---|
1 /* | |
2 | |
3 TiMidity -- Experimental MIDI to WAVE converter | |
4 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi> | |
5 | |
6 This program is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program; if not, write to the Free Software | |
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | |
20 */ | |
21 | |
22 #if HAVE_CONFIG_H | |
23 # include <config.h> | |
24 #endif | |
25 | |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 #include <string.h> | |
29 | |
30 #include "timidity.h" | |
31 #include "timidity_internal.h" | |
32 #include "options.h" | |
33 #include "common.h" | |
34 #include "instrum.h" | |
35 #include "playmidi.h" | |
36 | |
37 /* Computes how many (fractional) samples one MIDI delta-time unit contains */ | |
38 static void compute_sample_increment(MidSong *song, sint32 tempo, | |
39 sint32 divisions) | |
40 { | |
41 double a; | |
42 a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) / | |
43 (double)(divisions); | |
44 | |
45 song->sample_correction = (sint32)(a) & 0xFFFF; | |
46 song->sample_increment = (sint32)(a) >> 16; | |
47 | |
48 DEBUG_MSG("Samples per delta-t: %d (correction %d)\n", | |
49 song->sample_increment, song->sample_correction); | |
50 } | |
51 | |
52 /* Read variable-length number (7 bits per byte, MSB first) */ | |
53 static sint32 getvl(MidIStream *stream) | |
54 { | |
55 sint32 l=0; | |
56 uint8 c; | |
57 for (;;) | |
58 { | |
59 mid_istream_read(stream, &c, 1, 1); | |
60 l += (c & 0x7f); | |
61 if (!(c & 0x80)) return l; | |
62 l<<=7; | |
63 } | |
64 } | |
65 | |
66 /* Print a string from the file, followed by a newline. Any non-ASCII | |
67 or unprintable characters will be converted to periods. */ | |
68 static int read_meta_data(MidIStream *stream, sint32 len, uint8 type, MidSong *song) | |
69 { | |
70 char *s=safe_malloc(len+1); | |
71 MidSongMetaId id; | |
72 static char *label[] = { | |
73 "Text event: ", "Text: ", "Copyright: ", "Track name: ", | |
74 "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "}; | |
75 | |
76 if (len != (sint32) mid_istream_read(stream, s, 1, len)) | |
77 { | |
78 free(s); | |
79 return -1; | |
80 } | |
81 s[len]='\0'; | |
82 while (len--) | |
83 { | |
84 if (((unsigned char)s[len])<32) | |
85 s[len]='.'; | |
86 } | |
87 DEBUG_MSG("%s%s\n", label[(type > 7) ? 0 : type], s); | |
88 | |
89 switch (type) | |
90 { | |
91 case 1: id = MID_SONG_TEXT; break; | |
92 case 2: id = MID_SONG_COPYRIGHT; break; | |
93 default: free(s); s = NULL; | |
94 } | |
95 if (s) | |
96 { | |
97 if (song->meta_data[id]) | |
98 free(song->meta_data[id]); | |
99 song->meta_data[id] = s; | |
100 } | |
101 | |
102 return 0; | |
103 } | |
104 | |
105 #define MIDIEVENT(at,t,ch,pa,pb) \ | |
106 new=safe_malloc(sizeof(MidEventList)); \ | |
107 new->event.time=at; new->event.type=t; new->event.channel=ch; \ | |
108 new->event.a=pa; new->event.b=pb; new->next=0;\ | |
109 return new; | |
110 | |
111 #define MAGIC_EOT ((MidEventList *)(-1)) | |
112 | |
113 /* Read a MIDI event, returning a freshly allocated element that can | |
114 be linked to the event list */ | |
115 static MidEventList *read_midi_event(MidIStream *stream, MidSong *song) | |
116 { | |
117 static uint8 laststatus, lastchan; | |
118 static uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */ | |
119 uint8 me, type, a,b,c; | |
120 sint32 len; | |
121 MidEventList *new; | |
122 | |
123 for (;;) | |
124 { | |
125 song->at += getvl(stream); | |
126 if (mid_istream_read(stream, &me, 1, 1) != 1) | |
127 { | |
128 DEBUG_MSG("read_midi_event: mid_istream_read() failure\n"); | |
129 return 0; | |
130 } | |
131 | |
132 if(me==0xF0 || me == 0xF7) /* SysEx event */ | |
133 { | |
134 len=getvl(stream); | |
135 mid_istream_skip(stream, len); | |
136 } | |
137 else if(me==0xFF) /* Meta event */ | |
138 { | |
139 mid_istream_read(stream, &type, 1, 1); | |
140 len=getvl(stream); | |
141 if (type>0 && type<16) | |
142 { | |
143 read_meta_data(stream, len, type, song); | |
144 } | |
145 else | |
146 switch(type) | |
147 { | |
148 case 0x2F: /* End of Track */ | |
149 return MAGIC_EOT; | |
150 | |
151 case 0x51: /* Tempo */ | |
152 mid_istream_read(stream, &a, 1, 1); | |
153 mid_istream_read(stream, &b, 1, 1); | |
154 mid_istream_read(stream, &c, 1, 1); | |
155 MIDIEVENT(song->at, ME_TEMPO, c, a, b); | |
156 | |
157 default: | |
158 DEBUG_MSG("(Meta event type 0x%02x, length %d)\n", type, len); | |
159 mid_istream_skip(stream, len); | |
160 break; | |
161 } | |
162 } | |
163 else | |
164 { | |
165 a=me; | |
166 if (a & 0x80) /* status byte */ | |
167 { | |
168 lastchan=a & 0x0F; | |
169 laststatus=(a>>4) & 0x07; | |
170 mid_istream_read(stream, &a, 1, 1); | |
171 a &= 0x7F; | |
172 } | |
173 switch(laststatus) | |
174 { | |
175 case 0: /* Note off */ | |
176 mid_istream_read(stream, &b, 1, 1); | |
177 b &= 0x7F; | |
178 MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b); | |
179 | |
180 case 1: /* Note on */ | |
181 mid_istream_read(stream, &b, 1, 1); | |
182 b &= 0x7F; | |
183 MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b); | |
184 | |
185 case 2: /* Key Pressure */ | |
186 mid_istream_read(stream, &b, 1, 1); | |
187 b &= 0x7F; | |
188 MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b); | |
189 | |
190 case 3: /* Control change */ | |
191 mid_istream_read(stream, &b, 1, 1); | |
192 b &= 0x7F; | |
193 { | |
194 int control=255; | |
195 switch(a) | |
196 { | |
197 case 7: control=ME_MAINVOLUME; break; | |
198 case 10: control=ME_PAN; break; | |
199 case 11: control=ME_EXPRESSION; break; | |
200 case 64: control=ME_SUSTAIN; break; | |
201 case 120: control=ME_ALL_SOUNDS_OFF; break; | |
202 case 121: control=ME_RESET_CONTROLLERS; break; | |
203 case 123: control=ME_ALL_NOTES_OFF; break; | |
204 | |
205 /* These should be the SCC-1 tone bank switch | |
206 commands. I don't know why there are two, or | |
207 why the latter only allows switching to bank 0. | |
208 Also, some MIDI files use 0 as some sort of | |
209 continuous controller. This will cause lots of | |
210 warnings about undefined tone banks. */ | |
211 case 0: control=ME_TONE_BANK; break; | |
212 case 32: | |
213 if (b!=0) | |
214 DEBUG_MSG("(Strange: tone bank change 0x20%02x)\n", b); | |
215 else | |
216 control=ME_TONE_BANK; | |
217 break; | |
218 | |
219 case 100: nrpn=0; rpn_msb[lastchan]=b; break; | |
220 case 101: nrpn=0; rpn_lsb[lastchan]=b; break; | |
221 case 99: nrpn=1; rpn_msb[lastchan]=b; break; | |
222 case 98: nrpn=1; rpn_lsb[lastchan]=b; break; | |
223 | |
224 case 6: | |
225 if (nrpn) | |
226 { | |
227 DEBUG_MSG("(Data entry (MSB) for NRPN %02x,%02x: %d)\n", | |
228 rpn_msb[lastchan], rpn_lsb[lastchan], b); | |
229 break; | |
230 } | |
231 | |
232 switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan]) | |
233 { | |
234 case 0x0000: /* Pitch bend sensitivity */ | |
235 control=ME_PITCH_SENS; | |
236 break; | |
237 | |
238 case 0x7F7F: /* RPN reset */ | |
239 /* reset pitch bend sensitivity to 2 */ | |
240 MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0); | |
241 | |
242 default: | |
243 DEBUG_MSG("(Data entry (MSB) for RPN %02x,%02x: %d)\n", | |
244 rpn_msb[lastchan], rpn_lsb[lastchan], b); | |
245 break; | |
246 } | |
247 break; | |
248 | |
249 default: | |
250 DEBUG_MSG("(Control %d: %d)\n", a, b); | |
251 break; | |
252 } | |
253 if (control != 255) | |
254 { | |
255 MIDIEVENT(song->at, control, lastchan, b, 0); | |
256 } | |
257 } | |
258 break; | |
259 | |
260 case 4: /* Program change */ | |
261 a &= 0x7f; | |
262 MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0); | |
263 | |
264 case 5: /* Channel pressure - NOT IMPLEMENTED */ | |
265 break; | |
266 | |
267 case 6: /* Pitch wheel */ | |
268 mid_istream_read(stream, &b, 1, 1); | |
269 b &= 0x7F; | |
270 MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b); | |
271 | |
272 default: | |
273 DEBUG_MSG("*** Can't happen: status 0x%02X, channel 0x%02X\n", | |
274 laststatus, lastchan); | |
275 break; | |
276 } | |
277 } | |
278 } | |
279 | |
280 return new; | |
281 } | |
282 | |
283 #undef MIDIEVENT | |
284 | |
285 /* Read a midi track into the linked list, either merging with any previous | |
286 tracks or appending to them. */ | |
287 static int read_track(MidIStream *stream, MidSong *song, int append) | |
288 { | |
289 MidEventList *meep; | |
290 MidEventList *next, *new; | |
291 sint32 len; | |
292 char tmp[4]; | |
293 | |
294 meep = song->evlist; | |
295 if (append && meep) | |
296 { | |
297 /* find the last event in the list */ | |
298 for (; meep->next; meep=meep->next) | |
299 ; | |
300 song->at = meep->event.time; | |
301 } | |
302 else | |
303 song->at=0; | |
304 | |
305 /* Check the formalities */ | |
306 | |
307 if (mid_istream_read(stream, tmp, 1, 4) != 4 || mid_istream_read(stream, &len, 4, 1) != 1) | |
308 { | |
309 DEBUG_MSG("Can't read track header.\n"); | |
310 return -1; | |
311 } | |
312 len=SWAPBE32(len); | |
313 if (memcmp(tmp, "MTrk", 4)) | |
314 { | |
315 DEBUG_MSG("Corrupt MIDI file.\n"); | |
316 return -2; | |
317 } | |
318 | |
319 for (;;) | |
320 { | |
321 if (!(new=read_midi_event(stream, song))) /* Some kind of error */ | |
322 return -2; | |
323 | |
324 if (new==MAGIC_EOT) /* End-of-track Hack. */ | |
325 { | |
326 return 0; | |
327 } | |
328 | |
329 next=meep->next; | |
330 while (next && (next->event.time < new->event.time)) | |
331 { | |
332 meep=next; | |
333 next=meep->next; | |
334 } | |
335 | |
336 new->next=next; | |
337 meep->next=new; | |
338 | |
339 song->event_count++; /* Count the event. (About one?) */ | |
340 meep=new; | |
341 } | |
342 } | |
343 | |
344 /* Free the linked event list from memory. */ | |
345 static void free_midi_list(MidSong *song) | |
346 { | |
347 MidEventList *meep, *next; | |
348 if (!(meep = song->evlist)) return; | |
349 while (meep) | |
350 { | |
351 next=meep->next; | |
352 free(meep); | |
353 meep=next; | |
354 } | |
355 song->evlist=0; | |
356 } | |
357 | |
358 /* Allocate an array of MidiEvents and fill it from the linked list of | |
359 events, marking used instruments for loading. Convert event times to | |
360 samples: handle tempo changes. Strip unnecessary events from the list. | |
361 Free the linked list. */ | |
362 static MidEvent *groom_list(MidSong *song, sint32 divisions,sint32 *eventsp, | |
363 sint32 *samplesp) | |
364 { | |
365 MidEvent *groomed_list, *lp; | |
366 MidEventList *meep; | |
367 sint32 i, our_event_count, tempo, skip_this_event, new_value; | |
368 sint32 sample_cum, samples_to_do, at, st, dt, counting_time; | |
369 | |
370 int current_bank[16], current_set[16], current_program[16]; | |
371 /* Or should each bank have its own current program? */ | |
372 | |
373 for (i=0; i<16; i++) | |
374 { | |
375 current_bank[i]=0; | |
376 current_set[i]=0; | |
377 current_program[i]=song->default_program; | |
378 } | |
379 | |
380 tempo=500000; | |
381 compute_sample_increment(song, tempo, divisions); | |
382 | |
383 /* This may allocate a bit more than we need */ | |
384 groomed_list=lp=safe_malloc(sizeof(MidEvent) * (song->event_count+1)); | |
385 meep=song->evlist; | |
386 | |
387 our_event_count=0; | |
388 st=at=sample_cum=0; | |
389 counting_time=2; /* We strip any silence before the first NOTE ON. */ | |
390 | |
391 for (i = 0; i < song->event_count; i++) | |
392 { | |
393 skip_this_event=0; | |
394 | |
395 if (meep->event.type==ME_TEMPO) | |
396 { | |
397 tempo= | |
398 meep->event.channel + meep->event.b * 256 + meep->event.a * 65536; | |
399 compute_sample_increment(song, tempo, divisions); | |
400 skip_this_event=1; | |
401 } | |
402 else switch (meep->event.type) | |
403 { | |
404 case ME_PROGRAM: | |
405 if (ISDRUMCHANNEL(song, meep->event.channel)) | |
406 { | |
407 if (song->drumset[meep->event.a]) /* Is this a defined drumset? */ | |
408 new_value=meep->event.a; | |
409 else | |
410 { | |
411 DEBUG_MSG("Drum set %d is undefined\n", meep->event.a); | |
412 new_value=meep->event.a=0; | |
413 } | |
414 if (current_set[meep->event.channel] != new_value) | |
415 current_set[meep->event.channel]=new_value; | |
416 else | |
417 skip_this_event=1; | |
418 } | |
419 else | |
420 { | |
421 new_value=meep->event.a; | |
422 if ((current_program[meep->event.channel] != SPECIAL_PROGRAM) | |
423 && (current_program[meep->event.channel] != new_value)) | |
424 current_program[meep->event.channel] = new_value; | |
425 else | |
426 skip_this_event=1; | |
427 } | |
428 break; | |
429 | |
430 case ME_NOTEON: | |
431 if (counting_time) | |
432 counting_time=1; | |
433 if (ISDRUMCHANNEL(song, meep->event.channel)) | |
434 { | |
435 /* Mark this instrument to be loaded */ | |
436 if (!(song->drumset[current_set[meep->event.channel]] | |
437 ->instrument[meep->event.a])) | |
438 song->drumset[current_set[meep->event.channel]] | |
439 ->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT; | |
440 } | |
441 else | |
442 { | |
443 if (current_program[meep->event.channel]==SPECIAL_PROGRAM) | |
444 break; | |
445 /* Mark this instrument to be loaded */ | |
446 if (!(song->tonebank[current_bank[meep->event.channel]] | |
447 ->instrument[current_program[meep->event.channel]])) | |
448 song->tonebank[current_bank[meep->event.channel]] | |
449 ->instrument[current_program[meep->event.channel]] = | |
450 MAGIC_LOAD_INSTRUMENT; | |
451 } | |
452 break; | |
453 | |
454 case ME_TONE_BANK: | |
455 if (ISDRUMCHANNEL(song, meep->event.channel)) | |
456 { | |
457 skip_this_event=1; | |
458 break; | |
459 } | |
460 if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */ | |
461 new_value=meep->event.a; | |
462 else | |
463 { | |
464 DEBUG_MSG("Tone bank %d is undefined\n", meep->event.a); | |
465 new_value=meep->event.a=0; | |
466 } | |
467 if (current_bank[meep->event.channel]!=new_value) | |
468 current_bank[meep->event.channel]=new_value; | |
469 else | |
470 skip_this_event=1; | |
471 break; | |
472 } | |
473 | |
474 /* Recompute time in samples*/ | |
475 if ((dt=meep->event.time - at) && !counting_time) | |
476 { | |
477 samples_to_do = song->sample_increment * dt; | |
478 sample_cum += song->sample_correction * dt; | |
479 if (sample_cum & 0xFFFF0000) | |
480 { | |
481 samples_to_do += ((sample_cum >> 16) & 0xFFFF); | |
482 sample_cum &= 0x0000FFFF; | |
483 } | |
484 st += samples_to_do; | |
485 } | |
486 else if (counting_time==1) counting_time=0; | |
487 if (!skip_this_event) | |
488 { | |
489 /* Add the event to the list */ | |
490 *lp=meep->event; | |
491 lp->time=st; | |
492 lp++; | |
493 our_event_count++; | |
494 } | |
495 at=meep->event.time; | |
496 meep=meep->next; | |
497 } | |
498 /* Add an End-of-Track event */ | |
499 lp->time=st; | |
500 lp->type=ME_EOT; | |
501 our_event_count++; | |
502 free_midi_list(song); | |
503 | |
504 *eventsp=our_event_count; | |
505 *samplesp=st; | |
506 return groomed_list; | |
507 } | |
508 | |
509 MidEvent *read_midi_file(MidIStream *stream, MidSong *song, sint32 *count, sint32 *sp) | |
510 { | |
511 sint32 len, divisions; | |
512 sint16 format, tracks, divisions_tmp; | |
513 int i; | |
514 char tmp[4]; | |
515 | |
516 song->event_count=0; | |
517 song->at=0; | |
518 song->evlist=0; | |
519 | |
520 if (mid_istream_read(stream, tmp, 1, 4) != 4 || mid_istream_read(stream, &len, 4, 1) != 1) | |
521 { | |
522 DEBUG_MSG("Not a MIDI file!\n"); | |
523 return 0; | |
524 } | |
525 len=SWAPBE32(len); | |
526 if (memcmp(tmp, "MThd", 4) || len < 6) | |
527 { | |
528 DEBUG_MSG("Not a MIDI file!\n"); | |
529 return 0; | |
530 } | |
531 | |
532 mid_istream_read(stream, &format, 2, 1); | |
533 mid_istream_read(stream, &tracks, 2, 1); | |
534 mid_istream_read(stream, &divisions_tmp, 2, 1); | |
535 format=SWAPBE16(format); | |
536 tracks=SWAPBE16(tracks); | |
537 divisions_tmp=SWAPBE16(divisions_tmp); | |
538 | |
539 if (divisions_tmp<0) | |
540 { | |
541 /* SMPTE time -- totally untested. Got a MIDI file that uses this? */ | |
542 divisions= | |
543 (sint32)(-(divisions_tmp/256)) * (sint32)(divisions_tmp & 0xFF); | |
544 } | |
545 else divisions=(sint32)(divisions_tmp); | |
546 | |
547 if (len > 6) | |
548 { | |
549 DEBUG_MSG("MIDI file header size %u bytes", len); | |
550 mid_istream_skip(stream, len-6); /* skip the excess */ | |
551 } | |
552 if (format<0 || format >2) | |
553 { | |
554 DEBUG_MSG("Unknown MIDI file format %d\n", format); | |
555 return 0; | |
556 } | |
557 DEBUG_MSG("Format: %d Tracks: %d Divisions: %d\n", | |
558 format, tracks, divisions); | |
559 | |
560 /* Put a do-nothing event first in the list for easier processing */ | |
561 song->evlist=safe_malloc(sizeof(MidEventList)); | |
562 song->evlist->event.time=0; | |
563 song->evlist->event.type=ME_NONE; | |
564 song->evlist->next=0; | |
565 song->event_count++; | |
566 | |
567 switch(format) | |
568 { | |
569 case 0: | |
570 if (read_track(stream, song, 0)) | |
571 { | |
572 free_midi_list(song); | |
573 return 0; | |
574 } | |
575 break; | |
576 | |
577 case 1: | |
578 for (i=0; i<tracks; i++) | |
579 if (read_track(stream, song, 0)) | |
580 { | |
581 free_midi_list(song); | |
582 return 0; | |
583 } | |
584 break; | |
585 | |
586 case 2: /* We simply play the tracks sequentially */ | |
587 for (i=0; i<tracks; i++) | |
588 if (read_track(stream, song, 1)) | |
589 { | |
590 free_midi_list(song); | |
591 return 0; | |
592 } | |
593 break; | |
594 } | |
595 return groom_list(song, divisions, count, sp); | |
596 } |