fluidmax.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:46k
源码类别:

midi

开发平台:

C/C++

  1. /***************************************************************************************
  2.  *
  3.  *  fluidsynth~
  4.  *
  5.  *  Fluid Synth soundfont synthesizer for Max/MSP.
  6.  *
  7.  *  Fluid Synth is written by Peter Hanappe et al.
  8.  *  see http://www.fluidsynth.org/
  9.  *
  10.  *  Max/MSP integration by Norbert Schnell ATR IRCAM - Centre Pompidou
  11.  *
  12.  *  This program is free software; you can redistribute it and/or
  13.  *  modify it under the terms of the GNU General Public License
  14.  *  as published by the Free Software Foundation; either version 2.1
  15.  *  of the License, or (at your option) any later version.
  16.  *  
  17.  *  See file COPYING.LIB for further informations on licensing terms.
  18.  * 
  19.  *  This program is distributed in the hope that it will be useful,
  20.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.  *  GNU General Public License for more details.
  23.  * 
  24.  *  You should have received a copy of the GNU General Public License
  25.  *  along with this program; if not, write to the Free Software
  26.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  27.  *
  28.  */
  29.  
  30. /************************************************************************
  31.  *
  32.  *  versions:
  33.  *   (14): adapted to latest code base
  34.  *   (13): ???
  35.  *   (12): fixed voice stealing
  36.  *   (11): fixed arguments of fluidmax_tuning_octave() (third has to be float)
  37.  *   (10): added micro-tuning methods
  38.  *    (9): bug fix: now polyphony and # of midi channel arguments take effect
  39.  *    (8): added message resample permitting to chose resampling interpolation method
  40.  *    (7): added names for soundfonts (== file name without path and postfix)
  41.  *    (6): added message 'info'
  42.  *    (5): fixed bogus path translation at file loading
  43.  * 
  44.  */
  45. #define FLUIDMAX_VERSION "01/2009 (14)"
  46. #include "ftmax.h"
  47. #include "fluidsynth.h"
  48. #include "fluid_synth.h"
  49. #include "fluid_sfont.h"
  50. #include "fluid_chan.h"
  51. #include "fluidsynth/version.h"
  52. typedef struct
  53. {
  54.   ftmax_dsp_object_t obj;
  55.   
  56.   fluid_synth_t *synth;
  57.   fluid_settings_t *settings;
  58.   int reverb;
  59.   int chorus;
  60.   int mute;
  61.   void *outlet;
  62. } fluidmax_t;
  63. static t_messlist *fluidmax_class;
  64. static ftmax_symbol_t sym_on = NULL;
  65. static ftmax_symbol_t sym_off = NULL;
  66. static ftmax_symbol_t sym_undefined = NULL;
  67. static ftmax_symbol_t sym_gain = NULL;
  68. static ftmax_symbol_t sym_channels = NULL;
  69. static ftmax_symbol_t sym_channel = NULL;
  70. static ftmax_symbol_t sym_soundfonts = NULL;
  71. static ftmax_symbol_t sym_soundfont = NULL;
  72. static ftmax_symbol_t sym_presets = NULL;
  73. static ftmax_symbol_t sym_preset = NULL;
  74. static ftmax_symbol_t sym_reverb = NULL;
  75. static ftmax_symbol_t sym_chorus = NULL;
  76. static ftmax_symbol_t sym_polyphony = NULL;
  77. static ftmax_symbol_t sym_nearest = NULL;
  78. static ftmax_symbol_t sym_linear = NULL;
  79. static ftmax_symbol_t sym_cubic = NULL;
  80. static ftmax_symbol_t sym_sinc = NULL;
  81. /***************************************************************
  82.  *
  83.  *  generators
  84.  *
  85.  */
  86. typedef struct
  87. {
  88.   int index;
  89.   const char *name;
  90.   const char *unit;
  91. } fluidmax_gen_descr_t; 
  92. static fluidmax_gen_descr_t fluidmax_gen_info[] =
  93. {
  94.   {0, "startAddrsOffset", "samples"}, 
  95.   {1, "endAddrsOffset", "samples"}, 
  96.   {2, "startloopAddrsOffset", "samples"}, 
  97.   {3, "endloopAddrsOffset", "samples"}, 
  98.   {4, "startAddrsCoarseOffset", "32k samples"}, 
  99.   {5, "modLfoToPitch", "cent fs"}, 
  100.   {6, "vibLfoToPitch", "cent fs"}, 
  101.   {7, "modEnvToPitch", "cent fs"}, 
  102.   {8, "initialFilterFc", "cent 8.176 Hz"}, 
  103.   {9, "initialFilterQ", "cB"}, 
  104.   {10, "modLfoToFilterFc", "cent fs"}, 
  105.   {11, "modEnvToFilterFc", "cent fs "}, 
  106.   {12, "endAddrsCoarseOffset", "32k samples"}, 
  107.   {13, "modLfoToVolume", "cB fs"}, 
  108.   {14, "unused1", ""}, 
  109.   {15, "chorusEffectsSend", "0.1%"}, 
  110.   {16, "reverbEffectsSend", "0.1% "}, 
  111.   {17, "pan", "0.1%"}, 
  112.   {18, "unused2", ""}, 
  113.   {19, "unused3", ""}, 
  114.   {20, "unused4", ""}, 
  115.   {21, "delayModLFO", "timecent"}, 
  116.   {22, "freqModLFO", "cent 8.176 "}, 
  117.   {23, "delayVibLFO", "timecent "}, 
  118.   {24, "freqVibLFO", "cent 8.176"}, 
  119.   {25, "delayModEnv", "timecent"}, 
  120.   {26, "attackModEnv", "timecent "}, 
  121.   {27, "holdModEnv", "timecent"}, 
  122.   {28, "decayModEnv", "timecent"}, 
  123.   {29, "sustainModEnv", "-0.1%"}, 
  124.   {30, "releaseModEnv", "timecent"}, 
  125.   {31, "keynumToModEnvHold", "tcent/key"}, 
  126.   {32, "keynumToModEnvDecay", "tcent/key"}, 
  127.   {33, "delayVolEnv", "timecent"}, 
  128.   {34, "attackVolEnv", "timecent"}, 
  129.   {35, "holdVolEnv", "timecent"}, 
  130.   {36, "decayVolEnv", "timecent"}, 
  131.   {37, "sustainVolEnv", "cB"}, 
  132.   {38, "releaseVolEnv", "timecent "}, 
  133.   {39, "keynumToVolEnvHold", "tcent/key"}, 
  134.   {40, "keynumToVolEnvDecay", "tcent/key "}, 
  135.   {41, "instrument", ""}, 
  136.   {42, "reserved1", ""}, 
  137.   {43, "keyRange MIDI", ""},  
  138.   {44, "velRange MIDI", ""}, 
  139.   {45, "startloopAddrsCoarseOffset", "samples"}, 
  140.   {46, "keynum MIDI", ""}, 
  141.   {47, "velocity MIDI", ""}, 
  142.   {48, "initialAttenuation", "cB"}, 
  143.   {49, "reserved2", ""}, 
  144.   {50, "endloopAddrsCoarseOffset", "samples"}, 
  145.   {51, "coarseTune", "semitone"}, 
  146.   {52, "fineTune", "cent"}, 
  147.   {53, "sampleId", ""}, 
  148.   {54, "sampleModes", "Bit Flags"}, 
  149.   {55, "reserved3", ""}, 
  150.   {56, "scaleTuning", "cent/key"}, 
  151.   {57, "exclusiveClass", "arbitrary#"}, 
  152.   {58, "unused5", ""},
  153.   {59, "unused6", ""},
  154.   {60, "unused7", ""},
  155.   {61, "unused8", ""},
  156.   {62, "unused9", ""},
  157.   {63, "unused10", ""}
  158. };
  159. /***************************************************************
  160.  *
  161.  *  dsp
  162.  *
  163.  */
  164. static t_int *
  165. fluidmax_perform(t_int *w)
  166. {
  167.   fluidmax_t *self = (fluidmax_t *)(w[1]);
  168.   t_float *left = (t_float *)(w[2]);
  169.   t_float *right = (t_float *)(w[3]);
  170.   int n_tick = (int)(w[4]);
  171.   if(self->mute == 0)
  172.     fluid_synth_write_float(self->synth, n_tick, left, 0, 1, right, 0, 1);
  173.  else
  174.  {
  175.   int i;
  176.   
  177.   for(i=0; i<n_tick; i++)
  178.     left[i] = right[i] = 0.0;
  179.  }
  180.   
  181.   return (w + 5);
  182. }
  183. static void 
  184. fluidmax_dsp(fluidmax_t *self, t_signal **sp, short *count)
  185. {
  186.   int n_tick = sp[0]->s_n;
  187.         
  188.   dsp_add(fluidmax_perform, 4, self, sp[0]->s_vec, sp[1]->s_vec, n_tick);
  189. }
  190. /***************************************************************
  191.  *
  192.  *  load utlilities
  193.  *
  194.  */
  195. static char *
  196. fluidmax_translate_fullpath(char *maxpath, char *fullpath)
  197. {
  198.   int i;
  199.   strcpy(fullpath, "/Volumes/");
  200.   
  201.   for(i=0; maxpath[i] != ':'; i++)
  202.     fullpath[i + 9] = maxpath[i];
  203.     
  204.   /* skip ':' */
  205.   i++;
  206.     
  207.   strcpy(fullpath + i + 8, maxpath + i);
  208.   
  209.   return fullpath;
  210. }
  211.     
  212. static ftmax_symbol_t
  213. fluidmax_get_stripped_name(const char *fullpath)
  214. {
  215.   char stripped[1024];
  216.   int i;
  217.   
  218.   for(i=strlen(fullpath)-1; i>=0; i--)
  219.   {
  220.     if(fullpath[i] == '/')
  221.       break;
  222.   }
  223.   
  224.   if(i != 0)
  225.     i++;    
  226.   
  227.   strcpy(stripped, fullpath + i);
  228.   
  229.   for(i=0; stripped[i] != ''; i++)
  230.   {
  231.     if((stripped[i] == '.') && 
  232.        (stripped[i + 1] == 's' || stripped[i + 1] == 'S') && 
  233.        (stripped[i + 2] == 'f' || stripped[i + 2] == 'F') && 
  234.        (stripped[i + 3] == '2'))
  235.     {
  236.       stripped[i] = '';
  237.       break;
  238.     }
  239.   }
  240.   
  241.   return ftmax_new_symbol(stripped);
  242. }
  243.     
  244. static ftmax_symbol_t
  245. fluidmax_sfont_get_name(fluid_sfont_t *sfont)
  246. {
  247.   return fluidmax_get_stripped_name(fluid_sfont_get_name(sfont));
  248. }
  249.     
  250. static fluid_sfont_t *
  251. fluidmax_sfont_get_by_name(fluidmax_t *self, ftmax_symbol_t name)
  252. {
  253.   int n = fluid_synth_sfcount(self->synth);
  254.   int i;
  255.   
  256.   for(i=0; i<n; i++)
  257.   {
  258.     fluid_sfont_t *sfont = fluid_synth_get_sfont(self->synth, i);
  259.     if(fluidmax_sfont_get_name(sfont) == name)
  260.       return sfont;
  261.   }
  262.   return NULL;
  263. }
  264. static void 
  265. fluidmax_do_load(t_object *o, Symbol *s, short ac, Atom *at)
  266. {
  267.   fluidmax_t *self = (fluidmax_t *)o;
  268.   
  269.   if(ac > 0 && ftmax_is_symbol(at))  
  270.   {
  271.     const char *filename = ftmax_symbol_name(ftmax_get_symbol(at));
  272.     ftmax_symbol_t name = fluidmax_get_stripped_name(filename);
  273.     fluid_sfont_t *sf = fluidmax_sfont_get_by_name(self, name);
  274.     
  275.     if(sf == NULL)
  276.     {
  277.       int id = fluid_synth_sfload(self->synth, filename, 0);
  278.     
  279.       if(id >= 0)
  280.       {
  281.         post("fluidsynth~: loaded soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  282.         fluid_synth_program_reset(self->synth);
  283.         
  284.         outlet_bang(self->outlet);
  285.       }
  286.       else
  287.         error("fluidsynth~: cannot load soundfont from file '%s'", filename);
  288.     }
  289.     else
  290.     {
  291.       error("fluidsynth~: soundfont named '%s' is already loaded", ftmax_symbol_name(name));
  292.       return;
  293.     }
  294.   }
  295. }
  296. static void
  297. fluidmax_load_with_dialog(t_object *o, t_symbol *s, short argc, t_atom *argv)
  298. {
  299.   char filename[256];
  300.   char maxpath[1024];
  301.   char fullpath[1024];
  302.   long type;
  303.   short path;
  304.   
  305.   open_promptset("open SoundFont 2 file");
  306.   
  307.   if(open_dialog(filename, &path, &type, 0, 0))
  308.     return;
  309.     
  310.   if(path_topotentialname(path, filename, maxpath, 0) == 0)
  311.   {
  312.     ftmax_atom_t a;
  313.     
  314.     ftmax_set_symbol(&a, ftmax_new_symbol(fluidmax_translate_fullpath(maxpath, fullpath)));
  315.     fluidmax_do_load(o, NULL, 1, &a);
  316.   }
  317. }  
  318. /***************************************************************
  319.  *
  320.  *  user methods
  321.  *
  322.  */
  323. static void 
  324. fluidmax_load(t_object *o, Symbol *s, short ac, Atom *at)
  325.   if(ac == 0)
  326.     defer(o, (method)fluidmax_load_with_dialog, NULL, 0, 0);
  327.   else
  328.   {
  329.     if(ftmax_is_symbol(at))
  330.     {
  331.       ftmax_symbol_t name = ftmax_get_symbol(at);
  332.       char *string = (char *)ftmax_symbol_name(name);
  333.       
  334.       if(string[0] == '/')
  335.         defer(o, (method)fluidmax_do_load, NULL, ac, at);
  336.       else
  337.       {
  338.         char maxpath[1024];
  339.         char fullpath[1024];
  340.         short path;
  341.         long type;
  342.         ftmax_atom_t a;
  343.         
  344.         if(locatefile_extended(string, &path, &type, 0, 0) || path_topotentialname(path, string, maxpath, 0) != 0)
  345.         {
  346.           error("fluidsynth~: cannot find file '%s'", string);
  347.           return;
  348.         }
  349.         
  350.         ftmax_set_symbol(&a, ftmax_new_symbol(fluidmax_translate_fullpath(maxpath, fullpath)));
  351.         defer(o, (method)fluidmax_do_load, NULL, 1, &a);
  352.       }
  353.     }
  354.   }
  355. }
  356. static void 
  357. fluidmax_unload(t_object *o, Symbol *s, short ac, Atom *at)
  358. {
  359.   fluidmax_t *self = (fluidmax_t *)o;
  360.   
  361.   if(ac > 0)
  362.   {
  363.     if(ftmax_is_number(at))  
  364.     {
  365.       int id = ftmax_get_number_int(at);
  366.       fluid_sfont_t *sf = fluid_synth_get_sfont_by_id(self->synth, id);
  367.       
  368.       if(sf != NULL)
  369.       {  
  370.         ftmax_symbol_t name = fluidmax_sfont_get_name(sf);
  371.         
  372.         if(fluid_synth_sfunload(self->synth, id, 0) >= 0)
  373.         {
  374.           post("fluidsynth~: unloaded soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  375.           return;
  376.         }
  377.       }
  378.             
  379.       error("fluidsynth~: cannot unload soundfont %d", id);
  380.     }
  381.     else if (ftmax_is_symbol(at))
  382.     {
  383.       ftmax_symbol_t sym = ftmax_get_symbol(at);
  384.       
  385.       if(sym == ftmax_new_symbol("all"))
  386.       {
  387.         fluid_sfont_t *sf = fluid_synth_get_sfont(self->synth, 0);
  388.         
  389.         fluid_synth_system_reset(self->synth);
  390.         while(sf != NULL)
  391.         {
  392.           ftmax_symbol_t name = fluidmax_sfont_get_name(sf);
  393.           unsigned int id = fluid_sfont_get_id(sf);
  394.         
  395.           if(fluid_synth_sfunload(self->synth, id, 0) >= 0)
  396.             post("fluidsynth~: unloaded soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  397.           else
  398.             error("fluidsynth~: cannot unload soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  399.         
  400.           sf = fluid_synth_get_sfont(self->synth, 0);
  401.         }
  402.       }
  403.       else
  404.       {
  405.         fluid_sfont_t *sf = fluidmax_sfont_get_by_name(self, sym);
  406.         
  407.         if(sf != NULL)
  408.         {
  409.           unsigned int id = fluid_sfont_get_id(sf);
  410.           
  411.           if(fluid_synth_sfunload(self->synth, id, 0) >= 0)
  412.           {
  413.             post("fluidsynth~: unloaded soundfont '%s' (id %d)", ftmax_symbol_name(sym), id);
  414.             return;
  415.           }
  416.         }
  417.         
  418.         error("fluidsynth~: cannot unload soundfont '%s'", ftmax_symbol_name(sym));
  419.       }
  420.     }
  421.   }
  422. }
  423. static void 
  424. fluidmax_reload(t_object *o, Symbol *s, short ac, Atom *at)
  425. {
  426.   fluidmax_t *self = (fluidmax_t *)o;
  427.   
  428.   if(ac > 0)
  429.   {
  430.     if(ftmax_is_number(at))  
  431.     {
  432.       int id = ftmax_get_number_int(at);
  433.       fluid_sfont_t *sf = fluid_synth_get_sfont_by_id(self->synth, id);
  434.       
  435.       if(sf != NULL)
  436.       {
  437.         if (fluid_synth_sfreload(self->synth, id) >= 0)
  438.         {
  439.           post("fluidsynth~: reloaded soundfont '%s' (id %d)", id);
  440.           return;
  441.         }
  442.         error("fluidsynth~: cannot reload soundfont %d", id);
  443.       }
  444.     }
  445.     else if (ftmax_is_symbol(at))
  446.     {
  447.       ftmax_symbol_t sym = ftmax_get_symbol(at);
  448.       
  449.       if(sym == ftmax_new_symbol("all"))
  450.       {
  451.         int n = fluid_synth_sfcount(self->synth);
  452.         int i;
  453.         
  454.         fluid_synth_system_reset(self->synth);
  455.         for(i=0; i<n; i++)
  456.         {
  457.           fluid_sfont_t *sf = fluid_synth_get_sfont(self->synth, i);
  458.           ftmax_symbol_t name = fluidmax_sfont_get_name(sf);
  459.           unsigned int id = fluid_sfont_get_id(sf);
  460.           
  461.         
  462.           if (fluid_synth_sfreload(self->synth, id) >= 0)
  463.             post("fluidsynth~: reloaded soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  464.           else
  465.             error("fluidsynth~: cannot reload soundfont '%s' (id %d)", ftmax_symbol_name(name), id);
  466.         }
  467.       }
  468.       else
  469.       {
  470.         fluid_sfont_t *sf = fluidmax_sfont_get_by_name(self, sym);
  471.         
  472.         if(sf != NULL)
  473.         {
  474.           unsigned int id = fluid_sfont_get_id(sf);
  475.           
  476.           if(fluid_synth_sfreload(self->synth, id) >= 0)
  477.           {
  478.             post("fluidsynth~: reloaded soundfont '%s' (id %d)", ftmax_symbol_name(sym), id);
  479.             return;
  480.           }
  481.         }
  482.         
  483.         error("fluidsynth~: cannot reload soundfont '%s'", ftmax_symbol_name(sym));
  484.       }
  485.     }
  486.   }
  487. }
  488. static void 
  489. fluidmax_note(t_object *o, Symbol *s, short ac, Atom *at)
  490. {
  491.   fluidmax_t *self = (fluidmax_t *)o;
  492.   
  493.   if(ac > 0 && ftmax_is_number(at))
  494.   {
  495.     int velocity = 64;
  496.     int channel = 1;
  497.     
  498.     switch(ac)
  499.     {
  500.       default:
  501.       case 3:
  502.         if(ftmax_is_number(at + 2))
  503.         {
  504.           channel = ftmax_get_number_int(at + 2);
  505.                     
  506.           if(channel < 1)
  507.             channel = 1;
  508.           else if(channel > fluid_synth_count_midi_channels(self->synth))
  509.             channel = fluid_synth_count_midi_channels(self->synth);
  510.         }
  511.       case 2:
  512.         if(ftmax_is_number(at + 1))
  513.           velocity = ftmax_get_number_int(at + 1);
  514.       case 1:
  515.         fluid_synth_noteon(self->synth, channel - 1, ftmax_get_number_int(at), velocity);
  516.       case 0:
  517.         break;
  518.     }
  519.   }
  520. }
  521. static void 
  522. fluidmax_list(t_object *o, Symbol *s, short ac, Atom *at)
  523. {
  524.   fluidmax_note(o, NULL, ac, at);
  525. }
  526. static void 
  527. fluidmax_control_change(t_object *o, Symbol *s, short ac, Atom *at)
  528. {
  529.   fluidmax_t *self = (fluidmax_t *)o;
  530.   
  531.   if(ac > 0 && ftmax_is_number(at))
  532.   {
  533.     int value = 64;
  534.     int channel = 1;
  535.     
  536.     switch(ac)
  537.     {
  538.       default:
  539.       case 3:
  540.         if(ftmax_is_number(at + 2))
  541.         {
  542.           channel = ftmax_get_number_int(at + 2);
  543.           
  544.           if(channel < 1)
  545.             channel = 1;
  546.           else if(channel > fluid_synth_count_midi_channels(self->synth))
  547.             channel = fluid_synth_count_midi_channels(self->synth);
  548.         }
  549.       case 2:
  550.         if(ftmax_is_number(at + 1))
  551.           value = ftmax_get_number_int(at + 1);
  552.       case 1:
  553.         fluid_synth_cc(self->synth, channel - 1, ftmax_get_number_int(at), value);
  554.       case 0:
  555.         break;
  556.     }
  557.   }
  558. }
  559. static void 
  560. fluidmax_mod(t_object *o, Symbol *s, short ac, Atom *at)
  561. {
  562.   fluidmax_t *self = (fluidmax_t *)o;
  563.   
  564.   if(ac > 1 && ftmax_is_number(at) && ftmax_is_number(at + 1))
  565.   {
  566.     int param = ftmax_get_number_int(at);
  567.     float value = ftmax_get_number_float(at + 1);
  568.     int channel = 1;
  569.     
  570.     if(ac > 2 && ftmax_is_number(at + 2))
  571.     {
  572.       channel = ftmax_get_number_int(at + 2);
  573.       
  574.       if(channel < 1)
  575.         channel = 1;
  576.       else if(channel > fluid_synth_count_midi_channels(self->synth))
  577.         channel = fluid_synth_count_midi_channels(self->synth);
  578.     }
  579.     fluid_synth_set_gen(self->synth, channel - 1, param, value);
  580.   }
  581. }
  582. static void 
  583. fluidmax_pitch_bend(t_object *o, Symbol *s, short ac, Atom *at)
  584. {  
  585.   fluidmax_t *self = (fluidmax_t *)o;
  586.   
  587.   if(ac > 0 && ftmax_is_number(at))
  588.   {
  589.     int channel = 1;
  590.     double bend = 0.0;
  591.     
  592.     if(ac > 1 && ftmax_is_number(at + 1))
  593.     {
  594.       channel = ftmax_get_number_int(at + 1);
  595.           
  596.       if(channel < 1)
  597.         channel = 1;
  598.       else if(channel > fluid_synth_count_midi_channels(self->synth))
  599.         channel = fluid_synth_count_midi_channels(self->synth);
  600.     }
  601.       
  602.     bend = ftmax_get_number_float(at);
  603.     
  604.     if(bend < 0.0)
  605.       bend = 0.0;
  606.     else if(bend > 127.0)
  607.       bend = 127.0;
  608.   
  609.     fluid_synth_pitch_bend(self->synth, channel - 1, (int)(bend * 128.0));
  610.   }
  611. }
  612. static void 
  613. fluidmax_pitch_bend_wheel(t_object *o, Symbol *s, short ac, Atom *at)
  614. {  
  615.   fluidmax_t *self = (fluidmax_t *)o;
  616.   
  617.   if(ac > 0 && ftmax_is_number(at))
  618.   {
  619.     int channel = 1;
  620.     
  621.     if(ac > 1 && ftmax_is_number(at + 1))
  622.       channel = ftmax_get_number_int(at + 1);
  623.       
  624.     fluid_synth_pitch_wheel_sens(self->synth, channel - 1, ftmax_get_number_int(at));
  625.   }
  626. }
  627. static void 
  628. fluidmax_program_change(t_object *o, Symbol *s, short ac, Atom *at)
  629. {  
  630.   fluidmax_t *self = (fluidmax_t *)o;
  631.   
  632.   if(ac > 0 && ftmax_is_number(at))
  633.   {
  634.     int channel = 1;
  635.     
  636.     if(ac > 1 && ftmax_is_number(at + 1))
  637.     {
  638.       channel = ftmax_get_number_int(at + 1);
  639.           
  640.       if(channel < 1)
  641.         channel = 1;
  642.       else if(channel > fluid_synth_count_midi_channels(self->synth))
  643.         channel = fluid_synth_count_midi_channels(self->synth);
  644.     }
  645.       
  646.     fluid_synth_program_change(self->synth, channel - 1, ftmax_get_number_int(at));
  647.   }
  648. }
  649. static void 
  650. fluidmax_bank_select(t_object *o, Symbol *s, short ac, Atom *at)
  651. {
  652.   fluidmax_t *self = (fluidmax_t *)o;
  653.   
  654.   if(ac > 0 && ftmax_is_number(at))
  655.   {
  656.     int channel = 1;
  657.     unsigned int sf_id;
  658.     unsigned int bank_num;
  659.     unsigned int prog_num;
  660.     
  661.     if(ac > 1 && ftmax_is_number(at + 1))
  662.     {
  663.       channel = ftmax_get_number_int(at + 1);
  664.           
  665.       if(channel < 1)
  666.         channel = 1;
  667.       else if(channel > fluid_synth_count_midi_channels(self->synth))
  668.         channel = fluid_synth_count_midi_channels(self->synth);
  669.     }
  670.       
  671.     fluid_synth_bank_select(self->synth, channel - 1, ftmax_get_number_int(at));
  672.     fluid_synth_get_program(self->synth, channel - 1, &sf_id, &bank_num, &prog_num);
  673.     fluid_synth_program_change(self->synth, channel - 1, prog_num);
  674.   }
  675. }
  676. static void 
  677. fluidmax_select(t_object *o, Symbol *s, short ac, Atom *at)
  678. {
  679.   fluidmax_t *self = (fluidmax_t *)o;
  680.   unsigned int bank = 0;
  681.   unsigned int preset = 0;  
  682.   int channel = 1;
  683.   
  684.   switch(ac)
  685.   {
  686.     default:
  687.     case 4:
  688.       if(ftmax_is_number(at + 3))
  689.         channel = ftmax_get_number_int(at + 3);
  690.       if(channel < 1)
  691.         channel = 1;
  692.       else if(channel > fluid_synth_count_midi_channels(self->synth))
  693.         channel = fluid_synth_count_midi_channels(self->synth);
  694.         
  695.     case 3:
  696.       if(ftmax_is_number(at + 2))
  697.         preset = ftmax_get_number_int(at + 2);
  698.         
  699.     case 2:
  700.       if(ftmax_is_number(at + 1))
  701.         bank = ftmax_get_number_int(at + 1);
  702.         
  703.     case 1:
  704.       if(ftmax_is_number(at))
  705.         fluid_synth_program_select(self->synth, channel - 1, ftmax_get_number_int(at), bank, preset);
  706.       else if(ftmax_is_symbol(at))
  707.       {
  708.         ftmax_symbol_t name = ftmax_get_symbol(at);
  709.         fluid_sfont_t *sf = fluidmax_sfont_get_by_name(self, name);
  710.         
  711.         if(sf != NULL)
  712.           fluid_synth_program_select(self->synth, channel - 1, fluid_sfont_get_id(sf), bank, preset);
  713.         else
  714.           error("fluidsynth~ select:蔯annot find soundfont named '%s'", ftmax_symbol_name(name));
  715.       }
  716.     case 0:
  717.       break;
  718.   }
  719. }
  720. static void 
  721. fluidmax_reverb(t_object *o, Symbol *s, short ac, Atom *at)
  722. {
  723.   fluidmax_t *self = (fluidmax_t *)o;
  724.   
  725.   if(ac == 0)
  726.   {
  727.     fluid_synth_set_reverb_on(self->synth, 1);
  728.     fluid_revmodel_reset(self->synth->reverb);
  729.     self->reverb = 1;
  730.   }
  731.   else if(ftmax_is_number(at))
  732.   {
  733.     double room = fluid_synth_get_reverb_roomsize(self->synth);
  734.     double damping = fluid_synth_get_reverb_damp(self->synth);
  735.     double width = fluid_synth_get_reverb_width(self->synth);
  736.     fluid_synth_set_reverb_on(self->synth, 1);
  737.     self->reverb = 1;
  738.     
  739.     switch(ac)
  740.     {
  741.       default:
  742.       case 4:
  743.         if(ftmax_is_number(at + 3))
  744.           width = ftmax_get_number_float(at + 3);
  745.       case 3:
  746.         if(ftmax_is_number(at + 2))
  747.           damping = ftmax_get_number_float(at + 2);
  748.       case 2:
  749.         if(ftmax_is_number(at + 1))
  750.           room = ftmax_get_number_float(at + 1);
  751.       case 1:
  752.         fluid_synth_set_reverb(self->synth, room, damping, width, ftmax_get_number_float(at));
  753.       case 0:
  754.         break;
  755.     }
  756.   }
  757.   else if(ftmax_is_symbol(at))
  758.   {
  759.     ftmax_symbol_t sym = ftmax_get_symbol(at);
  760.     
  761.     if(sym == sym_on)
  762.     {
  763.       fluid_synth_set_reverb_on(self->synth, 1);
  764.       self->reverb = 1;
  765.     }
  766.     else if(sym == sym_off)
  767.     {
  768.       fluid_synth_set_reverb_on(self->synth, 0);
  769.       self->reverb = 0;
  770.     }
  771.   }
  772. }
  773. static void 
  774. fluidmax_chorus(t_object *o, Symbol *s, short ac, Atom *at)
  775. {
  776.   fluidmax_t *self = (fluidmax_t *)o;
  777.   
  778.   if(ac == 0)
  779.   {
  780.     fluid_synth_set_chorus_on(self->synth, 1);
  781.     fluid_chorus_reset(self->synth->chorus);
  782.     self->chorus = 1;
  783.   }
  784.   else if(ftmax_is_number(at))
  785.   {
  786.     double speed = fluid_synth_get_chorus_speed_Hz(self->synth);
  787.     double depth = fluid_synth_get_chorus_depth_ms(self->synth);
  788.     int type = fluid_synth_get_chorus_type(self->synth);
  789.     int nr = fluid_synth_get_chorus_nr(self->synth);
  790.     fluid_synth_set_chorus_on(self->synth, 1);
  791.     self->chorus = 1;
  792.     switch(ac)
  793.     {
  794.       default:
  795.       case 5:
  796.         if(ftmax_is_number(at + 4))
  797.           nr = ftmax_get_number_int(at + 4);
  798.       case 4:
  799.         if(ftmax_is_number(at + 3))
  800.           type = ftmax_get_number_int(at + 3);
  801.       case 3:
  802.         if(ftmax_is_number(at + 2))
  803.           depth = ftmax_get_number_float(at + 2);
  804.       case 2:
  805.         if(ftmax_is_number(at + 1))
  806.           speed = ftmax_get_number_float(at + 1);
  807.       case 1:
  808.         fluid_synth_set_chorus(self->synth, nr, ftmax_get_number_float(at), speed, depth, type);
  809.       case 0:
  810.         break;
  811.     }
  812.   }
  813.   else if(ftmax_is_symbol(at))
  814.   {
  815.     ftmax_symbol_t sym = ftmax_get_symbol(at);
  816.     
  817.     if(sym == sym_on)
  818.     {
  819.       fluid_synth_set_chorus_on(self->synth, 1);
  820.       self->chorus = 1;
  821.     }
  822.     else if(sym == sym_off)
  823.     {
  824.       fluid_synth_set_chorus_on(self->synth, 0);
  825.       self->chorus = 0;
  826.     }
  827.   }
  828. }
  829. static void 
  830. fluidmax_set_gain(t_object *o, Symbol *s, short ac, Atom *at)
  831. {
  832.   fluidmax_t *self = (fluidmax_t *)o;
  833.   
  834.   if(ac > 0 && ftmax_is_number(at))
  835.   {
  836.     float gain = ftmax_get_number_float(at);
  837.     
  838.     fluid_synth_set_gain(self->synth, gain);
  839.   }
  840. }
  841. static void 
  842. fluidmax_set_resampling_method(t_object *o, Symbol *s, short ac, Atom *at)
  843. {
  844.   fluidmax_t *self = (fluidmax_t *)o;
  845.   
  846.   if(ac > 0)
  847.   {
  848.     if(ftmax_is_number(at))
  849.     {
  850.       int ip = ftmax_get_int(at);
  851.       
  852.       if(ip == 0)
  853.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_NONE);
  854.       else if(ip < 3)
  855.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_LINEAR);
  856.       else if(ip < 6)
  857.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_4THORDER);
  858.       else
  859.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_7THORDER);
  860.     }
  861.     else if(ftmax_is_symbol(at))
  862.     {
  863.       ftmax_symbol_t sym = ftmax_get_symbol(at);
  864.       
  865.       if(sym == sym_nearest)
  866.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_NONE);
  867.       else if(sym == sym_linear)
  868.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_LINEAR);
  869.       else if(sym == sym_cubic)
  870.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_4THORDER);
  871.       else if(sym == sym_sinc)
  872.         fluid_synth_set_interp_method(self->synth, -1, FLUID_INTERP_7THORDER);      
  873.       else
  874.         error("fluidsynth~: undefined resampling method: %s", ftmax_symbol_name(sym));
  875.     }
  876.   }
  877. }
  878. static void 
  879. fluidmax_panic(t_object *o, Symbol *s, short ac, Atom *at)
  880. {
  881.   fluidmax_t *self = (fluidmax_t *)o;
  882.   fluid_synth_system_reset(self->synth);
  883. }
  884. static void 
  885. fluidmax_reset(t_object *o, Symbol *s, short ac, Atom *at)
  886. {
  887.   fluidmax_t *self = (fluidmax_t *)o;
  888.   int n = fluid_synth_count_midi_channels(self->synth);
  889.   int i;
  890.   for (i=0; i<n; i++)
  891.     fluid_channel_reset(self->synth->channel[i]);
  892. }
  893. static void 
  894. fluidmax_mute(t_object *o, Symbol *s, short ac, Atom *at)
  895. {
  896.   fluidmax_t *self = (fluidmax_t *)o;
  897.   int mute = 1;
  898.   
  899.   if(ac > 0 && ftmax_is_number(at))
  900.     mute = (ftmax_get_number_int(at) != 0);
  901.   
  902.   fluid_synth_system_reset(self->synth);
  903.    
  904.   self->mute = mute;
  905. }
  906. static void 
  907. fluidmax_unmute(t_object *o)
  908. {
  909.   ftmax_atom_t a;
  910.   
  911.   ftmax_set_int(&a, 0);  
  912.   fluidmax_mute(o, NULL, 1, &a);
  913. }
  914. /* 
  915. int fluid_synth_count_audio_channels (fluid_synth_t *synth)
  916. int fluid_synth_count_audio_groups (fluid_synth_t *synth)
  917. int fluid_synth_count_effects_channels (fluid_synth_t *synth)
  918. */
  919. static void 
  920. fluidmax_tuning_octave(t_object *o, Symbol *s, short ac, Atom *at)
  921. {
  922.   fluidmax_t *self = (fluidmax_t *)o;
  923.   ftmax_symbol_t name;
  924.   int tuning_bank = 0;
  925.   int tuning_prog = 0;
  926.   double pitch[12];
  927.   int i, n;
  928.   
  929.   if(ac > 0 && ftmax_is_symbol(at))
  930.   {
  931.     name = ftmax_get_symbol(at);
  932.     at++;
  933.     ac--;
  934.   }
  935.   
  936.   n = ac - 2;
  937.   if(n > 12)
  938.     n = 12;
  939.   if(ac > 0 && ftmax_is_number(at))
  940.     tuning_bank = ftmax_get_number_int(at) % 128;
  941.   
  942.   if(ac > 1 && ftmax_is_number(at + 1))
  943.     tuning_prog = ftmax_get_number_int(at) % 128;
  944.     
  945.   for(i=0; i<n; i++)
  946.   {
  947.     if(ftmax_is_number(at + i + 2))
  948.       pitch[i] = ftmax_get_number_float(at + i + 2);
  949.     else
  950.       pitch[i] = 0.0;
  951.   }
  952.   
  953.   for(; i<12; n++)
  954.     pitch[i] = 0.0;
  955.   fluid_synth_create_octave_tuning(self->synth, tuning_bank, tuning_prog, ftmax_symbol_name(name), pitch);
  956. }
  957. static void 
  958. fluidmax_tuning_select(t_object *o, Symbol *s, short ac, Atom *at)
  959. {
  960.   fluidmax_t *self = (fluidmax_t *)o;
  961.   int tuning_bank = 0;
  962.   int tuning_prog = 0;
  963.   int channel = 1;
  964.   
  965.   if(ac > 0 && ftmax_is_number(at))
  966.     tuning_bank = ftmax_get_number_int(at) % 128;
  967.     
  968.   if(ac > 1 && ftmax_is_number(at + 1))
  969.     tuning_prog = ftmax_get_number_int(at + 1) % 128;
  970.   
  971.   if(ac > 2 && ftmax_is_number(at + 2))
  972.     channel = ftmax_get_number_int(at + 2);
  973.     
  974.   if(channel < 1)
  975.     channel = 1;
  976.   else if(channel > fluid_synth_count_midi_channels(self->synth))
  977.     channel = fluid_synth_count_midi_channels(self->synth);
  978.     
  979.   fluid_synth_select_tuning(self->synth, channel - 1, tuning_bank, tuning_prog);
  980. }
  981. static void 
  982. fluidmax_tuning_reset(t_object *o, Symbol *s, short ac, Atom *at)
  983. {
  984.   fluidmax_t *self = (fluidmax_t *)o;
  985.   int channel = 0;
  986.   
  987.   if(ac > 0 && ftmax_is_number(at))
  988.     channel = ftmax_get_number_int(at);
  989.   if(channel < 1)
  990.     channel = 1;
  991.   else if(channel > fluid_synth_count_midi_channels(self->synth))
  992.     channel = fluid_synth_count_midi_channels(self->synth);
  993.     
  994.   fluid_synth_reset_tuning(self->synth, channel - 1);
  995. }
  996. /* more tuning ??
  997. fluid_synth_create_key_tuning (fluid_synth_t *synth, int tuning_bank, int tuning_prog, char *name, double *pitch)
  998. fluid_synth_tune_notes (fluid_synth_t *synth, int tuning_bank, int tuning_prog, int len, int *keys, double *pitch, int apply)
  999. fluid_synth_tuning_iteration_start (fluid_synth_t *synth)
  1000. fluid_synth_tuning_iteration_next (fluid_synth_t *synth, int *bank, int *prog)
  1001. fluid_synth_tuning_dump (fluid_synth_t *synth, int bank, int prog, char *name, int len, double *pitch)
  1002. */
  1003. static void
  1004. fluidmax_version(t_object *o)
  1005. {
  1006.   post("fluidsynth~, version %s (based on FluidSynth %s)", FLUIDMAX_VERSION, FLUIDSYNTH_VERSION);
  1007.   post("  FluidSynth is written by Peter Hanappe et al. (see fluidsynth.org)");
  1008.   post("  Max/MSP integration by Norbert Schnell IMTR IRCAM - Centre Pompidou");
  1009. }
  1010. extern fluid_gen_info_t fluid_gen_info[];
  1011. static void 
  1012. fluidmax_print(t_object *o, Symbol *s, short ac, Atom *at)
  1013. {
  1014.   fluidmax_t *self = (fluidmax_t *)o;
  1015.   
  1016.   if(ac > 0)
  1017.   {
  1018.     if(ftmax_is_symbol(at))
  1019.     {
  1020.       ftmax_symbol_t sym = ftmax_get_symbol(at);
  1021.       
  1022.       if(sym == sym_soundfonts)
  1023.       {
  1024.         int n = fluid_synth_sfcount(self->synth);
  1025.         int i;
  1026.         
  1027.         if(n > 0)
  1028.           post("fluidsynth~ soundfonts:");
  1029.         else
  1030.           post("fluidsynth~: no soundfonts loaded");          
  1031.         
  1032.         for(i=0; i<n; i++)
  1033.         {
  1034.           fluid_sfont_t *sf = fluid_synth_get_sfont(self->synth, i);
  1035.           ftmax_symbol_t name = fluidmax_sfont_get_name(sf);
  1036.           unsigned int id = fluid_sfont_get_id(sf);
  1037.           
  1038.           post("  %d: '%s' (id %d)", i, ftmax_symbol_name(name), id);
  1039.         }
  1040.       }
  1041.       else if(sym == sym_presets)
  1042.       {
  1043.         int n = fluid_synth_sfcount(self->synth);
  1044.         
  1045.         if(n > 0)
  1046.         {
  1047.           if(ac > 1)
  1048.           {
  1049.             fluid_sfont_t *sf = NULL;
  1050.             ftmax_symbol_t name;
  1051.          
  1052.             if(ftmax_is_symbol(at + 1))
  1053.             {
  1054.               name = ftmax_get_symbol(at + 1);
  1055.               sf = fluidmax_sfont_get_by_name(self, name);
  1056.             }
  1057.             else if(ftmax_is_int(at + 1))
  1058.             {
  1059.               int id = ftmax_get_int(at + 1);
  1060.               
  1061.               sf = fluid_synth_get_sfont_by_id(self->synth, id);
  1062.               name = fluidmax_sfont_get_name(sf);
  1063.             }
  1064.             
  1065.             if(sf != NULL)
  1066.             {
  1067.               fluid_preset_t preset;
  1068.               
  1069.               fluid_sfont_iteration_start(sf);
  1070.               
  1071.               post("fluidsynth~ presets of soundfont '%s':", ftmax_symbol_name(name));
  1072.               
  1073.               while(fluid_sfont_iteration_next(sf, &preset) > 0)
  1074.               {
  1075.                 char *preset_str = fluid_preset_get_name(&preset);
  1076.                 ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1077.                 int bank_num = fluid_preset_get_banknum(&preset);
  1078.                 int prog_num = fluid_preset_get_num(&preset);
  1079.                 
  1080.                 post("  '%s': bank %d, program %d", ftmax_symbol_name(preset_name), bank_num, prog_num);
  1081.               }
  1082.             }
  1083.           }
  1084.           else
  1085.           {
  1086.             int i;
  1087.             post("fluidsynth~ presets:");
  1088.             
  1089.             for(i=0; i<128; i++)
  1090.             {
  1091.               int j;
  1092.               
  1093.               for(j=0; j<128; j++)
  1094.               {
  1095.                 fluid_preset_t *preset = NULL;
  1096.                 fluid_sfont_t *sf = NULL;
  1097.                 int k;
  1098.                 
  1099.                 for(k=0; k<n; k++)
  1100.                 {
  1101.                   sf = fluid_synth_get_sfont(self->synth, k);                  
  1102.                   preset = fluid_sfont_get_preset(sf, i, j);
  1103.                   
  1104.                   if(preset != NULL)
  1105.                     break;
  1106.                 }
  1107.                 
  1108.                 if(preset != NULL)
  1109.                 {
  1110.                   ftmax_symbol_t sf_name = fluidmax_sfont_get_name(sf);
  1111.                   char *preset_str = fluid_preset_get_name(preset);
  1112.                   ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1113.                   
  1114.                   post("  '%s': soundfont '%s', bank %d, program %d", 
  1115.                     ftmax_symbol_name(preset_name), ftmax_symbol_name(sf_name), i, j);
  1116.                 }
  1117.               }
  1118.             }
  1119.           }
  1120.         }
  1121.         else
  1122.           error("fluidsynth~: no soundfonts loaded");
  1123.       }
  1124.       else if(sym == sym_channels)
  1125.       {
  1126.         int n = fluid_synth_count_midi_channels(self->synth);
  1127.         int i;
  1128.         
  1129.         post("fluidsynth~ channels:");
  1130.         
  1131.         for(i=0; i<n; i++)
  1132.         {
  1133.           fluid_preset_t *preset = fluid_synth_get_channel_preset(self->synth, i);
  1134.           
  1135.           if(preset != NULL)
  1136.           {
  1137.             char *preset_str = fluid_preset_get_name(preset);
  1138.             ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1139.             unsigned int sf_id;
  1140.             unsigned int bank_num;
  1141.             unsigned int prog_num;
  1142.             fluid_sfont_t *sf;
  1143.             
  1144.             fluid_synth_get_program(self->synth, i, &sf_id, &bank_num, &prog_num);
  1145.             sf = fluid_synth_get_sfont_by_id(self->synth, sf_id);
  1146.             
  1147.             post("  %d: soundfont '%s', bank %d, program %d: '%s'", 
  1148.               i + 1, ftmax_symbol_name(fluidmax_sfont_get_name(sf)), bank_num, prog_num, ftmax_symbol_name(preset_name));
  1149.           }
  1150.           else
  1151.             post("  channel %d: no preset", i + 1);
  1152.         }
  1153.       }
  1154.       else if(sym == ftmax_new_symbol("generators"))
  1155.       {
  1156.         int channel = 1;
  1157.         int n = GEN_LAST;
  1158.         int i;
  1159.         
  1160.         if(ac > 1 && ftmax_is_number(at + 1))
  1161.           channel = ftmax_get_number_int(at + 1);
  1162.         if(channel < 1)
  1163.           channel = 1;
  1164.         else if(channel > fluid_synth_count_midi_channels(self->synth))
  1165.           channel = fluid_synth_count_midi_channels(self->synth);
  1166.           
  1167.         post("fluidsynth~ generators of channel %d:", channel);
  1168.         
  1169.         for(i=0; i<n; i++)
  1170.         {
  1171.           const char *name = fluidmax_gen_info[i].name;
  1172.           const char *unit = fluidmax_gen_info[i].unit;
  1173.           double incr = fluid_synth_get_gen(self->synth, channel - 1, i);
  1174.           double min = fluid_gen_info[i].min;
  1175.           double max = fluid_gen_info[i].max;
  1176.           
  1177.           post("  %d '%s': %s %g [%g ... %g] (%s)", i, name, (incr >= 0)? "": "-" , fabs(incr), min, max, unit);
  1178.         }
  1179.       }
  1180.       else if(sym == sym_gain)
  1181.       {
  1182.         double gain = fluid_synth_get_gain(self->synth);
  1183.         post("gain: %g", gain);
  1184.       }
  1185.       else if(sym == sym_reverb)
  1186.       {
  1187.         double level = fluid_synth_get_reverb_level(self->synth);
  1188.         double room = fluid_synth_get_reverb_roomsize(self->synth);
  1189.         double damping = fluid_synth_get_reverb_damp(self->synth);
  1190.         double width = fluid_synth_get_reverb_width(self->synth);
  1191.         
  1192.         if(self->reverb != 0)
  1193.         {
  1194.           post("fluidsynth~ current reverb parameters:");
  1195.           post("  level: %f", level);
  1196.           post("  room size: %f", room);
  1197.           post("  damping: %f", damping);
  1198.           post("  width: %f", width);
  1199.         }
  1200.         else
  1201.           post("fluidsynth~: reverb off");        
  1202.       }
  1203.       else if(sym == sym_chorus)
  1204.       {
  1205.         if(self->chorus != 0)
  1206.         {
  1207.           double level = fluid_synth_get_chorus_level(self->synth);
  1208.           double speed = fluid_synth_get_chorus_speed_Hz(self->synth);
  1209.           double depth = fluid_synth_get_chorus_depth_ms(self->synth);
  1210.           int type = fluid_synth_get_chorus_type(self->synth);
  1211.           int nr = fluid_synth_get_chorus_nr(self->synth);
  1212.           
  1213.           post("fluidsynth~ current chorus parameters:");
  1214.           post("  level: %f", level);
  1215.           post("  speed: %f Hz", speed);
  1216.           post("  depth: %f msec", depth);
  1217.           post("  type: %d (%s)", type, type? "triangle": "sine");
  1218.           post("  %d units", nr);
  1219.         }
  1220.         else
  1221.           post("fluidsynth~: chorus off");
  1222.       }
  1223.     }
  1224.   }
  1225. }
  1226. static void 
  1227. fluidmax_info(t_object *o, Symbol *s, short ac, Atom *at)
  1228. {
  1229.   fluidmax_t *self = (fluidmax_t *)o;
  1230.   
  1231.   if(ac > 0)
  1232.   {
  1233.     if(ftmax_is_symbol(at))
  1234.     {
  1235.       ftmax_symbol_t sym = ftmax_get_symbol(at);
  1236.       
  1237.       if(sym == sym_soundfonts)
  1238.       {
  1239.         int n = fluid_synth_sfcount(self->synth);
  1240.         int i;
  1241.         
  1242.         for(i=0; i<n; i++)
  1243.         {
  1244.           fluid_sfont_t *sf = fluid_synth_get_sfont(self->synth, i);
  1245.           unsigned int id = fluid_sfont_get_id(sf);
  1246.           ftmax_atom_t a[2];
  1247.           
  1248.           ftmax_set_int(a, i);
  1249.           ftmax_set_symbol(a + 1, fluidmax_sfont_get_name(sf));
  1250.           ftmax_set_int(a + 2, id);
  1251.           outlet_anything(self->outlet, sym_soundfont, 3, a);
  1252.         }
  1253.       }
  1254.       else if(sym == sym_presets)
  1255.       {
  1256.         int n = fluid_synth_sfcount(self->synth);
  1257.         
  1258.         if(n > 0)
  1259.         {
  1260.           if(ac > 1)
  1261.           {
  1262.             fluid_sfont_t *sf = NULL;
  1263.             ftmax_symbol_t sf_name;
  1264.          
  1265.             if(ftmax_is_symbol(at + 1))
  1266.             {
  1267.               sf_name = ftmax_get_symbol(at + 1);
  1268.               sf = fluidmax_sfont_get_by_name(self, sf_name);
  1269.             }
  1270.             else if(ftmax_is_int(at + 1))
  1271.             {
  1272.               int id = ftmax_get_int(at + 1);
  1273.               
  1274.               sf = fluid_synth_get_sfont_by_id(self->synth, id);
  1275.               sf_name = fluidmax_sfont_get_name(sf);
  1276.             }
  1277.             
  1278.             if(sf != NULL)
  1279.             {
  1280.               fluid_preset_t preset;
  1281.               
  1282.               fluid_sfont_iteration_start(sf);
  1283.               
  1284.               while(fluid_sfont_iteration_next(sf, &preset) > 0)
  1285.               {
  1286.                 char *preset_str = fluid_preset_get_name(&preset);
  1287.                 ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1288.                 int bank_num = fluid_preset_get_banknum(&preset);
  1289.                 int prog_num = fluid_preset_get_num(&preset);
  1290.                 ftmax_atom_t a[4];
  1291.                 
  1292.                 ftmax_set_symbol(a , preset_name);
  1293.                 ftmax_set_symbol(a + 1, sf_name);
  1294.                 ftmax_set_int(a + 2, bank_num);
  1295.                 ftmax_set_int(a + 3, prog_num);
  1296.                 outlet_anything(self->outlet, sym_preset, 4, a);
  1297.               }
  1298.             }
  1299.           }
  1300.           else
  1301.           {
  1302.             int i;
  1303.             for(i=0; i<128; i++)
  1304.             {
  1305.               int j;
  1306.               
  1307.               for(j=0; j<128; j++)
  1308.               {
  1309.                 fluid_preset_t *preset = NULL;
  1310.                 fluid_sfont_t *sf = NULL;
  1311.                 int k;
  1312.                 
  1313.                 for(k=0; k<n; k++)
  1314.                 {
  1315.                   sf = fluid_synth_get_sfont(self->synth, k);                  
  1316.                   preset = fluid_sfont_get_preset(sf, i, j);
  1317.                   
  1318.                   if(preset != NULL)
  1319.                     break;
  1320.                 }
  1321.                 
  1322.                 if(preset != NULL)
  1323.                 {
  1324.                   ftmax_symbol_t sf_name = fluidmax_sfont_get_name(sf);
  1325.                   char *preset_str = fluid_preset_get_name(preset);
  1326.                   ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1327.                   ftmax_atom_t a[4];
  1328.                   
  1329.                   ftmax_set_symbol(a , preset_name);
  1330.                   ftmax_set_symbol(a + 1, sf_name);
  1331.                   ftmax_set_int(a + 2, i);
  1332.                   ftmax_set_int(a + 3, j);
  1333.                   outlet_anything(self->outlet, sym_preset, 4, a);
  1334.                 }
  1335.               }
  1336.             }
  1337.           }
  1338.         }
  1339.         else
  1340.           error("fluidsynth~ info: no soundfonts loaded");
  1341.       }
  1342.       else if(sym == sym_channels)
  1343.       {
  1344.         int n = fluid_synth_count_midi_channels(self->synth);
  1345.         int i;
  1346.         
  1347.         for(i=0; i<n; i++)
  1348.         {
  1349.           fluid_preset_t *preset = fluid_synth_get_channel_preset(self->synth, i);
  1350.           
  1351.           if(preset != NULL)
  1352.           {
  1353.             char *preset_str = fluid_preset_get_name(preset);
  1354.             ftmax_symbol_t preset_name = ftmax_new_symbol(preset_str);
  1355.             unsigned int sf_id, bank_num, prog_num;
  1356.             fluid_sfont_t *sf;
  1357.             ftmax_atom_t a[5];
  1358.             
  1359.             fluid_synth_get_program(self->synth, i, &sf_id, &bank_num, &prog_num);
  1360.             sf = fluid_synth_get_sfont_by_id(self->synth, sf_id);
  1361.             ftmax_set_int(a, i + 1);
  1362.             ftmax_set_symbol(a + 1, fluidmax_sfont_get_name(sf));
  1363.             ftmax_set_int(a + 2, bank_num);
  1364.             ftmax_set_int(a + 3, prog_num);
  1365.             ftmax_set_symbol(a + 4, preset_name);
  1366.             outlet_anything(self->outlet, sym_channel, 5, a);
  1367.           }
  1368.           else
  1369.           {
  1370.             ftmax_atom_t a[2];
  1371.             
  1372.             ftmax_set_int(a, i + 1);
  1373.             ftmax_set_symbol(a + 1, sym_undefined);
  1374.             outlet_anything(self->outlet, sym_channel, 2, a);
  1375.           }
  1376.         }
  1377.       }
  1378.       else if(sym == sym_gain)
  1379.       {
  1380.         ftmax_atom_t a;
  1381.         double gain = fluid_synth_get_gain(self->synth);
  1382.         ftmax_set_float(&a, gain);
  1383.         outlet_anything(self->outlet, sym_channel, 1, &a);
  1384.       }
  1385.       else if(sym == sym_reverb)
  1386.       {
  1387.         if(self->reverb != 0)
  1388.         {
  1389.           double level = fluid_synth_get_reverb_level(self->synth);
  1390.           double room = fluid_synth_get_reverb_roomsize(self->synth);
  1391.           double damping = fluid_synth_get_reverb_damp(self->synth);
  1392.           double width = fluid_synth_get_reverb_width(self->synth);
  1393.           ftmax_atom_t a[4];
  1394.           
  1395.           ftmax_set_float(a, level);
  1396.           ftmax_set_float(a + 1, room);
  1397.           ftmax_set_float(a + 2, damping);
  1398.           ftmax_set_float(a + 3, width);
  1399.           outlet_anything(self->outlet, sym_reverb, 4, a);          
  1400.         }
  1401.         else
  1402.         {
  1403.           ftmax_atom_t a;
  1404.           
  1405.           ftmax_set_symbol(&a, sym_off);
  1406.           outlet_anything(self->outlet, sym_reverb, 1, &a);
  1407.         }
  1408.       }
  1409.       else if(sym == sym_chorus)
  1410.       {
  1411.         if(self->chorus != 0)
  1412.         {
  1413.           double level = fluid_synth_get_chorus_level(self->synth);
  1414.           double speed = fluid_synth_get_chorus_speed_Hz(self->synth);
  1415.           double depth = fluid_synth_get_chorus_depth_ms(self->synth);
  1416.           int type = fluid_synth_get_chorus_type(self->synth);
  1417.           int nr = fluid_synth_get_chorus_nr(self->synth);
  1418.           ftmax_atom_t a[5];
  1419.           
  1420.           ftmax_set_float(a, level);
  1421.           ftmax_set_float(a + 1, speed);
  1422.           ftmax_set_float(a + 2, depth);
  1423.           ftmax_set_int(a + 3, type);
  1424.           ftmax_set_int(a + 4, nr);
  1425.           outlet_anything(self->outlet, sym_chorus, 5, a);
  1426.         }
  1427.         else
  1428.         {
  1429.           ftmax_atom_t a;
  1430.           
  1431.           ftmax_set_symbol(&a, sym_off);
  1432.           outlet_anything(self->outlet, sym_chorus, 1, &a);
  1433.         }
  1434.       }
  1435.       else if(sym == sym_polyphony)
  1436.       {
  1437.         int polyphony = fluid_synth_get_polyphony(self->synth);
  1438.         ftmax_atom_t a;
  1439.         
  1440.         ftmax_set_int(&a, polyphony);
  1441.         outlet_anything(self->outlet, sym_polyphony, 1, &a);
  1442.       }
  1443.     }
  1444.   }
  1445. }
  1446. /***************************************************************
  1447.  *
  1448.  *  class
  1449.  *
  1450.  */
  1451. static void *
  1452. fluidmax_new(Symbol *s, short ac, Atom *at)
  1453. {  
  1454.   fluidmax_t *self = (fluidmax_t *)newobject(fluidmax_class);
  1455.   int polyphony = 256;
  1456.   int midi_channels = 16;
  1457.   self->outlet = outlet_new(self, "anything");
  1458.   dsp_setup((t_pxobject *)self, 0);
  1459.   outlet_new(self, "signal");
  1460.   outlet_new(self, "signal");
  1461.   self->synth = NULL;
  1462.   self->settings = new_fluid_settings();
  1463.   self->reverb = 0;
  1464.   self->chorus = 0;
  1465.   self->mute = 0;
  1466.   
  1467.   if(ac > 0 && ftmax_is_number(at))
  1468.   {
  1469.     polyphony = ftmax_get_number_int(at);
  1470.     ac--;
  1471.     at++;
  1472.   }
  1473.   
  1474.   if(ac > 0 && ftmax_is_number(at))
  1475.   {
  1476.     midi_channels = ftmax_get_number_int(at);
  1477.     ac--;
  1478.     at++;
  1479.   }
  1480.   
  1481.   if(ac > 0 && ftmax_is_symbol(at))
  1482.   {
  1483.     fluidmax_load((t_object *)self, NULL, 1, at);
  1484.   }
  1485.   
  1486.   if(self->settings != NULL)
  1487.   {
  1488.     fluid_settings_setint(self->settings, "synth.midi-channels", midi_channels);
  1489.     fluid_settings_setint(self->settings, "synth.polyphony", polyphony);
  1490.     fluid_settings_setnum(self->settings, "synth.gain", 0.600000);
  1491.     fluid_settings_setnum(self->settings, "synth.sample-rate", sys_getsr());
  1492.   
  1493.     self->synth = new_fluid_synth(self->settings);
  1494.     
  1495.     if(self->synth != NULL)
  1496.     {
  1497.       fluid_synth_set_reverb_on(self->synth, 0);
  1498.       fluid_synth_set_chorus_on(self->synth, 0);      
  1499.     
  1500.       if(ac > 0 && ftmax_is_symbol(at))
  1501.         fluidmax_load((t_object *)self, NULL, ac, at);
  1502.       return self;
  1503.     }
  1504.     delete_fluid_settings(self->settings);
  1505.   }
  1506.   error("fluidsynth~: cannot create FluidSynth core");
  1507.   
  1508.   return NULL;
  1509. }
  1510. static void
  1511. fluidmax_free(t_pxobject *o)
  1512. {
  1513.   fluidmax_t *self = (fluidmax_t *)o;
  1514.   if(self->settings != NULL )
  1515.     delete_fluid_settings(self->settings);
  1516.   if(self->synth != NULL )
  1517.     delete_fluid_synth(self->synth);
  1518.   dsp_free(o);
  1519. }
  1520. int 
  1521. main(void)
  1522. {
  1523.   setup(&fluidmax_class, (method)fluidmax_new, (method)fluidmax_free, (short)sizeof(fluidmax_t), 0, A_GIMME, 0);
  1524.   dsp_initclass();
  1525.   addmess((method)fluidmax_dsp, "dsp", A_CANT, 0);
  1526.   addmess((method)fluidmax_version, "version", 0);
  1527.   addmess((method)fluidmax_print, "print", A_GIMME, 0);
  1528.   addmess((method)fluidmax_load, "load", A_GIMME, 0);
  1529.   addmess((method)fluidmax_unload, "unload", A_GIMME, 0);
  1530.   addmess((method)fluidmax_reload, "reload", A_GIMME, 0);
  1531.   addmess((method)fluidmax_info, "info", A_GIMME, 0);
  1532.   
  1533.   addmess((method)fluidmax_panic, "panic", A_GIMME, 0);
  1534.   addmess((method)fluidmax_reset, "reset", A_GIMME, 0);
  1535.   addmess((method)fluidmax_mute, "mute", A_GIMME, 0);
  1536.   addmess((method)fluidmax_unmute, "unmute", 0);
  1537.   /*addmess((method)fluidmax_tuning_keys, "tuning-keys", A_GIMME, 0);*/
  1538.   addmess((method)fluidmax_tuning_octave, "tuning-octave", A_GIMME, 0);
  1539.   addmess((method)fluidmax_tuning_select, "tuning-select", A_GIMME, 0);
  1540.   addmess((method)fluidmax_tuning_reset, "tuning-reset", A_GIMME, 0);
  1541.   addmess((method)fluidmax_reverb, "reverb", A_GIMME, 0);
  1542.   addmess((method)fluidmax_chorus, "chorus", A_GIMME, 0);  
  1543.   addmess((method)fluidmax_set_gain, "gain", A_GIMME, 0);  
  1544.   addmess((method)fluidmax_set_resampling_method, "resample", A_GIMME, 0);  
  1545.     
  1546.   addmess((method)fluidmax_note, "note", A_GIMME, 0);
  1547.   addmess((method)fluidmax_list, "list", A_GIMME, 0);
  1548.   addmess((method)fluidmax_control_change, "control", A_GIMME, 0);
  1549.   addmess((method)fluidmax_mod, "mod", A_GIMME, 0);
  1550.   
  1551.   addmess((method)fluidmax_pitch_bend, "bend", A_GIMME, 0);
  1552.   addmess((method)fluidmax_pitch_bend_wheel, "wheel", A_GIMME, 0);
  1553.   addmess((method)fluidmax_program_change, "program", A_GIMME, 0);
  1554.   addmess((method)fluidmax_bank_select, "bank", A_GIMME, 0);
  1555.   addmess((method)fluidmax_select, "select", A_GIMME, 0);
  1556.   sym_on = ftmax_new_symbol("on");
  1557.   sym_off = ftmax_new_symbol("off");
  1558.   sym_undefined = ftmax_new_symbol("undefined");
  1559.   sym_gain = ftmax_new_symbol("gain");
  1560.   sym_channels = ftmax_new_symbol("channels");
  1561.   sym_channel = ftmax_new_symbol("channel");
  1562.   sym_soundfonts = ftmax_new_symbol("soundfonts");
  1563.   sym_soundfont = ftmax_new_symbol("soundfont");
  1564.   sym_presets = ftmax_new_symbol("presets");
  1565.   sym_preset = ftmax_new_symbol("preset");
  1566.   sym_reverb = ftmax_new_symbol("reverb");
  1567.   sym_chorus = ftmax_new_symbol("chorus");
  1568.   sym_polyphony = ftmax_new_symbol("polyphony");
  1569.   sym_nearest = ftmax_new_symbol("nearest");
  1570.   sym_linear = ftmax_new_symbol("linear");
  1571.   sym_cubic = ftmax_new_symbol("cubic");
  1572.   sym_sinc = ftmax_new_symbol("sinc");
  1573.   
  1574.   fluidmax_version(NULL);
  1575.   
  1576.   return 0;
  1577. }