/project/jni/sdl_sound/decoders/timidity/timidity.c

https://github.com/aichunyu/FFPlayer · C · 602 lines · 447 code · 58 blank · 97 comment · 144 complexity · ea8c0855df231dd7b2bb16343793a757 MD5 · raw file

  1. /*
  2. TiMidity -- Experimental MIDI to WAVE converter
  3. Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #if HAVE_CONFIG_H
  17. # include <config.h>
  18. #endif
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "SDL_sound.h"
  23. #define __SDL_SOUND_INTERNAL__
  24. #include "SDL_sound_internal.h"
  25. #include "timidity.h"
  26. #include "options.h"
  27. #include "common.h"
  28. #include "instrum.h"
  29. #include "playmidi.h"
  30. #include "readmidi.h"
  31. #include "output.h"
  32. #include "tables.h"
  33. ToneBank *master_tonebank[128], *master_drumset[128];
  34. static char def_instr_name[256] = "";
  35. #define MAXWORDS 10
  36. /* Quick-and-dirty fgets() replacement. */
  37. static char *RWgets(SDL_RWops *rw, char *s, int size)
  38. {
  39. int num_read = 0;
  40. int newline = 0;
  41. while (num_read < size && !newline)
  42. {
  43. if (SDL_RWread(rw, &s[num_read], 1, 1) != 1)
  44. break;
  45. /* Unlike fgets(), don't store newline. Under Windows/DOS we'll
  46. * probably get an extra blank line for every line that's being
  47. * read, but that should be ok.
  48. */
  49. if (s[num_read] == '\n' || s[num_read] == '\r')
  50. {
  51. s[num_read] = '\0';
  52. newline = 1;
  53. }
  54. num_read++;
  55. }
  56. s[num_read] = '\0';
  57. return (num_read != 0) ? s : NULL;
  58. }
  59. static int read_config_file(char *name)
  60. {
  61. SDL_RWops *rw;
  62. char tmp[1024], *w[MAXWORDS], *cp;
  63. ToneBank *bank=0;
  64. int i, j, k, line=0, words;
  65. static int rcf_count=0;
  66. if (rcf_count>50)
  67. {
  68. SNDDBG(("Probable source loop in configuration files\n"));
  69. return (-1);
  70. }
  71. if (!(rw=open_file(name)))
  72. return -1;
  73. while (RWgets(rw, tmp, sizeof(tmp)))
  74. {
  75. line++;
  76. w[words=0]=strtok(tmp, " \t\240");
  77. if (!w[0]) continue;
  78. /* Originally the TiMidity++ extensions were prefixed like this */
  79. if (strcmp(w[0], "#extension") == 0)
  80. words = -1;
  81. else if (*w[0] == '#')
  82. continue;
  83. while (w[words] && *w[words] != '#' && (words < MAXWORDS))
  84. w[++words]=strtok(0," \t\240");
  85. /*
  86. * TiMidity++ adds a number of extensions to the config file format.
  87. * Many of them are completely irrelevant to SDL_sound, but at least
  88. * we shouldn't choke on them.
  89. *
  90. * Unfortunately the documentation for these extensions is often quite
  91. * vague, gramatically strange or completely absent.
  92. */
  93. if (
  94. !strcmp(w[0], "comm") /* "comm" program second */
  95. || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */
  96. || !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */
  97. || !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */
  98. || !strcmp(w[0], "opt") /* "opt" timidity-options */
  99. )
  100. {
  101. /*
  102. * + "comm" sets some kind of comment -- the documentation is too
  103. * vague for me to understand at this time.
  104. * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data
  105. * over a network, rather than from the file system.
  106. * + "opt" specifies default options for TiMidity++.
  107. *
  108. * These are all quite useless for our version of TiMidity, so
  109. * they can safely remain no-ops.
  110. */
  111. } else if (!strcmp(w[0], "timeout")) /* "timeout" program second */
  112. {
  113. /*
  114. * Specifies a timeout value of the program. A number of seconds
  115. * before TiMidity kills the note. This may be useful to implement
  116. * later, but I don't see any urgent need for it.
  117. */
  118. SNDDBG(("FIXME: Implement \"timeout\" in TiMidity config.\n"));
  119. } else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */
  120. || !strcmp(w[0], "copybank")) /* "copybank" bank */
  121. {
  122. /*
  123. * Copies all the settings of the specified drumset or bank to
  124. * the current drumset or bank. May be useful later, but not a
  125. * high priority.
  126. */
  127. SNDDBG(("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]));
  128. } else if (!strcmp(w[0], "undef")) /* "undef" progno */
  129. {
  130. /*
  131. * Undefines the tone "progno" of the current tone bank (or
  132. * drum set?). Not a high priority.
  133. */
  134. SNDDBG(("FIXME: Implement \"undef\" in TiMidity config.\n"));
  135. } else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
  136. {
  137. /*
  138. * Sets the alternate assign for drum set. Whatever that's
  139. * supposed to mean.
  140. */
  141. SNDDBG(("FIXME: Implement \"altassign\" in TiMidity config.\n"));
  142. } else if (!strcmp(w[0], "soundfont")
  143. || !strcmp(w[0], "font"))
  144. {
  145. /*
  146. * I can't find any documentation for these, but I guess they're
  147. * an alternative way of loading/unloading instruments.
  148. *
  149. * "soundfont" sf_file "remove"
  150. * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
  151. * ["reso=" reso] ["amp=" amp]
  152. * "font" "exclude" bank preset keynote
  153. * "font" "order" order bank preset keynote
  154. */
  155. SNDDBG(("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]));
  156. } else if (!strcmp(w[0], "progbase"))
  157. {
  158. /*
  159. * The documentation for this makes absolutely no sense to me, but
  160. * apparently it sets some sort of base offset for tone numbers.
  161. * Why anyone would want to do this is beyond me.
  162. */
  163. SNDDBG(("FIXME: Implement \"progbase\" in TiMidity config.\n"));
  164. } else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
  165. {
  166. /*
  167. * This extension is the one we will need to implement, as it is
  168. * used by the "eawpats". Unfortunately I cannot find any
  169. * documentation whatsoever for it, but it looks like it's used
  170. * for remapping one instrument to another somehow.
  171. */
  172. SNDDBG(("FIXME: Implement \"map\" in TiMidity config.\n"));
  173. }
  174. /* Standard TiMidity config */
  175. else if (!strcmp(w[0], "dir"))
  176. {
  177. if (words < 2)
  178. {
  179. SNDDBG(("%s: line %d: No directory given\n", name, line));
  180. return -2;
  181. }
  182. for (i=1; i<words; i++)
  183. add_to_pathlist(w[i]);
  184. }
  185. else if (!strcmp(w[0], "source"))
  186. {
  187. if (words < 2)
  188. {
  189. SNDDBG(("%s: line %d: No file name given\n", name, line));
  190. return -2;
  191. }
  192. for (i=1; i<words; i++)
  193. {
  194. rcf_count++;
  195. read_config_file(w[i]);
  196. rcf_count--;
  197. }
  198. }
  199. else if (!strcmp(w[0], "default"))
  200. {
  201. if (words != 2)
  202. {
  203. SNDDBG(("%s: line %d: Must specify exactly one patch name\n",
  204. name, line));
  205. return -2;
  206. }
  207. strncpy(def_instr_name, w[1], 255);
  208. def_instr_name[255]='\0';
  209. }
  210. else if (!strcmp(w[0], "drumset"))
  211. {
  212. if (words < 2)
  213. {
  214. SNDDBG(("%s: line %d: No drum set number given\n", name, line));
  215. return -2;
  216. }
  217. i=atoi(w[1]);
  218. if (i<0 || i>127)
  219. {
  220. SNDDBG(("%s: line %d: Drum set must be between 0 and 127\n",
  221. name, line));
  222. return -2;
  223. }
  224. if (!master_drumset[i])
  225. {
  226. master_drumset[i] = safe_malloc(sizeof(ToneBank));
  227. memset(master_drumset[i], 0, sizeof(ToneBank));
  228. master_drumset[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
  229. memset(master_drumset[i]->tone, 0, 128 * sizeof(ToneBankElement));
  230. }
  231. bank=master_drumset[i];
  232. }
  233. else if (!strcmp(w[0], "bank"))
  234. {
  235. if (words < 2)
  236. {
  237. SNDDBG(("%s: line %d: No bank number given\n", name, line));
  238. return -2;
  239. }
  240. i=atoi(w[1]);
  241. if (i<0 || i>127)
  242. {
  243. SNDDBG(("%s: line %d: Tone bank must be between 0 and 127\n",
  244. name, line));
  245. return -2;
  246. }
  247. if (!master_tonebank[i])
  248. {
  249. master_tonebank[i] = safe_malloc(sizeof(ToneBank));
  250. memset(master_tonebank[i], 0, sizeof(ToneBank));
  251. master_tonebank[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
  252. memset(master_tonebank[i]->tone, 0, 128 * sizeof(ToneBankElement));
  253. }
  254. bank=master_tonebank[i];
  255. }
  256. else
  257. {
  258. if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
  259. {
  260. SNDDBG(("%s: line %d: syntax error\n", name, line));
  261. return -2;
  262. }
  263. i=atoi(w[0]);
  264. if (i<0 || i>127)
  265. {
  266. SNDDBG(("%s: line %d: Program must be between 0 and 127\n",
  267. name, line));
  268. return -2;
  269. }
  270. if (!bank)
  271. {
  272. SNDDBG(("%s: line %d: Must specify tone bank or drum set before assignment\n",
  273. name, line));
  274. return -2;
  275. }
  276. if (bank->tone[i].name)
  277. free(bank->tone[i].name);
  278. strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
  279. bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
  280. bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
  281. bank->tone[i].strip_tail=-1;
  282. for (j=2; j<words; j++)
  283. {
  284. if (!(cp=strchr(w[j], '=')))
  285. {
  286. SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
  287. return -2;
  288. }
  289. *cp++=0;
  290. if (!strcmp(w[j], "amp"))
  291. {
  292. k=atoi(cp);
  293. if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
  294. {
  295. SNDDBG(("%s: line %d: amplification must be between 0 and %d\n",
  296. name, line, MAX_AMPLIFICATION));
  297. return -2;
  298. }
  299. bank->tone[i].amp=k;
  300. }
  301. else if (!strcmp(w[j], "note"))
  302. {
  303. k=atoi(cp);
  304. if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
  305. {
  306. SNDDBG(("%s: line %d: note must be between 0 and 127\n",
  307. name, line));
  308. return -2;
  309. }
  310. bank->tone[i].note=k;
  311. }
  312. else if (!strcmp(w[j], "pan"))
  313. {
  314. if (!strcmp(cp, "center"))
  315. k=64;
  316. else if (!strcmp(cp, "left"))
  317. k=0;
  318. else if (!strcmp(cp, "right"))
  319. k=127;
  320. else
  321. k=((atoi(cp)+100) * 100) / 157;
  322. if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
  323. {
  324. SNDDBG(("%s: line %d: panning must be left, right, center, or between -100 and 100\n",
  325. name, line));
  326. return -2;
  327. }
  328. bank->tone[i].pan=k;
  329. }
  330. else if (!strcmp(w[j], "keep"))
  331. {
  332. if (!strcmp(cp, "env"))
  333. bank->tone[i].strip_envelope=0;
  334. else if (!strcmp(cp, "loop"))
  335. bank->tone[i].strip_loop=0;
  336. else
  337. {
  338. SNDDBG(("%s: line %d: keep must be env or loop\n", name, line));
  339. return -2;
  340. }
  341. }
  342. else if (!strcmp(w[j], "strip"))
  343. {
  344. if (!strcmp(cp, "env"))
  345. bank->tone[i].strip_envelope=1;
  346. else if (!strcmp(cp, "loop"))
  347. bank->tone[i].strip_loop=1;
  348. else if (!strcmp(cp, "tail"))
  349. bank->tone[i].strip_tail=1;
  350. else
  351. {
  352. SNDDBG(("%s: line %d: strip must be env, loop, or tail\n",
  353. name, line));
  354. return -2;
  355. }
  356. }
  357. else
  358. {
  359. SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
  360. return -2;
  361. }
  362. }
  363. }
  364. }
  365. SDL_RWclose(rw);
  366. return 0;
  367. }
  368. int Timidity_Init_NoConfig()
  369. {
  370. /* Allocate memory for the standard tonebank and drumset */
  371. master_tonebank[0] = safe_malloc(sizeof(ToneBank));
  372. memset(master_tonebank[0], 0, sizeof(ToneBank));
  373. master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
  374. memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement));
  375. master_drumset[0] = safe_malloc(sizeof(ToneBank));
  376. memset(master_drumset[0], 0, sizeof(ToneBank));
  377. master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
  378. memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement));
  379. return 0;
  380. }
  381. int Timidity_Init()
  382. {
  383. /* !!! FIXME: This may be ugly, but slightly less so than requiring the
  384. * default search path to have only one element. I think.
  385. *
  386. * We only need to include the likely locations for the config
  387. * file itself since that file should contain any other directory
  388. * that needs to be added to the search path.
  389. */
  390. #ifdef WIN32
  391. add_to_pathlist("\\TIMIDITY");
  392. #else
  393. add_to_pathlist("/usr/local/lib/timidity");
  394. add_to_pathlist("/etc");
  395. #endif
  396. Timidity_Init_NoConfig();
  397. return read_config_file(CONFIG_FILE);
  398. }
  399. MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio)
  400. {
  401. MidiSong *song;
  402. Sint32 events;
  403. int i;
  404. if (rw == NULL)
  405. return NULL;
  406. /* Allocate memory for the song */
  407. song = (MidiSong *)safe_malloc(sizeof(*song));
  408. memset(song, 0, sizeof(*song));
  409. song->patches = patches;
  410. for (i = 0; i < 128; i++)
  411. {
  412. if (master_tonebank[i])
  413. {
  414. song->tonebank[i] = safe_malloc(sizeof(ToneBank));
  415. memset(song->tonebank[i], 0, sizeof(ToneBank));
  416. song->tonebank[i]->tone = master_tonebank[i]->tone;
  417. }
  418. if (master_drumset[i])
  419. {
  420. song->drumset[i] = safe_malloc(sizeof(ToneBank));
  421. memset(song->drumset[i], 0, sizeof(ToneBank));
  422. song->drumset[i]->tone = master_drumset[i]->tone;
  423. }
  424. }
  425. song->amplification = DEFAULT_AMPLIFICATION;
  426. song->voices = DEFAULT_VOICES;
  427. song->drumchannels = DEFAULT_DRUMCHANNELS;
  428. song->rw = rw;
  429. song->rate = audio->freq;
  430. song->encoding = 0;
  431. if ((audio->format & 0xFF) == 16)
  432. song->encoding |= PE_16BIT;
  433. if (audio->format & 0x8000)
  434. song->encoding |= PE_SIGNED;
  435. if (audio->channels == 1)
  436. song->encoding |= PE_MONO;
  437. switch (audio->format) {
  438. case AUDIO_S8:
  439. song->write = s32tos8;
  440. break;
  441. case AUDIO_U8:
  442. song->write = s32tou8;
  443. break;
  444. case AUDIO_S16LSB:
  445. song->write = s32tos16l;
  446. break;
  447. case AUDIO_S16MSB:
  448. song->write = s32tos16b;
  449. break;
  450. case AUDIO_U16LSB:
  451. song->write = s32tou16l;
  452. break;
  453. default:
  454. SNDDBG(("Unsupported audio format"));
  455. song->write = s32tou16l;
  456. break;
  457. }
  458. song->buffer_size = audio->samples;
  459. song->resample_buffer = safe_malloc(audio->samples * sizeof(sample_t));
  460. song->common_buffer = safe_malloc(audio->samples * 2 * sizeof(Sint32));
  461. song->control_ratio = audio->freq / CONTROLS_PER_SECOND;
  462. if (song->control_ratio < 1)
  463. song->control_ratio = 1;
  464. else if (song->control_ratio > MAX_CONTROL_RATIO)
  465. song->control_ratio = MAX_CONTROL_RATIO;
  466. song->lost_notes = 0;
  467. song->cut_notes = 0;
  468. song->events = read_midi_file(song, &events, &song->samples);
  469. /* The RWops can safely be closed at this point, but let's make that the
  470. * responsibility of the caller.
  471. */
  472. /* Make sure everything is okay */
  473. if (!song->events) {
  474. free(song);
  475. return(NULL);
  476. }
  477. song->default_instrument = 0;
  478. song->default_program = DEFAULT_PROGRAM;
  479. if (*def_instr_name)
  480. set_default_instrument(song, def_instr_name);
  481. load_missing_instruments(song);
  482. return(song);
  483. }
  484. MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
  485. {
  486. return Timidity_LoadDLSSong(rw, NULL, audio);
  487. }
  488. void Timidity_FreeSong(MidiSong *song)
  489. {
  490. int i;
  491. free_instruments(song);
  492. for (i = 0; i < 128; i++)
  493. {
  494. if (song->tonebank[i])
  495. free(song->tonebank[i]);
  496. if (song->drumset[i])
  497. free(song->drumset[i]);
  498. }
  499. free(song->common_buffer);
  500. free(song->resample_buffer);
  501. free(song->events);
  502. free(song);
  503. }
  504. void Timidity_Exit(void)
  505. {
  506. int i, j;
  507. for (i = 0; i < 128; i++)
  508. {
  509. if (master_tonebank[i])
  510. {
  511. ToneBankElement *e = master_tonebank[i]->tone;
  512. if (e != NULL)
  513. {
  514. for (j = 0; j < 128; j++)
  515. {
  516. if (e[j].name != NULL)
  517. free(e[j].name);
  518. }
  519. free(e);
  520. }
  521. free(master_tonebank[i]);
  522. }
  523. if (master_drumset[i])
  524. {
  525. ToneBankElement *e = master_drumset[i]->tone;
  526. if (e != NULL)
  527. {
  528. for (j = 0; j < 128; j++)
  529. {
  530. if (e[j].name != NULL)
  531. free(e[j].name);
  532. }
  533. free(e);
  534. }
  535. free(master_drumset[i]);
  536. }
  537. }
  538. free_pathlist();
  539. }