From: Robin Gareus Date: Tue, 23 Aug 2016 20:17:46 +0000 (+0200) Subject: add basic libardour wrapper for fluidsynth (for Lua bindings) X-Git-Tag: 5.1~22 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=2d5166606b2b18bda0dbe615cc07759c5a1263e2;p=ardour.git add basic libardour wrapper for fluidsynth (for Lua bindings) --- diff --git a/libs/ardour/ardour/fluid_synth.h b/libs/ardour/ardour/fluid_synth.h new file mode 100644 index 0000000000..80fdea2f50 --- /dev/null +++ b/libs/ardour/ardour/fluid_synth.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 Robin Gareus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef _ardour_fluidsynth_h_ +#define _ardour_fluidsynth_h_ + +#include +#include +#include + +#include "ardour/libardour_visibility.h" +#include "ardour/types.h" + +#include "fluidsynth.h" + +namespace ARDOUR { + + class LIBARDOUR_API FluidSynth { + public: + /** instantiate a Synth + * + * @param samplerate samplerate + */ + FluidSynth (float samplerate, int polyphony = 32); + ~FluidSynth (); + + bool load_sf2 (const std::string& fn); + + bool synth (float* left, float* right, uint32_t n_samples); + bool midi_event (uint8_t const* const data, size_t len); + void panic (); + + /* load a preset + * @pgm BankProgram index + * @chan midi channel (0..15) + * @return true on succcess + */ + bool select_program (uint32_t pgm, uint8_t chan); + + uint32_t program_count () const { return _presets.size(); } + + std::string program_name (uint32_t pgm) const { + if (pgm >= _presets.size()) { return ""; } + return _presets[pgm].name; + } + + private: + fluid_settings_t* _settings; + fluid_synth_t* _synth; + int _synth_id; + fluid_midi_event_t* _f_midi_event; + + struct BankProgram { + BankProgram (const std::string& n, int b, int p) + : name (n) + , bank (b) + , program (p) + {} + + BankProgram (const BankProgram& other) + : name (other.name) + , bank (other.bank) + , program (other.program) + {} + + std::string name; + int bank; + int program; + }; + + std::vector _presets; + }; + +} /* namespace */ +#endif diff --git a/libs/ardour/fluid_synth.cc b/libs/ardour/fluid_synth.cc new file mode 100644 index 0000000000..df856af561 --- /dev/null +++ b/libs/ardour/fluid_synth.cc @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 Robin Gareus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "pbd/failed_constructor.h" +#include "ardour/fluid_synth.h" + +using namespace ARDOUR; + +FluidSynth::FluidSynth (float samplerate, int polyphony) + : _settings (0) + , _synth (0) + , _f_midi_event (0) +{ + _settings = new_fluid_settings (); + + if (!_settings) { + throw failed_constructor (); + } + + _f_midi_event = new_fluid_midi_event (); + + if (!_f_midi_event) { + throw failed_constructor (); + } + + fluid_settings_setnum (_settings, "synth.sample-rate", samplerate); + fluid_settings_setint (_settings, "synth.parallel-render", 1); + fluid_settings_setint (_settings, "synth.threadsafe-api", 0); + + _synth = new_fluid_synth (_settings); + + fluid_synth_set_gain (_synth, 1.0f); + fluid_synth_set_polyphony (_synth, polyphony); + fluid_synth_set_sample_rate (_synth, (float)samplerate); +} + +FluidSynth::~FluidSynth () +{ + delete_fluid_synth (_synth); + delete_fluid_settings (_settings); + delete_fluid_midi_event (_f_midi_event); +} + +bool +FluidSynth::load_sf2 (const std::string& fn) +{ + _synth_id = fluid_synth_sfload (_synth, fn.c_str (), 1); + if (_synth_id == FLUID_FAILED) { + return false; + } + + fluid_sfont_t* const sfont = fluid_synth_get_sfont_by_id (_synth, _synth_id); + if (!sfont) { + return false; + } + + size_t count; + fluid_preset_t preset; + + sfont->iteration_start (sfont); + for (count = 0; sfont->iteration_next (sfont, &preset) != 0; ++count) { + _presets.push_back (BankProgram ( + preset.get_name (&preset), + preset.get_banknum (&preset), + preset.get_num (&preset))); + } + + if (count == 0) { + return false; + } + + select_program (0, 0); + + return true; +} + +bool +FluidSynth::select_program (uint32_t pgm, uint8_t chan) +{ + if (pgm >= _presets.size ()) { + return false; + } + const BankProgram& bp = _presets[pgm]; + return FLUID_OK == fluid_synth_program_select (_synth, chan, _synth_id, bp.bank, bp.program); +} + +void +FluidSynth::panic () +{ + fluid_synth_all_notes_off (_synth, -1); + fluid_synth_all_sounds_off (_synth, -1); +} + +bool +FluidSynth::synth (float* left, float* right, uint32_t n_samples) +{ + return FLUID_OK == fluid_synth_write_float (_synth, n_samples, left, 0, 1, right, 0, 1); +} + +bool +FluidSynth::midi_event (uint8_t const* const data, size_t len) +{ + if (len > 3) { + return false; + } + fluid_midi_event_set_type (_f_midi_event, data[0] & 0xf0); + fluid_midi_event_set_channel (_f_midi_event, data[0] & 0x0f); + if (len > 1) { + fluid_midi_event_set_key (_f_midi_event, data[1]); + } + if (len > 2) { + fluid_midi_event_set_value (_f_midi_event, data[2]); + } + return FLUID_OK == fluid_synth_handle_midi_event (_synth, _f_midi_event); +} diff --git a/libs/ardour/wscript b/libs/ardour/wscript index d85e6a4d4a..a3ec926485 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -95,6 +95,7 @@ libardour_sources = [ 'filter.cc', 'find_session.cc', 'fixed_delay.cc', + 'fluid_synth.cc', 'gain_control.cc', 'globals.cc', 'graph.cc', @@ -396,9 +397,9 @@ def build(bld): if bld.env['build_target'] != 'mingw': obj.uselib += ['DL'] if bld.is_defined('USE_EXTERNAL_LIBS'): - obj.uselib.extend(['VAMPSDK', 'LIBLTC']) + obj.uselib.extend(['VAMPSDK', 'LIBLTC', 'LIBFLUIDSYNTH']) else: - obj.use.extend(['librubberband', 'libltc_includes', 'libltc']) + obj.use.extend(['librubberband', 'libltc_includes', 'libltc', 'libfluidsynth_includes', 'libfluidsynth']) obj.vnum = LIBARDOUR_LIB_VERSION obj.install_path = bld.env['LIBDIR'] @@ -497,9 +498,9 @@ def build(bld): testcommon.use = ['libpbd','libmidipp','libevoral', 'libaudiographer','libardour'] if bld.is_defined('USE_EXTERNAL_LIBS'): - testcommon.uselib.extend(['LIBLTC',]) + testcommon.uselib.extend(['LIBLTC', 'LIBFLUIDSYNTH']) else: - testcommon.use.extend(['libltc', 'librubberband']) + testcommon.use.extend(['libltc', 'librubberband', 'libfluidsynth']) testcommon.defines = [ 'PACKAGE="libardour' + str(bld.env['MAJOR']) + 'test"', 'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"', @@ -617,9 +618,9 @@ def create_ardour_test_program(bld, includes, name, target, sources): testobj.use = ['libpbd','libmidipp','libevoral', 'libaudiographer','libardour','testcommon'] if bld.is_defined('USE_EXTERNAL_LIBS'): - testobj.uselib.extend(['LIBLTC']) + testobj.uselib.extend(['LIBLTC', 'LIBFLUIDSYNTH']) else: - testobj.use.extend(['libltc']) + testobj.use.extend(['libltc', 'libfluidsynth']) testobj.name = name testobj.target = target