fluidsynth - a Lua interface to the fluidsynth library
local FS = require 'fluidsynth' -- convert midi to wav local soundfonts = FS.read_config_file() -- default is ~/.fluidsynth local synth1 = FS.new_synth( { ['synth.gain'] = 0.4, -- be careful... ['audio.driver'] = 'file', -- overrides the config file ['audio.file.name'] = 'foo.wav', ['fast.render'] = true, -- not part of the C-library API } ) FS.sf_load(synth1, soundfonts) local player1 = FS.new_player(synth1,'foo.mid') assert(FS.player_play(player1)) assert(FS.player_join(player1)) -- wait for foo.mid to finish os.execute('sleep 1') -- don't chop final reverb FS.delete_synth(synth1) -- deletes player,audio_driver,synth,settings os.remove(FS.error_file_name()) -- remove tmp file
local FS = require 'fluidsynth' -- an alsa-client soundfont-synth local ALSA = require 'midialsa' ALSA.client( 'fluidsynth-alsa-client', 1, 0 ) ALSA.connectfrom( 0, 'Keystation' ) local soundfonts = FS.read_config_file('/unusual/config_file') local synth2 = FS.new_synth( { ['audio.driver'] = 'pulseaudio', ['audio.periods'] = 2, -- min, for low latency ['audio.period-size'] = 64, -- min, for low latency } ) FS.sf_load(synth2, soundfonts) -- you will need to set a patch before any output can be generated! while true do local alsaevent = ALSA.input() if alsaevent[1]==ALSA.SND_SEQ_EVENT_PORT_UNSUBSCRIBED then break end FS.play_event(synth2, alsaevent) end FS.delete_synth(synth2) os.remove(FS.error_file_name()) -- remove tmp file
This Lua module offers a simplified calling interface to the Fluidsynth Library.
It is a relatively thick wrapper. Various higher-level functions are introduced, the library's voluminous output on stderr has been redirected so the module can be used for example within a Curses app, and the return codes on failure have adopted the nil,errormessage convention of Lua so they can be used for example with assert().
These higer-level functions wrap the fluidsynth library
functions in a way that retains functionality,
but is easy to use and hides some of the dangerous internals.
Unless otherwise stated,
these functions all return nil,errormessage on failure.
Included are basic functions:
read_config_file,
new_synth,
sf_load,
delete_synth,
functions for playing midi files:
new_player,
player_play,
player_join,
player_stop,
functions for playing in real-time:
note_on,
note_off,
patch_change,
control_change,
pitch_bend,
play_event,
functions returning state:
is_soundfont,
is_midifile,
default_settings,
all_synth_errors,
error_file_name,
get
If filename is nil,
the default configuration file is $HOME/.fluidsynth
and if that does not exist then /etc/fluidsynth.conf
This file can also be used as a configuration file for the fluidsynth executable (except that fluidsynth is not able to use the set commands); for example:
fluidsynth -f ~/.fluidsynth
This module only recognises set, load and select commands; see man fluidsynth
In the following example, the select command chooses:
for channel 9,
from soundfont 1 (Chaos4m.sf2) the bank 127
patch 99, which happens to be a percussion set,
as you typically want on channel 9.
This is the format:
set audio.driver pulseaudio set synth.polyphony 1024 load /home/soundfonts/Chaos4m.sf2 load /home/soundfonts/MyGM.sf2 load /home/soundfonts/ReallyGoodPiano.sf2 select 9 1 127 99
Invoking the function soundfonts = FS.read_config_file() (before creating the first synth!) then changes the default settings for audio.driver and synth.polyphony, and returns an array of load and select commands ready for later use by sf_load(synth,soundfonts)
When called with no argument, or with a table argument, new_synth wraps the library routines new_fluid_synth(), invoking new_fluid_settings, fluid_settings_setstr(), fluid_settings_setnum(), fluid_settings_setint(), and new_fluid_audio_driver() automatically as needed.
The return value is a C pointer to the synth, so don't change that or the library will crash.
Multiple synths may be started.
The meanings and permitted values of the various parameters are documented in fluidsynth.sourceforge.net/api/ with just two additions:
This wraps the library routine fluid_synth_sfload(), calling it once for each soundfont. Often, a synth has more than one soundfont; they go onto a sort of stack, and for a given patch, fluidsynth will use that soundfont closest to the top of the stack which can supply the requested patch. In the above example, my_gm.sf2 is a good general-midi soundfont, except that my_piano.sf2 offers a much nicer piano sound.
In practice, the array of soundfonts will usually be the output of a
previous call to read_config_file()
Since version 1.7 it can include both load and select commands.
It returns a table where the keys are filenames of the soundfonts, and the values are the soundfont_ids that represent them. The soundfont_ids are stack indexes starting from 1; They are only needed if you want to invoke fluid_synth_sfont_select(), fluid_synth_sfunload() or fluid_synth_sfreload(), so in most cases you can ignore the return value.
This does all the administrivia necessary to delete the synth, invoking delete_fluid_player, delete_fluid_audio_driver, delete_fluid_synth and delete_fluid_settings as necessary.
When called with no argument it deletes all running synths.
This wraps the library routines new_fluid_player(), and then fluid_player_add() or fluid_player_add_mem(), allowing you to play a MIDI file. The return value is a C pointer.
One synth may have multiple midi_players running at the same time (eg: to play several midi files, each starting at a different moment). Therefore, you still need to call player_play(player), player_join(player) and player_stop(player) by hand.
This corresponds to the library routine fluid_player_play()
This corresponds to the library routine fluid_player_join()
It waits until the midiplayer has got to the end of the last note
in its midi file.
This calls the library routines fluid_player_stop() and delete_fluid_player()
This corresponds to the library routine fluid_synth_noteon()
This corresponds to the library routine fluid_synth_noteoff()
This corresponds to the library routine fluid_synth_program_change()
This corresponds to the library routine fluid_synth_cc()
The fluidsynth C-library implements only a selection of controllers:
0 (bank select), 1 (modulation), 7 (channel volume), 10 (pan),
11 (expression), 64 (sustain pedal); also 91 (reverb), and 93 (chorus).
The last two depend on the corresponding generator as defined in the SoundFont.
This corresponds to the library routine fluid_synth_pitch_bend(). The value should lie between 0 and 16383, where 8192 represents the default, central, pitch-wheel position.
(Note that midialsa uses a different convention, in which the value is from -8192 to 8191 and 0 represents the central position.)
This is a wrapper for the above note_on, note_off, patch_change, control_change and pitch_bend routines, which accepts events of two different types used in the author's other midi-related modules:
It will currently only handle real-time events, so every event received will be played immediately. It will currently not handle 'note' events (of either type).
This corresponds to the library routine fluid_is_soundfont() which checks for the "RIFF" header in the file. It is useful only to distinguish between SoundFont and MIDI files. It returns only true or false.
This corresponds to the library routine fluid_is_midifile() The current implementation only checks for the "MThd" header in the file. It is useful only to distinguish between SoundFont and MIDI files. It returns only true or false.
Returns a table of all the supported parameters, with their default values. This could be useful, for example, in an application, to offer the user a menu of available parameters.
The meanings and permitted values of the various parameters are documented in fluidsynth.sourceforge.net/api/
Returns a multi-line string containing all the C-library's stderr output.
Returns the file-name of the temporary-file used to hold all the C-library's
stderr output. This file is not removed automatically by
delete_synth() because during the lifetime of
the process many synths may be started and stopped.
Therefore the application should explicity remove the file just before exit:
os.remove(FS.error_file_name())
Returns the current value of the setting of parameter, invoking either fluid_settings_getstr(), fluid_settings_getnum() or fluid_settings_getint(), as appropriate.
These are also available in the examples directory in the tarball.
See:
luarocks.org/modules/peterbillam/fluidsynth/,
choose the latest version, click on src and download it,
unzip the .src.rock, then un-tar the .tar.gz.
This module is available as a LuaRock in
luarocks.org/modules/peterbillam
so you should be able to install it with the command:
$ su
Password:
# luarocks install fluidsynth
or:
# luarocks install https://pjb.com.au/comp/lua/fluidsynth-2.3-0.rockspec
It depends on the fluidsynth library and its header-files;
for example on Debian you may need:
# aptitude install libfluidsynth1 libfluidsynth-dev
or on Centos you may need:
# yum install fluidsynth-devel
You can see the source-code in:
https://pjb.com.au/comp/lua/fluidsynth-2.3.tar.gz
20201103 2.3 adapt to gcc9 and libfluidsynth 2.1 20171112 2.1 fix compiler warnings on 64-bit machines 20150424 2.0 keep ptrs in C arrays and return indexes; C returns nil on error 20150421 include lua5.3, and move pod and doc back to luarocks.org 20140913 1.8 introduce get(synth, parameter) to get a current setting 20140904 1.7 get both 'load' and 'select' commands from the config file 20140901 1.6 delete_synth doesn't automatically remove TmpFile 20140830 1.5 new_player knows '-' is stdin, and can play in-memory MIDI-data 20140828 1.4 eliminate Settings2numSynths and M.delete_settings 20140827 1.3 use fluid_get_sysconf, fluid_get_userconf, config file 'set k v' 20140826 1.2 sf_load takes 2nd arg as an array; ~/.config/fluidsynth k = v 20140825 1.1 new calling-interface at much higher level 20140818 1.0 first working version
Peter Billam https://pjb.com.au/comp/contact.html
man fluidsynth /usr/include/fluidsynth.h /usr/include/fluidsynth/*.h /usr/share/soundfonts/*.sf2 /usr/share/sounds/sf2/*.sf2 http://fluidsynth.sourceforge.net/api/ http://www.pjb.com.au http://www.pjb.com.au/muscript/gm.html http://www.pjb.com.au/comp/index.html#lua http://www.pjb.com.au/comp/lua/fluidsynth.html http://www.pjb.com.au/comp/lua/midialsa.html http://www.pjb.com.au/comp/lua/MIDI.html http://www.pjb.com.au/midi/fluadity.html http://www.pjb.com.au/midi/midi2wavs.html