comparison decoders/timidity/readmidi.c @ 199:2d887640d300

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