From cd0705b13c41182344c68b7316309d0461cf4ade Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 12 Jan 2014 04:26:52 +0000 Subject: [PATCH] More work for carla-plugin, rack mode now kinda working --- source/backend/engine/CarlaEngineNative.cpp | 488 +++++++++++++++++++- source/carla-plugin | 303 ++++++++++-- source/externalui.py | 11 +- source/utils/CarlaPipeUtils.hpp | 52 ++- 4 files changed, 795 insertions(+), 59 deletions(-) diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 50d4f52a1..376314fcd 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -77,17 +77,6 @@ public: protected: void msgReceived(const char* const msg) override { - /* - * TODO: - * load_file load_project save_project patchbay_connect patchbay_disconnect patchbay_refresh - * transport_play transport_pause transport_relocate - * *add_plugin* remove_plugin remove_all_plugins rename_plugin clone_plugin replace_plugin switch_plugins - * load_plugin_state save_plugin_state - * set_option *set_active* set_drywet set_volume set_balance_left set_balance_right set_panning set_ctrl_channel - * set_parameter_value set_parameter_midi_channel set_parameter_midi_cc set_program set_midi_program set_custom_data set_chunk_data - * prepare_for_save send_midi_note show_custom_ui - */ - if (std::strcmp(msg, "exiting") == 0) { waitChildClose(); @@ -103,21 +92,196 @@ protected: CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(valueStr),); fEngine->setOption((EngineOption)option, value, valueStr); + + delete[] valueStr; + } + else if (std::strcmp(msg, "load_file") == 0) + { + const char* filename; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + + fEngine->loadFile(filename); + + delete[] filename; + } + else if (std::strcmp(msg, "load_project") == 0) + { + const char* filename; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + + fEngine->loadProject(filename); + + delete[] filename; + } + else if (std::strcmp(msg, "save_project") == 0) + { + const char* filename; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + + fEngine->saveProject(filename); + + delete[] filename; + } + else if (std::strcmp(msg, "patchbay_connect") == 0) + { + int portA, portB; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(portA),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(portB),); + + fEngine->patchbayConnect(portA, portB); + } + else if (std::strcmp(msg, "patchbay_disconnect") == 0) + { + int connectionId; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(connectionId),); + + fEngine->patchbayDisconnect(connectionId); + } + else if (std::strcmp(msg, "patchbay_refresh") == 0) + { + fEngine->patchbayRefresh(); + } + else if (std::strcmp(msg, "transport_play") == 0) + { + fEngine->transportPlay(); + } + else if (std::strcmp(msg, "transport_pause") == 0) + { + fEngine->transportPause(); + } + else if (std::strcmp(msg, "transport_relocate") == 0) + { + long frame; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsLong(frame),); + + fEngine->transportRelocate((uint64_t)frame); } else if (std::strcmp(msg, "add_plugin") == 0) { int btype, ptype; - const char* filename; + const char* filename = nullptr; const char* name; const char* label; CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(btype),); CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(ptype),); - CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + readNextLineAsString(filename); // can be null CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(name),); CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(label),); + if (filename != nullptr && std::strcmp(filename, "(null)") == 0) + { + delete[] filename; + filename = nullptr; + } + + if (std::strcmp(name, "(null)") == 0) + { + delete[] name; + name = nullptr; + } + fEngine->addPlugin((BinaryType)btype, (PluginType)ptype, filename, name, label); + + if (filename != nullptr) + delete[] filename; + if (name != nullptr) + delete[] name; + delete[] label; + } + else if (std::strcmp(msg, "remove_plugin") == 0) + { + int pluginId; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + + fEngine->removePlugin(pluginId); + } + else if (std::strcmp(msg, "remove_all_plugins") == 0) + { + fEngine->removeAllPlugins(); + } + else if (std::strcmp(msg, "rename_plugin") == 0) + { + int pluginId; + const char* newName; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(newName),); + + /*const char* name =*/ fEngine->renamePlugin(pluginId, newName); + + delete[] newName; + } + else if (std::strcmp(msg, "clone_plugin") == 0) + { + int pluginId; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + + fEngine->clonePlugin(pluginId); + } + else if (std::strcmp(msg, "replace_plugin") == 0) + { + int pluginId; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + + fEngine->replacePlugin(pluginId); + } + else if (std::strcmp(msg, "switch_plugins") == 0) + { + int pluginIdA, pluginIdB; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginIdA),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginIdB),); + + fEngine->switchPlugins(pluginIdA, pluginIdB); + } + else if (std::strcmp(msg, "load_plugin_state") == 0) + { + int pluginId; + const char* filename; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->loadStateFromFile(filename); + + delete[] filename; + } + else if (std::strcmp(msg, "save_plugin_state") == 0) + { + int pluginId; + const char* filename; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(filename),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->saveStateToFile(filename); + + delete[] filename; + } + else if (std::strcmp(msg, "set_option") == 0) + { + int pluginId; + int option; + bool yesNo; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(option),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(yesNo),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setOption(option, yesNo); } else if (std::strcmp(msg, "set_active") == 0) { @@ -130,6 +294,198 @@ protected: if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) plugin->setActive(onOff, true, false); } + else if (std::strcmp(msg, "set_drywet") == 0) + { + int pluginId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setDryWet(value, true, false); + } + else if (std::strcmp(msg, "set_volume") == 0) + { + int pluginId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setVolume(value, true, false); + } + else if (std::strcmp(msg, "set_balance_left") == 0) + { + int pluginId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setBalanceLeft(value, true, false); + } + else if (std::strcmp(msg, "set_balance_right") == 0) + { + int pluginId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setBalanceRight(value, true, false); + } + else if (std::strcmp(msg, "set_panning") == 0) + { + int pluginId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setPanning(value, true, false); + } + else if (std::strcmp(msg, "set_ctrl_channel") == 0) + { + int pluginId; + int channel; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(channel),); + CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setCtrlChannel(int8_t(channel), true, false); + } + else if (std::strcmp(msg, "set_parameter_value") == 0) + { + int pluginId; + int parameterId; + float value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(parameterId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setParameterValue(parameterId, value, true, true, false); + } + else if (std::strcmp(msg, "set_parameter_midi_channel") == 0) + { + int pluginId; + int parameterId; + int channel; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(parameterId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(channel),); + CARLA_SAFE_ASSERT_RETURN(channel >= 0 && channel < MAX_MIDI_CHANNELS,); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setParameterMidiChannel(parameterId, uint8_t(channel), true, false); + } + else if (std::strcmp(msg, "set_parameter_midi_cc") == 0) + { + int pluginId; + int parameterId; + int cc; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(parameterId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(cc),); + CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < 0x5F,); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setParameterMidiCC(parameterId, int16_t(cc), true, false); + } + else if (std::strcmp(msg, "set_program") == 0) + { + int pluginId; + int index; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(index),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setProgram(index, true, true, false); + } + else if (std::strcmp(msg, "set_midi_program") == 0) + { + int pluginId; + int index; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(index),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setMidiProgram(index, true, true, false); + } + else if (std::strcmp(msg, "set_custom_data") == 0) + { + int pluginId; + const char* type; + const char* key; + const char* value; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(type),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setCustomData(type, key, value, true); + } + else if (std::strcmp(msg, "set_chunk_data") == 0) + { + int pluginId; + const char* cdata; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(cdata),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->setChunkData(cdata); + } + else if (std::strcmp(msg, "prepare_for_save") == 0) + { + int pluginId; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->prepareForSave(); + } + else if (std::strcmp(msg, "send_midi_note") == 0) + { + int pluginId; + int channel, note, velocity; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(channel),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(note),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(velocity),); + CARLA_SAFE_ASSERT_RETURN(channel >= 0 && channel < MAX_MIDI_CHANNELS,); + CARLA_SAFE_ASSERT_RETURN(note >= 0 && channel < MAX_MIDI_VALUE,); + CARLA_SAFE_ASSERT_RETURN(velocity >= 0 && channel < MAX_MIDI_VALUE,); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->sendMidiSingleNote(uint8_t(channel), uint8_t(note), uint8_t(velocity), true, true, false); + } + else if (std::strcmp(msg, "show_custom_ui") == 0) + { + int pluginId; + bool yesNo; + + CARLA_SAFE_ASSERT_RETURN(readNextLineAsInt(pluginId),); + CARLA_SAFE_ASSERT_RETURN(readNextLineAsBool(yesNo),); + + if (CarlaPlugin* const plugin = fEngine->getPlugin(pluginId)) + plugin->showCustomUI(yesNo); + } else { carla_stderr("msgReceived : %s", msg); @@ -256,6 +612,97 @@ protected: return; char strBuf[STR_MAX+1]; + + switch (action) + { + case ENGINE_CALLBACK_PLUGIN_ADDED: + if (CarlaPlugin* const plugin = getPlugin(pluginId)) + { + CARLA_SAFE_ASSERT_BREAK(plugin->getId() == pluginId); + + std::sprintf(strBuf, "PLUGIN_INFO_%i\n", pluginId); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%i:%i:%i:%li\n", plugin->getType(), plugin->getCategory(), plugin->getHints(), plugin->getUniqueId()); + fUiServer.writeMsg(strBuf); + plugin->getRealName(strBuf); + fUiServer.writeAndFixMsg(strBuf); + std::sprintf(strBuf, "%s", plugin->getName()); + fUiServer.writeAndFixMsg(strBuf); + plugin->getLabel(strBuf); + fUiServer.writeAndFixMsg(strBuf); + plugin->getMaker(strBuf); + fUiServer.writeAndFixMsg(strBuf); + plugin->getCopyright(strBuf); + fUiServer.writeAndFixMsg(strBuf); + + std::sprintf(strBuf, "AUDIO_COUNT_%i\n", pluginId); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%i:%i\n", plugin->getAudioInCount(), plugin->getAudioOutCount()); + fUiServer.writeMsg(strBuf); + + std::sprintf(strBuf, "MIDI_COUNT_%i\n", pluginId); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%i:%i\n", plugin->getMidiInCount(), plugin->getMidiOutCount()); + fUiServer.writeMsg(strBuf); + + uint32_t ins, outs, count; + std::sprintf(strBuf, "PARAMETER_COUNT_%i\n", pluginId); + fUiServer.writeMsg(strBuf); + plugin->getParameterCountInfo(ins, outs); + count = plugin->getParameterCount(); + std::sprintf(strBuf, "%i:%i:%i\n", ins, outs, count); + fUiServer.writeMsg(strBuf); + + for (uint32_t i=0; igetParameterData(i)); + const ParameterRanges& paramRanges(plugin->getParameterRanges(i)); + + std::sprintf(strBuf, "PARAMETER_DATA_%i:%i\n", pluginId, i); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%i:%i\n", paramData.type, paramData.hints); + fUiServer.writeMsg(strBuf); + plugin->getParameterName(i, strBuf); + fUiServer.writeAndFixMsg(strBuf); + plugin->getParameterUnit(i, strBuf); + fUiServer.writeAndFixMsg(strBuf); + + std::sprintf(strBuf, "PARAMETER_MIDI_STUFF_%i:%i\n", pluginId, i); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%i:%i\n", paramData.midiChannel, paramData.midiCC); + fUiServer.writeMsg(strBuf); + + std::sprintf(strBuf, "PARAMETER_RANGES_%i:%i\n", pluginId, i); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%f:%f:%f:%f:%f:%f\n", paramRanges.def, paramRanges.min, paramRanges.max, paramRanges.step, paramRanges.stepSmall, paramRanges.stepLarge); + fUiServer.writeMsg(strBuf); + + std::sprintf(strBuf, "PARAMETER_VALUE_%i:%i\n", pluginId, i); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%f\n", plugin->getParameterValue(i)); + fUiServer.writeMsg(strBuf); + } + } + break; + + case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: + std::sprintf(strBuf, "PARAMETER_VALUE_%i:%i\n", pluginId, value1); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%f\n", value3); + fUiServer.writeMsg(strBuf); + break; + + case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: + std::sprintf(strBuf, "PARAMETER_DEFAULT_%i:%i\n", pluginId, value1); + fUiServer.writeMsg(strBuf); + std::sprintf(strBuf, "%f\n", value3); + fUiServer.writeMsg(strBuf); + break; + + default: + break; + } + std::sprintf(strBuf, "ENGINE_CALLBACK_%i\n", int(action)); fUiServer.writeMsg(strBuf); @@ -622,6 +1069,19 @@ protected: CarlaEngine::idle(); fUiServer.idle(); + char strBuf[STR_MAX+1]; + + for (uint i=0; i < pData->curPluginCount; ++i) + { + const EnginePluginData& plugData(pData->plugins[i]); + + std::sprintf(strBuf, "PEAKS_%i\n", i); + fUiServer.writeMsg(strBuf); + + std::sprintf(strBuf, "%f:%f:%f:%f\n", plugData.insPeak[0], plugData.insPeak[1], plugData.outsPeak[0], plugData.outsPeak[1]); + fUiServer.writeMsg(strBuf); + } + switch (fUiServer.getAndResetUiState()) { case CarlaEngineNativeUI::UiNone: @@ -876,6 +1336,8 @@ private: bool fIsActive, fIsRunning; CarlaEngineNativeUI fUiServer; + CarlaMutex fWriteLock; + CarlaPlugin* _getFirstPlugin() const noexcept { if (pData->curPluginCount == 0 || pData->plugins == nullptr) diff --git a/source/carla-plugin b/source/carla-plugin index f85853dc8..4cbe6ae37 100755 --- a/source/carla-plugin +++ b/source/carla-plugin @@ -27,6 +27,30 @@ from time import sleep from carla_host import * from externalui import ExternalUI +# ------------------------------------------------------------------------------------------------------------ +# Helper object + +class PluginStoreInfo(object): + __slots__ = [ + 'pluginInfo', + 'pluginRealName', + 'audioCountInfo', + 'midiCountInfo', + 'parameterCount', + 'parameterCountInfo', + 'parameterInfoS', + 'parameterDataS', + 'parameterRangeS', + 'parameterValueS', + 'programCount', + 'programCurrent', + 'programNameS', + 'midiProgramCount', + 'midiProgramCurrent', + 'midiProgramDataS', + 'peaks' + ] + # ------------------------------------------------------------------------------------------------------------ # Host Plugin object @@ -40,6 +64,126 @@ class PluginHost(object): self.fLastError = "" self.fIsRunning = True + self.fPluginsInfo = [] + + def _add(self, pluginId): + if len(self.fPluginsInfo) != pluginId: + return + + info = PluginStoreInfo() + info.pluginInfo = PyCarlaPluginInfo + info.pluginRealName = "" + info.audioCountInfo = PyCarlaPortCountInfo + info.midiCountInfo = PyCarlaPortCountInfo + info.parameterCount = 0 + info.parameterCountInfo = PyCarlaPortCountInfo + info.parameterInfoS = [] + info.parameterDataS = [] + info.parameterRangeS = [] + info.parameterValueS = [] + info.programCount = 0 + info.programCurrent = -1 + info.programNameS = [] + info.midiProgramCount = 0 + info.midiProgramCurrent = -1 + info.midiProgramDataS = [] + info.peaks = [0.0, 0.0, 0.0, 0.0] + self.fPluginsInfo.append(info) + + def _set_pluginInfo(self, pluginId, info): + self.fPluginsInfo[pluginId].pluginInfo = info + + def _set_pluginRealName(self, pluginId, realName): + self.fPluginsInfo[pluginId].pluginRealName = realName + + def _set_audioCountInfo(self, pluginId, info): + self.fPluginsInfo[pluginId].audioCountInfo = info + + def _set_midiCountInfo(self, pluginId, info): + self.fPluginsInfo[pluginId].midiCountInfo = info + + def _set_parameterCountInfo(self, pluginId, count, info): + self.fPluginsInfo[pluginId].parameterCount = count + self.fPluginsInfo[pluginId].parameterCountInfo = info + + # clear + self.fPluginsInfo[pluginId].parameterInfoS = [] + self.fPluginsInfo[pluginId].parameterDataS = [] + self.fPluginsInfo[pluginId].parameterRangeS = [] + self.fPluginsInfo[pluginId].parameterValueS = [] + + # add placeholders + for x in range(count): + self.fPluginsInfo[pluginId].parameterInfoS.append(PyCarlaParameterInfo) + self.fPluginsInfo[pluginId].parameterDataS.append(PyParameterData) + self.fPluginsInfo[pluginId].parameterRangeS.append(PyParameterRanges) + self.fPluginsInfo[pluginId].parameterValueS.append(0.0) + + def _set_programCount(self, pluginId, count): + self.fPluginsInfo[pluginId].programCount = count + + # clear + self.fPluginsInfo[pluginId].programNameS = [] + + # add placeholders + for x in range(count): + self.fPluginsInfo[pluginId].programNameS.append("") + + def _set_midiProgramCount(self, pluginId, count): + self.fPluginsInfo[pluginId].midiProgramCount = count + + # clear + self.fPluginsInfo[pluginId].midiProgramDataS = [] + + # add placeholders + for x in range(count): + self.fPluginsInfo[pluginId].midiProgramDataS.append(PyMidiProgramData) + + def _set_parameterInfoS(self, pluginId, paramIndex, info): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterInfoS[paramIndex] = info + + def _set_parameterDataS(self, pluginId, paramIndex, data): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterDataS[paramIndex] = data + + def _set_parameterRangeS(self, pluginId, paramIndex, ranges): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterRangeS[paramIndex] = ranges + + def _set_parameterValueS(self, pluginId, paramIndex, value): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterValueS[paramIndex] = value + + def _set_parameterDefaultValue(self, pluginId, paramIndex, value): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterRangeS[paramIndex]['def'] = value + + def _set_parameterMidiChannel(self, pluginId, paramIndex, channel): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiChannel'] = channel + + def _set_parameterMidiCC(self, pluginId, paramIndex, cc): + if paramIndex < self.fPluginsInfo[pluginId].parameterCount: + self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiCC'] = cc + + def _set_currentProgram(self, pluginId, pIndex): + self.fPluginsInfo[pluginId].programCurrent = pIndex + + def _set_currentMidiProgram(self, pluginId, mpIndex): + self.fPluginsInfo[pluginId].midiProgramCurrent = mpIndex + + def _set_programNameS(self, pluginId, pIndex, name): + if pIndex < self.fPluginsInfo[pluginId].programCount: + self.fPluginsInfo[pluginId].programNameS[pIndex] = name + + def _set_midiProgramDataS(self, pluginId, mpIndex, data): + if mpIndex < self.fPluginsInfo[pluginId].midiProgramCount: + self.fPluginsInfo[pluginId].midiProgramDataS[mpIndex] = data + + def _set_peaks(self, pluginId, in1, in2, out1, out2): + self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2] + # ------------------------------------------------------------------- def get_complete_license_text(self): @@ -65,7 +209,7 @@ class PluginHost(object): # ------------------------------------------------------------------- def get_internal_plugin_count(self): - return int(self.lib.carla_get_internal_plugin_count()) + return 0 def get_internal_plugin_info(self, index): return None @@ -188,19 +332,19 @@ class PluginHost(object): # ------------------------------------------------------------------- def get_plugin_info(self, pluginId): - return PyCarlaPluginInfo + return self.fPluginsInfo[pluginId].pluginInfo def get_audio_port_count_info(self, pluginId): - return PyCarlaPortCountInfo + return self.fPluginsInfo[pluginId].audioCountInfo def get_midi_port_count_info(self, pluginId): - return PyCarlaPortCountInfo + return self.fPluginsInfo[pluginId].midiCountInfo def get_parameter_count_info(self, pluginId): - return PyCarlaPortCountInfo + return self.fPluginsInfo[pluginId].parameterCountInfo def get_parameter_info(self, pluginId, parameterId): - return PyCarlaParameterInfo + return self.fPluginsInfo[pluginId].parameterInfoS[parameterId] def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId): return PyCarlaScalePointInfo @@ -208,13 +352,13 @@ class PluginHost(object): # ------------------------------------------------------------------- def get_parameter_data(self, pluginId, parameterId): - return PyParameterData + return self.fPluginsInfo[pluginId].parameterDataS[parameterId] def get_parameter_ranges(self, pluginId, parameterId): - return PyParameterRanges + return self.fPluginsInfo[pluginId].parameterRangeS[parameterId] def get_midi_program_data(self, pluginId, midiProgramId): - return PyMidiProgramData + return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId] def get_custom_data(self, pluginId, customDataId): return PyCustomData @@ -225,13 +369,13 @@ class PluginHost(object): # ------------------------------------------------------------------- def get_parameter_count(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].parameterCount def get_program_count(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].programCount def get_midi_program_count(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].midiProgramCount def get_custom_data_count(self, pluginId): return 0 @@ -242,33 +386,33 @@ class PluginHost(object): return "" def get_program_name(self, pluginId, programId): - return "" + return self.fPluginsInfo[pluginId].programNameS[programId] def get_midi_program_name(self, pluginId, midiProgramId): - return "" + return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]['label'] def get_real_plugin_name(self, pluginId): - return "" + return self.fPluginsInfo[pluginId].pluginRealName # ------------------------------------------------------------------- def get_current_program_index(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].programCurrent def get_current_midi_program_index(self, pluginId): - return 0 + return self.fPluginsInfo[pluginId].midiProgramCurrent def get_default_parameter_value(self, pluginId, parameterId): - return 0.0 + return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]['def'] def get_current_parameter_value(self, pluginId, parameterId): - return 0.0 + return self.fPluginsInfo[pluginId].parameterValueS[parameterId] def get_input_peak_value(self, pluginId, isLeft): - return 0.0 + return self.fPluginsInfo[pluginId].peaks[0 if isLeft else 1] def get_output_peak_value(self, pluginId, isLeft): - return 0.0 + return self.fPluginsInfo[pluginId].peaks[2 if isLeft else 3] # ------------------------------------------------------------------- @@ -406,6 +550,114 @@ class CarlaMiniW(HostWindow, ExternalUI): if not msg: return True + elif msg.startswith("PEAKS_"): + pluginId = int(msg.replace("PEAKS_", "")) + in1, in2, out1, out2 = [float(i) for i in self.fPipeRecv.readline().strip().split(":")] + Carla.host._set_peaks(pluginId, in1, in2, out1, out2) + + elif msg.startswith("ENGINE_CALLBACK_"): + action = int(msg.replace("ENGINE_CALLBACK_", "")) + pluginId = int(self.fPipeRecv.readline().strip()) + value1 = int(self.fPipeRecv.readline().strip()) + value2 = int(self.fPipeRecv.readline().strip()) + value3 = float(self.fPipeRecv.readline().strip()) + valueStr = self.fPipeRecv.readline().strip().replace("\r", "\n") + engineCallback(None, action, pluginId, value1, value2, value3, valueStr) + + elif msg.startswith("PLUGIN_INFO_"): + pluginId = int(msg.replace("PLUGIN_INFO_", "")) + Carla.host._add(pluginId) + + type_, category, hints, uniqueId = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + realName = self.fPipeRecv.readline().strip().replace("\r", "\n") + name = self.fPipeRecv.readline().strip().replace("\r", "\n") + label = self.fPipeRecv.readline().strip().replace("\r", "\n") + maker = self.fPipeRecv.readline().strip().replace("\r", "\n") + copyright = self.fPipeRecv.readline().strip().replace("\r", "\n") + + pinfo = { + 'type': type_, + 'category': category, + 'hints': hints, + 'optionsAvailable': 0x0, # TODO + 'optionsEnabled': 0x0, # TODO + 'filename': "", # TODO + 'name': name, + 'label': label, + 'maker': maker, + 'copyright': copyright, + 'iconName': None, # TODO + 'patchbayClientId': 0, + 'uniqueId': uniqueId + } + + Carla.host._set_pluginInfo(pluginId, pinfo) + Carla.host._set_pluginRealName(pluginId, realName) + + elif msg.startswith("AUDIO_COUNT_"): + pluginId = int(msg.replace("AUDIO_COUNT_", "")) + ins, outs = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + Carla.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs}) + + elif msg.startswith("MIDI_COUNT_"): + pluginId = int(msg.replace("MIDI_COUNT_", "")) + ins, outs = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + Carla.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs}) + + elif msg.startswith("PARAMETER_COUNT_"): + pluginId = int(msg.replace("PARAMETER_COUNT_", "")) + ins, outs, count = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + Carla.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs}) + + elif msg.startswith("PARAMETER_DATA_"): + pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")] + paramType, paramHints = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + paramName = self.fPipeRecv.readline().strip().replace("\r", "\n") + paramUnit = self.fPipeRecv.readline().strip().replace("\r", "\n") + + paramInfo = { + 'name': paramName, + 'symbol': "", + 'unit': paramUnit, + 'scalePointCount': 0, + } + Carla.host._set_parameterInfoS(pluginId, paramId, paramInfo) + + paramData = { + 'type': paramType, + 'hints': paramHints, + 'index': paramId, + 'rindex': -1, + 'midiCC': -1, + 'midiChannel': 0 + } + Carla.host._set_parameterDataS(pluginId, paramId, paramData) + + elif msg.startswith("PARAMETER_MIDI_STUFF_"): + pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_MIDI_STUFF_", "").split(":")] + midiChannel, midiCC = [int(i) for i in self.fPipeRecv.readline().strip().split(":")] + Carla.host._set_parameterMidiChannel(pluginId, paramId, midiChannel) + Carla.host._set_parameterMidiCC(pluginId, paramId, midiCC) + + elif msg.startswith("PARAMETER_RANGES_"): + pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")] + def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.fPipeRecv.readline().strip().split(":")] + + paramRanges = { + 'def': def_, + 'min': min_, + 'max': max_, + 'step': step, + 'stepSmall': stepSmall, + 'stepLarge': stepLarge + } + Carla.host._set_parameterRangeS(pluginId, paramId, paramRanges) + + elif msg.startswith("PARAMETER_VALUE_"): + pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_VALUE_", "").split(":")] + paramValue = float(self.fPipeRecv.readline().strip()) + Carla.host._set_parameterValueS(pluginId, paramId, paramValue) + elif msg == "show": self.d_uiShow() @@ -420,15 +672,6 @@ class CarlaMiniW(HostWindow, ExternalUI): uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n") self.d_uiTitleChanged(uiTitle) - elif msg.startswith("ENGINE_CALLBACK_"): - action = int(msg.replace("ENGINE_CALLBACK_", "")) - pluginId = int(self.fPipeRecv.readline()) - value1 = int(self.fPipeRecv.readline()) - value2 = int(self.fPipeRecv.readline()) - value3 = float(self.fPipeRecv.readline()) - valueStr = self.fPipeRecv.readline().strip().replace("\r", "\n") - engineCallback(None, action, pluginId, value1, value2, value3, valueStr) - else: print("unknown message: \"" + msg + "\"") diff --git a/source/externalui.py b/source/externalui.py index b4cc24c84..72c6a57f6 100755 --- a/source/externalui.py +++ b/source/externalui.py @@ -182,7 +182,9 @@ class ExternalUI(object): return for line in lines: - if isinstance(line, str): + if line is None: + line2 = "(null)" + elif isinstance(line, str): line2 = line.replace("\n", "\r") else: if isinstance(line, bool): @@ -192,11 +194,8 @@ class ExternalUI(object): elif isinstance(line, float): line2 = "%.10f" % line else: - try: - line2 = str(line) - except: - print("unknown data type to send:", type(line2)) - return + print("unknown data type to send:", type(line)) + return self.fPipeSend.write(line2 + "\n") self.fPipeSend.flush() diff --git a/source/utils/CarlaPipeUtils.hpp b/source/utils/CarlaPipeUtils.hpp index ec22db0bd..9c11a4e5c 100644 --- a/source/utils/CarlaPipeUtils.hpp +++ b/source/utils/CarlaPipeUtils.hpp @@ -309,6 +309,20 @@ public: return false; } + bool readNextLineAsLong(long& value) + { + CARLA_SAFE_ASSERT_RETURN(fIsReading, false); + + if (const char* const msg = readline()) + { + value = std::atol(msg); + delete[] msg; + return true; + } + + return false; + } + bool readNextLineAsFloat(float& value) { CARLA_SAFE_ASSERT_RETURN(fIsReading, false); @@ -360,22 +374,40 @@ public: { CARLA_SAFE_ASSERT_RETURN(fPipeSend != -1,); - const size_t size(std::strlen(msg)); + const size_t size(msg != nullptr ? std::strlen(msg) : 0); - char fixedMsg[size+1]; - std::strcpy(fixedMsg, msg); + char fixedMsg[size+2]; - for (size_t i=0; i < size; ++i) + if (size > 0) { - if (fixedMsg[i] == '\n') - fixedMsg[i] = '\r'; - } + std::strcpy(fixedMsg, msg); + + for (size_t i=0; i < size; ++i) + { + if (fixedMsg[i] == '\n') + fixedMsg[i] = '\r'; + } - fixedMsg[size-1] = '\n'; - fixedMsg[size] = '\0'; + if (fixedMsg[size+1] == '\r') + { + fixedMsg[size-1] = '\n'; + fixedMsg[size] = '\0'; + fixedMsg[size+1] = '\0'; + } + else + { + fixedMsg[size] = '\n'; + fixedMsg[size+1] = '\0'; + } + } + else + { + fixedMsg[0] = '\n'; + fixedMsg[1] = '\0'; + } try { - ::write(fPipeSend, fixedMsg, size); + ::write(fPipeSend, fixedMsg, size+1); } catch (...) {} }