diff --git a/externals/fluid~/fluid~-help.pd b/externals/fluid~/fluid~-help.pd index 1587a76282feedfc934fb05ce5859c6b58346af1..ab98aa274d8bea304e3dddb89fff2e032bcf0cfa 100644 --- a/externals/fluid~/fluid~-help.pd +++ b/externals/fluid~/fluid~-help.pd @@ -1,109 +1,141 @@ -#N canvas 8 25 1015 671 10; -#X text 35 71 A soundfont player using If I Were You \, from www.iiwu.org +#N canvas 645 66 561 627 10; +#X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0 +14 #dcdcdc #404040 0; +#X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header fluid~ 3 12 0 18 +#c4dcdc #000000 0; +#X obj 0 294 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13 +#dcdcdc #000000 0; +#N canvas 484 286 496 371 META 0; +#X text 12 5 KEYWORDS synthesizer soundfont; +#X text 12 25 LICENSE GPLv2+; +#X text 12 75 AUTHOR Frank Barknecht \, Jonathan Wilkes \, Albert Gräf ; -#X text 170 296 fluid~ wants channel # first: should I change this? +#X text 12 115 RELEASE_DATE 2003 \, 2016 \, 2020; +#X text 12 45 DESCRIPTION MIDI synthesizer using fluidsynth; +#X text 12 95 WEBSITE http://www.fluidsynth.org/; +#X text 12 135 HELP_PATCH_AUTHORS Albert Gräf \, based on an earlier +help patch by Frank Barknecht and others.; +#X restore 500 597 pd META; +#X obj 0 441 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0 +13 #dcdcdc #000000 0; +#X obj 0 510 cnv 3 550 3 empty \$0-pddp.cnv.argument arguments 8 12 +0 13 #dcdcdc #000000 0; +#X obj 0 568 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12 +0 13 #dcdcdc #000000 0; +#X obj 78 303 cnv 17 3 130 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc +#9c9c9c 0; +#X obj 78 450 cnv 17 3 17 empty \$0-pddp.cnv.let.n l 5 9 0 16 #dcdcdc +#9c9c9c 0; +#X obj 78 472 cnv 17 3 17 empty \$0-pddp.cnv.let.r r 5 9 0 16 #dcdcdc +#9c9c9c 0; +#X text 98 450 signal; +#X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide ; -#X text 287 518 Program change ( prog or p + chan + value); -#X text 170 246 Note messages start with note \, n or with nothing -(pure list input): chan + note + velocity; -#X obj 36 34 cnv 15 102 32 empty empty empty 20 12 1 14 -1 -66577 0 +#X obj 492 12 fluid~; +#X text 11 23 soundfont synthesizer based on fluidsynth; +#X obj 14 118 output~; +#X obj 14 89 fluid~ -smmf TimGM6mb; +#X text 164 61 Download Tim Brechbill's small (~6MB) GM soundfont here: ; -#X obj 37 35 cnv 15 100 30 empty empty fluid~ 20 15 1 14 -257472 -66577 -0; -#X obj 593 18 cnv 15 374 160 empty empty empty 20 12 1 14 -1 -66577 -0; -#X text 181 120 load soundfonts. Creation argument is possible as well: +#X obj 164 91 pddp/pddplink https://musescore.org/en/handbook/soundfonts-and-sfz-files#list +-text More soundfonts here (musescore.org); +#X obj 14 60 r \$0-fluid; +#X msg 90 60 help; +#X text 98 473 signal; +#X text 168 449 - [fluid~] outputs a stereo signal to its two signal +outlets.; +#X text 79 519 1) -smmf; +#X text 79 536 2) symbol; +#X text 168 519 - (optional) enables SMMF mode.; +#X text 98 303 sym f f f; +#X text 180 390 - load the given soundfont file (automatic .sf2 extension). ; -#X obj 594 19 cnv 15 372 158 empty Notes Soundfonts 20 12 1 14 -228992 --66577 0; -#X msg 650 109 load /usr/lib/awe/sfbank/2gmgsmt.sf2; -#X msg 644 89 load \$1; -#X obj 644 67 openpanel; -#X obj 644 47 bng 15 250 50 0 empty empty empty 0 -6 0 8 -260818 -1 --1; -#X obj 629 134 s \$0-iiwu; -#X obj 375 146 fluid~ notavail.sf2; -#X obj 593 182 cnv 15 374 160 empty empty empty 20 12 1 14 -1 -66577 -0; -#X obj 594 183 cnv 15 372 158 empty Notes Notes 20 12 1 14 -228992 --66577 0; -#X obj 837 224 notein; -#X obj 837 246 pack 0 0 0; -#X msg 695 288 n 1 60 0; -#X obj 640 311 s \$0-iiwu; -#X obj 695 244 bang; -#X msg 837 268 \$3 \$1 \$2; -#X obj 837 290 s \$0-iiwu; -#X obj 593 345 cnv 15 374 160 empty empty empty 20 12 1 14 -1 -66577 -0; -#X text 159 413 Controller Change: control or c or cc + chan + cc# -+ value; -#X obj 594 346 cnv 15 372 158 empty Notes Controller_Change/Pitch_Bend -20 12 1 14 -228992 -66577 0; -#X obj 632 473 s \$0-iiwu; -#X floatatom 632 388 5 0 0 0 - - -, f 5; -#X msg 649 441 c 2 \$1; -#X msg 632 407 control 1 2 \$1; -#X obj 593 509 cnv 15 374 160 empty empty empty 20 12 1 14 -1 -66577 +#X text 168 536 - (optional) any other symbol specifies a soundfont +file to be loaded at creation time.; +#X text 216 415 - reinitialize \, load the given soundfont file if +any.; +#X obj 15 196 notein; +#X obj 15 221 pack 0 0 0; +#X msg 15 246 \$3 \$1 \$2; +#X text 15 172 MIDI input (legacy mode):; +#X obj 95 221 pack 0 0 0; +#X obj 95 196 ctlin; +#X obj 175 196 bendin 0 1; +#X obj 175 221 pack 0 0; +#X msg 95 246 cc \$3 \$2 \$1; +#X floatatom 264 221 5 0 0 0 - - -, f 5; +#X msg 264 245 prog 1 \$1; +#X floatatom 341 221 5 0 0 0 - - -, f 5; +#X msg 341 245 bank 1 \$1; +#X text 261 200 prog change; +#X text 339 200 bank select; +#X msg 175 246 b \$2 \$1; +#X obj 15 271 s \$0-legacy; +#N canvas 769 250 453 354 switch 0; +#X obj 40 110 r \$0-legacy; +#X obj 40 135 spigot 1; +#X obj 121 110 r \$0-smmf; +#X obj 121 135 spigot; +#X obj 85 15 inlet; +#X obj 85 40 t f f; +#X obj 85 65 == 0; +#X obj 154 65 != 0; +#X obj 40 160 outlet; +#X connect 0 0 1 0; +#X connect 1 0 8 0; +#X connect 2 0 3 0; +#X connect 3 0 8 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 5 1 7 0; +#X connect 6 0 1 1; +#X connect 7 0 3 1; +#X restore 460 159 pd switch; +#X obj 460 134 tgl 15 0 empty empty smmf-mode 17 7 0 10 #fcfcfc #000000 +#000000 0 1; +#X obj 460 184 s \$0-fluid; +#X obj 460 86 midi-input; +#X obj 460 111 s \$0-smmf; +#X text 182 113 SMMF mode supports all voice messages and sysex (useful +for transmitting MTS tuning data). This is usually to be preferred +because it offers more capabilities. See:, f 42; +#X text 168 303 - MIDI message. In "legacy" mode (default) \, args +are channel \, first and second data byte (if any) \, and the supported +message selectors are (shortcuts in parentheses): note (n \, list) +\, control (c \, cc) \, prog (p). In SMMF mode (-smmf) \, all SMMF +voice messages and sysex are supported (most legacy messages still +continue to work as well)., f 62; +#X obj 264 270 s \$0-fluid; +#N canvas 1990 266 450 302 generators 0; +#X obj 22 64 cnv 15 302 110 empty empty empty 20 12 1 14 #000000 #404040 0; -#X obj 594 510 cnv 15 372 158 empty Notes Program_Change 20 12 1 14 --228992 -66577 0; -#X obj 703 627 s \$0-iiwu; -#X msg 703 580 prog 1 \$1; -#X msg 783 580 p 2 \$1; -#X floatatom 703 550 5 0 0 0 - - -, f 5; -#X obj 695 202 bng 15 250 50 0 empty empty empty 0 -6 0 8 -24198 -1 --1; -#X floatatom 783 550 5 0 0 0 - - -, f 5; -#X floatatom 673 388 5 0 0 0 - - -, f 5; -#X msg 695 222 note 1 60 120; -#X obj 741 388 ctlin; -#X obj 741 410 pack 0 0 0; -#X obj 856 396 bendin; -#X obj 856 418 pack 0 0; -#X obj 856 462 s \$0-iiwu; -#X msg 856 440 bend \$2 \$1; -#X text 159 445 Pitch Bend works the same: bend or b + chan + val; -#X msg 857 574 bank 1 \$1; -#X floatatom 857 555 5 0 0 0 - - -, f 5; -#X text 857 595 bank select; -#X obj 789 187 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 -1; -#X obj 715 187 metro 1000; -#X obj 40 261 cnv 15 102 32 empty empty empty 20 12 1 14 -1 -66577 -0; -#X obj 41 262 cnv 15 100 30 empty empty empty 20 15 1 14 -257472 -66577 -0; -#X obj 66 199 r \$0-iiwu; -#X msg 66 233 help; -#X msg 146 217 init /usr/lib/awe/sfbank/2gmgsmt.sf2; -#X obj 66 269 fluid~; -#X text 145 185 init [soundfont] can (re)initialize fluid~ for example -to adapt to new samplerates.; -#X msg 741 432 cc \$3 \$2 \$1; -#X obj 203 617 cnv 15 302 110 empty empty empty 20 12 1 14 -1 -66577 -0; -#X obj 204 618 cnv 15 300 108 empty Notes generators 20 12 1 14 -228992 --66577 0; -#X msg 231 682 gen 1 \$2 \$1; -#X obj 231 704 s \$0-iiwu; -#X floatatom 289 642 5 0 60 0 - - -, f 5; -#X floatatom 231 642 5 0 0 0 - - -, f 5; -#X obj 231 662 pack 0 17; -#X text 78 607 gen 17 is "pan".; -#X text 78 594 Setting generators like for example:; -#X obj 695 266 del 1000; -#X symbolatom 343 684 20 0 0 0 - - -, f 20; -#X obj 343 656 fluid.gen2sym; -#X text 345 700 a little helper; -#N canvas 402 274 605 444 dust 0; +#X obj 23 65 cnv 15 300 108 empty Notes generators 20 12 1 14 #dce4fc +#404040 0; +#X msg 50 129 gen 1 \$2 \$1; +#X floatatom 108 89 5 0 60 0 - - -, f 5; +#X floatatom 50 89 5 0 0 0 - - -, f 5; +#X obj 50 109 pack 0 17; +#X text 23 32 gen 17 is "pan".; +#X text 23 19 Setting generators like for example:; +#X symbolatom 162 131 20 0 0 0 - - -, f 20; +#X obj 162 103 fluid.gen2sym; +#X text 164 147 a little helper; +#X obj 50 151 s \$0-fluid; +#X connect 2 0 11 0; +#X connect 3 0 5 1; +#X connect 3 0 9 0; +#X connect 4 0 5 0; +#X connect 5 0 2 0; +#X connect 9 0 8 0; +#X restore 435 214 pd generators; +#X text 435 239 A composition:; +#N canvas 400 273 610 524 dust 0; #X obj 119 135 del 10; -#X obj 119 41 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1 -; +#X obj 119 41 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 +0 1; #X floatatom 386 66 5 0 0 1 dustiness - -, f 5; #X floatatom 386 164 5 0 0 1 note_range - -, f 5; #X floatatom 387 198 5 0 0 1 note_center - -, f 5; -#X obj 237 417 s \$0-iiwu; #X obj 387 242 / 2; #X floatatom 387 223 5 0 0 1 pan_mod - -, f 5; #X msg 237 281 gen 1 17 \$1; @@ -112,7 +144,6 @@ to adapt to new samplerates.; #X obj 119 273 pack 0 0; #X obj 119 63 metro; #X obj 126 339 pack 0 0; -#X msg 126 371 note 1 \$1 \$2; #X obj 119 251 makenote 100 2; #X obj 119 212 + 60; #X obj 119 178 random 24; @@ -121,80 +152,61 @@ to adapt to new samplerates.; #X obj 198 108 t f f; #X text 98 11 Inspired by Hans-Christoph Steiner and Derek Holzer; #X text 15 11 __Dust__; -#X connect 0 0 9 0; -#X connect 0 0 17 0; -#X connect 1 0 12 0; -#X connect 2 0 18 1; -#X connect 3 0 17 1; -#X connect 4 0 16 1; -#X connect 6 0 10 1; -#X connect 7 0 6 0; -#X connect 7 0 9 1; -#X connect 8 0 5 0; -#X connect 9 0 10 0; -#X connect 10 0 8 0; -#X connect 11 0 19 0; -#X connect 12 0 0 0; -#X connect 12 0 18 0; -#X connect 13 0 14 0; -#X connect 14 0 5 0; -#X connect 15 0 11 0; -#X connect 15 1 11 1; -#X connect 16 0 15 0; -#X connect 17 0 16 0; -#X connect 18 0 20 0; -#X connect 19 1 13 0; -#X connect 19 2 13 1; -#X connect 20 0 0 1; -#X restore 709 715 pd dust; -#X text 601 716 A composition:; -#X msg 705 87 load /home/ico/Downloads/Soundfonts/jRhodes3.sf2; -#X obj 66 320 output~; -#X connect 9 0 13 0; -#X connect 10 0 13 0; -#X connect 11 0 10 0; -#X connect 12 0 11 0; -#X connect 17 0 18 0; -#X connect 17 1 18 1; -#X connect 17 2 18 2; -#X connect 18 0 22 0; -#X connect 19 0 20 0; -#X connect 21 0 70 0; -#X connect 22 0 23 0; -#X connect 28 0 30 0; -#X connect 29 0 27 0; -#X connect 30 0 27 0; +#X obj 237 417 s \$0-fluid; +#X msg 126 371 1 \$1 \$2; +#X connect 0 0 8 0; +#X connect 0 0 15 0; +#X connect 1 0 11 0; +#X connect 2 0 16 1; +#X connect 3 0 15 1; +#X connect 4 0 14 1; +#X connect 5 0 9 1; +#X connect 6 0 5 0; +#X connect 6 0 8 1; +#X connect 7 0 21 0; +#X connect 8 0 9 0; +#X connect 9 0 7 0; +#X connect 10 0 17 0; +#X connect 11 0 0 0; +#X connect 11 0 16 0; +#X connect 12 0 22 0; +#X connect 13 0 10 0; +#X connect 13 1 10 1; +#X connect 14 0 13 0; +#X connect 15 0 14 0; +#X connect 16 0 18 0; +#X connect 17 1 12 0; +#X connect 17 2 12 1; +#X connect 18 0 0 1; +#X connect 22 0 21 0; +#X restore 435 259 pd dust; +#X obj 182 169 pddp/pddplink https://bitbucket.org/agraef/pd-smmf; +#X text 86 390 load sf-file; +#X text 86 415 init [-smmf] sf-file; +#X obj 164 78 pddp/pddplink http://sourceforge.net/p/mscore/code/HEAD/tree/trunk/mscore/share/sound/TimGM6mb.sf2?format=raw +-text TimGM6mb.sf2 (sf.net); +#X connect 15 0 14 0; +#X connect 15 1 14 1; +#X connect 18 0 15 0; +#X connect 19 0 15 0; +#X connect 29 0 30 0; +#X connect 29 1 30 1; +#X connect 29 2 30 2; +#X connect 30 0 31 0; +#X connect 31 0 45 0; +#X connect 33 0 37 0; #X connect 34 0 33 0; -#X connect 35 0 33 0; -#X connect 36 0 34 0; -#X connect 37 0 40 0; -#X connect 38 0 35 0; -#X connect 39 0 29 0; -#X connect 40 0 20 0; -#X connect 40 0 21 0; -#X connect 41 0 42 0; -#X connect 41 1 42 1; -#X connect 41 2 42 2; -#X connect 42 0 60 0; -#X connect 43 0 44 0; -#X connect 43 1 44 1; -#X connect 44 0 46 0; -#X connect 46 0 45 0; -#X connect 48 0 33 0; -#X connect 49 0 48 0; -#X connect 51 0 52 0; -#X connect 52 0 37 0; -#X connect 55 0 58 0; -#X connect 56 0 58 0; -#X connect 57 0 58 0; -#X connect 58 0 77 0; -#X connect 58 1 77 1; -#X connect 60 0 27 0; -#X connect 63 0 64 0; -#X connect 65 0 67 1; -#X connect 65 0 72 0; -#X connect 66 0 67 0; -#X connect 67 0 63 0; -#X connect 70 0 19 0; -#X connect 72 0 71 0; -#X connect 76 0 13 0; +#X connect 34 1 33 1; +#X connect 34 2 33 2; +#X connect 35 0 36 0; +#X connect 35 1 36 1; +#X connect 36 0 44 0; +#X connect 37 0 45 0; +#X connect 38 0 39 0; +#X connect 39 0 53 0; +#X connect 40 0 41 0; +#X connect 41 0 53 0; +#X connect 44 0 45 0; +#X connect 46 0 48 0; +#X connect 47 0 46 0; +#X connect 49 0 50 0; diff --git a/externals/fluid~/fluid~.c b/externals/fluid~/fluid~.c index 8aca760cf1553c87f14a5bd4d53030be6f16341d..f9ab423a55521006bd0fa25d418e0a961bbf148f 100644 --- a/externals/fluid~/fluid~.c +++ b/externals/fluid~/fluid~.c @@ -1,4 +1,11 @@ +// Original version by Frank Barknecht (fbar@footils.org) 2003 +// Ported from Flext/C++ to plain C/pdlibbuilder by Jonathan Wilkes 2016 +// SMMF mode and various other little improvements by Albert Gräf 2020 +// Distributed under the GPLv2+, please check the LICENSE file for details. + #include <fluidsynth.h> +#include <string.h> +#include <unistd.h> #include "m_pd.h" @@ -10,8 +17,10 @@ typedef struct _fluid_tilde { fluid_settings_t *x_settings; t_outlet *x_out_left; t_outlet *x_out_right; + t_canvas *x_canvas; + int smmf_mode; } t_fluid_tilde; - + t_int *fluid_tilde_perform(t_int *w) { t_fluid_tilde *x = (t_fluid_tilde *)(w[1]); @@ -33,18 +42,20 @@ static void fluid_tilde_dsp(t_fluid_tilde *x, t_signal **sp) static void fluid_tilde_free(t_fluid_tilde *x) { - outlet_free(x->x_out_left); - outlet_free(x->x_out_right); + if (x->x_synth) delete_fluid_synth(x->x_synth); + if (x->x_settings) delete_fluid_settings(x->x_settings); } static void fluid_help(void) { const char * helptext = - "_ __fluid~_ _ a soundfont external for Pd and Max/MSP \n" - "_ argument: \"/path/to/soundfont.sf\" to load on object creation\n" - "_ messages: \n" - "load /path/to/soundfont.sf2 --- Loads a Soundfont \n" - "note 0 0 0 --- Play note. Arguments: \n" + "fluid~: a soundfont external for Pd and Max/MSP\n" + "options:\n" + "-smmf: enable SMMF mode (https://bitbucket.org/agraef/pd-smmf)\n" + "any other symbol: soundfont file to load on object creation\n" + "messages:\n" + "load /path/to/soundfont.sf2 --- Loads a Soundfont\n" + "note 0 0 0 --- Play note, arguments:\n" " channel-# note-# veloc-#\n" "n 0 0 0 --- Play note, same as above\n" "0 0 0 --- Play note, same as above\n" @@ -57,7 +68,7 @@ static void fluid_help(void) post("%s", helptext); } -static void fluid_note(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +static void fluid_legacy_note(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; if (argc == 3) @@ -70,7 +81,7 @@ static void fluid_note(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) } } -static void fluid_program_change(t_fluid_tilde *x, t_symbol *s, int argc, +static void fluid_legacy_program_change(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; @@ -79,11 +90,11 @@ static void fluid_program_change(t_fluid_tilde *x, t_symbol *s, int argc, int chan, prog; chan = atom_getintarg(0, argc, argv); prog = atom_getintarg(1, argc, argv); - fluid_synth_program_change(x->x_synth, chan - 1, prog); + fluid_synth_program_change(x->x_synth, chan - 1, prog - 1); } } -static void fluid_control_change(t_fluid_tilde *x, t_symbol *s, int argc, +static void fluid_legacy_control_change(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; @@ -97,7 +108,7 @@ static void fluid_control_change(t_fluid_tilde *x, t_symbol *s, int argc, } } -static void fluid_pitch_bend(t_fluid_tilde *x, t_symbol *s, int argc, +static void fluid_legacy_pitch_bend(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; @@ -110,7 +121,7 @@ static void fluid_pitch_bend(t_fluid_tilde *x, t_symbol *s, int argc, } } -static void fluid_bank(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +static void fluid_legacy_bank(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; if (argc == 2) @@ -122,7 +133,7 @@ static void fluid_bank(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) } } -static void fluid_gen(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +static void fluid_legacy_gen(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) return; if (argc == 3) @@ -136,27 +147,160 @@ static void fluid_gen(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) } } +// Note that in all the SMMF methods we allow the channel to be omitted, in +// which case it defaults to 1. Also note that the channel argument *always* +// comes last, and that the argument order, being in 1-1 correspondence with +// the Pd MIDI objects, is a bit different from the legacy message format +// above which follows the MIDI standard instead. + +// The system realtime messages start, stop, and cont are in SMMF, but not +// recognized by fluidsynth, so we don't support them here either. (MTS) sysex +// messages (which fluidsynth recognizes) are supported, however. + +// Please check https://bitbucket.org/agraef/pd-smmf for details. + +static void fluid_note(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode) + { + fluid_legacy_note(x, s, argc, argv); return; + } + if (x->x_synth == NULL) return; + if (argc == 2 || argc == 3) + { + int key = atom_getintarg(0, argc, argv); + int vel = atom_getintarg(1, argc, argv); + int chan = argc>2 ? atom_getintarg(2, argc, argv) : 1; + fluid_synth_noteon(x->x_synth, chan - 1, key, vel); + } +} + +static void fluid_ctl(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode || x->x_synth == NULL) return; + if (argc == 2 || argc == 3) + { + int val = atom_getintarg(0, argc, argv); + int ctrl = atom_getintarg(1, argc, argv); + int chan = argc>2 ? atom_getintarg(2, argc, argv) : 1; + fluid_synth_cc(x->x_synth, chan - 1, ctrl, val); + } +} + +static void fluid_pgm(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode || x->x_synth == NULL) return; + if (argc == 1 || argc == 2) + { + int prog = atom_getintarg(0, argc, argv); + int chan = argc>1 ? atom_getintarg(1, argc, argv) : 1; + fluid_synth_program_change(x->x_synth, chan - 1, prog - 1); + } +} + +static void fluid_polytouch(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode || x->x_synth == NULL) return; + if (argc == 2 || argc == 3) + { + int val = atom_getintarg(0, argc, argv); + int key = atom_getintarg(1, argc, argv); + int chan = argc>2 ? atom_getintarg(2, argc, argv) : 1; + fluid_synth_key_pressure(x->x_synth, chan - 1, key, val); + } +} + +static void fluid_touch(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode || x->x_synth == NULL) return; + if (argc == 1 || argc == 2) + { + int val = atom_getintarg(0, argc, argv); + int chan = argc>1 ? atom_getintarg(1, argc, argv) : 1; + fluid_synth_channel_pressure(x->x_synth, chan - 1, val); + } +} + +static void fluid_bend(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode) + { + fluid_legacy_pitch_bend(x, s, argc, argv); return; + } + if (x->x_synth == NULL) return; + if (argc == 1 || argc == 2) + { + int val = atom_getintarg(0, argc, argv); + int chan = argc>1 ? atom_getintarg(1, argc, argv) : 1; + fluid_synth_pitch_bend(x->x_synth, chan - 1, val); + } +} + +// Maximum size of sysex data (excluding the f0 and f7 bytes) that we can +// handle. The size below should be plenty to handle any kind of MTS message, +// which at the time of this writing is the only kind of sysex message +// recognized by fluidsynth. +#define MAXSYSEXSIZE 1024 + +static void fluid_sysex(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) +{ + if (!x->smmf_mode || x->x_synth == NULL) return; + if (argc > 0) + { + char buf[MAXSYSEXSIZE]; + int len = 0; + while (len < MAXSYSEXSIZE && len < argc) { + buf[len] = atom_getintarg(len, argc, argv); + len++; + } + // TODO: In order to handle bulk dump requests in the future, we will + // have to pick up fluidsynth's response here and output that to a + // control outlet (which doesn't exist at present). + fluid_synth_sysex(x->x_synth, buf, len, NULL, NULL, NULL, 0); + } +} + static void fluid_load(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth == NULL) { - post("No fluidsynth"); + pd_error(x, "fluid~: no fluidsynth"); return; } if (argc >= 1 && argv->a_type == A_SYMBOL) { const char* filename = atom_getsymbolarg(0, argc, argv)->s_name; - if (fluid_synth_sfload(x->x_synth, filename, 0) >= 0) + const char* ext = strrchr(filename, '.'); + if (ext && !strchr(ext, '/')) + // extension already supplied, no default extension + ext = ""; + else + ext = ".sf2"; + char realdir[MAXPDSTRING], *realname = NULL; + int fd = canvas_open(x->x_canvas, filename, ext, realdir, + &realname, MAXPDSTRING, 0); + if (fd < 0) { + pd_error(x, "fluid~: can't find soundfont %s", filename); + return; + } + // Save the current working directory. + char buf[MAXPDSTRING], *cwd = getcwd(buf, MAXPDSTRING); + sys_close(fd); + if (chdir(realdir)) {} + if (fluid_synth_sfload(x->x_synth, realname, 0) >= 0) { - post("Loaded Soundfont: %s", filename); + post("fluid~: loaded soundfont %s", realname); fluid_synth_program_reset(x->x_synth); } + // Restore the working directory. + cwd && chdir(cwd); } } static void fluid_init(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) { if (x->x_synth) delete_fluid_synth(x->x_synth); + if (x->x_settings) delete_fluid_settings(x->x_settings); float sr = sys_getsr(); @@ -164,7 +308,7 @@ static void fluid_init(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) if (x->x_settings == NULL) { - post("fluid~: couldn't create synth settings\n"); + pd_error(x, "fluid~: couldn't create synth settings\n"); } else { @@ -186,24 +330,31 @@ static void fluid_init(t_fluid_tilde *x, t_symbol *s, int argc, t_atom *argv) x->x_synth = new_fluid_synth(x->x_settings); if (x->x_synth == NULL ) { - post("fluid~: couldn't create synth\n"); + pd_error(x, "fluid~: couldn't create synth"); + } + // check for SMMF mode + const char* arg = atom_getsymbolarg(0, argc, argv)->s_name; + if (strcmp(arg, "-smmf") == 0) + { + x->smmf_mode = 1; argc--; argv++; } // try to load argument as soundfont fluid_load(x, gensym("load"), argc, argv); - //if (settings != NULL ) - // delete_fluid_settings(settings); // We're done constructing: if (x->x_synth) - post("-- fluid~ for Pd ---"); + post("-- fluid~ for Pd%s --", x->smmf_mode?" (SMMF mode)":""); } } static void *fluid_tilde_new(t_symbol *s, int argc, t_atom *argv) { t_fluid_tilde *x = (t_fluid_tilde *)pd_new(fluid_tilde_class); + x->x_synth = NULL; x->x_settings = NULL; x->x_out_left = outlet_new(&x->x_obj, &s_signal); x->x_out_right = outlet_new(&x->x_obj, &s_signal); + x->smmf_mode = 0; + x->x_canvas = canvas_getcurrent(); fluid_init(x, gensym("init"), argc, argv); return (void *)x; } @@ -211,38 +362,67 @@ static void *fluid_tilde_new(t_symbol *s, int argc, t_atom *argv) void fluid_tilde_setup(void) { fluid_tilde_class = class_new(gensym("fluid~"), - (t_newmethod)fluid_tilde_new, 0, sizeof(t_fluid_tilde), + (t_newmethod)fluid_tilde_new, (t_method)fluid_tilde_free, + sizeof(t_fluid_tilde), CLASS_DEFAULT, A_GIMME, 0); class_addmethod(fluid_tilde_class, (t_method)fluid_init, gensym("init"), A_GIMME, 0); class_addmethod(fluid_tilde_class, (t_method)fluid_load, gensym("load"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_note, gensym("note"), + + // "legacy" methods. These are 100% backwards-compatible, and are all + // enabled by default. NOTE: When in SMMF mode (-smmf), the "note" and + // "bend" messages actually invoke the corresponding SMMF methods below, + // while all other legacy methods still work (in particular, the "note" + // and "bend" shortcuts are still available). +#if 0 + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_note, gensym("note"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_program_change, +#endif + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_program_change, gensym("prog"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_control_change, + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_control_change, gensym("control"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_pitch_bend, +#if 0 + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_pitch_bend, gensym("bend"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_bank, gensym("bank"), +#endif + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_bank, gensym("bank"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_gen, gensym("gen"), + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_gen, gensym("gen"), A_GIMME, 0); - // list input calls fluid_note(...) - class_addlist(fluid_tilde_class, (t_method)fluid_note); + // list input calls fluid_legacy_note(...) + class_addlist(fluid_tilde_class, (t_method)fluid_legacy_note); // some alias shortcuts: - class_addmethod(fluid_tilde_class, (t_method)fluid_note, gensym("n"), + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_note, gensym("n"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_program_change, + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_program_change, gensym("p"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_control_change, + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_control_change, gensym("c"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_control_change, + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_control_change, gensym("cc"), A_GIMME, 0); - class_addmethod(fluid_tilde_class, (t_method)fluid_pitch_bend, gensym("b"), + class_addmethod(fluid_tilde_class, (t_method)fluid_legacy_pitch_bend, gensym("b"), + A_GIMME, 0); + + // SMMF methods (new interface methods for MIDI, enabled with -smmf) + // NOTE: When in the default legacy mode, fluid_note and fluid_bend + // actually invoke the corresponding legacy methods above. + class_addmethod(fluid_tilde_class, (t_method)fluid_note, gensym("note"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_ctl, gensym("ctl"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_pgm, gensym("pgm"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_polytouch, gensym("polytouch"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_touch, gensym("touch"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_bend, gensym("bend"), + A_GIMME, 0); + class_addmethod(fluid_tilde_class, (t_method)fluid_sysex, gensym("sysex"), A_GIMME, 0); // Simulate Flext's help message diff --git a/externals/fluid~/makefile b/externals/fluid~/makefile index 1ff4c32fc0432589e3bad2b1ddc9b97f2db2cb46..6d425af85a8716a14103d0b48f7c343704ec9e97 100755 --- a/externals/fluid~/makefile +++ b/externals/fluid~/makefile @@ -6,6 +6,6 @@ class.sources = fluid~.c ldlibs = -lfluidsynth -datafiles = fluid~-help.pd fluid.gen2sym.pd simple_onthego_synth.pd fluid.gen.txt LICENSE README +datafiles = fluid~-help.pd fluid.gen2sym.pd midi-input.pd mts-tuning.pd simple_onthego_synth.pd fluid.gen.txt LICENSE README include Makefile.pdlibbuilder.revised diff --git a/externals/fluid~/midi-input.pd b/externals/fluid~/midi-input.pd new file mode 100644 index 0000000000000000000000000000000000000000..f436fbfd83aa7fbb6b23a9463d2b8568e11ce638 --- /dev/null +++ b/externals/fluid~/midi-input.pd @@ -0,0 +1,103 @@ +#N canvas 542 308 583 345 10; +#X obj 24 50 ctlin; +#X obj 24 71 pack f f f; +#X msg 24 92 ctl \$1 \$2 \$3; +#X obj 126 70 pack f f f; +#X obj 223 70 pack f f f; +#X obj 126 49 notein; +#X msg 126 91 note \$1 \$2 \$3; +#X obj 223 49 polytouchin; +#X msg 223 91 polytouch \$1 \$2 \$3; +#X obj 22 121 pgmin; +#X obj 22 142 pack f f; +#X msg 22 163 pgm \$1 \$2; +#X obj 126 142 pack f f; +#X obj 223 142 pack f f; +#X obj 126 121 bendin 0 1; +#X msg 126 163 bend \$1 \$2; +#X obj 223 121 touchin; +#X msg 223 163 touch \$1 \$2; +#X obj 21 193 midiin; +#X obj 21 214 sel 250 251 252; +#X msg 21 235 start; +#X msg 50 257 cont; +#X msg 79 237 stop; +#X obj 222 259 outlet; +#X obj 410 21 sysexin; +#X obj 410 51 sel 240; +#X msg 410 75 1; +#X obj 410 172 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 449 76 spigot; +#X obj 449 103 moses 128; +#X msg 500 156 0; +#X obj 449 216 list prepend; +#X obj 410 194 swap 1; +#X obj 410 216 -; +#X obj 410 241 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 +1; +#X obj 300 254 spigot; +#X obj 500 128 t b b b; +#X obj 300 281 list prepend sysex; +#X obj 300 302 list trim; +#X text 320 316 sysex input - this is a bit tricky; +#X obj 536 241 t l; +#X text 20 7 This is a little helper patch which encodes MIDI messages +in a symbolic format used by some pd-pure plugins.; +#X connect 0 0 1 0; +#X connect 0 1 1 1; +#X connect 0 2 1 2; +#X connect 1 0 2 0; +#X connect 2 0 23 0; +#X connect 3 0 6 0; +#X connect 4 0 8 0; +#X connect 5 0 3 0; +#X connect 5 1 3 1; +#X connect 5 2 3 2; +#X connect 6 0 23 0; +#X connect 7 0 4 0; +#X connect 7 1 4 1; +#X connect 7 2 4 2; +#X connect 8 0 23 0; +#X connect 9 0 10 0; +#X connect 9 1 10 1; +#X connect 10 0 11 0; +#X connect 11 0 23 0; +#X connect 12 0 15 0; +#X connect 13 0 17 0; +#X connect 14 0 12 0; +#X connect 14 1 12 1; +#X connect 15 0 23 0; +#X connect 16 0 13 0; +#X connect 16 1 13 1; +#X connect 17 0 23 0; +#X connect 18 0 19 0; +#X connect 19 0 20 0; +#X connect 19 1 21 0; +#X connect 19 2 22 0; +#X connect 20 0 23 0; +#X connect 21 0 23 0; +#X connect 22 0 23 0; +#X connect 24 0 25 0; +#X connect 25 0 26 0; +#X connect 25 1 28 0; +#X connect 26 0 27 0; +#X connect 27 0 28 1; +#X connect 27 0 32 0; +#X connect 28 0 29 0; +#X connect 29 0 31 0; +#X connect 29 1 36 0; +#X connect 30 0 27 0; +#X connect 31 0 35 0; +#X connect 31 0 40 0; +#X connect 32 0 33 0; +#X connect 32 1 33 1; +#X connect 33 0 34 0; +#X connect 34 0 35 1; +#X connect 35 0 37 0; +#X connect 36 0 31 1; +#X connect 36 1 31 0; +#X connect 36 2 30 0; +#X connect 37 0 38 0; +#X connect 38 0 23 0; +#X connect 40 0 31 1; diff --git a/externals/fluid~/mts-tuning.pd b/externals/fluid~/mts-tuning.pd new file mode 100644 index 0000000000000000000000000000000000000000..a5feb0eed3bd6655408acea8d97e53bd83687a91 --- /dev/null +++ b/externals/fluid~/mts-tuning.pd @@ -0,0 +1,24 @@ +#N canvas 513 180 490 406 12; +#X obj 90 183 midi-input; +#X obj 33 262 output~; +#X obj 33 233 fluid~ -smmf TimGM6mb; +#X text 20 327 Download Tim Brechbill's small (~6MB) GM soundfont here: +; +#X obj 19 375 pddp/pddplink https://musescore.org/en/handbook/soundfonts-and-sfz-files#list +-text More soundfonts here (musescore.org); +#X obj 19 351 pddp/pddplink http://sourceforge.net/p/mscore/code/HEAD/tree/trunk/mscore/share/sound/TimGM6mb.sf2?format=raw +-text TimGM6mb.sf2 (sf.net); +#X msg 219 184 pgm 20 1 \, pgm 20 2 \, pgm 20 3; +#X msg 33 41 sysex 127 127 8 8 3 127 127 64 64 64 64 64 64 64 64 64 +64 64 64, f 33; +#X msg 33 91 sysex 127 127 8 8 3 127 127 74 50 67 85 61 78 54 71 47 64 81 57, f 33; +#X text 218 157 church organ on channels 1-3; +#X text 288 48 12-tet (default tuning); +#X text 286 91 quarter-comma meantone (has wolf fifth at Ab - Eb), +f 27; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 2 1 1 1; +#X connect 6 0 2 0; +#X connect 7 0 2 0; +#X connect 8 0 2 0; diff --git a/externals/fluid~/simple_onthego_synth.pd b/externals/fluid~/simple_onthego_synth.pd index f4227d17e52ce022e49d0c505e1a98beb86b4630..19de30e5201604ce3756c671d12e3e094a07ea5f 100644 --- a/externals/fluid~/simple_onthego_synth.pd +++ b/externals/fluid~/simple_onthego_synth.pd @@ -1,5 +1,4 @@ -#N canvas 480 117 389 508 10; -#X declare -lib maxlib; +#N canvas 480 116 390 511 10; #X obj 25 197 notein; #X obj 25 222 + 0; #X obj 25 20 key; @@ -7,16 +6,20 @@ #X msg 25 64 -12; #X msg 50 85 12; #X obj 25 117 +; -#X obj 109 134 nbx 3 88 -60 60 0 0 empty empty empty 0 -8 0 70 -262144 --1 -1 0 256 1; +#X obj 109 134 nbx 3 88 -60 60 0 0 empty empty empty 0 -8 0 70 #fcfcfc +#000000 #000000 0 256 1; #X obj 25 253 pack 0 0 0; #X msg 25 275 \$3 \$1 \$2; -#X obj 25 296 fluid~ /home/l2orkist/Downloads/Soundfonts/jRhodes3.sf2 +#X obj 139 295 loadbang; +#X obj 25 296 fluid~ TimGM6mb; +#X obj 25 357 output~; +#X msg 139 320 1; +#X text 24 431 Download Tim Brechbill's small (~6MB) GM soundfont here: ; -#X obj 26 377 l2ork_output~; -#X obj 105 334 loadbang; -#X obj 36 350 freeverb~; -#X obj 105 355 t 50 1; +#X obj 23 479 pddp/pddplink https://musescore.org/en/handbook/soundfonts-and-sfz-files#list +-text More soundfonts here (musescore.org); +#X obj 23 455 pddp/pddplink http://sourceforge.net/p/mscore/code/HEAD/tree/trunk/mscore/share/sound/TimGM6mb.sf2?format=raw +-text TimGM6mb.sf2 (sf.net); #X connect 0 0 1 0; #X connect 0 1 8 1; #X connect 0 2 8 2; @@ -30,10 +33,8 @@ #X connect 7 0 6 1; #X connect 7 0 1 1; #X connect 8 0 9 0; -#X connect 9 0 10 0; +#X connect 9 0 11 0; #X connect 10 0 13 0; -#X connect 10 0 11 0; -#X connect 12 0 14 0; -#X connect 13 0 11 0; -#X connect 14 0 11 6; -#X connect 14 1 11 7; +#X connect 11 0 12 0; +#X connect 11 1 12 1; +#X connect 13 0 12 2; diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 800a9c31bbef89a4a90ab079c0a785320c48802c..64e80ab85453a7bca051f3509c3a068ff54e36fd 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -5796,7 +5796,7 @@ function gui_dropdown_dialog(did, attr_array) { // Just reuse the "gatom" dialog (this is not true anymore, see below) // ico@vt.edu 2020-08-21: made this into a separate dialog due to inability to easily retitle // the window - dialogwin[did] = create_window(did, "dropdown", 222, 268-5, + dialogwin[did] = create_window(did, "dropdown", 228, 268-5, popup_coords[2], popup_coords[3], attr_array_to_object(attr_array)); // ico@vt.edu 2020-08-21: the following does not work because the window is not created yet? diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h index 6b7201108237274a4b9b87e44e40cde5dcee1e9d..f4eb4ebcc8560805573167874b2a632760b0c653 100644 --- a/pd/src/m_pd.h +++ b/pd/src/m_pd.h @@ -14,7 +14,7 @@ extern "C" { #define PD_MINOR_VERSION 48 #define PD_BUGFIX_VERSION 0 #define PD_TEST_VERSION "" -#define PD_L2ORK_VERSION "2.15.0" +#define PD_L2ORK_VERSION "2.15.1" #define PDL2ORK extern int pd_compatibilitylevel; /* e.g., 43 for pd 0.43 compatibility */