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