zynaddsubfx

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

commit 0233336ac07c762dd1b9ab0625bd37497e6dd127
parent b436f3d7b14bd2d539f3f8c7eddded1aec782e9f
Author: Olivier Jolly <[email protected]>
Date:   Tue, 17 Nov 2015 13:59:01 +0100

Expose Midi controls as DSSI controls to ease sound manipulation from DSSI hosts

Diffstat:
Msrc/Output/DSSIaudiooutput.cpp | 41++++++++++++++++++++++++++++++++++++++++-
Msrc/Output/DSSIaudiooutput.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/src/Output/DSSIaudiooutput.cpp b/src/Output/DSSIaudiooutput.cpp @@ -40,6 +40,22 @@ 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; @@ -197,6 +213,11 @@ void DSSIaudiooutput::connectPort(unsigned long port, LADSPA_Data *data) case 1: outr = data; break; + default: + if ( port - 2 < MAX_DSSI_CONTROLS ) { + dssi_control[port - 2].data = data; + } + break; } } @@ -431,6 +452,11 @@ 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) { + dssi_control[dssi_control_index].forward_control(master); + } + do { /* Find the time of the next event, if any */ if((events == NULL) || (event_index >= event_count)) @@ -535,23 +561,32 @@ DSSI_Descriptor *DSSIaudiooutput::initDssiDescriptor() newLadspaDescriptor->Maker = "Nasca Octavian Paul <[email protected]>"; newLadspaDescriptor->Copyright = "GNU General Public License v2 or later"; - newLadspaDescriptor->PortCount = 2; + newLadspaDescriptor->PortCount = 2 + 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; + } 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) { + newPortDescriptors[2 + dssi_control_index] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + } newLadspaDescriptor->PortDescriptors = newPortDescriptors; newPortRangeHints = 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; + } newLadspaDescriptor->PortRangeHints = newPortRangeHints; newLadspaDescriptor->activate = stub_activate; @@ -684,3 +719,7 @@ 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 @@ -91,6 +91,66 @@ 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);