Mercurial > audlegacy-plugins
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 } |
