prof-spock / FluidSynthPlugin

Simple Wrappers Around the FluidSynth Library as DAW Plugin and Pedantic Command Line Processor
5 stars 0 forks source link

FluidSynth Plugin for DAWs and Pedantic FluidSynth Command Line Processor

Overview

FluidSynth is one of the most prominent open source MIDI players. It is reasonably flexible, delivers a good audio quality and is available for the typical platforms. A common scenario is to use it for either rendering live MIDI data on some audio device or converting MIDI files into audio files by command-line batch processing.

Basis of FluidSynth are the so-called soundfonts. Soundfonts contain sampled instruments together with envelope and modulation definitions and other descriptive settings. It is easy to find really usable ones in the internet and also several of those cover all general MIDI instruments (for example, the FluidR3_GM.sf2).

So when using FluidSynth in a command-line driven context all is well. But when you want play around with settings for FluidSynth interactively in a DAW, you need some approximation of the command-line fluidsynth as a DAW plugin rendering audio from MIDI as close as possible to the original.

There were some previous efforts like Alexey Zhelezov's FluidSynthVST or Birch Labs' JuicySFPlugin, but those are a bit tricky to use and support for them is unclear. But the main point is that even though they rely on the FluidSynth library, they do not exactly reproduce an external fluidsynth rendition of some MIDI data. Reasons for that will be explained below.

The reason for being picky about the exact rendering is as follows: my scenario is a command-line based rendering of notation videos for a band (the LilypondToBandVideoConverter). Part of that chain is FluidSynth, but I want to experiment interactively with settings in a DAW to optimize the audio and then have a faithful reproduction of the external rendering pipeline within the DAW.

The first component of this package is a DAW plugin called FluidSynthPlugin. It has a simplistic interface where you specify a soundfont, several fluidsynth settings and possibly a MIDI program to be selected by putting text data in a text field. Then you are able to convert an incoming MIDI stream in a DAW to audio using the FluidSynth library.

When playing around with that plugin some inexplicable differences to the command-line FluidSynth occured. Even when using innocent soundfonts (without chorus and other modulators), sample playback in the plugin and the command-line player were not absolutely identical. Analysis and contact with the FluidSynth team revealed that in that program MIDI events are quantized onto some processing raster in the millisecond range while the plugin quantizes them onto the smallest time unit: the sample raster itself.

Hence another tool in this package circumvents the rasterization by the player of FluidSynth. That second component is a simplistic but pedantic command-line converter called FluidSynthConverter. It converts a MIDI file into a WAV file, is also based on the fluidsynth library and does the same sample-exact event feeding into that library as the plugin.

When using both components (command-line and DAW) on the same MIDI data they typically produce audio output with a difference of less than -200dBFS in a spectrum analysis.

Those components are currently available - as x86_64 versions - for Windows and Linux as VST3, for MacOSX as VST3 and AU.

All the code is open-source; hence you can check and adapt it to your needs.

Installation

The installation is as follows:

  1. Expand the appropriate binary archive of FluidSynthPlugin for your platform from this repository into the directory for VST plugins of your DAW.

  2. The distribution also contains a documentation pdf file in subdirectory doc and test files in subdirectory test (for details on the regression test see below).

  3. When installing the plugins and program on Windows, they require the so-called Microsoft Visual C++ Redistributable library. Very often this is already installed on your system; if not, you have to install it from the Microsoft site.

  4. Restart your DAW and rescan the plugins. You should now be able to select the FluidSynthPlugin.

  5. The command-line version FluidSynthFileConverter can be put in an arbitrary location for executables. Ensure that the dynamic libraries in its directory are also placed appropriately.

Usage

FluidSynthPlugin

Panel for FluidSynthPlugin

The above diagram shows the UI for the FluidSynthPlugin. It is very simplistic: a multiline edit field can be used for command entry. In this multiline field FluidSynth commands and some extension can be written (like e.g. synth.chorus.active, synth.reverb.level or program). Each command is on a single line followed by an equal sign and its associated value.

Edits have to be confirmed with the "Confirm"-button and then the audio output is active.

Note that the plugin listens to all MIDI channels, but is not multi-timbral (i.e. only a single sound can be produced as specified by the "program" setting or program changes within the MIDI event stream).

FluidSynthFileConverter

The FluidSynthFileConverter is merely a functionally reduced clone of FluidSynth, but with a special property: it places MIDI events onto the raster given by the sample rate (as far as possible).

Similarly to FluidSynth, the FluidSynthFileConverter is a command-line program. But the converter does not have to do real-time processing, so the list of its options is reduced, but it is a subset of the options of FluidSynth. On top of that it only supports a conversion from a MIDI file into an audio file.

E.g. the command

fluidSynthFileConverter -g 1.0 -R 0 test.mid FluidR3_GM.sf2 -F test.wav

produces a wave file test.wav from MIDI file test.mid using sound font FluidR3_GM.sf2 with reverb set to inactive and gain set to unity.

Testing the Plugin and the Command-Line Processor

The test script makeTestFiles.bat or makeTestFiles.sh in the test directory assumes that the FluidSynthFileConverter is available in the program search path.

The test script produces a sound file from a demo MIDI file.

Since there are so many DAWs available, it is hard to provide a test project for each of those. The distribution contains a Reaper project file testFluidSynthPlugin.rpp referencing that audio test file and the originating MIDI file in two tracks. Adaption to other DAW should be straightforward.

Ideally (because the result files have inverted phase), everything should cancel out as shown here:

Example Noise Floor for Regression
Test

Restrictions

Missing Timelocking Functionality

To be able to reproduce the phase of modulators in an external audio file within a plugin, one could use a parameter telling the relative time of the plugin with respect to the externally rendered audio. While this method would lead to perfect reproduction of the external rendering, it is not feasible for the FluidSynthPlugin. There is no direct way to set the modulators in the underlying FluidSynth library to a specific phase. Another approach is to reset all modulators at playback start and first silently have the synthesizer process samples for some duration (to bring its modulators to the correct phases) before then finally putting out the "real" samples. But this is tedious, takes a lot of processing time and also does not help in a situation where the playback has to start before the start time of the corresponding fragment.

So when you need a bit-exact reproduction of externally rendered audio by the FluidSynthPlugin, some workaround has to be made as follows:

Forced Rasterization by FluidSynth

As mentioned in the introduction the important difference between using the standard FluidSynth from the command-line versus from a DAW is that there is a forced rasterization to 64 samples' intervals.

Unfortunately this rasterization is not just done by FluidSynth when communicating with audio drivers or its file renderer, but also done internally by the fluidsynth synthesizer in the library. The length of the smallest unit for which FluidSynth can make state changes and does buffering is a constant called FLUID_BUFSIZE and this is fixed to the value 64.

As a workaround a script can help, when your DAW allows to change the loop interval and also the play head position via its API. As an example a Lua script is provided for the Reaper DAW for demonstration purposes.

Details

A more thorough discussion can be found in the detailed user manual here.

Acknowledgements

This project is a derivative work based on the foundations laid by the FluidSynth community.

My thanks go to the FluidSynth team: Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson and Tom Moebert. Without your effort this would not have been possible!

Special thanks go to S. Christian Collins for very helpful discussions and his suggestions to improve the plugin, especially the great input to enhance the user interface beyond the original academic approach.