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:
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);