| @@ -7,7 +7,7 @@ | |||
| <x>0</x> | |||
| <y>0</y> | |||
| <width>369</width> | |||
| <height>22</height> | |||
| <height>33</height> | |||
| </rect> | |||
| </property> | |||
| <property name="windowTitle"> | |||
| @@ -41,43 +41,9 @@ | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <widget class="QSpinBox" name="sb_control"> | |||
| <property name="contextMenuPolicy"> | |||
| <enum>Qt::CustomContextMenu</enum> | |||
| </property> | |||
| <property name="specialValueText"> | |||
| <string>(none)</string> | |||
| </property> | |||
| <property name="prefix"> | |||
| <string>cc #</string> | |||
| </property> | |||
| <property name="minimum"> | |||
| <number>-1</number> | |||
| </property> | |||
| <property name="maximum"> | |||
| <number>119</number> | |||
| </property> | |||
| <property name="value"> | |||
| <number>-1</number> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| <item> | |||
| <widget class="QSpinBox" name="sb_channel"> | |||
| <property name="contextMenuPolicy"> | |||
| <enum>Qt::CustomContextMenu</enum> | |||
| </property> | |||
| <property name="prefix"> | |||
| <string>ch </string> | |||
| </property> | |||
| <property name="minimum"> | |||
| <number>1</number> | |||
| </property> | |||
| <property name="maximum"> | |||
| <number>16</number> | |||
| </property> | |||
| <property name="value"> | |||
| <number>1</number> | |||
| <widget class="QToolButton" name="tb_options"> | |||
| <property name="text"> | |||
| <string>...</string> | |||
| </property> | |||
| </widget> | |||
| </item> | |||
| @@ -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. | |||
| */ | |||
| @@ -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. | |||
| @@ -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. | |||
| @@ -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) | |||
| @@ -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<double>(paramData.mappedMinimum), | |||
| static_cast<double>(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<uint8_t>(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<uint8_t>(channel), true, false); | |||
| plugin->setParameterMappedControlIndex(parameterId, static_cast<int16_t>(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<int16_t>(cc), true, false); | |||
| plugin->setParameterMappedRange(parameterId, minimum, maximum, true, false); | |||
| } | |||
| else if (std::strcmp(msg, "set_parameter_touch") == 0) | |||
| { | |||
| @@ -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); | |||
| @@ -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<uint32_t>(index), static_cast<int16_t>(cc), false, true); | |||
| plugin->setParameterMappedControlIndex(static_cast<uint32_t>(index), static_cast<int16_t>(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<uint32_t>(index), minimum, maximum, false, true); | |||
| return 0; | |||
| } | |||
| @@ -149,7 +149,7 @@ void CarlaEngineOsc::sendPluginParameterInfo(const CarlaPlugin* const plugin, co | |||
| try_lo_send(fControlDataTCP.target, targetPath, "iiiiiissfffffff", | |||
| static_cast<int32_t>(plugin->getId()), static_cast<int32_t>(index), | |||
| static_cast<int32_t>(paramData.type), static_cast<int32_t>(paramData.hints), | |||
| static_cast<int32_t>(paramData.midiChannel), static_cast<int32_t>(paramData.midiCC), | |||
| static_cast<int32_t>(paramData.mappedControlIndex), static_cast<int32_t>(paramData.midiChannel), | |||
| bufName, bufUnit, | |||
| static_cast<double>(paramRanges.def), | |||
| static_cast<double>(paramRanges.min), | |||
| @@ -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<uint32_t>(index), stateParameter->midiCC, true, true); | |||
| setParameterMappedControlIndex(static_cast<uint32_t>(index), stateParameter->mappedControlIndex, true, true); | |||
| setParameterMidiChannel(static_cast<uint32_t>(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<int>(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<int>(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<int>(parameterId), | |||
| 0, 0, 0.0f, | |||
| @@ -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<uint16_t>(pData->param.data[k].midiCC), value); | |||
| pData->event.portOut->writeControlEvent(0, | |||
| pData->param.data[k].midiChannel, | |||
| kEngineControlEventTypeParameter, | |||
| static_cast<uint16_t>(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<int32_t>(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; | |||
| @@ -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<uint16_t>(pData->param.data[k].midiCC), value); | |||
| pData->event.portOut->writeControlEvent(0, | |||
| pData->param.data[k].midiChannel, | |||
| kEngineControlEventTypeParameter, | |||
| static_cast<uint16_t>(pData->param.data[k].mappedControlIndex), | |||
| value); | |||
| } | |||
| } // End of Control Output | |||
| @@ -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]; | |||
| @@ -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; | |||
| @@ -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<uint16_t>(pData->param.data[k].midiCC); | |||
| param = static_cast<uint16_t>(pData->param.data[k].mappedControlIndex); | |||
| value = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]); | |||
| pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter, param, value); | |||
| } | |||
| @@ -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<int16_t>(portMidiMap.Number); | |||
| pData->param.data[j].mappedControlIndex = static_cast<int16_t>(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<uint16_t>(pData->param.data[k].midiCC); | |||
| param = static_cast<uint16_t>(pData->param.data[k].mappedControlIndex); | |||
| value = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]); | |||
| pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter, param, value); | |||
| } | |||
| @@ -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<uint16_t>(pData->param.data[k].midiCC), value); | |||
| pData->event.portOut->writeControlEvent(0, | |||
| pData->param.data[k].midiChannel, | |||
| kEngineControlEventTypeParameter, | |||
| static_cast<uint16_t>(pData->param.data[k].mappedControlIndex), | |||
| value); | |||
| } | |||
| } | |||
| } // End of Control Output | |||
| @@ -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; | |||
| @@ -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; | |||
| @@ -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) | |||
| @@ -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) | |||
| @@ -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) | |||
| @@ -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: | |||
| @@ -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) | |||
| @@ -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() | |||
| @@ -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 | |||
| @@ -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) | |||
| @@ -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"; | |||
| } | |||
| @@ -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 | |||
| @@ -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: | |||
| @@ -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<int16_t>(cc); | |||
| if (cc > 0 && cc < MAX_MIDI_CONTROL) | |||
| stateParameter->mappedControlIndex = static_cast<int16_t>(cc); | |||
| } | |||
| else if (pTag == "MappedControlIndex") | |||
| { | |||
| const int ctrl(pText.getIntValue()); | |||
| if (ctrl > CONTROL_INDEX_NONE && ctrl <= CONTROL_INDEX_MAX_ALLOWED) | |||
| stateParameter->mappedControlIndex = static_cast<int16_t>(ctrl); | |||
| } | |||
| #endif | |||
| } | |||
| @@ -598,10 +604,18 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||
| parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; | |||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
| if (stateParameter->midiCC > 0) | |||
| if (stateParameter->mappedControlIndex > CONTROL_INDEX_NONE && stateParameter->mappedControlIndex <= CONTROL_INDEX_MAX_ALLOWED) | |||
| { | |||
| parameterXml << " <MidiCC>" << stateParameter->midiCC << "</MidiCC>\n"; | |||
| parameterXml << " <MidiChannel>" << stateParameter->midiChannel+1 << "</MidiChannel>\n"; | |||
| parameterXml << " <MidiChannel>" << stateParameter->midiChannel+1 << "</MidiChannel>\n"; | |||
| /* | |||
| parameterXml << " <MappedMinimum>" << stateParameter->mappedMinimum << "</MappedMinimum>\n"; | |||
| parameterXml << " <MappedMaximum>" << stateParameter->mappedMaximum << "</MappedMaximum>\n"; | |||
| */ | |||
| parameterXml << " <MappedControlIndex>" << stateParameter->mappedControlIndex << "</MappedControlIndex>\n"; | |||
| // backwards compatibility for older carla versions | |||
| if (stateParameter->mappedControlIndex > 0 && stateParameter->mappedControlIndex < MAX_MIDI_CONTROL) | |||
| parameterXml << " <MidiCC>" << stateParameter->mappedControlIndex << "</MidiCC>\n"; | |||
| } | |||
| #endif | |||
| @@ -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; | |||