199
|
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 }
|