comparison src/timidity/libtimidity/timidity.c @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/timidity/libtimidity/timidity.c@088092a52fea
children f14d11bf9cbb
comparison
equal deleted inserted replaced
11:cff1d04026ae 12:3da1b8942b8b
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 "audacious/vfs.h"
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "timidity.h"
31 #include "timidity_internal.h"
32
33 #include "options.h"
34 #include "common.h"
35 #include "instrum.h"
36 #include "playmidi.h"
37 #include "readmidi.h"
38 #include "output.h"
39
40 #include "tables.h"
41
42 MidToneBank *master_tonebank[128], *master_drumset[128];
43
44 static char def_instr_name[256] = "";
45
46 #define MAXWORDS 10
47
48 /* Quick-and-dirty fgets() replacement. */
49
50 static char *__fgets(char *s, int size, VFSFile *fp)
51 {
52 int num_read = 0;
53 int newline = 0;
54
55 while (num_read < size && !newline)
56 {
57 if (vfs_fread(&s[num_read], 1, 1, fp) != 1)
58 break;
59
60 /* Unlike fgets(), don't store newline. Under Windows/DOS we'll
61 * probably get an extra blank line for every line that's being
62 * read, but that should be ok.
63 */
64 if (s[num_read] == '\n' || s[num_read] == '\r')
65 {
66 s[num_read] = '\0';
67 newline = 1;
68 }
69
70 num_read++;
71 }
72
73 s[num_read] = '\0';
74
75 return (num_read != 0) ? s : NULL;
76 }
77
78 static int read_config_file(char *name)
79 {
80 VFSFile *fp;
81 char tmp[1024], *w[MAXWORDS], *cp;
82 MidToneBank *bank=0;
83 int i, j, k, line=0, words;
84 static int rcf_count=0;
85
86 if (rcf_count>50)
87 {
88 DEBUG_MSG("Probable source loop in configuration files\n");
89 return (-1);
90 }
91
92 if (!(fp=open_file(name)))
93 return -1;
94
95 while (__fgets(tmp, sizeof(tmp), fp))
96 {
97 line++;
98 w[words=0]=strtok(tmp, " \t\240");
99 if (!w[0]) continue;
100
101 /* Originally the TiMidity++ extensions were prefixed like this */
102 if (strcmp(w[0], "#extension") == 0)
103 words = -1;
104 else if (*w[0] == '#')
105 continue;
106
107 while (w[words] && *w[words] != '#' && (words < MAXWORDS))
108 w[++words]=strtok(0," \t\240");
109
110 /*
111 * TiMidity++ adds a number of extensions to the config file format.
112 * Many of them are completely irrelevant to SDL_sound, but at least
113 * we shouldn't choke on them.
114 *
115 * Unfortunately the documentation for these extensions is often quite
116 * vague, gramatically strange or completely absent.
117 */
118 if (
119 !strcmp(w[0], "comm") /* "comm" program second */
120 || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */
121 || !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */
122 || !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */
123 || !strcmp(w[0], "opt") /* "opt" timidity-options */
124 )
125 {
126 /*
127 * + "comm" sets some kind of comment -- the documentation is too
128 * vague for me to understand at this time.
129 * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data
130 * over a network, rather than from the file system.
131 * + "opt" specifies default options for TiMidity++.
132 *
133 * These are all quite useless for our version of TiMidity, so
134 * they can safely remain no-ops.
135 */
136 } else if (!strcmp(w[0], "timeout")) /* "timeout" program second */
137 {
138 /*
139 * Specifies a timeout value of the program. A number of seconds
140 * before TiMidity kills the note. This may be useful to implement
141 * later, but I don't see any urgent need for it.
142 */
143 DEBUG_MSG("FIXME: Implement \"timeout\" in TiMidity config.\n");
144 } else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */
145 || !strcmp(w[0], "copybank")) /* "copybank" bank */
146 {
147 /*
148 * Copies all the settings of the specified drumset or bank to
149 * the current drumset or bank. May be useful later, but not a
150 * high priority.
151 */
152 DEBUG_MSG("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]);
153 } else if (!strcmp(w[0], "undef")) /* "undef" progno */
154 {
155 /*
156 * Undefines the tone "progno" of the current tone bank (or
157 * drum set?). Not a high priority.
158 */
159 DEBUG_MSG("FIXME: Implement \"undef\" in TiMidity config.\n");
160 } else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
161 {
162 /*
163 * Sets the alternate assign for drum set. Whatever that's
164 * supposed to mean.
165 */
166 DEBUG_MSG("FIXME: Implement \"altassign\" in TiMidity config.\n");
167 } else if (!strcmp(w[0], "soundfont")
168 || !strcmp(w[0], "font"))
169 {
170 /*
171 * I can't find any documentation for these, but I guess they're
172 * an alternative way of loading/unloading instruments.
173 *
174 * "soundfont" sf_file "remove"
175 * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
176 * ["reso=" reso] ["amp=" amp]
177 * "font" "exclude" bank preset keynote
178 * "font" "order" order bank preset keynote
179 */
180 DEBUG_MSG("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]);
181 } else if (!strcmp(w[0], "progbase"))
182 {
183 /*
184 * The documentation for this makes absolutely no sense to me, but
185 * apparently it sets some sort of base offset for tone numbers.
186 * Why anyone would want to do this is beyond me.
187 */
188 DEBUG_MSG("FIXME: Implement \"progbase\" in TiMidity config.\n");
189 } else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
190 {
191 /*
192 * This extension is the one we will need to implement, as it is
193 * used by the "eawpats". Unfortunately I cannot find any
194 * documentation whatsoever for it, but it looks like it's used
195 * for remapping one instrument to another somehow.
196 */
197 DEBUG_MSG("FIXME: Implement \"map\" in TiMidity config.\n");
198 }
199
200 /* Standard TiMidity config */
201
202 else if (!strcmp(w[0], "dir"))
203 {
204 if (words < 2)
205 {
206 DEBUG_MSG("%s: line %d: No directory given\n", name, line);
207 return -2;
208 }
209 for (i=1; i<words; i++)
210 add_to_pathlist(w[i]);
211 }
212 else if (!strcmp(w[0], "source"))
213 {
214 if (words < 2)
215 {
216 DEBUG_MSG("%s: line %d: No file name given\n", name, line);
217 return -2;
218 }
219 for (i=1; i<words; i++)
220 {
221 rcf_count++;
222 read_config_file(w[i]);
223 rcf_count--;
224 }
225 }
226 else if (!strcmp(w[0], "default"))
227 {
228 if (words != 2)
229 {
230 DEBUG_MSG("%s: line %d: Must specify exactly one patch name\n",
231 name, line);
232 return -2;
233 }
234 strncpy(def_instr_name, w[1], 255);
235 def_instr_name[255]='\0';
236 }
237 else if (!strcmp(w[0], "drumset"))
238 {
239 if (words < 2)
240 {
241 DEBUG_MSG("%s: line %d: No drum set number given\n", name, line);
242 return -2;
243 }
244 i=atoi(w[1]);
245 if (i<0 || i>127)
246 {
247 DEBUG_MSG("%s: line %d: Drum set must be between 0 and 127\n",
248 name, line);
249 return -2;
250 }
251 if (!master_drumset[i])
252 {
253 master_drumset[i] = safe_malloc(sizeof(MidToneBank));
254 memset(master_drumset[i], 0, sizeof(MidToneBank));
255 master_drumset[i]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
256 memset(master_drumset[i]->tone, 0, 128 * sizeof(MidToneBankElement));
257 }
258 bank=master_drumset[i];
259 }
260 else if (!strcmp(w[0], "bank"))
261 {
262 if (words < 2)
263 {
264 DEBUG_MSG("%s: line %d: No bank number given\n", name, line);
265 return -2;
266 }
267 i=atoi(w[1]);
268 if (i<0 || i>127)
269 {
270 DEBUG_MSG("%s: line %d: Tone bank must be between 0 and 127\n",
271 name, line);
272 return -2;
273 }
274 if (!master_tonebank[i])
275 {
276 master_tonebank[i] = safe_malloc(sizeof(MidToneBank));
277 memset(master_tonebank[i], 0, sizeof(MidToneBank));
278 master_tonebank[i]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
279 memset(master_tonebank[i]->tone, 0, 128 * sizeof(MidToneBankElement));
280 }
281 bank=master_tonebank[i];
282 }
283 else
284 {
285 if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
286 {
287 DEBUG_MSG("%s: line %d: syntax error\n", name, line);
288 return -2;
289 }
290 i=atoi(w[0]);
291 if (i<0 || i>127)
292 {
293 DEBUG_MSG("%s: line %d: Program must be between 0 and 127\n",
294 name, line);
295 return -2;
296 }
297 if (!bank)
298 {
299 DEBUG_MSG("%s: line %d: Must specify tone bank or drum set before assignment\n",
300 name, line);
301 return -2;
302 }
303 if (bank->tone[i].name)
304 free(bank->tone[i].name);
305 strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
306 bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
307 bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
308 bank->tone[i].strip_tail=-1;
309
310 for (j=2; j<words; j++)
311 {
312 if (!(cp=strchr(w[j], '=')))
313 {
314 DEBUG_MSG("%s: line %d: bad patch option %s\n", name, line, w[j]);
315 return -2;
316 }
317 *cp++=0;
318 if (!strcmp(w[j], "amp"))
319 {
320 k=atoi(cp);
321 if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
322 {
323 DEBUG_MSG("%s: line %d: amplification must be between 0 and %d\n",
324 name, line, MAX_AMPLIFICATION);
325 return -2;
326 }
327 bank->tone[i].amp=k;
328 }
329 else if (!strcmp(w[j], "note"))
330 {
331 k=atoi(cp);
332 if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
333 {
334 DEBUG_MSG("%s: line %d: note must be between 0 and 127\n",
335 name, line);
336 return -2;
337 }
338 bank->tone[i].note=k;
339 }
340 else if (!strcmp(w[j], "pan"))
341 {
342 if (!strcmp(cp, "center"))
343 k=64;
344 else if (!strcmp(cp, "left"))
345 k=0;
346 else if (!strcmp(cp, "right"))
347 k=127;
348 else
349 k=((atoi(cp)+100) * 100) / 157;
350 if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
351 {
352 DEBUG_MSG("%s: line %d: panning must be left, right, center, or between -100 and 100\n",
353 name, line);
354 return -2;
355 }
356 bank->tone[i].pan=k;
357 }
358 else if (!strcmp(w[j], "keep"))
359 {
360 if (!strcmp(cp, "env"))
361 bank->tone[i].strip_envelope=0;
362 else if (!strcmp(cp, "loop"))
363 bank->tone[i].strip_loop=0;
364 else
365 {
366 DEBUG_MSG("%s: line %d: keep must be env or loop\n", name, line);
367 return -2;
368 }
369 }
370 else if (!strcmp(w[j], "strip"))
371 {
372 if (!strcmp(cp, "env"))
373 bank->tone[i].strip_envelope=1;
374 else if (!strcmp(cp, "loop"))
375 bank->tone[i].strip_loop=1;
376 else if (!strcmp(cp, "tail"))
377 bank->tone[i].strip_tail=1;
378 else
379 {
380 DEBUG_MSG("%s: line %d: strip must be env, loop, or tail\n",
381 name, line);
382 return -2;
383 }
384 }
385 else
386 {
387 DEBUG_MSG("%s: line %d: bad patch option %s\n", name, line, w[j]);
388 return -2;
389 }
390 }
391 }
392 }
393 vfs_fclose(fp);
394 return 0;
395 }
396
397 int mid_init_no_config()
398 {
399 /* Allocate memory for the standard tonebank and drumset */
400 master_tonebank[0] = safe_malloc(sizeof(MidToneBank));
401 memset(master_tonebank[0], 0, sizeof(MidToneBank));
402 master_tonebank[0]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
403 memset(master_tonebank[0]->tone, 0, 128 * sizeof(MidToneBankElement));
404
405 master_drumset[0] = safe_malloc(sizeof(MidToneBank));
406 memset(master_drumset[0], 0, sizeof(MidToneBank));
407 master_drumset[0]->tone = safe_malloc(128 * sizeof(MidToneBankElement));
408 memset(master_drumset[0]->tone, 0, 128 * sizeof(MidToneBankElement));
409
410 return 0;
411 }
412
413 int mid_init(char *config_file)
414 {
415 /* !!! FIXME: This may be ugly, but slightly less so than requiring the
416 * default search path to have only one element. I think.
417 *
418 * We only need to include the likely locations for the config
419 * file itself since that file should contain any other directory
420 * that needs to be added to the search path.
421 */
422 #ifdef WIN32
423 add_to_pathlist("\\TIMIDITY");
424 #else
425 add_to_pathlist("/usr/local/lib/timidity");
426 add_to_pathlist("/etc");
427 #endif
428
429 mid_init_no_config();
430
431 if (config_file == NULL || *config_file == '\0')
432 config_file = CONFIG_FILE;
433
434 return read_config_file(config_file);
435 }
436
437 MidSong *mid_song_load_dls(MidIStream *stream, MidDLSPatches *patches, MidSongOptions *options)
438 {
439 MidSong *song;
440 int i;
441
442 if (stream == NULL)
443 return NULL;
444
445 /* Allocate memory for the song */
446 song = (MidSong *)safe_malloc(sizeof(*song));
447 memset(song, 0, sizeof(*song));
448 song->patches = patches;
449
450 for (i = 0; i < 128; i++)
451 {
452 if (master_tonebank[i])
453 {
454 song->tonebank[i] = safe_malloc(sizeof(MidToneBank));
455 memset(song->tonebank[i], 0, sizeof(MidToneBank));
456 song->tonebank[i]->tone = master_tonebank[i]->tone;
457 }
458 if (master_drumset[i])
459 {
460 song->drumset[i] = safe_malloc(sizeof(MidToneBank));
461 memset(song->drumset[i], 0, sizeof(MidToneBank));
462 song->drumset[i]->tone = master_drumset[i]->tone;
463 }
464 }
465
466 song->amplification = DEFAULT_AMPLIFICATION;
467 song->voices = DEFAULT_VOICES;
468 song->drumchannels = DEFAULT_DRUMCHANNELS;
469
470 song->rate = options->rate;
471 song->encoding = 0;
472 if ((options->format & 0xFF) == 16)
473 song->encoding |= PE_16BIT;
474 if (options->format & 0x8000)
475 song->encoding |= PE_SIGNED;
476 if (options->channels == 1)
477 song->encoding |= PE_MONO;
478 switch (options->format) {
479 case MID_AUDIO_S8:
480 song->write = s32tos8;
481 break;
482 case MID_AUDIO_U8:
483 song->write = s32tou8;
484 break;
485 case MID_AUDIO_S16LSB:
486 song->write = s32tos16l;
487 break;
488 case MID_AUDIO_S16MSB:
489 song->write = s32tos16b;
490 break;
491 case MID_AUDIO_U16LSB:
492 song->write = s32tou16l;
493 break;
494 default:
495 DEBUG_MSG("Unsupported audio format\n");
496 song->write = s32tou16l;
497 break;
498 }
499
500 song->buffer_size = options->buffer_size;
501 song->resample_buffer = safe_malloc(options->buffer_size * sizeof(sample_t));
502 song->common_buffer = safe_malloc(options->buffer_size * 2 * sizeof(sint32));
503
504 song->bytes_per_sample =
505 ((song->encoding & PE_MONO) ? 1 : 2)
506 * ((song->encoding & PE_16BIT) ? 2 : 1);
507
508 song->control_ratio = options->rate / CONTROLS_PER_SECOND;
509 if (song->control_ratio < 1)
510 song->control_ratio = 1;
511 else if (song->control_ratio > MAX_CONTROL_RATIO)
512 song->control_ratio = MAX_CONTROL_RATIO;
513
514 song->lost_notes = 0;
515 song->cut_notes = 0;
516
517 song->events = read_midi_file(stream, song, &(song->groomed_event_count),
518 &song->samples);
519
520 /* Make sure everything is okay */
521 if (!song->events) {
522 free(song);
523 return(NULL);
524 }
525
526 song->default_instrument = 0;
527 song->default_program = DEFAULT_PROGRAM;
528
529 if (*def_instr_name)
530 set_default_instrument(song, def_instr_name);
531
532 load_missing_instruments(song);
533
534 return(song);
535 }
536
537 MidSong *mid_song_load(MidIStream *stream, MidSongOptions *options)
538 {
539 return mid_song_load_dls(stream, NULL, options);
540 }
541
542 void mid_song_free(MidSong *song)
543 {
544 size_t i;
545
546 free_instruments(song);
547
548 for (i = 0; i < 128; i++)
549 {
550 if (song->tonebank[i])
551 free(song->tonebank[i]);
552 if (song->drumset[i])
553 free(song->drumset[i]);
554 }
555
556 free(song->common_buffer);
557 free(song->resample_buffer);
558 free(song->events);
559
560 for (i = 0; i < (sizeof(song->meta_data) / sizeof(song->meta_data[0])); i++)
561 {
562 if (song->meta_data[i])
563 free(song->meta_data[i]);
564 }
565
566 free(song);
567 }
568
569 void mid_exit(void)
570 {
571 int i, j;
572
573 for (i = 0; i < 128; i++)
574 {
575 if (master_tonebank[i])
576 {
577 MidToneBankElement *e = master_tonebank[i]->tone;
578 if (e != NULL)
579 {
580 for (j = 0; j < 128; j++)
581 {
582 if (e[j].name != NULL)
583 free(e[j].name);
584 }
585 free(e);
586 }
587 free(master_tonebank[i]);
588 }
589 if (master_drumset[i])
590 {
591 MidToneBankElement *e = master_drumset[i]->tone;
592 if (e != NULL)
593 {
594 for (j = 0; j < 128; j++)
595 {
596 if (e[j].name != NULL)
597 free(e[j].name);
598 }
599 free(e);
600 }
601 free(master_drumset[i]);
602 }
603 }
604
605 free_pathlist();
606 }