diff --git a/resources/ui/carla_parameter.ui b/resources/ui/carla_parameter.ui index 288abe345..2d3cf6009 100644 --- a/resources/ui/carla_parameter.ui +++ b/resources/ui/carla_parameter.ui @@ -7,7 +7,7 @@ 0 0 369 - 22 + 33 @@ -41,43 +41,9 @@ - - - Qt::CustomContextMenu - - - (none) - - - cc # - - - -1 - - - 119 - - - -1 - - - - - - - Qt::CustomContextMenu - - - ch - - - 1 - - - 16 - - - 1 + + + ... diff --git a/source/backend/CarlaBackend.h b/source/backend/CarlaBackend.h index 272e11ade..8e51044fd 100644 --- a/source/backend/CarlaBackend.h +++ b/source/backend/CarlaBackend.h @@ -748,6 +748,37 @@ typedef enum { } InternalParameterIndex; +/* ------------------------------------------------------------------------------------------------------------ + * Special Mapped Control Index */ + +/*! + * Specially designated mapped control indexes. + * Values between 0 and 119 (0x77) are reserved for MIDI CC, which uses direct values. + * @see ParameterData::mappedControlIndex + */ +typedef enum { + /*! + * Unused control index, meaning no mapping is enabled. + */ + CONTROL_INDEX_NONE = -1, + + /*! + * CV control index, meaning the parameter is exposed as CV port. + */ + CONTROL_INDEX_CV = 130, + + /*! + * Special value to indicate MIDI pitchbend. + */ + CONTROL_INDEX_MIDI_PITCHBEND = 131, + + /*! + * Highest index allowed for mappings. + */ + CONTROL_INDEX_MAX_ALLOWED = CONTROL_INDEX_MIDI_PITCHBEND, + +} SpecialMappedControlIndex; + /* ------------------------------------------------------------------------------------------------------------ * Engine Callback Opcode */ @@ -808,12 +839,12 @@ typedef enum { #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH /*! - * A parameter's MIDI CC has changed. + * A parameter's mapped control index has changed. * @a pluginId Plugin Id * @a value1 Parameter index - * @a value2 New MIDI CC + * @a value2 New control index */ - ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED = 7, + ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED = 7, /*! * A parameter's MIDI channel has changed. @@ -1104,21 +1135,13 @@ typedef enum { */ ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED = 45, - /*! - * A parameter's CV controlled status has changed. - * @a pluginId Plugin Id - * @a value1 Parameter index - * @a value2 New CV controlled status (boolean) - */ - ENGINE_CALLBACK_PARAMETER_CV_CONTROLLED_STATUS_CHANGED = 46, - /*! * A parameter's mapped range has changed. * @a pluginId Plugin Id * @a value1 Parameter index * @a valueStr New mapped range as "%f:%f" syntax */ - ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED = 47, + ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED = 46, } EngineCallbackOpcode; @@ -1565,19 +1588,18 @@ typedef struct { */ int32_t rindex; - /*! - * Currently mapped MIDI CC. - * A value lower than 0 means invalid or unused. - * Maximum allowed value is 119 (0x77). - */ - int16_t midiCC; - /*! * Currently mapped MIDI channel. * Counts from 0 to 15. */ uint8_t midiChannel; + /*! + * Currently mapped index. + * @see SpecialMappedControlIndex + */ + int16_t mappedControlIndex; + /*! * Minimum value that this parameter maps to. */ diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index 700b20ba2..626b5110f 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -941,14 +941,6 @@ CARLA_EXPORT void carla_set_option(uint pluginId, uint option, bool yesNo); CARLA_EXPORT void carla_set_parameter_value(uint pluginId, uint32_t parameterId, float value); #ifndef BUILD_BRIDGE -/*! - * Change a plugin's parameter cv controlled status. - * @param pluginId Plugin - * @param parameterId Parameter index - * @param cv_controlled New CV controlled Status - */ -CARLA_EXPORT void carla_set_parameter_cv_controlled(uint pluginId, uint32_t parameterId, bool cv_controlled); - /*! * Change a plugin's parameter MIDI channel. * @param pluginId Plugin @@ -958,12 +950,12 @@ CARLA_EXPORT void carla_set_parameter_cv_controlled(uint pluginId, uint32_t para CARLA_EXPORT void carla_set_parameter_midi_channel(uint pluginId, uint32_t parameterId, uint8_t channel); /*! - * Change a plugin's parameter MIDI cc. + * Change a plugin's parameter mapped control index. * @param pluginId Plugin * @param parameterId Parameter index - * @param cc New MIDI cc + * @param cc New control index */ -CARLA_EXPORT void carla_set_parameter_midi_cc(uint pluginId, uint32_t parameterId, int16_t cc); +CARLA_EXPORT void carla_set_parameter_mapped_control_index(uint pluginId, uint32_t parameterId, int16_t index); /*! * Change a plugin's parameter mapped range. diff --git a/source/backend/CarlaPlugin.hpp b/source/backend/CarlaPlugin.hpp index 4877f95c5..fa042721f 100644 --- a/source/backend/CarlaPlugin.hpp +++ b/source/backend/CarlaPlugin.hpp @@ -592,13 +592,6 @@ public: */ void setParameterValueByRealIndex(int32_t rindex, float value, bool sendGui, bool sendOsc, bool sendCallback) noexcept; -#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - /*! - * Change parameter's @a parameterId CV controlled status. - */ - void setParameterAsCvControl(uint32_t parameterId, bool cv_controlled, bool sendOsc, bool sendCallback) noexcept; -#endif - /*! * Set parameter's @a parameterId MIDI channel to @a channel. * @a channel must be between 0 and 15. @@ -606,10 +599,10 @@ public: virtual void setParameterMidiChannel(uint32_t parameterId, uint8_t channel, bool sendOsc, bool sendCallback) noexcept; /*! - * Set parameter's @a parameterId MIDI CC to @a cc. - * @a cc must be between 0 and 119 (0x77), or -1 for invalid. + * Set parameter's @a parameterId mapped control index to @a index. + * @see ParameterData::mappedControlIndex */ - virtual void setParameterMidiCC(uint32_t parameterId, int16_t cc, bool sendOsc, bool sendCallback) noexcept; + virtual void setParameterMappedControlIndex(uint32_t parameterId, int16_t index, bool sendOsc, bool sendCallback) noexcept; /*! * Set parameter's @a parameterId mapped range to @a minimum and @a maximum. diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index e3cc6122a..d1ba3789a 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -1443,8 +1443,10 @@ const ParameterData* carla_get_parameter_data(uint pluginId, uint32_t parameterI retParamData.hints = 0x0; retParamData.index = CB::PARAMETER_NULL; retParamData.rindex = -1; - retParamData.midiCC = -1; retParamData.midiChannel = 0; + retParamData.mappedControlIndex = CB::CONTROL_INDEX_NONE; + retParamData.mappedMinimum = 0.0f; + retParamData.mappedMaximum = 0.0f; CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, &retParamData); @@ -1459,8 +1461,10 @@ const ParameterData* carla_get_parameter_data(uint pluginId, uint32_t parameterI retParamData.hints = pluginParamData.hints; retParamData.index = pluginParamData.index; retParamData.rindex = pluginParamData.rindex; - retParamData.midiCC = pluginParamData.midiCC; retParamData.midiChannel = pluginParamData.midiChannel; + retParamData.mappedControlIndex = pluginParamData.mappedControlIndex; + retParamData.mappedMinimum = pluginParamData.mappedMinimum; + retParamData.mappedMaximum = pluginParamData.mappedMaximum; return &plugin->getParameterData(parameterId); } @@ -1984,18 +1988,6 @@ void carla_set_parameter_value(uint pluginId, uint32_t parameterId, float value) } #ifndef BUILD_BRIDGE -void carla_set_parameter_cv_controlled(uint pluginId, uint32_t parameterId, bool cv_controlled) -{ - CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr,); - - CarlaPlugin* const plugin(gStandalone.engine->getPlugin(pluginId)); - CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); - - carla_debug("carla_set_parameter_cv_controlled(%u, %u, %s)", pluginId, parameterId, bool2str(cv_controlled)); - CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),); - - return plugin->setParameterAsCvControl(parameterId, cv_controlled, true, false); -} void carla_set_parameter_midi_channel(uint pluginId, uint32_t parameterId, uint8_t channel) { @@ -2011,18 +2003,18 @@ void carla_set_parameter_midi_channel(uint pluginId, uint32_t parameterId, uint8 return plugin->setParameterMidiChannel(parameterId, channel, true, false); } -void carla_set_parameter_midi_cc(uint pluginId, uint32_t parameterId, int16_t cc) +void carla_set_parameter_mapped_control_index(uint pluginId, uint32_t parameterId, int16_t index) { CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr,); - CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,); + CARLA_SAFE_ASSERT_RETURN(index >= CB::CONTROL_INDEX_NONE && index <= CB::CONTROL_INDEX_MAX_ALLOWED,); CarlaPlugin* const plugin(gStandalone.engine->getPlugin(pluginId)); CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); - carla_debug("carla_set_parameter_midi_cc(%i, %i, %i)", pluginId, parameterId, cc); + carla_debug("carla_set_parameter_mapped_control_index(%i, %i, %i)", pluginId, parameterId, cc); CARLA_SAFE_ASSERT_RETURN(parameterId < plugin->getParameterCount(),); - return plugin->setParameterMidiCC(parameterId, cc, true, false); + return plugin->setParameterMappedControlIndex(parameterId, index, true, false); } void carla_set_parameter_mapped_range(uint pluginId, uint32_t parameterId, float minimum, float maximum) diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 72ce4a1af..291a71a0e 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -559,7 +559,11 @@ protected: CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),); std::snprintf(tmpBuf, STR_MAX, "%i:%i:%i:%i\n", paramData.type, paramData.hints, - paramData.midiChannel, paramData.midiCC); + paramData.mappedControlIndex, paramData.midiChannel); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),); + + std::snprintf(tmpBuf, STR_MAX, "%.12g:%.12g\n", static_cast(paramData.mappedMinimum), + static_cast(paramData.mappedMaximum)); CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),); if (plugin->getParameterName(i, tmpBuf)) { @@ -2074,42 +2078,43 @@ bool CarlaEngineNativeUI::msgReceived(const char*const msg) noexcept fEngine->setParameterValueFromUI(pluginId, parameterId, value); } } - else if (std::strcmp(msg, "set_parameter_cv_controlled") == 0) + else if (std::strcmp(msg, "set_parameter_midi_channel") == 0) { - uint32_t pluginId, parameterId; - bool cv_controlled; + uint32_t pluginId, parameterId, channel; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(pluginId), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(parameterId), true); - CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(cv_controlled), true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(channel), true); + CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, true); if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) - plugin->setParameterAsCvControl(parameterId, cv_controlled, true, false); + plugin->setParameterMidiChannel(parameterId, static_cast(channel), true, false); } - else if (std::strcmp(msg, "set_parameter_midi_channel") == 0) + else if (std::strcmp(msg, "set_parameter_mapped_control_index") == 0) { - uint32_t pluginId, parameterId, channel; + uint32_t pluginId, parameterId; + int32_t ctrl; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(pluginId), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(parameterId), true); - CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(channel), true); - CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(ctrl), true); + CARLA_SAFE_ASSERT_RETURN(ctrl >= CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED, true); if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) - plugin->setParameterMidiChannel(parameterId, static_cast(channel), true, false); + plugin->setParameterMappedControlIndex(parameterId, static_cast(ctrl), true, false); } - else if (std::strcmp(msg, "set_parameter_midi_cc") == 0) + else if (std::strcmp(msg, "set_parameter_mapped_range") == 0) { uint32_t pluginId, parameterId; - int32_t cc; + float minimum, maximum; CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(pluginId), true); CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(parameterId), true); - CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(cc), true); - CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL, true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(minimum), true); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(maximum), true); if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) - plugin->setParameterMidiCC(parameterId, static_cast(cc), true, false); + plugin->setParameterMappedRange(parameterId, minimum, maximum, true, false); } else if (std::strcmp(msg, "set_parameter_touch") == 0) { diff --git a/source/backend/engine/CarlaEngineOsc.hpp b/source/backend/engine/CarlaEngineOsc.hpp index 7c6cbbd06..26da48764 100644 --- a/source/backend/engine/CarlaEngineOsc.hpp +++ b/source/backend/engine/CarlaEngineOsc.hpp @@ -149,7 +149,8 @@ private: int handleMsgSetBalanceRight(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetPanning(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetParameterValue(CARLA_ENGINE_OSC_HANDLE_ARGS); - int handleMsgSetParameterMidiCC(CARLA_ENGINE_OSC_HANDLE_ARGS); + int handleMsgSetParameterMappedControlIndex(CARLA_ENGINE_OSC_HANDLE_ARGS); + int handleMsgSetParameterMappedRange(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetParameterMidiChannel(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetProgram(CARLA_ENGINE_OSC_HANDLE_ARGS); int handleMsgSetMidiProgram(CARLA_ENGINE_OSC_HANDLE_ARGS); diff --git a/source/backend/engine/CarlaEngineOscHandlers.cpp b/source/backend/engine/CarlaEngineOscHandlers.cpp index ce344ddf9..1cea6c8a6 100644 --- a/source/backend/engine/CarlaEngineOscHandlers.cpp +++ b/source/backend/engine/CarlaEngineOscHandlers.cpp @@ -160,8 +160,10 @@ int CarlaEngineOsc::handleMessage(const bool isTCP, const char* const path, cons return 0; //handleMsgSetControlChannel(plugin, argc, argv, types); // TODO if (std::strcmp(method, "set_parameter_value") == 0) return handleMsgSetParameterValue(plugin, argc, argv, types); - if (std::strcmp(method, "set_parameter_midi_cc") == 0) - return handleMsgSetParameterMidiCC(plugin, argc, argv, types); + if (std::strcmp(method, "set_parameter_mapped_control_index") == 0) + return handleMsgSetParameterMappedControlIndex(plugin, argc, argv, types); + if (std::strcmp(method, "set_parameter_mapped_range") == 0) + return handleMsgSetParameterMappedRange(plugin, argc, argv, types); if (std::strcmp(method, "set_parameter_midi_channel") == 0) return handleMsgSetParameterMidiChannel(plugin, argc, argv, types); if (std::strcmp(method, "set_program") == 0) @@ -630,18 +632,33 @@ int CarlaEngineOsc::handleMsgSetParameterValue(CARLA_ENGINE_OSC_HANDLE_ARGS) return 0; } -int CarlaEngineOsc::handleMsgSetParameterMidiCC(CARLA_ENGINE_OSC_HANDLE_ARGS) +int CarlaEngineOsc::handleMsgSetParameterMappedControlIndex(CARLA_ENGINE_OSC_HANDLE_ARGS) { - carla_debug("CarlaEngineOsc::handleMsgSetParameterMidiCC()"); + carla_debug("CarlaEngineOsc::handleMsgSetParameterMappedIndex()"); CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "ii"); const int32_t index = argv[0]->i; - const int32_t cc = argv[1]->i; + const int32_t ctrl = argv[1]->i; CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); - CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL, 0); + CARLA_SAFE_ASSERT_RETURN(ctrl >= CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED, 0); - plugin->setParameterMidiCC(static_cast(index), static_cast(cc), false, true); + plugin->setParameterMappedControlIndex(static_cast(index), static_cast(ctrl), false, true); + return 0; +} + +int CarlaEngineOsc::handleMsgSetParameterMappedRange(CARLA_ENGINE_OSC_HANDLE_ARGS) +{ + carla_debug("CarlaEngineOsc::handleMsgSetParameterMappedRange()"); + CARLA_ENGINE_OSC_CHECK_OSC_TYPES(2, "iff"); + + const int32_t index = argv[0]->i; + const float minimum = argv[1]->f; + const float maximum = argv[2]->f; + + CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); + + plugin->setParameterMappedRange(static_cast(index), minimum, maximum, false, true); return 0; } diff --git a/source/backend/engine/CarlaEngineOscSend.cpp b/source/backend/engine/CarlaEngineOscSend.cpp index bc11e3ac7..4247969a4 100644 --- a/source/backend/engine/CarlaEngineOscSend.cpp +++ b/source/backend/engine/CarlaEngineOscSend.cpp @@ -149,7 +149,7 @@ void CarlaEngineOsc::sendPluginParameterInfo(const CarlaPlugin* const plugin, co try_lo_send(fControlDataTCP.target, targetPath, "iiiiiissfffffff", static_cast(plugin->getId()), static_cast(index), static_cast(paramData.type), static_cast(paramData.hints), - static_cast(paramData.midiChannel), static_cast(paramData.midiCC), + static_cast(paramData.mappedControlIndex), static_cast(paramData.midiChannel), bufName, bufUnit, static_cast(paramRanges.def), static_cast(paramRanges.min), diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index f57e9cecc..89a0359c5 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -45,7 +45,7 @@ CARLA_BACKEND_START_NAMESPACE // ------------------------------------------------------------------- // Fallback data -static const ParameterData kParameterDataNull = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, -1, 0, 0.0f, 1.0f }; +static const ParameterData kParameterDataNull = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, 0, CONTROL_INDEX_NONE, 0.0f, 1.0f }; static const ParameterRanges kParameterRangesNull = { 0.0f, 0.0f, 1.0f, 0.01f, 0.0001f, 0.1f }; static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr }; @@ -600,7 +600,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) const bool dummy = paramData.type != PARAMETER_INPUT || usingChunk; - if (dummy && paramData.midiCC <= -1) + if (dummy && paramData.mappedControlIndex <= CONTROL_INDEX_NONE) continue; CarlaStateSave::Parameter* const stateParameter(new CarlaStateSave::Parameter()); @@ -608,8 +608,8 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) stateParameter->dummy = dummy; stateParameter->index = paramData.index; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - stateParameter->midiCC = paramData.midiCC; - stateParameter->midiChannel = paramData.midiChannel; + stateParameter->mappedControlIndex = paramData.mappedControlIndex; + stateParameter->midiChannel = paramData.midiChannel; #endif if (! getParameterName(i, strBuf)) @@ -821,7 +821,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) } #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - setParameterMidiCC(static_cast(index), stateParameter->midiCC, true, true); + setParameterMappedControlIndex(static_cast(index), stateParameter->mappedControlIndex, true, true); setParameterMidiChannel(static_cast(index), stateParameter->midiChannel, true, true); #endif } @@ -1670,49 +1670,6 @@ void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float } } -#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH -void CarlaPlugin::setParameterAsCvControl(uint32_t parameterId, bool cv_controlled, bool sendOsc, bool sendCallback) noexcept -{ - if (pData->engineBridged) { - CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); - } else { - CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT - } - CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); - CARLA_SAFE_ASSERT_RETURN(pData->param.data[parameterId].type == PARAMETER_INPUT,); - CARLA_SAFE_ASSERT_RETURN(pData->param.data[parameterId].hints & PARAMETER_CAN_BE_CV_CONTROLLED,); - CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,); - - if (cv_controlled) - { - char strBuf[STR_MAX+1]; - carla_zeroChars(strBuf, STR_MAX+1); - if (! getParameterName(parameterId, strBuf)) - std::snprintf(strBuf, STR_MAX, "Param %u", parameterId); - - const uint portNameSize = pData->engine->getMaxPortNameSize(); - if (portNameSize < STR_MAX) - strBuf[portNameSize] = '\0'; - - CarlaEngineCVPort* const cvPort = - (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, strBuf, true, parameterId); - cvPort->setRange(pData->param.ranges[parameterId].min, pData->param.ranges[parameterId].max); - pData->event.cvSourcePorts->addCVSource(cvPort, parameterId); - } - else - { - pData->event.cvSourcePorts->removeCVSource(parameterId); - } - - pData->engine->callback(sendCallback, sendOsc, - ENGINE_CALLBACK_PARAMETER_CV_CONTROLLED_STATUS_CHANGED, - pData->id, - static_cast(parameterId), - cv_controlled ? 1 : 0, - 0, 0.0f, nullptr); -} -#endif - void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept { if (pData->engineBridged) { @@ -1723,6 +1680,9 @@ void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,); + if (pData->param.data[parameterId].midiChannel == channel) + return; + pData->param.data[parameterId].midiChannel = channel; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH @@ -1735,7 +1695,7 @@ void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint #endif } -void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t cc, const bool sendOsc, const bool sendCallback) noexcept +void CarlaPlugin::setParameterMappedControlIndex(const uint32_t parameterId, const int16_t index, const bool sendOsc, const bool sendCallback) noexcept { if (pData->engineBridged) { CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); @@ -1743,16 +1703,44 @@ void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t c CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT } CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); - CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,); + CARLA_SAFE_ASSERT_RETURN(index >= CONTROL_INDEX_NONE && index <= CONTROL_INDEX_MAX_ALLOWED,); + + if (pData->param.data[parameterId].mappedControlIndex == index) + return; + + if (index == CONTROL_INDEX_CV) + { + CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,); + + char strBuf[STR_MAX+1]; + carla_zeroChars(strBuf, STR_MAX+1); + if (! getParameterName(parameterId, strBuf)) + std::snprintf(strBuf, STR_MAX, "Param %u", parameterId); + + const uint portNameSize = pData->engine->getMaxPortNameSize(); + if (portNameSize < STR_MAX) + strBuf[portNameSize] = '\0'; + + CarlaEngineCVPort* const cvPort = + (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, strBuf, true, parameterId); + cvPort->setRange(pData->param.ranges[parameterId].min, pData->param.ranges[parameterId].max); + pData->event.cvSourcePorts->addCVSource(cvPort, parameterId); + } + else if (pData->param.data[parameterId].mappedControlIndex == CONTROL_INDEX_CV) + { + CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,); + + pData->event.cvSourcePorts->removeCVSource(parameterId); + } - pData->param.data[parameterId].midiCC = cc; + pData->param.data[parameterId].mappedControlIndex = index; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH pData->engine->callback(sendCallback, sendOsc, - ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED, + ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED, pData->id, static_cast(parameterId), - cc, + index, 0, 0.0f, nullptr); #endif } @@ -1766,6 +1754,10 @@ void CarlaPlugin::setParameterMappedRange(const uint32_t parameterId, const floa } CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); + if (carla_isEqual(pData->param.data[parameterId].mappedMinimum, minimum) && + carla_isEqual(pData->param.data[parameterId].mappedMaximum, maximum)) + return; + pData->param.data[parameterId].mappedMinimum = minimum; pData->param.data[parameterId].mappedMaximum = maximum; @@ -1775,7 +1767,7 @@ void CarlaPlugin::setParameterMappedRange(const uint32_t parameterId, const floa #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH pData->engine->callback(sendCallback, sendOsc, - ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED, + ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED, pData->id, static_cast(parameterId), 0, 0, 0.0f, diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index 380710909..02d17c657 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -749,22 +749,22 @@ public: CarlaPlugin::setParameterMidiChannel(parameterId, channel, sendOsc, sendCallback); } - void setParameterMidiCC(const uint32_t parameterId, const int16_t cc, const bool sendOsc, const bool sendCallback) noexcept override + void setParameterMappedControlIndex(const uint32_t parameterId, const int16_t index, const bool sendOsc, const bool sendCallback) noexcept override { CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); - CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,); + CARLA_SAFE_ASSERT_RETURN(index >= CONTROL_INDEX_NONE && index <= CONTROL_INDEX_MAX_ALLOWED,); CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); { const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); - fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetParameterMidiCC); + fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetParameterMappedControlIndex); fShmNonRtClientControl.writeUInt(parameterId); - fShmNonRtClientControl.writeShort(cc); + fShmNonRtClientControl.writeShort(index); fShmNonRtClientControl.commitWrite(); } - CarlaPlugin::setParameterMidiCC(parameterId, cc, sendOsc, sendCallback); + CarlaPlugin::setParameterMappedControlIndex(parameterId, index, sendOsc, sendCallback); } void setParameterMappedRange(const uint32_t parameterId, const float minimum, const float maximum, const bool sendOsc, const bool sendCallback) noexcept override @@ -1533,10 +1533,14 @@ public: if (pData->param.data[k].type != PARAMETER_OUTPUT) continue; - if (pData->param.data[k].midiCC > 0) + if (pData->param.data[k].mappedControlIndex > 0) { value = pData->param.ranges[k].getNormalizedValue(fParams[k].value); - pData->event.portOut->writeControlEvent(0, pData->param.data[k].midiChannel, kEngineControlEventTypeParameter, static_cast(pData->param.data[k].midiCC), value); + pData->event.portOut->writeControlEvent(0, + pData->param.data[k].midiChannel, + kEngineControlEventTypeParameter, + static_cast(pData->param.data[k].mappedControlIndex), + value); } } @@ -2117,9 +2121,9 @@ public: const int32_t rindex = fShmNonRtServerControl.readInt(); const uint32_t type = fShmNonRtServerControl.readUInt(); const uint32_t hints = fShmNonRtServerControl.readUInt(); - const int16_t midiCC = fShmNonRtServerControl.readShort(); + const int16_t ctrl = fShmNonRtServerControl.readShort(); - CARLA_SAFE_ASSERT_BREAK(midiCC >= -1 && midiCC < MAX_MIDI_CONTROL); + CARLA_SAFE_ASSERT_BREAK(ctrl >= CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED); CARLA_SAFE_ASSERT_INT2(index < pData->param.count, index, pData->param.count); if (index < pData->param.count) @@ -2128,7 +2132,7 @@ public: pData->param.data[index].index = static_cast(index); pData->param.data[index].rindex = rindex; pData->param.data[index].hints = hints; - pData->param.data[index].midiCC = midiCC; + pData->param.data[index].mappedControlIndex = ctrl; } } break; diff --git a/source/backend/plugin/CarlaPluginFluidSynth.cpp b/source/backend/plugin/CarlaPluginFluidSynth.cpp index 60f19b756..b5e43e5af 100644 --- a/source/backend/plugin/CarlaPluginFluidSynth.cpp +++ b/source/backend/plugin/CarlaPluginFluidSynth.cpp @@ -777,7 +777,7 @@ public: pData->param.data[j].hints = PARAMETER_IS_ENABLED /*| PARAMETER_IS_AUTOMABLE*/; pData->param.data[j].index = j; pData->param.data[j].rindex = j; - pData->param.data[j].midiCC = MIDI_CONTROL_REVERB_SEND_LEVEL; + pData->param.data[j].mappedControlIndex = MIDI_CONTROL_REVERB_SEND_LEVEL; pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].max = 1.0f; pData->param.ranges[j].def = sFluidDefaults[j]; @@ -1239,7 +1239,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].hints != PARAMETER_INPUT) continue; @@ -1427,10 +1427,14 @@ public: fParamBuffers[k] = float(fluid_synth_get_active_voice_count(fSynth)); pData->param.ranges[k].fixValue(fParamBuffers[k]); - if (pData->param.data[k].midiCC > 0) + if (pData->param.data[k].mappedControlIndex > 0) { float value(pData->param.ranges[k].getNormalizedValue(fParamBuffers[k])); - pData->event.portOut->writeControlEvent(0, pData->param.data[k].midiChannel, kEngineControlEventTypeParameter, static_cast(pData->param.data[k].midiCC), value); + pData->event.portOut->writeControlEvent(0, + pData->param.data[k].midiChannel, + kEngineControlEventTypeParameter, + static_cast(pData->param.data[k].mappedControlIndex), + value); } } // End of Control Output diff --git a/source/backend/plugin/CarlaPluginInternal.cpp b/source/backend/plugin/CarlaPluginInternal.cpp index 4f572e02b..dce584904 100644 --- a/source/backend/plugin/CarlaPluginInternal.cpp +++ b/source/backend/plugin/CarlaPluginInternal.cpp @@ -222,7 +222,7 @@ void PluginParameterData::createNew(const uint32_t newCount, const bool withSpec { data[i].index = PARAMETER_NULL; data[i].rindex = PARAMETER_NULL; - data[i].midiCC = -1; + data[i].mappedControlIndex = CONTROL_INDEX_NONE; } ranges = new ParameterRanges[newCount]; diff --git a/source/backend/plugin/CarlaPluginJuce.cpp b/source/backend/plugin/CarlaPluginJuce.cpp index d8bb20f7f..cf7b5e99f 100644 --- a/source/backend/plugin/CarlaPluginJuce.cpp +++ b/source/backend/plugin/CarlaPluginJuce.cpp @@ -881,7 +881,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].type != PARAMETER_INPUT) continue; diff --git a/source/backend/plugin/CarlaPluginLADSPADSSI.cpp b/source/backend/plugin/CarlaPluginLADSPADSSI.cpp index f200fbe78..1603a5779 100644 --- a/source/backend/plugin/CarlaPluginLADSPADSSI.cpp +++ b/source/backend/plugin/CarlaPluginLADSPADSSI.cpp @@ -1132,7 +1132,7 @@ public: { const int16_t cc = DSSI_CC_NUMBER(ctrl); if (! MIDI_IS_CONTROL_BANK_SELECT(cc)) - pData->param.data[j].midiCC = cc; + pData->param.data[j].mappedControlIndex = cc; } } } @@ -1702,7 +1702,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].type != PARAMETER_INPUT) continue; @@ -1943,10 +1943,10 @@ public: pData->param.ranges[k].fixValue(fParamBuffers[k]); - if (pData->param.data[k].midiCC > 0) + if (pData->param.data[k].mappedControlIndex > 0) { channel = pData->param.data[k].midiChannel; - param = static_cast(pData->param.data[k].midiCC); + param = static_cast(pData->param.data[k].mappedControlIndex); value = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]); pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter, param, value); } diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index f7214418a..9ae5482fa 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -2574,7 +2574,7 @@ public: if (LV2_IS_PORT_MIDI_MAP_CC(portMidiMap.Type)) { if (portMidiMap.Number < MAX_MIDI_CONTROL && ! MIDI_IS_CONTROL_BANK_SELECT(portMidiMap.Number)) - pData->param.data[j].midiCC = static_cast(portMidiMap.Number); + pData->param.data[j].mappedControlIndex = static_cast(portMidiMap.Number); } } else if (LV2_IS_PORT_OUTPUT(portTypes)) @@ -3678,7 +3678,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].type != PARAMETER_INPUT) continue; @@ -4039,10 +4039,10 @@ public: // plugin is responsible to ensure correct bounds pData->param.ranges[k].fixValue(fParamBuffers[k]); - if (pData->param.data[k].midiCC > 0) + if (pData->param.data[k].mappedControlIndex > 0) { channel = pData->param.data[k].midiChannel; - param = static_cast(pData->param.data[k].midiCC); + param = static_cast(pData->param.data[k].mappedControlIndex); value = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]); pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter, param, value); } diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index ee9b7aaa4..0ee60dd83 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -1941,7 +1941,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].type != PARAMETER_INPUT) continue; @@ -2191,10 +2191,14 @@ public: curValue = fDescriptor->get_parameter_value(fHandle, k); pData->param.ranges[k].fixValue(curValue); - if (pData->param.data[k].midiCC > 0) + if (pData->param.data[k].mappedControlIndex > 0) { value = pData->param.ranges[k].getNormalizedValue(curValue); - pData->event.portOut->writeControlEvent(0, pData->param.data[k].midiChannel, kEngineControlEventTypeParameter, static_cast(pData->param.data[k].midiCC), value); + pData->event.portOut->writeControlEvent(0, + pData->param.data[k].midiChannel, + kEngineControlEventTypeParameter, + static_cast(pData->param.data[k].mappedControlIndex), + value); } } } // End of Control Output diff --git a/source/backend/plugin/CarlaPluginSFZero.cpp b/source/backend/plugin/CarlaPluginSFZero.cpp index 843893955..a87856a43 100644 --- a/source/backend/plugin/CarlaPluginSFZero.cpp +++ b/source/backend/plugin/CarlaPluginSFZero.cpp @@ -457,7 +457,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].hints != PARAMETER_INPUT) continue; diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 07c030378..2c73999bb 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -1389,7 +1389,7 @@ public: { if (pData->param.data[k].midiChannel != event.channel) continue; - if (pData->param.data[k].midiCC != ctrlEvent.param) + if (pData->param.data[k].mappedControlIndex != ctrlEvent.param) continue; if (pData->param.data[k].type != PARAMETER_INPUT) continue; diff --git a/source/frontend/carla_backend.py b/source/frontend/carla_backend.py index 2c89641de..c496ee831 100644 --- a/source/frontend/carla_backend.py +++ b/source/frontend/carla_backend.py @@ -539,6 +539,22 @@ PARAMETER_CTRL_CHANNEL = -8 # Max value, defined only for convenience. PARAMETER_MAX = -9 +# ------------------------------------------------------------------------------------------------------------ +# Special Mapped Control Index + +# Specially designated mapped control indexes. +# Values between 0 and 119 (0x77) are reserved for MIDI CC, which uses direct values. +# @see ParameterData::mappedControlIndex + +# Unused control index, meaning no mapping is enabled. +CONTROL_VALUE_NONE = -1 + +# CV control index, meaning the parameter is exposed as CV port. +CONTROL_VALUE_CV = 130 + +# Special value to indicate MIDI pitchbend. +CONTROL_VALUE_MIDI_PITCHBEND = 131 + # ------------------------------------------------------------------------------------------------------------ # Engine Callback Opcode # Engine callback opcodes. @@ -580,11 +596,11 @@ ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED = 5 # @a valuef New default value ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED = 6 -# A parameter's MIDI CC has changed. +# A parameter's mapped control index has changed. # @a pluginId Plugin Id # @a value1 Parameter index -# @a value2 New MIDI CC -ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED = 7 +# @a value2 New control index +ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED = 7 # A parameter's MIDI channel has changed. # @a pluginId Plugin Id @@ -796,17 +812,11 @@ ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_REMOVED = 44 # @see PatchbayPortGroupHints ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED = 45 -# A parameter's CV controlled status has changed. -# @a pluginId Plugin Id -# @a value1 Parameter index -# @a value2 New CV controlled status (boolean) -ENGINE_CALLBACK_PARAMETER_CV_CONTROLLED_STATUS_CHANGED = 46 - # A parameter's mapped range has changed. # @a pluginId Plugin Id # @a value1 Parameter index # @a valueStr New mapped range as "%f:%f" syntax -ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED = 47 +ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED = 46 # ------------------------------------------------------------------------------------------------------------ # NSM Callback Opcode @@ -1089,15 +1099,14 @@ class ParameterData(Structure): # Real index as seen by plugins. ("rindex", c_int32), - # Currently mapped MIDI CC. - # A value lower than 0 means invalid or unused. - # Maximum allowed value is 119 (0x77). - ("midiCC", c_int16), - # Currently mapped MIDI channel. # Counts from 0 to 15. ("midiChannel", c_uint8), + # Currently mapped index. + # @see SpecialMappedControlIndex + ("mappedControlIndex", c_int16), + # Minimum value that this parameter maps to. ("mappedMinimum", c_uint8), @@ -1180,8 +1189,8 @@ PyParameterData = { 'hints': 0x0, 'index': PARAMETER_NULL, 'rindex': -1, - 'midiCC': -1, 'midiChannel': 0, + 'mappedControlIndex': CONTROL_VALUE_NONE, 'mappedMinimum': 0.0, 'mappedMaximum': 1.0, } @@ -2050,15 +2059,7 @@ class CarlaHostMeta(object): def set_parameter_value(self, pluginId, parameterId, value): raise NotImplementedError - # Change a plugin's parameter cv controlled status. - # @param pluginId Plugin - # @param parameterId Parameter index - # @param cv_controlled New CV controlled Status - @abstractmethod - def set_parameter_cv_controlled(self, pluginId, parameterId, cv_controlled): - raise NotImplementedError - - # Change a plugin's parameter MIDI cc. + # Change a plugin's parameter mapped control index. # @param pluginId Plugin # @param parameterId Parameter index # @param cc New MIDI cc @@ -2069,9 +2070,9 @@ class CarlaHostMeta(object): # Change a plugin's parameter MIDI channel. # @param pluginId Plugin # @param parameterId Parameter index - # @param channel New MIDI channel + # @param channel New control index @abstractmethod - def set_parameter_midi_cc(self, pluginId, parameterId, cc): + def set_parameter_mapped_control_index(self, pluginId, parameterId, index): raise NotImplementedError # Change a plugin's parameter mapped range. @@ -2464,13 +2465,10 @@ class CarlaHostNull(CarlaHostMeta): def set_parameter_value(self, pluginId, parameterId, value): return - def set_parameter_cv_controlled(self, pluginId, parameterId, cv_controlled): - return - def set_parameter_midi_channel(self, pluginId, parameterId, channel): return - def set_parameter_midi_cc(self, pluginId, parameterId, cc): + def set_parameter_mapped_control_index(self, pluginId, parameterId, index): return def set_parameter_mapped_range(self, pluginId, parameterId, minimum, maximum): @@ -2782,14 +2780,11 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_set_parameter_value.argtypes = [c_uint, c_uint32, c_float] self.lib.carla_set_parameter_value.restype = None - self.lib.carla_set_parameter_cv_controlled.argtypes = [c_uint, c_uint32, c_bool] - self.lib.carla_set_parameter_cv_controlled.restype = None - self.lib.carla_set_parameter_midi_channel.argtypes = [c_uint, c_uint32, c_uint8] self.lib.carla_set_parameter_midi_channel.restype = None - self.lib.carla_set_parameter_midi_cc.argtypes = [c_uint, c_uint32, c_int16] - self.lib.carla_set_parameter_midi_cc.restype = None + self.lib.carla_set_parameter_mapped_control_index.argtypes = [c_uint, c_uint32, c_int16] + self.lib.carla_set_parameter_mapped_control_index.restype = None self.lib.carla_set_parameter_mapped_range.argtypes = [c_uint, c_uint32, c_float, c_float] self.lib.carla_set_parameter_mapped_range.restype = None @@ -3107,14 +3102,11 @@ class CarlaHostDLL(CarlaHostMeta): def set_parameter_value(self, pluginId, parameterId, value): self.lib.carla_set_parameter_value(pluginId, parameterId, value) - def set_parameter_cv_controlled(self, pluginId, parameterId, cv_controlled): - self.lib.carla_set_parameter_cv_controlled(pluginId, parameterId, cv_controlled) - def set_parameter_midi_channel(self, pluginId, parameterId, channel): self.lib.carla_set_parameter_midi_channel(pluginId, parameterId, channel) - def set_parameter_midi_cc(self, pluginId, parameterId, cc): - self.lib.carla_set_parameter_midi_cc(pluginId, parameterId, cc) + def set_parameter_mapped_control_index(self, pluginId, parameterId, index): + self.lib.carla_set_parameter_mapped_control_index(pluginId, parameterId, index) def set_parameter_mapped_range(self, pluginId, parameterId, minimum, maximum): self.lib.carla_set_parameter_mapped_range(pluginId, parameterId, minimum, maximum) @@ -3513,16 +3505,18 @@ class CarlaHostPlugin(CarlaHostMeta): self.sendMsg(["set_parameter_value", pluginId, parameterId, value]) self.fPluginsInfo[pluginId].parameterValues[parameterId] = value - def set_parameter_cv_controlled(self, pluginId, parameterId, cv_controlled): - self.sendMsg(["set_parameter_cv_controlled", pluginId, parameterId, cv_controlled]) - def set_parameter_midi_channel(self, pluginId, parameterId, channel): self.sendMsg(["set_parameter_midi_channel", pluginId, parameterId, channel]) - self.fPluginsInfo[pluginId].parameterData[parameterId]['midiCC'] = channel + self.fPluginsInfo[pluginId].parameterData[parameterId]['midiChannel'] = channel - def set_parameter_midi_cc(self, pluginId, parameterId, cc): - self.sendMsg(["set_parameter_midi_cc", pluginId, parameterId, cc]) - self.fPluginsInfo[pluginId].parameterData[parameterId]['midiCC'] = cc + def set_parameter_mapped_control_index(self, pluginId, parameterId, index): + self.sendMsg(["set_parameter_mapped_control_index", pluginId, parameterId, index]) + self.fPluginsInfo[pluginId].parameterData[parameterId]['mappedControlIndex'] = index + + def set_parameter_mapped_range(self, pluginId, parameterId, minimum, maximum): + self.sendMsg(["set_parameter_mapped_range", pluginId, parameterId, minimum, maximum]) + self.fPluginsInfo[pluginId].parameterData[parameterId]['mappedMinimum'] = minimum + self.fPluginsInfo[pluginId].parameterData[parameterId]['mappedMaximum'] = maximum def set_parameter_touch(self, pluginId, parameterId, touch): self.sendMsg(["set_parameter_touch", pluginId, parameterId, touch]) @@ -3768,36 +3762,36 @@ class CarlaHostPlugin(CarlaHostMeta): else: print("_set_parameterDefault failed for", pluginId, "and index", paramIndex) - def _set_parameterMidiChannel(self, pluginId, paramIndex, channel): + def _set_parameterMappedControlIndex(self, pluginId, paramIndex, index): plugin = self.fPluginsInfo.get(pluginId, None) if plugin is None: - print("_set_parameterMidiChannel failed for", pluginId) + print("_set_parameterMappedControlIndex failed for", pluginId) return if paramIndex < plugin.parameterCount: - plugin.parameterData[paramIndex]['midiChannel'] = channel + plugin.parameterData[paramIndex]['mappedControlIndex'] = index else: - print("_set_parameterMidiChannel failed for", pluginId, "and index", paramIndex) + print("_set_parameterMappedControlIndex failed for", pluginId, "and index", paramIndex) - def _set_parameterMidiCC(self, pluginId, paramIndex, cc): + def _set_parameterMappedRange(self, pluginId, paramIndex, minimum, maximum): plugin = self.fPluginsInfo.get(pluginId, None) if plugin is None: - print("_set_parameterMidiCC failed for", pluginId) + print("_set_parameterMappedRange failed for", pluginId) return if paramIndex < plugin.parameterCount: - plugin.parameterData[paramIndex]['midiCC'] = cc + plugin.parameterData[paramIndex]['mappedMinimum'] = minimum + plugin.parameterData[paramIndex]['mappedMaximum'] = maximum else: - print("_set_parameterMidiCC failed for", pluginId, "and index", paramIndex) + print("_set_parameterMappedRange failed for", pluginId, "and index", paramIndex) - def _set_parameterMappedRange(self, pluginId, paramIndex, minimum, maximum): + def _set_parameterMidiChannel(self, pluginId, paramIndex, channel): plugin = self.fPluginsInfo.get(pluginId, None) if plugin is None: - print("_set_parameterMappedRange failed for", pluginId) + print("_set_parameterMidiChannel failed for", pluginId) return if paramIndex < plugin.parameterCount: - plugin.parameterData[paramIndex]['mappedMinimum'] = minimum - plugin.parameterData[paramIndex]['mappedMaximum'] = maximum + plugin.parameterData[paramIndex]['midiChannel'] = channel else: - print("_set_parameterMappedRange failed for", pluginId, "and index", paramIndex) + print("_set_parameterMidiChannel failed for", pluginId, "and index", paramIndex) def _set_currentProgram(self, pluginId, pIndex): plugin = self.fPluginsInfo.get(pluginId, None) @@ -3877,16 +3871,16 @@ class CarlaHostPlugin(CarlaHostMeta): elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: self._set_parameterDefault(pluginId, value1, valuef) - elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: - self._set_parameterMidiCC(pluginId, value1, value2) - - elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: - self._set_parameterMidiChannel(pluginId, value1, value2) + elif action == ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED: + self._set_parameterMappedControlIndex(pluginId, value1, value2) elif action == ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED: minimum, maximum = (float(i) for i in valueStr.split(":")) self._set_parameterMappedRange(pluginId, value1, minimum, maximum) + elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: + self._set_parameterMidiChannel(pluginId, value1, value2) + elif action == ENGINE_CALLBACK_PROGRAM_CHANGED: self._set_currentProgram(pluginId, value1) diff --git a/source/frontend/carla_backend_qt.py b/source/frontend/carla_backend_qt.py index 2aee74b65..44cfd79fe 100644 --- a/source/frontend/carla_backend_qt.py +++ b/source/frontend/carla_backend_qt.py @@ -38,7 +38,7 @@ class CarlaHostSignals(QObject): PluginUnavailableCallback = pyqtSignal(int, str) ParameterValueChangedCallback = pyqtSignal(int, int, float) ParameterDefaultChangedCallback = pyqtSignal(int, int, float) - ParameterMidiCcChangedCallback = pyqtSignal(int, int, int) + ParameterMappedControlIndexChangedCallback = pyqtSignal(int, int, int) ParameterMidiChannelChangedCallback = pyqtSignal(int, int, int) ProgramChangedCallback = pyqtSignal(int, int) MidiProgramChangedCallback = pyqtSignal(int, int) diff --git a/source/frontend/carla_control.py b/source/frontend/carla_control.py index 51066c354..a9345de72 100755 --- a/source/frontend/carla_control.py +++ b/source/frontend/carla_control.py @@ -381,7 +381,7 @@ class CarlaControlServerTCP(Server): if DEBUG: print(path, args) self.fReceivedMsgs = True ( - pluginId, paramId, type_, hints, midiChan, midiCC, name, unit, + pluginId, paramId, type_, hints, mappedControlIndex, midiChan, name, unit, def_, min_, max_, step, stepSmall, stepLarge, value ) = args @@ -400,7 +400,7 @@ class CarlaControlServerTCP(Server): 'hints': hints, 'index': paramId, 'rindex': -1, - 'midiCC': midiCC, + 'mappedControlIndex': mappedControlIndex, 'midiChannel': midiChan, } self.host._set_parameterData(pluginId, paramId, paramData) diff --git a/source/frontend/carla_host.py b/source/frontend/carla_host.py index 75aa17a05..632b69f8e 100644 --- a/source/frontend/carla_host.py +++ b/source/frontend/carla_host.py @@ -2749,8 +2749,8 @@ def engineCallback(host, action, pluginId, value1, value2, value3, valuef, value host.ParameterValueChangedCallback.emit(pluginId, value1, valuef) elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: host.ParameterDefaultChangedCallback.emit(pluginId, value1, valuef) - elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: - host.ParameterMidiCcChangedCallback.emit(pluginId, value1, value2) + elif action == ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED: + host.ParameterMappedControlIndexChangedCallback.emit(pluginId, value1, value2) elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: host.ParameterMidiChannelChangedCallback.emit(pluginId, value1, value2) elif action == ENGINE_CALLBACK_PROGRAM_CHANGED: diff --git a/source/frontend/carla_skin.py b/source/frontend/carla_skin.py index 2d1b9884f..902069dd8 100644 --- a/source/frontend/carla_skin.py +++ b/source/frontend/carla_skin.py @@ -286,8 +286,8 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback) host.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback) host.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback) + host.ParameterMappedControlIndexChangedCallback.connect(self.slot_handleParameterMappedControlIndexChangedCallback) host.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback) - host.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback) host.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback) host.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback) host.OptionChangedCallback.connect(self.slot_handleOptionChangedCallback) @@ -322,9 +322,9 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): self.setParameterDefault(index, value) @pyqtSlot(int, int, int) - def slot_handleParameterMidiCcChangedCallback(self, pluginId, index, cc): + def slot_handleParameterMappedControlIndexChangedCallback(self, pluginId, index, ctrl): if self.fPluginId == pluginId: - self.setParameterMidiControl(index, cc) + self.setParameterMappedControlIndex(index, ctrl) @pyqtSlot(int, int, int) def slot_handleParameterMidiChannelChangedCallback(self, pluginId, index, channel): @@ -738,8 +738,8 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): def setParameterDefault(self, parameterId, value): self.fEditDialog.setParameterDefault(parameterId, value) - def setParameterMidiControl(self, parameterId, control): - self.fEditDialog.setParameterMidiControl(parameterId, control) + def setParameterMappedControlIndex(self, parameterId, control): + self.fEditDialog.setParameterMappedControlIndex(parameterId, control) def setParameterMidiChannel(self, parameterId, channel): self.fEditDialog.setParameterMidiChannel(parameterId, channel) diff --git a/source/frontend/carla_widgets.py b/source/frontend/carla_widgets.py index 2e4138414..5a92fe693 100755 --- a/source/frontend/carla_widgets.py +++ b/source/frontend/carla_widgets.py @@ -211,9 +211,9 @@ class JuceAboutW(QDialog): # Plugin Parameter class PluginParameter(QWidget): - midiControlChanged = pyqtSignal(int, int) - midiChannelChanged = pyqtSignal(int, int) - valueChanged = pyqtSignal(int, float) + mappedControlChanged = pyqtSignal(int, int) + midiChannelChanged = pyqtSignal(int, int) + valueChanged = pyqtSignal(int, float) def __init__(self, parent, host, pInfo, pluginId, tabIndex): QWidget.__init__(self, parent) @@ -229,7 +229,7 @@ class PluginParameter(QWidget): # ------------------------------------------------------------- # Internal stuff - self.fMidiControl = -1 + self.fMappedCtrl = CONTROL_VALUE_NONE self.fMidiChannel = 1 self.fParameterId = pInfo['index'] self.fPluginId = pluginId @@ -261,23 +261,21 @@ class PluginParameter(QWidget): self.ui.label.setEnabled(False) self.ui.widget.setEnabled(False) self.ui.widget.setReadOnly(True) - self.ui.sb_control.setEnabled(False) - self.ui.sb_channel.setEnabled(False) + self.ui.tb_options.setEnabled(False) elif not pHints & PARAMETER_IS_AUTOMABLE: - self.ui.sb_control.setEnabled(False) - self.ui.sb_channel.setEnabled(False) + self.ui.tb_options.setEnabled(False) if pHints & PARAMETER_IS_READ_ONLY: self.ui.widget.setReadOnly(True) + self.ui.tb_options.setEnabled(False) elif pType == PARAMETER_OUTPUT: self.ui.widget.setReadOnly(True) else: self.ui.widget.setVisible(False) - self.ui.sb_control.setVisible(False) - self.ui.sb_channel.setVisible(False) + self.ui.tb_options.setVisible(False) # Only set value after all hints are handled self.ui.widget.setValue(pInfo['current']) @@ -288,16 +286,13 @@ class PluginParameter(QWidget): self.ui.widget.setValueCallback(self._valueCallBack) self.ui.widget.updateAll() - self.setMidiControl(pInfo['midiCC']) + self.setMappedControlIndex(pInfo['mappedControlIndex']) self.setMidiChannel(pInfo['midiChannel']) # ------------------------------------------------------------- # Set-up connections - self.ui.sb_control.customContextMenuRequested.connect(self.slot_controlSpinboxCustomMenu) - self.ui.sb_channel.customContextMenuRequested.connect(self.slot_channelSpinboxCustomMenu) - self.ui.sb_control.valueChanged.connect(self.slot_controlSpinboxChanged) - self.ui.sb_channel.valueChanged.connect(self.slot_channelSpinboxChanged) + self.ui.tb_options.clicked.connect(self.slot_optionsCustomMenu) self.ui.widget.dragStateChanged.connect(self.slot_parameterDragStateChanged) # ------------------------------------------------------------- @@ -319,55 +314,91 @@ class PluginParameter(QWidget): self.ui.widget.setValue(value) self.ui.widget.blockSignals(False) - def setMidiControl(self, control): - self.fMidiControl = control - self.ui.sb_control.blockSignals(True) - self.ui.sb_control.setValue(control) - self.ui.sb_control.blockSignals(False) + def setMappedControlIndex(self, control): + self.fMappedCtrl = control def setMidiChannel(self, channel): self.fMidiChannel = channel - self.ui.sb_channel.blockSignals(True) - self.ui.sb_channel.setValue(channel) - self.ui.sb_channel.blockSignals(False) def setLabelWidth(self, width): self.ui.label.setFixedWidth(width) @pyqtSlot() - def slot_controlSpinboxCustomMenu(self): + def slot_optionsCustomMenu(self): menu = QMenu(self) - actNone = menu.addAction(self.tr("None")) + if self.fMappedCtrl == CONTROL_VALUE_NONE: + title = self.tr("Unmapped") + elif self.fMappedCtrl == CONTROL_VALUE_CV: + title = self.tr("Exposed as CV") + else: + title = self.tr("Mapped to CC %i, channel %i" % (self.fMappedCtrl, self.fMidiChannel)) - if self.fMidiControl == -1: - actNone.setCheckable(True) - actNone.setChecked(True) + actTitle = menu.addAction(title) + actTitle.setEnabled(False) + + menu.addSeparator() + + actUnmap = menu.addAction(self.tr("Unmap")) + + if self.fMappedCtrl == CONTROL_VALUE_NONE: + actUnmap.setCheckable(True) + actUnmap.setChecked(True) + + menu.addSection("CV") + + actCV = menu.addAction(self.tr("Expose as CV port")) + if self.fMappedCtrl == CONTROL_VALUE_CV: + actCV.setCheckable(True) + actCV.setChecked(True) + + menu.addSection("MIDI") + + menuMIDI = menu.addMenu(self.tr("MIDI Control")) + + if self.fMappedCtrl not in (CONTROL_VALUE_NONE, CONTROL_VALUE_CV, CONTROL_VALUE_MIDI_PITCHBEND): + action = menuMIDI.menuAction() + action.setCheckable(True) + action.setChecked(True) + + inlist = False + actCCs = [] for cc in MIDI_CC_LIST: - action = menu.addAction(cc) + action = menuMIDI.addAction(cc) + actCCs.append(action) - if self.fMidiControl != -1 and int(cc.split(" ", 1)[0], 16) == self.fMidiControl: - action.setCheckable(True) - action.setChecked(True) + if self.fMappedCtrl >= 0: + ccx = int(cc.split(" ", 1)[0], 16) - actSel = menu.exec_(QCursor.pos()) + if ccx > self.fMappedCtrl and not inlist: + inlist = True + action = menuMIDI.addAction(self.tr("0x%x (Custom)" % self.fMappedCtrl)) + action.setCheckable(True) + action.setChecked(True) + actCCs.append(action) - if not actSel: - pass - elif actSel == actNone: - self.ui.sb_control.setValue(-1) - else: - selControlStr = actSel.text() - selControl = int(selControlStr.split(" ", 1)[0].replace("&",""), 16) - self.ui.sb_control.setValue(selControl) + elif ccx == self.fMappedCtrl: + inlist = True + action.setCheckable(True) + action.setChecked(True) - @pyqtSlot() - def slot_channelSpinboxCustomMenu(self): - menu = QMenu(self) + # TODO + #menuMIDI.addAction(self.tr("Custom...")) + + # TODO + #actPitchbend = menu.addAction(self.tr("MIDI Pitchbend")) + #if self.fMappedCtrl == CONTROL_VALUE_MIDI_PITCHBEND: + #actPitchbend.setCheckable(True) + #actPitchbend.setChecked(True) + + menuChannel = menu.addMenu(self.tr("MIDI Channel")) + + actChannels = [] for i in range(1, 16+1): - action = menu.addAction("%i" % i) + action = menuChannel.addAction("%i" % i) + actChannels.append(action) if self.fMidiChannel == i: action.setCheckable(True) @@ -375,19 +406,28 @@ class PluginParameter(QWidget): actSel = menu.exec_(QCursor.pos()) - if actSel: - selChannel = int(actSel.text()) - self.ui.sb_channel.setValue(selChannel) + if not actSel: + return - @pyqtSlot(int) - def slot_controlSpinboxChanged(self, control): - self.fMidiControl = control - self.midiControlChanged.emit(self.fParameterId, control) + if actSel in actChannels: + channel = int(actSel.text()) + self.fMidiChannel = channel + self.midiChannelChanged.emit(self.fParameterId, channel) + return - @pyqtSlot(int) - def slot_channelSpinboxChanged(self, channel): - self.fMidiChannel = channel - self.midiChannelChanged.emit(self.fParameterId, channel) + if actSel == actUnmap: + ctrl = CONTROL_VALUE_NONE + elif actSel == actCV: + ctrl = CONTROL_VALUE_CV + elif actSel in actCCs: + ctrl = int(actSel.text().split(" ", 1)[0].replace("&",""), 16) + #elif actSel in actPitchbend: + #ctrl = CONTROL_VALUE_MIDI_PITCHBEND + else: + return + + self.fMappedCtrl = ctrl + self.mappedControlChanged.emit(self.fParameterId, ctrl) @pyqtSlot(bool) def slot_parameterDragStateChanged(self, touch): @@ -856,7 +896,7 @@ class PluginEdit(QDialog): 'step': paramRanges['step'], 'stepSmall': paramRanges['stepSmall'], 'stepLarge': paramRanges['stepLarge'], - 'midiCC': paramData['midiCC'], + 'mappedControlIndex': paramData['mappedControlIndex'], 'midiChannel': paramData['midiChannel']+1, 'comment': paramInfo['comment'], @@ -1000,10 +1040,10 @@ class PluginEdit(QDialog): paramWidget.setDefault(value) break - def setParameterMidiControl(self, parameterId, control): + def setParameterMappedControlIndex(self, parameterId, control): for paramType, paramId, paramWidget in self.fParameterList: if paramId == parameterId: - paramWidget.setMidiControl(control) + paramWidget.setMappedControlIndex(control) break def setParameterMidiChannel(self, parameterId, channel): @@ -1310,8 +1350,8 @@ class PluginEdit(QDialog): self.fParent.editDialogParameterValueChanged(self.fPluginId, parameterId, value) @pyqtSlot(int, int) - def slot_parameterMidiControlChanged(self, parameterId, control): - self.host.set_parameter_midi_cc(self.fPluginId, parameterId, control) + def slot_parameterMappedControlChanged(self, parameterId, control): + self.host.set_parameter_mapped_control_index(self.fPluginId, parameterId, control) @pyqtSlot(int, int) def slot_parameterMidiChannelChanged(self, parameterId, channel): @@ -1514,7 +1554,7 @@ class PluginEdit(QDialog): if paramType == PARAMETER_INPUT: paramWidget.valueChanged.connect(self.slot_parameterValueChanged) - paramWidget.midiControlChanged.connect(self.slot_parameterMidiControlChanged) + paramWidget.mappedControlChanged.connect(self.slot_parameterMappedControlChanged) paramWidget.midiChannelChanged.connect(self.slot_parameterMidiChannelChanged) scrollAreaLayout.addStretch() diff --git a/source/includes/CarlaMIDI.h b/source/includes/CarlaMIDI.h index 566892967..50b58b080 100644 --- a/source/includes/CarlaMIDI.h +++ b/source/includes/CarlaMIDI.h @@ -21,7 +21,7 @@ #define MAX_MIDI_CHANNELS 16 #define MAX_MIDI_NOTE 128 #define MAX_MIDI_VALUE 128 -#define MAX_MIDI_CONTROL 120 /* 0x77 */ +#define MAX_MIDI_CONTROL 120 /* 0x77 + 1 */ #define MIDI_STATUS_BIT 0xF0 #define MIDI_CHANNEL_BIT 0x0F diff --git a/source/native-plugins/resources/carla-plugin b/source/native-plugins/resources/carla-plugin index 4f4136d71..a6b29d026 100755 --- a/source/native-plugins/resources/carla-plugin +++ b/source/native-plugins/resources/carla-plugin @@ -278,7 +278,8 @@ class CarlaMiniW(ExternalUI, HostWindow): elif msg.startswith("PARAMETER_DATA_"): pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")] - paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.readlineblock().split(":")] + paramType, paramHints, mappedControlIndex, midiChannel = [int(i) for i in self.readlineblock().split(":")] + mappedMinimum, mappedMaximum = [float(i) for i in self.readlineblock().split(":")] paramName = self.readlineblock().replace("\r", "\n") paramUnit = self.readlineblock().replace("\r", "\n") paramComment = self.readlineblock().replace("\r", "\n") @@ -299,8 +300,10 @@ class CarlaMiniW(ExternalUI, HostWindow): 'hints': paramHints, 'index': paramId, 'rindex': -1, - 'midiCC': midiCC, - 'midiChannel': midiChannel + 'midiChannel': midiChannel, + 'mappedControlIndex': mappedControlIndex, + 'mappedMinimum': mappedMinimum, + 'mappedMaximum': mappedMaximum, } self.host._set_parameterData(pluginId, paramId, paramData) diff --git a/source/utils/CarlaBackendUtils.hpp b/source/utils/CarlaBackendUtils.hpp index 2971be15c..9be61bb7f 100644 --- a/source/utils/CarlaBackendUtils.hpp +++ b/source/utils/CarlaBackendUtils.hpp @@ -232,10 +232,10 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: return "ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED"; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + case ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED: + return "ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED"; case ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: return "ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED"; - case ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: - return "ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED"; case ENGINE_CALLBACK_OPTION_CHANGED: return "ENGINE_CALLBACK_OPTION_CHANGED"; #endif @@ -313,8 +313,6 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept return "ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_REMOVED"; case ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED: return "ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED"; - case ENGINE_CALLBACK_PARAMETER_CV_CONTROLLED_STATUS_CHANGED: - return "ENGINE_CALLBACK_PARAMETER_CV_CONTROLLED_STATUS_CHANGED"; case ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED: return "ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED"; } diff --git a/source/utils/CarlaBridgeDefines.hpp b/source/utils/CarlaBridgeDefines.hpp index 281e484ca..b4affd899 100644 --- a/source/utils/CarlaBridgeDefines.hpp +++ b/source/utils/CarlaBridgeDefines.hpp @@ -48,35 +48,35 @@ enum PluginBridgeRtClientOpcode { // Server sends these to client during non-RT enum PluginBridgeNonRtClientOpcode { kPluginBridgeNonRtClientNull = 0, - kPluginBridgeNonRtClientVersion, // uint + kPluginBridgeNonRtClientVersion, // uint kPluginBridgeNonRtClientPing, - kPluginBridgeNonRtClientPingOnOff, // bool + kPluginBridgeNonRtClientPingOnOff, // bool kPluginBridgeNonRtClientActivate, kPluginBridgeNonRtClientDeactivate, - kPluginBridgeNonRtClientInitialSetup, // uint, double - kPluginBridgeNonRtClientSetParameterValue, // uint, float - kPluginBridgeNonRtClientSetParameterMidiChannel, // uint, byte - kPluginBridgeNonRtClientSetParameterMidiCC, // uint, short - kPluginBridgeNonRtClientSetProgram, // int - kPluginBridgeNonRtClientSetMidiProgram, // int - kPluginBridgeNonRtClientSetCustomData, // uint/size, str[], uint/size, str[], uint/size, str[] - kPluginBridgeNonRtClientSetChunkDataFile, // uint/size, str[] (filename, base64 content) - kPluginBridgeNonRtClientSetCtrlChannel, // short - kPluginBridgeNonRtClientSetOption, // uint/option, bool - kPluginBridgeNonRtClientGetParameterText, // uint + kPluginBridgeNonRtClientInitialSetup, // uint, double + kPluginBridgeNonRtClientSetParameterValue, // uint, float + kPluginBridgeNonRtClientSetParameterMidiChannel, // uint, byte + kPluginBridgeNonRtClientSetParameterMappedControlIndex, // uint, short + kPluginBridgeNonRtClientSetProgram, // int + kPluginBridgeNonRtClientSetMidiProgram, // int + kPluginBridgeNonRtClientSetCustomData, // uint/size, str[], uint/size, str[], uint/size, str[] + kPluginBridgeNonRtClientSetChunkDataFile, // uint/size, str[] (filename, base64 content) + kPluginBridgeNonRtClientSetCtrlChannel, // short + kPluginBridgeNonRtClientSetOption, // uint/option, bool + kPluginBridgeNonRtClientGetParameterText, // uint kPluginBridgeNonRtClientPrepareForSave, kPluginBridgeNonRtClientRestoreLV2State, kPluginBridgeNonRtClientShowUI, kPluginBridgeNonRtClientHideUI, - kPluginBridgeNonRtClientUiParameterChange, // uint, float - kPluginBridgeNonRtClientUiProgramChange, // uint - kPluginBridgeNonRtClientUiMidiProgramChange, // uint - kPluginBridgeNonRtClientUiNoteOn, // byte, byte, byte - kPluginBridgeNonRtClientUiNoteOff, // byte, byte + kPluginBridgeNonRtClientUiParameterChange, // uint, float + kPluginBridgeNonRtClientUiProgramChange, // uint + kPluginBridgeNonRtClientUiMidiProgramChange, // uint + kPluginBridgeNonRtClientUiNoteOn, // byte, byte, byte + kPluginBridgeNonRtClientUiNoteOff, // byte, byte kPluginBridgeNonRtClientQuit, // stuff added in API 7 - kPluginBridgeNonRtClientSetParameterMappedRange, // uint, float, float - kPluginBridgeNonRtClientSetOptions, // uint + kPluginBridgeNonRtClientSetParameterMappedRange, // uint, float, float + kPluginBridgeNonRtClientSetOptions, // uint }; // Client sends these to server during non-RT diff --git a/source/utils/CarlaBridgeUtils.hpp b/source/utils/CarlaBridgeUtils.hpp index 862e8a48d..4e9b56190 100644 --- a/source/utils/CarlaBridgeUtils.hpp +++ b/source/utils/CarlaBridgeUtils.hpp @@ -85,8 +85,8 @@ const char* PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcod return "kPluginBridgeNonRtClientSetParameterValue"; case kPluginBridgeNonRtClientSetParameterMidiChannel: return "kPluginBridgeNonRtClientSetParameterMidiChannel"; - case kPluginBridgeNonRtClientSetParameterMidiCC: - return "kPluginBridgeNonRtClientSetParameterMidiCC"; + case kPluginBridgeNonRtClientSetParameterMappedControlIndex: + return "kPluginBridgeNonRtClientSetParameterMappedControlIndex"; case kPluginBridgeNonRtClientSetProgram: return "kPluginBridgeNonRtClientSetProgram"; case kPluginBridgeNonRtClientSetMidiProgram: diff --git a/source/utils/CarlaStateUtils.cpp b/source/utils/CarlaStateUtils.cpp index c209500e3..7ecf86871 100644 --- a/source/utils/CarlaStateUtils.cpp +++ b/source/utils/CarlaStateUtils.cpp @@ -124,8 +124,8 @@ CarlaStateSave::Parameter::Parameter() noexcept symbol(nullptr), #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH value(0.0f), - midiChannel(0), - midiCC(-1) {} + mappedControlIndex(CONTROL_INDEX_NONE), + midiChannel(0) {} #else value(0.0f) {} #endif @@ -441,8 +441,14 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) else if (pTag == "MidiCC") { const int cc(pText.getIntValue()); - if (cc >= -1 && cc < MAX_MIDI_CONTROL) - stateParameter->midiCC = static_cast(cc); + if (cc > 0 && cc < MAX_MIDI_CONTROL) + stateParameter->mappedControlIndex = static_cast(cc); + } + else if (pTag == "MappedControlIndex") + { + const int ctrl(pText.getIntValue()); + if (ctrl > CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED) + stateParameter->mappedControlIndex = static_cast(ctrl); } #endif } @@ -598,10 +604,18 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const parameterXml << " " << xmlSafeString(stateParameter->symbol, true) << "\n"; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - if (stateParameter->midiCC > 0) + if (stateParameter->mappedControlIndex > CONTROL_INDEX_NONE && stateParameter->mappedControlIndex <= CONTROL_INDEX_MAX_ALLOWED) { - parameterXml << " " << stateParameter->midiCC << "\n"; - parameterXml << " " << stateParameter->midiChannel+1 << "\n"; + parameterXml << " " << stateParameter->midiChannel+1 << "\n"; + /* + parameterXml << " " << stateParameter->mappedMinimum << "\n"; + parameterXml << " " << stateParameter->mappedMaximum << "\n"; + */ + parameterXml << " " << stateParameter->mappedControlIndex << "\n"; + + // backwards compatibility for older carla versions + if (stateParameter->mappedControlIndex > 0 && stateParameter->mappedControlIndex < MAX_MIDI_CONTROL) + parameterXml << " " << stateParameter->mappedControlIndex << "\n"; } #endif diff --git a/source/utils/CarlaStateUtils.hpp b/source/utils/CarlaStateUtils.hpp index 65681aa44..c83f5b355 100644 --- a/source/utils/CarlaStateUtils.hpp +++ b/source/utils/CarlaStateUtils.hpp @@ -35,8 +35,8 @@ struct CarlaStateSave { const char* symbol; float value; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + int16_t mappedControlIndex; uint8_t midiChannel; - int16_t midiCC; #endif Parameter() noexcept;