zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 70678af0705b2c3e6be2c7397a8d05643a9a1747
parent 584ba99a897d1548581467840ba7dafe31904078
Author: Olivier Jolly <olivier@pcedev.com>
Date:   Mon, 30 Nov 2015 17:31:00 +0100

DSSI: allow multiple independant instances to run within a single host process and be controlled separately

Until now, the returned DSSI instance was a static instance and DSSI controls were incorrectly shared among all plugin instanciations within a single host process.
Thanks to taktik@renoise for pointing it out.

Diffstat:
Msrc/CMakeLists.txt | 11+++++++----
Asrc/Output/DSSIControl.cpp | 28++++++++++++++++++++++++++++
Asrc/Output/DSSIControl.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/DSSIControlDescription.cpp | 39+++++++++++++++++++++++++++++++++++++++
Asrc/Output/DSSIControlDescription.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Output/DSSIaudiooutput.cpp | 57++++++++++++++++++++++++++-------------------------------
Msrc/Output/DSSIaudiooutput.h | 63+++------------------------------------------------------------
7 files changed, 235 insertions(+), 95 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt @@ -428,10 +428,13 @@ target_link_libraries(zynaddsubfx if (DssiEnable) add_library(zynaddsubfx_dssi SHARED - UI/ConnectionDummy.cpp - Output/DSSIaudiooutput.cpp - globals.cpp - ) + UI/ConnectionDummy.cpp + Output/DSSIaudiooutput.cpp + globals.cpp + Output/DSSIControl.cpp + Output/DSSIControl.h + Output/DSSIControlDescription.cpp + Output/DSSIControlDescription.h) target_link_libraries(zynaddsubfx_dssi zynaddsubfx_core diff --git a/src/Output/DSSIControl.cpp b/src/Output/DSSIControl.cpp @@ -0,0 +1,28 @@ +/* + ZynAddSubFX - a software synthesizer + + DSSIControl.cpp - DSSI control ports "controller" + Copyright (C) 2015 Olivier Jolly + Author: Olivier Jolly + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "DSSIControl.h" +#include "../Misc/Master.h" + +void DSSIControl::forward_control(Master *master) { + master->setController(0, description.controller_code, get_scaled_data()); +} diff --git a/src/Output/DSSIControl.h b/src/Output/DSSIControl.h @@ -0,0 +1,66 @@ +/* + ZynAddSubFX - a software synthesizer + + DSSIControl.h - DSSI control ports "controller" + Copyright (C) 2015 Olivier Jolly + Author: Olivier Jolly + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ZYNADDSUBFX_DSSICONTROL_H +#define ZYNADDSUBFX_DSSICONTROL_H + + +#include "DSSIControlDescription.h" + +struct DSSIControl { + + DSSIControlDescription description; + + float *data; /// pointer to the value for this controller which is updated by the DSSI host + + /** + * Ctr for a DSSIControl based on a DSSIControl description + * @param controller_code the controller code + * @param name the human readable code name + */ + DSSIControl(DSSIControlDescription description) : description(description) { } + + /** + * update the current control to the Master in charge of dispatching them to the parts, effects, ... + * @param master the controller master in charge of further dispatch + */ + void forward_control(Master *master); + + /** + * scale the incoming value refereced by data in the hinted range to one expected by the Master dispatcher. + * Boolean are toggled to 0 or 127, ... + */ + int get_scaled_data() { + if (LADSPA_IS_HINT_TOGGLED(description.port_range_hint.HintDescriptor)) { + return *data <= 0 ? 0 : 127; + } else if (description.port_range_hint.UpperBound < 127) { + // when not using 127 or 128 as upper bound, scale the input using the port range hint to 0 .. 128 + return 128 * (*data - description.port_range_hint.LowerBound) / + (description.port_range_hint.UpperBound - description.port_range_hint.LowerBound); + } else { + return *data; + } + } + +}; + +#endif //ZYNADDSUBFX_DSSICONTROL_H diff --git a/src/Output/DSSIControlDescription.cpp b/src/Output/DSSIControlDescription.cpp @@ -0,0 +1,39 @@ +/* + ZynAddSubFX - a software synthesizer + + DSSIControlDescription.cpp - Description of DSSI control ports + Copyright (C) 2015 Olivier Jolly + Author: Olivier Jolly + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "DSSIControlDescription.h" + +// Mapping from dssi control index to midi CC +const DSSIControlDescription dssi_control_description[DSSIControlDescription::MAX_DSSI_CONTROLS] = { + { C_modwheel, "Modwheel", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 1, 127 }}, + { C_volume, "Volume", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, + { C_panning, "Panning"}, + { C_expression, "Expression", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, + { C_sustain, "Sustain", {LADSPA_HINT_TOGGLED| LADSPA_HINT_DEFAULT_0, 0, 1}}, + { C_portamento, "Portamento", {LADSPA_HINT_TOGGLED| LADSPA_HINT_DEFAULT_0, 0, 1}}, + { C_filterq, "Filter Q", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 0, 128 }}, + { C_filtercutoff, "Filter cutoff", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, + { C_bandwidth, "Bandwidth"}, + { C_fmamp, "FM amplification", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, + { C_resonance_center, "Renonance center", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, + { C_resonance_bandwidth, "Resonance bandwidth", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, +}; diff --git a/src/Output/DSSIControlDescription.h b/src/Output/DSSIControlDescription.h @@ -0,0 +1,66 @@ +/* + ZynAddSubFX - a software synthesizer + + DSSIControlDescription.h - Description of DSSI control ports + Copyright (C) 2015 Olivier Jolly + Author: Olivier Jolly + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ZYNADDSUBFX_DSSICONTROLDESCRIPTION_H +#define ZYNADDSUBFX_DSSICONTROLDESCRIPTION_H + + +#include <globals.h> +#include <ladspa.h> + +/** + * DSSIControlDescription represent one instance of DSSI control used to describe accepted values to the DSSI host + * and to forward DSSI host value change to ZynAddSubFx controller + */ +struct DSSIControlDescription { + + const static int MAX_DSSI_CONTROLS = 12; + + const MidiControllers controller_code; /// controler code, as accepted by the Controller class + const char *name; /// human readable name of this control + + /** hint about usable range of value for this control, defaulting to 0-128, initially at 64 */ + const LADSPA_PortRangeHint port_range_hint = { + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE, 0, 128}; + + /** + * Ctr for a DSSIControlDescription using the default hint (0-128 starting at 64) + * @param controller_code the controller code + * @param name the human readable code name + */ + DSSIControlDescription(MidiControllers controller_code, const char *name) : controller_code(controller_code), + name(name) { } + + /** + * Ctr for a DSSIControlDescription + * @param controller_code the controller code + * @param name the human readable code name + * @param port_range_hint the accepted range of values + */ + DSSIControlDescription(MidiControllers controller_code, const char *name, LADSPA_PortRangeHint port_range_hint) : + controller_code(controller_code), name(name), port_range_hint(port_range_hint) { } + +}; + +extern const DSSIControlDescription dssi_control_description[DSSIControlDescription::MAX_DSSI_CONTROLS]; + +#endif //ZYNADDSUBFX_DSSICONTROLDESCRIPTION_H diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -37,22 +37,6 @@ using std::set; using std::string; using std::vector; -// Mapping from dssi control index to midi CC -DSSIaudiooutput::DSSIControl dssi_control[DSSIaudiooutput::MAX_DSSI_CONTROLS] = { - { C_modwheel, "Modwheel", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 1, 127 }}, - { C_volume, "Volume", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, - { C_panning, "Panning"}, - { C_expression, "Expression", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, - { C_sustain, "Sustain", {LADSPA_HINT_TOGGLED| LADSPA_HINT_DEFAULT_0, 0, 1}}, - { C_portamento, "Portamento", {LADSPA_HINT_TOGGLED| LADSPA_HINT_DEFAULT_0, 0, 1}}, - { C_filterq, "Filter Q", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MIDDLE, 0, 128 }}, - { C_filtercutoff, "Filter cutoff", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, - { C_bandwidth, "Bandwidth"}, - { C_fmamp, "FM amplification", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_MAXIMUM, 1, 127 }}, - { C_resonance_center, "Renonance center", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, - { C_resonance_bandwidth, "Resonance bandwidth", {LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_DEFAULT_0, -1, 1 }}, -}; - //Dummy variables and functions for linking purposes const char *instance_name = 0; class WavFile; @@ -211,7 +195,7 @@ void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data *data) outr = data; break; default: - if ( port - 2 < MAX_DSSI_CONTROLS ) { + if ( port - 2 < DSSIControlDescription::MAX_DSSI_CONTROLS ) { dssi_control[port - 2].data = data; } break; @@ -450,7 +434,8 @@ void DSSIaudiooutput::runSynth(unsigned long sample_count, Master *master = middleware->spawnMaster(); // forward all dssi control values to the middleware - for (size_t dssi_control_index = 0; dssi_control_index < MAX_DSSI_CONTROLS; ++ dssi_control_index) { + for (size_t dssi_control_index = 0; + dssi_control_index < DSSIControlDescription::MAX_DSSI_CONTROLS; ++dssi_control_index) { dssi_control[dssi_control_index].forward_control(master); } @@ -523,10 +508,10 @@ void DSSIaudiooutput::runSynth(unsigned long sample_count, */ const DSSI_Descriptor *DSSIaudiooutput::getDssiDescriptor(unsigned long index) { - if((index > 0) || (dssiDescriptor == NULL)) + if(index > 0) return NULL; else - return dssiDescriptor; + return initDssiDescriptor(); } // @@ -556,19 +541,21 @@ DSSI_Descriptor *DSSIaudiooutput::initDssiDescriptor() newLadspaDescriptor->Maker = "Nasca Octavian Paul <zynaddsubfx@yahoo.com>"; newLadspaDescriptor->Copyright = "GNU General Public License v2 or later"; - newLadspaDescriptor->PortCount = 2 + MAX_DSSI_CONTROLS; + newLadspaDescriptor->PortCount = 2 + DSSIControlDescription::MAX_DSSI_CONTROLS; newPortNames = new const char *[newLadspaDescriptor->PortCount]; newPortNames[0] = "Output L"; newPortNames[1] = "Output R"; - for (size_t dssi_control_index = 0; dssi_control_index < MAX_DSSI_CONTROLS; ++ dssi_control_index) { - newPortNames[2 + dssi_control_index] = dssi_control[dssi_control_index].name; + for (size_t dssi_control_index = 0; + dssi_control_index < DSSIControlDescription::MAX_DSSI_CONTROLS; ++dssi_control_index) { + newPortNames[2 + dssi_control_index] = dssi_control_description[dssi_control_index].name; } newLadspaDescriptor->PortNames = newPortNames; newPortDescriptors = new LADSPA_PortDescriptor[newLadspaDescriptor->PortCount]; newPortDescriptors[0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; newPortDescriptors[1] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; - for (size_t dssi_control_index = 0; dssi_control_index < MAX_DSSI_CONTROLS; ++ dssi_control_index) { + for (size_t dssi_control_index = 0; + dssi_control_index < DSSIControlDescription::MAX_DSSI_CONTROLS; ++dssi_control_index) { newPortDescriptors[2 + dssi_control_index] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; } newLadspaDescriptor->PortDescriptors = newPortDescriptors; @@ -576,8 +563,9 @@ DSSI_Descriptor *DSSIaudiooutput::initDssiDescriptor() new LADSPA_PortRangeHint[newLadspaDescriptor->PortCount]; newPortRangeHints[0].HintDescriptor = 0; newPortRangeHints[1].HintDescriptor = 0; - for (size_t dssi_control_index = 0; dssi_control_index < MAX_DSSI_CONTROLS; ++ dssi_control_index) { - newPortRangeHints[2 + dssi_control_index] = dssi_control[dssi_control_index].port_range_hint; + for (size_t dssi_control_index = 0; + dssi_control_index < DSSIControlDescription::MAX_DSSI_CONTROLS; ++dssi_control_index) { + newPortRangeHints[2 + dssi_control_index] = dssi_control_description[dssi_control_index].port_range_hint; } newLadspaDescriptor->PortRangeHints = newPortRangeHints; newLadspaDescriptor->activate = stub_activate; @@ -624,7 +612,18 @@ DSSIaudiooutput *DSSIaudiooutput::getInstance(LADSPA_Handle instance) * @param sampleRate [in] the sample rate to be used by the synth. * @return */ -DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) +DSSIaudiooutput::DSSIaudiooutput(unsigned long sampleRate) : dssi_control({dssi_control_description[0], + dssi_control_description[1], + dssi_control_description[2], + dssi_control_description[3], + dssi_control_description[4], + dssi_control_description[5], + dssi_control_description[6], + dssi_control_description[7], + dssi_control_description[8], + dssi_control_description[9], + dssi_control_description[10], + dssi_control_description[11]}) { SYNTH_T synth; synth.samplerate = sampleRate; @@ -708,7 +707,3 @@ bool DSSIaudiooutput::mapNextBank() return true; } } - -void DSSIaudiooutput::DSSIControl::forward_control(Master *master) { - master->setController(0, controller_code, get_scaled_data()); -} diff --git a/src/Output/DSSIaudiooutput.h b/src/Output/DSSIaudiooutput.h @@ -27,6 +27,8 @@ #include "../globals.h" #include "../Misc/Config.h" #include "../Misc/MiddleWare.h" +#include "DSSIControlDescription.h" +#include "DSSIControl.h" #include <dssi.h> #include <ladspa.h> @@ -91,66 +93,6 @@ class DSSIaudiooutput std::string name; }; - /* - * DSSI Controls mapping - */ - const static int MAX_DSSI_CONTROLS = 12; - - /** - * DSSIControl represent one instance of DSSI control used to describe accepted values to the DSSI host - * and to forward DSSI host value change to ZynAddSubFx controller - */ - class DSSIControl { - public: - const MidiControllers controller_code; /// controler code, as accepted by the Controller class - const char *name; /// human readable name of this control - - /** hint about usable range of value for this control, defaulting to 0-128, initially at 64 */ - const LADSPA_PortRangeHint port_range_hint = { - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE, 0, 128}; - - - float *data; /// pointer to the value for this controller which is updated by the DSSI host - - /** - * Ctr for a DSSIControl using the default hint (0-128 starting at 64) - * @param controller_code the controller code - * @param name the human readable code name - */ - DSSIControl(MidiControllers controller_code, const char *name) : controller_code(controller_code), name(name) {} - - /** - * Ctr for a DSSIControl - * @param controller_code the controller code - * @param name the human readable code name - * @param port_range_hint the accepted range of values - */ - DSSIControl(MidiControllers controller_code, const char *name, LADSPA_PortRangeHint port_range_hint) : - controller_code(controller_code), name(name), port_range_hint(port_range_hint) {} - - /** - * update the current control to the Master in charge of dispatching them to the parts, effects, ... - * @param master the controller master in charge of further dispatch - */ - void forward_control(Master *master); - - /** - * scale the incoming value refereced by data in the hinted range to one expected by the Master dispatcher. - * Boolean are toggled to 0 or 127, ... - */ - int get_scaled_data() { - if (LADSPA_IS_HINT_TOGGLED(port_range_hint.HintDescriptor)) { - return *data <= 0 ? 0 : 127; - } else if (port_range_hint.UpperBound < 127) { - // when not using 127 or 128 as upper bound, scale the input using the port range hint to 0 .. 128 - return 128 * ( *data - port_range_hint.LowerBound ) / ( port_range_hint.UpperBound - port_range_hint.LowerBound ); - } else { - return *data; - } - } - - }; - private: DSSIaudiooutput(unsigned long sampleRate); @@ -169,6 +111,7 @@ class DSSIaudiooutput static std::string bankDirNames[]; static std::vector<ProgramDescriptor> programMap; + DSSIControl dssi_control[DSSIControlDescription::MAX_DSSI_CONTROLS]; /** * Flag controlling the list of bank directories