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;