diff --git a/source/backend/CarlaUtils.h b/source/backend/CarlaUtils.h index 8d76ca2bb..ec11030c2 100644 --- a/source/backend/CarlaUtils.h +++ b/source/backend/CarlaUtils.h @@ -78,6 +78,16 @@ typedef struct _CarlaCachedPluginInfo { */ uint32_t audioOuts; + /*! + * Number of CV inputs. + */ + uint32_t cvIns; + + /*! + * Number of CV outputs. + */ + uint32_t cvOuts; + /*! * Number of MIDI inputs. */ diff --git a/source/backend/engine/CarlaEngineDummy.cpp b/source/backend/engine/CarlaEngineDummy.cpp index f6b6cd98a..cc9b5e44a 100644 --- a/source/backend/engine/CarlaEngineDummy.cpp +++ b/source/backend/engine/CarlaEngineDummy.cpp @@ -72,7 +72,7 @@ public: pData->sampleRate = pData->options.audioSampleRate; pData->initTime(pData->options.transportExtra); - pData->graph.create(2, 2); + pData->graph.create(2, 2, 0, 0); if (! startThread(true)) { diff --git a/source/backend/engine/CarlaEngineGraph.cpp b/source/backend/engine/CarlaEngineGraph.cpp index 55ee0e6d1..fede85f47 100644 --- a/source/backend/engine/CarlaEngineGraph.cpp +++ b/source/backend/engine/CarlaEngineGraph.cpp @@ -1413,11 +1413,6 @@ public: return fPlugin->getName(); } - void processBlock(AudioSampleBuffer&, MidiBuffer&) override - { - carla_stderr2("CarlaPluginInstance::processBlock called, this is wrong!"); - } - void processBlockWithCV(AudioSampleBuffer& audio, const AudioSampleBuffer& cvIn, AudioSampleBuffer& cvOut, @@ -1605,14 +1600,20 @@ private: StringArray outputNames; }; -PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, const uint32_t outs) +PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, + const uint32_t audioIns, const uint32_t audioOuts, + const uint32_t cvIns, const uint32_t cvOuts) : CarlaThread("PatchbayReorderThread"), connections(), graph(), audioBuffer(), + cvInBuffer(), + cvOutBuffer(), midiBuffer(), - inputs(carla_fixedValue(0U, 64U, ins)), - outputs(carla_fixedValue(0U, 64U, outs)), + numAudioIns(carla_fixedValue(0U, 64U, audioIns)), + numAudioOuts(carla_fixedValue(0U, 64U, audioOuts)), + numCVIns(carla_fixedValue(0U, 8U, cvIns)), + numCVOuts(carla_fixedValue(0U, 8U, cvOuts)), retCon(), usingExternalHost(false), usingExternalOSC(false), @@ -1622,17 +1623,22 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons const uint32_t bufferSize(engine->getBufferSize()); const double sampleRate(engine->getSampleRate()); - graph.setPlayConfigDetails(inputs, outputs, 0, 0, 1, 1, sampleRate, static_cast(bufferSize)); + graph.setPlayConfigDetails(numAudioIns, numAudioOuts, + numCVIns, numCVOuts, + 1, 1, + sampleRate, static_cast(bufferSize)); graph.prepareToPlay(sampleRate, static_cast(bufferSize)); - audioBuffer.setSize(jmax(inputs, outputs), bufferSize); + audioBuffer.setSize(jmax(numAudioIns, numAudioOuts), bufferSize); + cvInBuffer.setSize(numCVIns, bufferSize); + cvOutBuffer.setSize(numCVOuts, bufferSize); midiBuffer.ensureSize(kMaxEngineEventInternalCount*2); midiBuffer.clear(); StringArray channelNames; - switch (inputs) + switch (numAudioIns) { case 2: channelNames.add("Left"); @@ -1645,6 +1651,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons break; } + if (numAudioIns != 0) { NamedAudioGraphIOProcessor* const proc( new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioInputNode)); @@ -1659,6 +1666,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons node->properties.set("isOSC", false); } + if (numAudioOuts != 0) { NamedAudioGraphIOProcessor* const proc( new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::audioOutputNode)); @@ -1673,6 +1681,36 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, cons node->properties.set("isOSC", false); } + if (numCVIns != 0) + { + NamedAudioGraphIOProcessor* const proc( + new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::cvInputNode)); + // proc->setNames(false, channelNames); + + AudioProcessorGraph::Node* const node(graph.addNode(proc)); + node->properties.set("isPlugin", false); + node->properties.set("isOutput", false); + node->properties.set("isAudio", false); + node->properties.set("isCV", true); + node->properties.set("isMIDI", false); + node->properties.set("isOSC", false); + } + + if (numCVOuts != 0) + { + NamedAudioGraphIOProcessor* const proc( + new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::cvOutputNode)); + // proc->setNames(true, channelNames); + + AudioProcessorGraph::Node* const node(graph.addNode(proc)); + node->properties.set("isPlugin", false); + node->properties.set("isOutput", false); + node->properties.set("isAudio", false); + node->properties.set("isCV", true); + node->properties.set("isMIDI", false); + node->properties.set("isOSC", false); + } + { NamedAudioGraphIOProcessor* const proc( new NamedAudioGraphIOProcessor(NamedAudioGraphIOProcessor::midiInputNode)); @@ -1710,6 +1748,8 @@ PatchbayGraph::~PatchbayGraph() graph.releaseResources(); graph.clear(); audioBuffer.clear(); + cvInBuffer.clear(); + cvOutBuffer.clear(); } void PatchbayGraph::setBufferSize(const uint32_t bufferSize) @@ -1719,6 +1759,8 @@ void PatchbayGraph::setBufferSize(const uint32_t bufferSize) graph.releaseResources(); graph.prepareToPlay(kEngine->getSampleRate(), static_cast(bufferSize)); audioBuffer.setSize(audioBuffer.getNumChannels(), bufferSize); + cvInBuffer.setSize(numCVIns, bufferSize); + cvOutBuffer.setSize(numCVOuts, bufferSize); } void PatchbayGraph::setSampleRate(const double sampleRate) @@ -2175,7 +2217,10 @@ bool PatchbayGraph::getGroupAndPortIdFromFullName(const bool external, const cha return false; } -void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames) +void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, + const float* const* const inBuf, + float* const* const outBuf, + const uint32_t frames) { CARLA_SAFE_ASSERT_RETURN(data != nullptr,); CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,); @@ -2188,29 +2233,48 @@ void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, const float* fillWaterMidiBufferFromEngineEvents(midiBuffer, data->events.in); } - // set audio buffer size, needed for water internals + // set audio and cv buffer size, needed for water internals if (! audioBuffer.setSizeRT(frames)) return; + if (! cvInBuffer.setSizeRT(frames)) + return; + if (! cvOutBuffer.setSizeRT(frames)) + return; - // put carla audio in water buffer + // put carla audio and cv in water buffer { uint32_t i=0; - for (; i < inputs; ++i) + for (; i < numAudioIns; ++i) { + CARLA_SAFE_ASSERT_BREAK(inBuf[i]); audioBuffer.copyFrom(i, 0, inBuf[i], frames); + } + + for (uint32_t j=0; j < numCVIns; ++j, ++i) { + CARLA_SAFE_ASSERT_BREAK(inBuf[i]); + cvInBuffer.copyFrom(j, 0, inBuf[i], frames); + } // clear remaining channels - for (const uint32_t count=audioBuffer.getNumChannels(); igetOptions().processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK); if (fIsRack) { CARLA_SAFE_ASSERT_RETURN(fRack == nullptr,); - fRack = new RackGraph(kEngine, inputs, outputs); + fRack = new RackGraph(kEngine, audioIns, audioOuts); } else { CARLA_SAFE_ASSERT_RETURN(fPatchbay == nullptr,); - fPatchbay = new PatchbayGraph(kEngine, inputs, outputs); + fPatchbay = new PatchbayGraph(kEngine, audioIns, audioOuts, cvIns, cvOuts); } fIsReady = true; diff --git a/source/backend/engine/CarlaEngineGraph.hpp b/source/backend/engine/CarlaEngineGraph.hpp index d3d95aab6..3b6094097 100644 --- a/source/backend/engine/CarlaEngineGraph.hpp +++ b/source/backend/engine/CarlaEngineGraph.hpp @@ -157,16 +157,22 @@ public: PatchbayConnectionList connections; AudioProcessorGraph graph; AudioSampleBuffer audioBuffer; + AudioSampleBuffer cvInBuffer; + AudioSampleBuffer cvOutBuffer; MidiBuffer midiBuffer; - const uint32_t inputs; - const uint32_t outputs; + const uint32_t numAudioIns; + const uint32_t numAudioOuts; + const uint32_t numCVIns; + const uint32_t numCVOuts; mutable CharStringListPtr retCon; bool usingExternalHost; bool usingExternalOSC; ExternalGraph extGraph; - PatchbayGraph(CarlaEngine* const engine, const uint32_t inputs, const uint32_t outputs); + PatchbayGraph(CarlaEngine* const engine, + const uint32_t audioIns, const uint32_t audioOuts, + const uint32_t cvIns, const uint32_t cvOuts); ~PatchbayGraph(); void setBufferSize(const uint32_t bufferSize); @@ -187,7 +193,10 @@ public: const char* const* getConnections(const bool external) const; bool getGroupAndPortIdFromFullName(const bool external, const char* const fullPortName, uint& groupId, uint& portId) const; - void process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames); + void process(CarlaEngine::ProtectedData* const data, + const float* const* const inBuf, + float* const* const outBuf, + const uint32_t frames); private: void run() override; diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index 65ecc5abd..fbc6435b5 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -74,7 +74,7 @@ public: EngineInternalGraph(CarlaEngine* const engine) noexcept; ~EngineInternalGraph() noexcept; - void create(const uint32_t inputs, const uint32_t outputs); + void create(const uint32_t audioIns, const uint32_t audioOuts, const uint32_t cvIns, const uint32_t cvOuts); void destroy() noexcept; void setBufferSize(const uint32_t bufferSize); diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index 12d8627d1..b3f8d4d6e 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -1004,11 +1004,11 @@ public: if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) { // FIXME? - pData->graph.create(0, 0); + pData->graph.create(0, 0, 0, 0); } else { - pData->graph.create(2, 2); + pData->graph.create(2, 2, 0, 0); // pData->graph.setUsingExternalHost(true); // pData->graph.setUsingExternalOSC(true); patchbayRefresh(true, false, false); diff --git a/source/backend/engine/CarlaEngineJuce.cpp b/source/backend/engine/CarlaEngineJuce.cpp index 47b071006..9d33ee348 100644 --- a/source/backend/engine/CarlaEngineJuce.cpp +++ b/source/backend/engine/CarlaEngineJuce.cpp @@ -218,7 +218,9 @@ public: pData->sampleRate = fDevice->getCurrentSampleRate(); pData->initTime(pData->options.transportExtra); - pData->graph.create(static_cast(inputNames.size()), static_cast(outputNames.size())); + pData->graph.create(static_cast(inputNames.size()), + static_cast(outputNames.size()), + 0, 0); fDevice->start(this); diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 7ad63c6f1..6bd1c766d 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -163,7 +163,8 @@ class CarlaEngineNative : public CarlaEngine { public: CarlaEngineNative(const NativeHostDescriptor* const host, const bool isPatchbay, const bool withMidiOut, - const uint32_t inChan = 2, uint32_t outChan = 2) + const uint32_t inChan = 2, uint32_t outChan = 2, + const uint32_t cvIns = 0, const uint32_t cvOuts = 0) : CarlaEngine(), pHost(host), #ifdef USE_JUCE_MESSAGE_THREAD @@ -211,7 +212,7 @@ public: pData->options.preferPluginBridges = false; pData->options.preferUiBridges = false; init("Carla-Patchbay"); - pData->graph.create(inChan, outChan); + pData->graph.create(inChan, outChan, cvIns, cvOuts); } else { @@ -223,7 +224,7 @@ public: pData->options.preferPluginBridges = false; pData->options.preferUiBridges = false; init("Carla-Rack"); - pData->graph.create(0, 0); // FIXME? + pData->graph.create(0, 0, 0, 0); // FIXME? } if (pData->options.resourceDir != nullptr) @@ -1567,6 +1568,11 @@ public: return new CarlaEngineNative(host, true, true, 64, 64); } + static NativePluginHandle _instantiatePatchbayCV(const NativeHostDescriptor* host) + { + return new CarlaEngineNative(host, true, true, 2, 2, 5, 5); + } + static void _cleanup(NativePluginHandle handle) { delete handlePtr; @@ -2345,7 +2351,9 @@ static const NativePluginDescriptor carlaRackDesc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaRackNoMidiOutDesc = { @@ -2387,7 +2395,9 @@ static const NativePluginDescriptor carlaRackNoMidiOutDesc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaPatchbayDesc = { @@ -2429,7 +2439,9 @@ static const NativePluginDescriptor carlaPatchbayDesc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaPatchbay3sDesc = { @@ -2471,7 +2483,9 @@ static const NativePluginDescriptor carlaPatchbay3sDesc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaPatchbay16Desc = { @@ -2513,7 +2527,9 @@ static const NativePluginDescriptor carlaPatchbay16Desc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaPatchbay32Desc = { @@ -2555,7 +2571,9 @@ static const NativePluginDescriptor carlaPatchbay32Desc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 }; static const NativePluginDescriptor carlaPatchbay64Desc = { @@ -2597,7 +2615,54 @@ static const NativePluginDescriptor carlaPatchbay64Desc = { CarlaEngineNative::_get_state, CarlaEngineNative::_set_state, CarlaEngineNative::_dispatcher, - /* _render_inline_dsplay */ nullptr + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 0, + /* cvOuts */ 0 +}; + +static const NativePluginDescriptor carlaPatchbayCVDesc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD + |NATIVE_PLUGIN_USES_CONTROL_VOLTAGE + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 2, + /* audioOuts */ 2, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ kNumInParams, + /* paramOuts */ kNumOutParams, + /* name */ "Carla-Patchbay (CV)", + /* label */ "carlapatchbaycv", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + CarlaEngineNative::_instantiatePatchbayCV, + CarlaEngineNative::_cleanup, + CarlaEngineNative::_get_parameter_count, + CarlaEngineNative::_get_parameter_info, + CarlaEngineNative::_get_parameter_value, + CarlaEngineNative::_get_midi_program_count, + CarlaEngineNative::_get_midi_program_info, + CarlaEngineNative::_set_parameter_value, + CarlaEngineNative::_set_midi_program, + /* _set_custom_data */ nullptr, + CarlaEngineNative::_ui_show, + CarlaEngineNative::_ui_idle, + /* _ui_set_parameter_value */ nullptr, + /* _ui_set_midi_program */ nullptr, + /* _ui_set_custom_data */ nullptr, + CarlaEngineNative::_activate, + CarlaEngineNative::_deactivate, + CarlaEngineNative::_process, + CarlaEngineNative::_get_state, + CarlaEngineNative::_set_state, + CarlaEngineNative::_dispatcher, + /* _render_inline_dsplay */ nullptr, + /* cvIns */ 5, + /* cvOuts */ 5 }; CARLA_BACKEND_END_NAMESPACE @@ -2617,6 +2682,7 @@ void carla_register_native_plugin_carla() carla_register_native_plugin(&carlaPatchbay16Desc); carla_register_native_plugin(&carlaPatchbay32Desc); carla_register_native_plugin(&carlaPatchbay64Desc); + carla_register_native_plugin(&carlaPatchbayCVDesc); } // ----------------------------------------------------------------------- @@ -2651,6 +2717,12 @@ const NativePluginDescriptor* carla_get_native_patchbay64_plugin() return &carlaPatchbay64Desc; } +const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin() +{ + CARLA_BACKEND_USE_NAMESPACE; + return &carlaPatchbayCVDesc; +} + // ----------------------------------------------------------------------- // Extra stuff for linking purposes diff --git a/source/backend/engine/CarlaEngineRtAudio.cpp b/source/backend/engine/CarlaEngineRtAudio.cpp index 661f2c678..c7f36dd8b 100644 --- a/source/backend/engine/CarlaEngineRtAudio.cpp +++ b/source/backend/engine/CarlaEngineRtAudio.cpp @@ -332,7 +332,7 @@ public: if (fAudioOutCount > 0) fAudioIntBufOut = new float[fAudioOutCount*bufferFrames]; - pData->graph.create(fAudioInCount, fAudioOutCount); + pData->graph.create(fAudioInCount, fAudioOutCount, 0, 0); try { fAudio.startStream(); diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index 2dd705331..d26bfaa98 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -254,8 +254,8 @@ public: fIsUiVisible(false), fInlineDisplayNeedsRedraw(false), fInlineDisplayLastRedrawTime(0), - fAudioInBuffers(nullptr), - fAudioOutBuffers(nullptr), + fAudioAndCvInBuffers(nullptr), + fAudioAndCvOutBuffers(nullptr), fMidiEventInCount(0), fMidiEventOutCount(0), fCurBufferSize(engine->getBufferSize()), @@ -421,8 +421,8 @@ public: if ((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) == 0x0) options |= PLUGIN_OPTION_FIXED_BUFFERS; - // can't disable forced stereo if enabled in the engine - if (pData->engine->getOptions().forceStereo) + // can't disable forced stereo if enabled in the engine, or using CV + if (pData->engine->getOptions().forceStereo || pData->cvIn.count != 0 || pData->cvOut.count != 0) pass(); // if inputs or outputs are just 1, then yes we can force stereo else if (pData->audioIn.count == 1 || pData->audioOut.count == 1 || fHandle2 != nullptr) @@ -978,7 +978,7 @@ public: const float sampleRate((float)pData->engine->getSampleRate()); - uint32_t aIns, aOuts, mIns, mOuts, params, j; + uint32_t aIns, aOuts, cvIns, cvOuts, mIns, mOuts, params, j; bool forcedStereoIn, forcedStereoOut; forcedStereoIn = forcedStereoOut = false; @@ -988,6 +988,8 @@ public: aIns = fDescriptor->audioIns; aOuts = fDescriptor->audioOuts; + cvIns = fDescriptor->cvIns; + cvOuts = fDescriptor->cvOuts; mIns = fDescriptor->midiIns; mOuts = fDescriptor->midiOuts; params = (fDescriptor->get_parameter_count != nullptr && fDescriptor->get_parameter_info != nullptr) ? fDescriptor->get_parameter_count(fHandle) : 0; @@ -1016,20 +1018,34 @@ public: if (aIns > 0) { pData->audioIn.createNew(aIns); - fAudioInBuffers = new float*[aIns]; - - for (uint32_t i=0; i < aIns; ++i) - fAudioInBuffers[i] = nullptr; } if (aOuts > 0) { pData->audioOut.createNew(aOuts); - fAudioOutBuffers = new float*[aOuts]; needsCtrlIn = true; + } - for (uint32_t i=0; i < aOuts; ++i) - fAudioOutBuffers[i] = nullptr; + if (cvIns > 0) + { + pData->cvIn.createNew(cvIns); + } + + if (cvOuts > 0) + { + pData->cvOut.createNew(cvOuts); + } + + if (const uint32_t acIns = aIns + cvIns) + { + fAudioAndCvInBuffers = new float*[acIns]; + carla_zeroPointers(fAudioAndCvInBuffers, acIns); + } + + if (const uint32_t acOuts = aOuts + cvOuts) + { + fAudioAndCvOutBuffers = new float*[acOuts]; + carla_zeroPointers(fAudioAndCvOutBuffers, acOuts); } if (mIns > 0) @@ -1118,6 +1134,56 @@ public: } } + // CV Ins + for (j=0; j < cvIns; ++j) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + if (cvIns > 1) + { + portName += "cv_input_"; + portName += CarlaString(j+1); + } + else + portName += "cv_input"; + + portName.truncate(portNameSize); + + pData->cvIn.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, true, j); + pData->cvIn.ports[j].rindex = j; + } + + // CV Outs + for (j=0; j < cvOuts; ++j) + { + portName.clear(); + + if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) + { + portName = pData->name; + portName += ":"; + } + + if (cvOuts > 1) + { + portName += "cv_output_"; + portName += CarlaString(j+1); + } + else + portName += "cv_output"; + + portName.truncate(portNameSize); + + pData->cvOut.ports[j].port = (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, portName, false, j); + pData->cvOut.ports[j].rindex = j; + } + // MIDI Input (only if multiple) if (mIns > 1) { @@ -1514,7 +1580,8 @@ public: return kNullEngineEvent; } - void process(const float** const audioIn, float** const audioOut, const float** const, float** const, const uint32_t frames) override + void process(const float** const audioIn, float** const audioOut, + const float** const cvIn, float** const cvOut, const uint32_t frames) override { // -------------------------------------------------------------------------------------------------------- // Check if active @@ -1524,6 +1591,8 @@ public: // disable any output sound for (uint32_t i=0; i < pData->audioOut.count; ++i) carla_zeroFloats(audioOut[i], frames); + for (uint32_t i=0; i < pData->cvOut.count; ++i) + carla_zeroFloats(cvOut[i], frames); return; } @@ -1697,7 +1766,7 @@ public: if (sampleAccurate && eventTime > timeOffset) { - if (processSingle(audioIn, audioOut, eventTime - timeOffset, timeOffset)) + if (processSingle(audioIn, audioOut, cvIn, cvOut, eventTime - timeOffset, timeOffset)) { startTime = 0; timeOffset = eventTime; @@ -2005,7 +2074,7 @@ public: pData->postRtEvents.trySplice(); if (frames > timeOffset) - processSingle(audioIn, audioOut, frames - timeOffset, timeOffset); + processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset); } // End of Event Input and Processing @@ -2014,7 +2083,7 @@ public: else { - processSingle(audioIn, audioOut, frames, 0); + processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0); } // End of Plugin processing (no events) @@ -2044,18 +2113,24 @@ public: #endif } - bool processSingle(const float** const audioIn, float** const audioOut, const uint32_t frames, const uint32_t timeOffset) + bool processSingle(const float** const audioIn, float** const audioOut, + const float** const cvIn, float** const cvOut, + const uint32_t frames, const uint32_t timeOffset) { CARLA_SAFE_ASSERT_RETURN(frames > 0, false); - if (pData->audioIn.count > 0) - { + if (pData->audioIn.count > 0) { CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); } - if (pData->audioOut.count > 0) - { + if (pData->audioOut.count > 0) { CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false); } + if (pData->cvIn.count > 0) { + CARLA_SAFE_ASSERT_RETURN(cvIn != nullptr, false); + } + if (pData->cvOut.count > 0) { + CARLA_SAFE_ASSERT_RETURN(cvOut != nullptr, false); + } // -------------------------------------------------------------------------------------------------------- // Try lock, silence otherwise @@ -2071,6 +2146,11 @@ public: for (uint32_t k=0; k < frames; ++k) audioOut[i][k+timeOffset] = 0.0f; } + for (uint32_t i=0; i < pData->cvOut.count; ++i) + { + for (uint32_t k=0; k < frames; ++k) + cvOut[i][k+timeOffset] = 0.0f; + } return false; } @@ -2078,11 +2158,17 @@ public: // -------------------------------------------------------------------------------------------------------- // Set audio buffers - for (uint32_t i=0; i < pData->audioIn.count; ++i) - carla_copyFloats(fAudioInBuffers[i], audioIn[i]+timeOffset, frames); + { + for (uint32_t i=0; i < pData->audioIn.count; ++i) + carla_copyFloats(fAudioAndCvInBuffers[i], audioIn[i]+timeOffset, frames); + for (uint32_t i=0; i < pData->cvIn.count; ++i) + carla_copyFloats(fAudioAndCvInBuffers[pData->audioIn.count+i], cvIn[i]+timeOffset, frames); - for (uint32_t i=0; i < pData->audioOut.count; ++i) - carla_zeroFloats(fAudioOutBuffers[i], frames); + for (uint32_t i=0; i < pData->audioOut.count; ++i) + carla_zeroFloats(fAudioAndCvOutBuffers[i], frames); + for (uint32_t i=0; i < pData->cvOut.count; ++i) + carla_zeroFloats(fAudioAndCvOutBuffers[pData->audioOut.count+i], frames); + } // -------------------------------------------------------------------------------------------------------- // Run plugin @@ -2092,19 +2178,19 @@ public: if (fHandle2 == nullptr) { fDescriptor->process(fHandle, - const_cast(fAudioInBuffers), fAudioOutBuffers, frames, + const_cast(fAudioAndCvInBuffers), fAudioAndCvOutBuffers, frames, fMidiInEvents, fMidiEventInCount); } else { fDescriptor->process(fHandle, - (pData->audioIn.count > 0) ? const_cast(&fAudioInBuffers[0]) : nullptr, - (pData->audioOut.count > 0) ? &fAudioOutBuffers[0] : nullptr, + (fAudioAndCvInBuffers != nullptr) ? const_cast(&fAudioAndCvInBuffers[0]) : nullptr, + (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[0] : nullptr, frames, fMidiInEvents, fMidiEventInCount); fDescriptor->process(fHandle2, - (pData->audioIn.count > 0) ? const_cast(&fAudioInBuffers[1]) : nullptr, - (pData->audioOut.count > 0) ? &fAudioOutBuffers[1] : nullptr, + (fAudioAndCvInBuffers != nullptr) ? const_cast(&fAudioAndCvInBuffers[1]) : nullptr, + (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[1] : nullptr, frames, fMidiInEvents, fMidiEventInCount); } @@ -2113,6 +2199,7 @@ public: if (fTimeInfo.playing) fTimeInfo.frame += frames; + uint32_t i=0; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH // -------------------------------------------------------------------------------------------------------- // Post-processing (dry/wet, volume and balance) @@ -2124,15 +2211,15 @@ public: bool isPair; float bufValue, oldBufLeft[doBalance ? frames : 1]; - for (uint32_t i=0; i < pData->audioOut.count; ++i) + for (; i < pData->audioOut.count; ++i) { // Dry/Wet if (doDryWet) { for (uint32_t k=0; k < frames; ++k) { - bufValue = fAudioInBuffers[(pData->audioIn.count == 1) ? 0 : i][k]; - fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); + bufValue = fAudioAndCvInBuffers[(pData->audioIn.count == 1) ? 0 : i][k]; + fAudioAndCvOutBuffers[i][k] = (fAudioAndCvOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); } } @@ -2144,7 +2231,7 @@ public: if (isPair) { CARLA_ASSERT(i+1 < pData->audioOut.count); - carla_copyFloats(oldBufLeft, fAudioOutBuffers[i], frames); + carla_copyFloats(oldBufLeft, fAudioAndCvOutBuffers[i], frames); } float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; @@ -2155,14 +2242,14 @@ public: if (isPair) { // left - fAudioOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL); - fAudioOutBuffers[i][k] += fAudioOutBuffers[i+1][k] * (1.0f - balRangeR); + fAudioAndCvOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL); + fAudioAndCvOutBuffers[i][k] += fAudioAndCvOutBuffers[i+1][k] * (1.0f - balRangeR); } else { // right - fAudioOutBuffers[i][k] = fAudioOutBuffers[i][k] * balRangeR; - fAudioOutBuffers[i][k] += oldBufLeft[k] * balRangeL; + fAudioAndCvOutBuffers[i][k] = fAudioAndCvOutBuffers[i][k] * balRangeR; + fAudioAndCvOutBuffers[i][k] += oldBufLeft[k] * balRangeL; } } } @@ -2170,18 +2257,24 @@ public: // Volume (and buffer copy) { for (uint32_t k=0; k < frames; ++k) - audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; + audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k] * pData->postProc.volume; } } } // End of Post-processing #else - for (uint32_t i=0; i < pData->audioOut.count; ++i) + for (; i < pData->audioOut.count; ++i) { for (uint32_t k=0; k < frames; ++k) - audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k]; + audioOut[i][k+timeOffset] = fAudioAndCvOutBuffers[i][k]; } #endif + // CV stuff too + for (; i < pData->cvOut.count; ++i) + { + for (uint32_t k=0; k < frames; ++k) + cvOut[i][k+timeOffset] = fAudioAndCvOutBuffers[pData->audioOut.count+i][k]; + } // -------------------------------------------------------------------------------------------------------- // MIDI Output @@ -2211,18 +2304,18 @@ public: CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize); carla_debug("CarlaPluginNative::bufferSizeChanged(%i)", newBufferSize); - for (uint32_t i=0; i < pData->audioIn.count; ++i) + for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i) { - if (fAudioInBuffers[i] != nullptr) - delete[] fAudioInBuffers[i]; - fAudioInBuffers[i] = new float[newBufferSize]; + if (fAudioAndCvInBuffers[i] != nullptr) + delete[] fAudioAndCvInBuffers[i]; + fAudioAndCvInBuffers[i] = new float[newBufferSize]; } - for (uint32_t i=0; i < pData->audioOut.count; ++i) + for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i) { - if (fAudioOutBuffers[i] != nullptr) - delete[] fAudioOutBuffers[i]; - fAudioOutBuffers[i] = new float[newBufferSize]; + if (fAudioAndCvOutBuffers[i] != nullptr) + delete[] fAudioAndCvOutBuffers[i]; + fAudioAndCvOutBuffers[i] = new float[newBufferSize]; } if (fCurBufferSize == newBufferSize) @@ -2289,34 +2382,34 @@ public: { carla_debug("CarlaPluginNative::clearBuffers() - start"); - if (fAudioInBuffers != nullptr) + if (fAudioAndCvInBuffers != nullptr) { - for (uint32_t i=0; i < pData->audioIn.count; ++i) + for (uint32_t i=0; i < (pData->audioIn.count+pData->cvIn.count); ++i) { - if (fAudioInBuffers[i] != nullptr) + if (fAudioAndCvInBuffers[i] != nullptr) { - delete[] fAudioInBuffers[i]; - fAudioInBuffers[i] = nullptr; + delete[] fAudioAndCvInBuffers[i]; + fAudioAndCvInBuffers[i] = nullptr; } } - delete[] fAudioInBuffers; - fAudioInBuffers = nullptr; + delete[] fAudioAndCvInBuffers; + fAudioAndCvInBuffers = nullptr; } - if (fAudioOutBuffers != nullptr) + if (fAudioAndCvOutBuffers != nullptr) { - for (uint32_t i=0; i < pData->audioOut.count; ++i) + for (uint32_t i=0; i < (pData->audioOut.count+pData->cvOut.count); ++i) { - if (fAudioOutBuffers[i] != nullptr) + if (fAudioAndCvOutBuffers[i] != nullptr) { - delete[] fAudioOutBuffers[i]; - fAudioOutBuffers[i] = nullptr; + delete[] fAudioAndCvOutBuffers[i]; + fAudioAndCvOutBuffers[i] = nullptr; } } - delete[] fAudioOutBuffers; - fAudioOutBuffers = nullptr; + delete[] fAudioAndCvOutBuffers; + fAudioAndCvOutBuffers = nullptr; } if (fMidiIn.count > 1) @@ -2699,8 +2792,8 @@ private: bool fInlineDisplayNeedsRedraw; int64_t fInlineDisplayLastRedrawTime; - float** fAudioInBuffers; - float** fAudioOutBuffers; + float** fAudioAndCvInBuffers; + float** fAudioAndCvOutBuffers; uint32_t fMidiEventInCount; uint32_t fMidiEventOutCount; NativeMidiEvent fMidiInEvents[kPluginMaxMidiEvents]; diff --git a/source/backend/utils/CachedPlugins.cpp b/source/backend/utils/CachedPlugins.cpp index 869e72c0e..202de1bc0 100644 --- a/source/backend/utils/CachedPlugins.cpp +++ b/source/backend/utils/CachedPlugins.cpp @@ -63,6 +63,8 @@ _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept hints(0x0), audioIns(0), audioOuts(0), + cvIns(0), + cvOuts(0), midiIns(0), midiOuts(0), parameterIns(0), @@ -119,6 +121,8 @@ static const CarlaCachedPluginInfo* get_cached_plugin_internal(const NativePlugi info.valid = true; info.audioIns = desc.audioIns; info.audioOuts = desc.audioOuts; + info.cvIns = desc.cvIns; + info.cvOuts = desc.cvOuts; info.midiIns = desc.midiIns; info.midiOuts = desc.midiOuts; info.parameterIns = desc.paramIns; @@ -336,6 +340,8 @@ static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2Worl info.audioIns = 0; info.audioOuts = 0; + info.cvIns = 0; + info.cvOuts = 0; info.midiIns = 0; info.midiOuts = 0; info.parameterIns = 0; @@ -429,6 +435,10 @@ static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2Worl } else if (lilvPort.is_a(lv2World.port_cv)) { + if (isInput) + ++(info.cvIns); + else + ++(info.cvOuts); } else if (lilvPort.is_a(lv2World.port_atom)) { @@ -527,6 +537,8 @@ static const CarlaCachedPluginInfo* get_cached_plugin_au(const juce::String plug info.audioIns = static_cast(desc->numInputChannels); info.audioOuts = static_cast(desc->numOutputChannels); + info.cvIns = 0; + info.cvOuts = 0; info.midiIns = desc->isInstrument ? 1 : 0; info.midiOuts = 0; info.parameterIns = 0; @@ -565,6 +577,8 @@ static const CarlaCachedPluginInfo* get_cached_plugin_sfz(const File file) info.valid = true; info.audioIns = 0; info.audioOuts = 2; + info.cvIns = 0; + info.cvOuts = 0; info.midiIns = 1; info.midiOuts = 0; info.parameterIns = 0; diff --git a/source/discovery/carla-discovery.cpp b/source/discovery/carla-discovery.cpp index 9825815b4..91d21108b 100644 --- a/source/discovery/carla-discovery.cpp +++ b/source/discovery/carla-discovery.cpp @@ -108,6 +108,8 @@ static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo) DISCOVERY_OUT("label", pinfo->label); DISCOVERY_OUT("audio.ins", pinfo->audioIns); DISCOVERY_OUT("audio.outs", pinfo->audioOuts); + DISCOVERY_OUT("cv.ins", pinfo->cvIns); + DISCOVERY_OUT("cv.outs", pinfo->cvOuts); DISCOVERY_OUT("midi.ins", pinfo->midiIns); DISCOVERY_OUT("midi.outs", pinfo->midiOuts); DISCOVERY_OUT("parameters.ins", pinfo->parameterIns); diff --git a/source/frontend/carla_database.py b/source/frontend/carla_database.py index 79439f522..ec5247855 100755 --- a/source/frontend/carla_database.py +++ b/source/frontend/carla_database.py @@ -133,7 +133,7 @@ def findFilenames(filePath, stype): # --------------------------------------------------------------------------------------------------------------------- # Plugin Query -PLUGIN_QUERY_API_VERSION = 8 +PLUGIN_QUERY_API_VERSION = 9 PyPluginInfo = { 'API': PLUGIN_QUERY_API_VERSION, @@ -148,6 +148,8 @@ PyPluginInfo = { 'uniqueId': 0, 'audio.ins': 0, 'audio.outs': 0, + 'cv.ins': 0, + 'cv.outs': 0, 'midi.ins': 0, 'midi.outs': 0, 'parameters.ins': 0, @@ -285,6 +287,10 @@ def runCarlaDiscovery(itype, stype, filename, tool, wineSettings=None): if value.isdigit(): pinfo['audio.ins'] = int(value) elif prop == "audio.outs": if value.isdigit(): pinfo['audio.outs'] = int(value) + elif prop == "cv.ins": + if value.isdigit(): pinfo['cv.ins'] = int(value) + elif prop == "cv.outs": + if value.isdigit(): pinfo['cv.outs'] = int(value) elif prop == "midi.ins": if value.isdigit(): pinfo['midi.ins'] = int(value) elif prop == "midi.outs": @@ -329,6 +335,9 @@ def checkPluginCached(desc, ptype): pinfo['audio.ins'] = desc['audioIns'] pinfo['audio.outs'] = desc['audioOuts'] + pinfo['cv.ins'] = desc['cvIns'] + pinfo['cv.outs'] = desc['cvOuts'] + pinfo['midi.ins'] = desc['midiIns'] pinfo['midi.outs'] = desc['midiOuts'] diff --git a/source/frontend/carla_utils.py b/source/frontend/carla_utils.py index 2450a3031..921b4394b 100644 --- a/source/frontend/carla_utils.py +++ b/source/frontend/carla_utils.py @@ -117,6 +117,12 @@ class CarlaCachedPluginInfo(Structure): # Number of audio outputs. ("audioOuts", c_uint32), + # Number of CV inputs. + ("cvIns", c_uint32), + + # Number of CV outputs. + ("cvOuts", c_uint32), + # Number of MIDI inputs. ("midiIns", c_uint32), @@ -152,6 +158,8 @@ PyCarlaCachedPluginInfo = { 'hints': 0x0, 'audioIns': 0, 'audioOuts': 0, + 'cvIns': 0, + 'cvOuts': 0, 'midiIns': 0, 'midiOuts': 0, 'parameterIns': 0, diff --git a/source/includes/CarlaNative.h b/source/includes/CarlaNative.h index 63f498887..562f3e226 100644 --- a/source/includes/CarlaNative.h +++ b/source/includes/CarlaNative.h @@ -64,7 +64,8 @@ typedef enum { NATIVE_PLUGIN_USES_STATE = 1 << 9, NATIVE_PLUGIN_USES_TIME = 1 << 10, NATIVE_PLUGIN_USES_PARENT_ID = 1 << 11, /** can set transient hint to parent */ - NATIVE_PLUGIN_HAS_INLINE_DISPLAY = 1 << 12 + NATIVE_PLUGIN_HAS_INLINE_DISPLAY = 1 << 12, + NATIVE_PLUGIN_USES_CONTROL_VOLTAGE = 1 << 13 } NativePluginHints; typedef enum { @@ -268,6 +269,10 @@ typedef struct _NativePluginDescriptor { const NativeInlineDisplayImageSurface* (*render_inline_display)(NativePluginHandle handle, uint32_t width, uint32_t height); + // placed at the end for backwards compatibility. only valid if NATIVE_PLUGIN_USES_CONTROL_VOLTAGE is set + const uint32_t cvIns; + const uint32_t cvOuts; + } NativePluginDescriptor; /* ------------------------------------------------------------------------------------------------------------ diff --git a/source/includes/CarlaNative.hpp b/source/includes/CarlaNative.hpp index dc229d198..e302f1b72 100644 --- a/source/includes/CarlaNative.hpp +++ b/source/includes/CarlaNative.hpp @@ -577,7 +577,8 @@ public: \ ClassName::_get_state, \ ClassName::_set_state, \ ClassName::_dispatcher, \ - ClassName::_render_inline_display + ClassName::_render_inline_display, \ + 0, 0 // ----------------------------------------------------------------------- diff --git a/source/includes/CarlaNativePlugin.h b/source/includes/CarlaNativePlugin.h index f5ec91605..6d1294ac2 100644 --- a/source/includes/CarlaNativePlugin.h +++ b/source/includes/CarlaNativePlugin.h @@ -58,6 +58,11 @@ CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay32_plugin(); */ CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay64_plugin(); +/*! + * Get the native plugin descriptor for the carla-patchbay-cv plugin. + */ +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin(); + #ifdef __cplusplus /*! * Get the internal CarlaEngine instance. diff --git a/source/modules/water/processors/AudioProcessor.cpp b/source/modules/water/processors/AudioProcessor.cpp index 932adf946..5ad3870e1 100644 --- a/source/modules/water/processors/AudioProcessor.cpp +++ b/source/modules/water/processors/AudioProcessor.cpp @@ -88,19 +88,6 @@ void AudioProcessor::suspendProcessing (const bool shouldBeSuspended) void AudioProcessor::reset() {} -void AudioProcessor::processBlockBypassed (AudioSampleBuffer& buffer, MidiBuffer&) -{ - for (uint ch = getTotalNumInputChannels(ChannelTypeAudio); ch < getTotalNumOutputChannels(ChannelTypeAudio); ++ch) - buffer.clear (ch, 0, buffer.getNumSamples()); -} - -void AudioProcessor::processBlockWithCV (AudioSampleBuffer& audioBuffer, - const AudioSampleBuffer&, AudioSampleBuffer&, - MidiBuffer& midiMessages) -{ - processBlock (audioBuffer, midiMessages); -} - uint AudioProcessor::getTotalNumInputChannels(ChannelType t) const noexcept { switch (t) diff --git a/source/modules/water/processors/AudioProcessor.h b/source/modules/water/processors/AudioProcessor.h index 3190a9750..6c9f249cc 100644 --- a/source/modules/water/processors/AudioProcessor.h +++ b/source/modules/water/processors/AudioProcessor.h @@ -154,26 +154,10 @@ public: @see AudiobusLayout::getBusBuffer */ - - virtual void processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) = 0; - virtual void processBlockWithCV (AudioSampleBuffer& audioBuffer, const AudioSampleBuffer& cvInBuffer, AudioSampleBuffer& cvOutBuffer, - MidiBuffer& midiMessages); - - /** Renders the next block when the processor is being bypassed. - - The default implementation of this method will pass-through any incoming audio, but - you may override this method e.g. to add latency compensation to the data to match - the processor's latency characteristics. This will avoid situations where bypassing - will shift the signal forward in time, possibly creating pre-echo effects and odd timings. - Another use for this method would be to cross-fade or morph between the wet (not bypassed) - and dry (bypassed) signals. - */ - virtual void processBlockBypassed (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages); + MidiBuffer& midiMessages) = 0; //============================================================================== /** Returns the total number of input channels. */ diff --git a/source/modules/water/processors/AudioProcessorGraph.cpp b/source/modules/water/processors/AudioProcessorGraph.cpp index c87e6fae0..84fde1ba3 100644 --- a/source/modules/water/processors/AudioProcessorGraph.cpp +++ b/source/modules/water/processors/AudioProcessorGraph.cpp @@ -1158,7 +1158,8 @@ void AudioProcessorGraph::Node::setParentGraph (AudioProcessorGraph* const graph struct AudioProcessorGraph::AudioProcessorGraphBufferHelpers { AudioProcessorGraphBufferHelpers() noexcept - : currentAudioInputBuffer (nullptr) {} + : currentAudioInputBuffer (nullptr), + currentCVInputBuffer (nullptr) {} void setRenderingBufferSize (int newNumAudioChannels, int newNumCVChannels, int newNumSamples) noexcept { @@ -1173,26 +1174,32 @@ struct AudioProcessorGraph::AudioProcessorGraphBufferHelpers { renderingAudioBuffers.setSize (1, 1); currentAudioInputBuffer = nullptr; + currentCVInputBuffer = nullptr; currentAudioOutputBuffer.setSize (1, 1); + currentCVOutputBuffer.setSize (1, 1); renderingCVBuffers.setSize (1, 1); } - void prepareInOutBuffers(int newNumChannels, int newNumSamples) noexcept + void prepareInOutBuffers (int newNumAudioChannels, int newNumCVChannels, int newNumSamples) noexcept { currentAudioInputBuffer = nullptr; - currentAudioOutputBuffer.setSize (newNumChannels, newNumSamples); + currentCVInputBuffer = nullptr; + currentAudioOutputBuffer.setSize (newNumAudioChannels, newNumSamples); + currentCVOutputBuffer.setSize (newNumCVChannels, newNumSamples); } - AudioSampleBuffer renderingAudioBuffers; - AudioSampleBuffer renderingCVBuffers; - AudioSampleBuffer* currentAudioInputBuffer; - AudioSampleBuffer currentAudioOutputBuffer; + AudioSampleBuffer renderingAudioBuffers; + AudioSampleBuffer renderingCVBuffers; + AudioSampleBuffer* currentAudioInputBuffer; + const AudioSampleBuffer* currentCVInputBuffer; + AudioSampleBuffer currentAudioOutputBuffer; + AudioSampleBuffer currentCVOutputBuffer; }; //============================================================================== AudioProcessorGraph::AudioProcessorGraph() - : lastNodeId (0), audioBuffers (new AudioProcessorGraphBufferHelpers), + : lastNodeId (0), audioAndCVBuffers (new AudioProcessorGraphBufferHelpers), currentMidiInputBuffer (nullptr), isPrepared (false), needsReorder (false) { } @@ -1525,9 +1532,9 @@ void AudioProcessorGraph::buildRenderingSequence() // swap over to the new rendering sequence.. const CarlaRecursiveMutexLocker cml (getCallbackLock()); - audioBuffers->setRenderingBufferSize (numAudioRenderingBuffersNeeded, - numCVRenderingBuffersNeeded, - getBlockSize()); + audioAndCVBuffers->setRenderingBufferSize (numAudioRenderingBuffersNeeded, + numCVRenderingBuffersNeeded, + getBlockSize()); for (int i = static_cast(midiBuffers.size()); --i >= 0;) midiBuffers.getUnchecked(i)->clear(); @@ -1547,7 +1554,9 @@ void AudioProcessorGraph::prepareToPlay (double sampleRate, int estimatedSamples { setRateAndBufferSizeDetails(sampleRate, estimatedSamplesPerBlock); - audioBuffers->prepareInOutBuffers(jmax(1U, getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio)), estimatedSamplesPerBlock); + audioAndCVBuffers->prepareInOutBuffers(jmax(1U, getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio)), + jmax(1U, getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV)), + estimatedSamplesPerBlock); currentMidiInputBuffer = nullptr; currentMidiOutputBuffer.clear(); @@ -1565,7 +1574,7 @@ void AudioProcessorGraph::releaseResources() for (int i = 0; i < nodes.size(); ++i) nodes.getUnchecked(i)->unprepare(); - audioBuffers->release(); + audioAndCVBuffers->release(); midiBuffers.clear(); currentMidiInputBuffer = nullptr; @@ -1590,23 +1599,24 @@ void AudioProcessorGraph::setNonRealtime (bool isProcessingNonRealtime) noexcept nodes.getUnchecked(i)->getProcessor()->setNonRealtime (isProcessingNonRealtime); } -void AudioProcessorGraph::processAudio (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +/* +void AudioProcessorGraph::processAudio (AudioSampleBuffer& audioBuffer, MidiBuffer& midiMessages) { - AudioSampleBuffer*& currentAudioInputBuffer = audioBuffers->currentAudioInputBuffer; - AudioSampleBuffer& currentAudioOutputBuffer = audioBuffers->currentAudioOutputBuffer; - AudioSampleBuffer& renderingAudioBuffers = audioBuffers->renderingAudioBuffers; - AudioSampleBuffer& renderingCVBuffers = audioBuffers->renderingCVBuffers; + AudioSampleBuffer*& currentAudioInputBuffer = audioAndCVBuffers->currentAudioInputBuffer; + AudioSampleBuffer& currentAudioOutputBuffer = audioAndCVBuffers->currentAudioOutputBuffer; + AudioSampleBuffer& renderingAudioBuffers = audioAndCVBuffers->renderingAudioBuffers; + AudioSampleBuffer& renderingCVBuffers = audioAndCVBuffers->renderingCVBuffers; - const int numSamples = buffer.getNumSamples(); + const int numSamples = audioBuffer.getNumSamples(); - if (! audioBuffers->currentAudioOutputBuffer.setSizeRT(numSamples)) + if (! audioAndCVBuffers->currentAudioOutputBuffer.setSizeRT(numSamples)) return; - if (! audioBuffers->renderingAudioBuffers.setSizeRT(numSamples)) + if (! audioAndCVBuffers->renderingAudioBuffers.setSizeRT(numSamples)) return; - if (! audioBuffers->renderingCVBuffers.setSizeRT(numSamples)) + if (! audioAndCVBuffers->renderingCVBuffers.setSizeRT(numSamples)) return; - currentAudioInputBuffer = &buffer; + currentAudioInputBuffer = &audioBuffer; currentAudioOutputBuffer.clear(); currentMidiInputBuffer = &midiMessages; currentMidiOutputBuffer.clear(); @@ -1619,27 +1629,78 @@ void AudioProcessorGraph::processAudio (AudioSampleBuffer& buffer, MidiBuffer& m op->perform (renderingAudioBuffers, renderingCVBuffers, midiBuffers, numSamples); } - for (uint32_t i = 0; i < buffer.getNumChannels(); ++i) - buffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); + for (uint32_t i = 0; i < audioBuffer.getNumChannels(); ++i) + audioBuffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); midiMessages.clear(); - midiMessages.addEvents (currentMidiOutputBuffer, 0, buffer.getNumSamples(), 0); + midiMessages.addEvents (currentMidiOutputBuffer, 0, audioBuffer.getNumSamples(), 0); +} +*/ + +void AudioProcessorGraph::processAudioAndCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages) +{ + AudioSampleBuffer*& currentAudioInputBuffer = audioAndCVBuffers->currentAudioInputBuffer; + const AudioSampleBuffer*& currentCVInputBuffer = audioAndCVBuffers->currentCVInputBuffer; + AudioSampleBuffer& currentAudioOutputBuffer = audioAndCVBuffers->currentAudioOutputBuffer; + AudioSampleBuffer& currentCVOutputBuffer = audioAndCVBuffers->currentCVOutputBuffer; + AudioSampleBuffer& renderingAudioBuffers = audioAndCVBuffers->renderingAudioBuffers; + AudioSampleBuffer& renderingCVBuffers = audioAndCVBuffers->renderingCVBuffers; + + const int numSamples = audioBuffer.getNumSamples(); + + if (! audioAndCVBuffers->currentAudioOutputBuffer.setSizeRT(numSamples)) + return; + if (! audioAndCVBuffers->currentCVOutputBuffer.setSizeRT(numSamples)) + return; + if (! audioAndCVBuffers->renderingAudioBuffers.setSizeRT(numSamples)) + return; + if (! audioAndCVBuffers->renderingCVBuffers.setSizeRT(numSamples)) + return; + + currentAudioInputBuffer = &audioBuffer; + currentCVInputBuffer = &cvInBuffer; + currentAudioOutputBuffer.clear(); + currentCVOutputBuffer.clear(); + currentMidiInputBuffer = &midiMessages; + currentMidiOutputBuffer.clear(); + + for (int i = 0; i < renderingOps.size(); ++i) + { + GraphRenderingOps::AudioGraphRenderingOpBase* const op + = (GraphRenderingOps::AudioGraphRenderingOpBase*) renderingOps.getUnchecked(i); + + op->perform (renderingAudioBuffers, renderingCVBuffers, midiBuffers, numSamples); + } + + for (uint32_t i = 0; i < audioBuffer.getNumChannels(); ++i) + audioBuffer.copyFrom (i, 0, currentAudioOutputBuffer, i, 0, numSamples); + + for (uint32_t i = 0; i < cvOutBuffer.getNumChannels(); ++i) + cvOutBuffer.copyFrom (i, 0, currentCVOutputBuffer, i, 0, numSamples); + + midiMessages.clear(); + midiMessages.addEvents (currentMidiOutputBuffer, 0, audioBuffer.getNumSamples(), 0); } bool AudioProcessorGraph::acceptsMidi() const { return true; } bool AudioProcessorGraph::producesMidi() const { return true; } +/* void AudioProcessorGraph::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) { processAudio (buffer, midiMessages); } +*/ -void AudioProcessorGraph::processBlockWithCV (AudioSampleBuffer& buffer, - const AudioSampleBuffer&, - AudioSampleBuffer&, +void AudioProcessorGraph::processBlockWithCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, MidiBuffer& midiMessages) { - processAudio (buffer, midiMessages); + processAudioAndCV (audioBuffer, cvInBuffer, cvOutBuffer, midiMessages); } void AudioProcessorGraph::reorderNowIfNeeded() @@ -1691,25 +1752,24 @@ void AudioProcessorGraph::AudioGraphIOProcessor::releaseResources() { } -void AudioProcessorGraph::AudioGraphIOProcessor::processAudio (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) +void AudioProcessorGraph::AudioGraphIOProcessor::processAudioAndCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages) { CARLA_SAFE_ASSERT_RETURN(graph != nullptr,); - AudioSampleBuffer*& currentAudioInputBuffer = - graph->audioBuffers->currentAudioInputBuffer; - - AudioSampleBuffer& currentAudioOutputBuffer = - graph->audioBuffers->currentAudioOutputBuffer; - switch (type) { case audioOutputNode: { + AudioSampleBuffer& currentAudioOutputBuffer = + graph->audioAndCVBuffers->currentAudioOutputBuffer; + for (int i = jmin (currentAudioOutputBuffer.getNumChannels(), - buffer.getNumChannels()); --i >= 0;) + audioBuffer.getNumChannels()); --i >= 0;) { - currentAudioOutputBuffer.addFrom (i, 0, buffer, i, 0, buffer.getNumSamples()); + currentAudioOutputBuffer.addFrom (i, 0, audioBuffer, i, 0, audioBuffer.getNumSamples()); } break; @@ -1717,21 +1777,52 @@ void AudioProcessorGraph::AudioGraphIOProcessor::processAudio (AudioSampleBuffer case audioInputNode: { + AudioSampleBuffer*& currentAudioInputBuffer = + graph->audioAndCVBuffers->currentAudioInputBuffer; + for (int i = jmin (currentAudioInputBuffer->getNumChannels(), - buffer.getNumChannels()); --i >= 0;) + audioBuffer.getNumChannels()); --i >= 0;) { - buffer.copyFrom (i, 0, *currentAudioInputBuffer, i, 0, buffer.getNumSamples()); + audioBuffer.copyFrom (i, 0, *currentAudioInputBuffer, i, 0, audioBuffer.getNumSamples()); + } + + break; + } + + case cvOutputNode: + { + AudioSampleBuffer& currentCVOutputBuffer = + graph->audioAndCVBuffers->currentCVOutputBuffer; + + for (int i = jmin (currentCVOutputBuffer.getNumChannels(), + cvInBuffer.getNumChannels()); --i >= 0;) + { + currentCVOutputBuffer.addFrom (i, 0, cvInBuffer, i, 0, cvInBuffer.getNumSamples()); + } + + break; + } + + case cvInputNode: + { + const AudioSampleBuffer*& currentCVInputBuffer = + graph->audioAndCVBuffers->currentCVInputBuffer; + + for (int i = jmin (currentCVInputBuffer->getNumChannels(), + cvOutBuffer.getNumChannels()); --i >= 0;) + { + cvOutBuffer.copyFrom (i, 0, *currentCVInputBuffer, i, 0, cvOutBuffer.getNumSamples()); } break; } case midiOutputNode: - graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, buffer.getNumSamples(), 0); + graph->currentMidiOutputBuffer.addEvents (midiMessages, 0, audioBuffer.getNumSamples(), 0); break; case midiInputNode: - midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, buffer.getNumSamples(), 0); + midiMessages.addEvents (*graph->currentMidiInputBuffer, 0, audioBuffer.getNumSamples(), 0); break; default: @@ -1739,10 +1830,12 @@ void AudioProcessorGraph::AudioGraphIOProcessor::processAudio (AudioSampleBuffer } } -void AudioProcessorGraph::AudioGraphIOProcessor::processBlock (AudioSampleBuffer& buffer, - MidiBuffer& midiMessages) +void AudioProcessorGraph::AudioGraphIOProcessor::processBlockWithCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages) { - processAudio (buffer, midiMessages); + processAudioAndCV (audioBuffer, cvInBuffer, cvOutBuffer, midiMessages); } bool AudioProcessorGraph::AudioGraphIOProcessor::acceptsMidi() const diff --git a/source/modules/water/processors/AudioProcessorGraph.h b/source/modules/water/processors/AudioProcessorGraph.h index cdb0cbc2c..8c66eb71e 100644 --- a/source/modules/water/processors/AudioProcessorGraph.h +++ b/source/modules/water/processors/AudioProcessorGraph.h @@ -318,12 +318,12 @@ public: ~AudioGraphIOProcessor(); const String getName() const override; -#if 0 - void fillInPluginDescription (PluginDescription&) const override; -#endif void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override; void releaseResources() override; - void processBlock (AudioSampleBuffer&, MidiBuffer&) override; + void processBlockWithCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages) override; bool acceptsMidi() const override; bool producesMidi() const override; @@ -336,7 +336,11 @@ public: AudioProcessorGraph* graph; //============================================================================== - void processAudio (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + //void processAudio (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + void processAudioAndCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages); CARLA_DECLARE_NON_COPY_CLASS (AudioGraphIOProcessor) }; @@ -345,8 +349,8 @@ public: const String getName() const override; void prepareToPlay (double, int) override; void releaseResources() override; - void processBlock (AudioSampleBuffer&, MidiBuffer&) override; - void processBlockWithCV (AudioSampleBuffer& buffer, + //void processBlock (AudioSampleBuffer&, MidiBuffer&) override; + void processBlockWithCV (AudioSampleBuffer& audioBuffer, const AudioSampleBuffer& cvInBuffer, AudioSampleBuffer& cvOutBuffer, MidiBuffer& midiMessages) override; @@ -362,7 +366,11 @@ public: private: //============================================================================== - void processAudio (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + // void processAudio (AudioSampleBuffer& audioBuffer, MidiBuffer& midiMessages); + void processAudioAndCV (AudioSampleBuffer& audioBuffer, + const AudioSampleBuffer& cvInBuffer, + AudioSampleBuffer& cvOutBuffer, + MidiBuffer& midiMessages); //============================================================================== ReferenceCountedArray nodes; @@ -373,7 +381,7 @@ private: friend class AudioGraphIOProcessor; struct AudioProcessorGraphBufferHelpers; - ScopedPointer audioBuffers; + ScopedPointer audioAndCVBuffers; MidiBuffer* currentMidiInputBuffer; MidiBuffer currentMidiOutputBuffer; diff --git a/source/native-plugins/_data.cpp b/source/native-plugins/_data.cpp index f6f23a595..43d4521c9 100644 --- a/source/native-plugins/_data.cpp +++ b/source/native-plugins/_data.cpp @@ -19,13 +19,16 @@ #include "CarlaMIDI.h" #include "CarlaUtils.hpp" -#undef DESCFUNCS -#define DESCFUNCS \ +#undef DESCFUNCS_WITHCV +#undef DESCFUNCS_WITHOUTCV +#define DESCFUNCS_WITHCV \ nullptr, nullptr, nullptr, nullptr, nullptr, \ nullptr, nullptr, nullptr, nullptr, nullptr, \ nullptr, nullptr, nullptr, nullptr, nullptr, \ nullptr, nullptr, nullptr, nullptr, nullptr, \ nullptr, nullptr +#define DESCFUNCS_WITHOUTCV \ + DESCFUNCS_WITHCV, 0, 0 static const NativePluginDescriptor sNativePluginDescriptors[] = { @@ -46,7 +49,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "audiogain", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -62,7 +65,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "audiogain_s", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_NONE, @@ -78,7 +81,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "bypass", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -94,7 +97,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "lfo", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -110,7 +113,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midichanfilter", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -126,7 +129,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midichanab", /* maker */ "Milk Brewster", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -142,7 +145,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midigain", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -158,7 +161,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midijoin", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -174,7 +177,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midisplit", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -190,7 +193,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midithrough", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -206,7 +209,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "miditranspose", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -222,7 +225,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midichannelize", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, // -------------------------------------------------------------------------------------------------------------------- @@ -245,7 +248,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "audiofile", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, // -------------------------------------------------------------------------------------------------------------------- @@ -269,7 +272,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midifile", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, #ifdef HAVE_PYQT { @@ -289,7 +292,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "midipattern", /* maker */ "falkTX, tatch", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, #endif @@ -315,7 +318,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlarack", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -335,7 +338,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlarack-nomidiout", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -355,7 +358,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlapatchbay", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -375,7 +378,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlapatchbay3s", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -395,7 +398,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlapatchbay16", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -415,7 +418,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlapatchbay32", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, @@ -435,7 +438,30 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "carlapatchbay64", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV +}, +{ + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD + |NATIVE_PLUGIN_USES_CONTROL_VOLTAGE + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 2, + /* audioOuts */ 2, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 100, + /* paramOuts */ 10, + /* name */ "Carla-Patchbay (CV)", + /* label */ "carlapatchbaycv", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + DESCFUNCS_WITHCV, + /* cvIns */ 5, + /* cvOuts */ 5, }, #endif @@ -459,7 +485,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "bigmeter", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, @@ -476,7 +502,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* label */ "notes", /* maker */ "falkTX", /* copyright */ "GNU GPL v2+", - DESCFUNCS + DESCFUNCS_WITHOUTCV }, #endif @@ -487,7 +513,8 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { }; -#undef DESCFUNCS +#undef DESCFUNCS_WITHCV +#undef DESCFUNCS_WITHOUTCV // -------------------------------------------------------------------------------------------------------------------- diff --git a/source/native-plugins/audio-gain.c b/source/native-plugins/audio-gain.c index 6f9811851..08516afe7 100644 --- a/source/native-plugins/audio-gain.c +++ b/source/native-plugins/audio-gain.c @@ -258,6 +258,8 @@ static const NativePluginDescriptor audiogainStereoDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING, .audioIns = 2, .audioOuts = 2, + .cvIns = 0, + .cvOuts = 0, .midiIns = 0, .midiOuts = 0, .paramIns = PARAM_COUNT_STEREO, diff --git a/source/native-plugins/bypass.c b/source/native-plugins/bypass.c index aabd5370e..e91a473e5 100644 --- a/source/native-plugins/bypass.c +++ b/source/native-plugins/bypass.c @@ -52,6 +52,8 @@ static const NativePluginDescriptor bypassDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING, .audioIns = 1, .audioOuts = 1, + .cvIns = 0, + .cvOuts = 0, .midiIns = 0, .midiOuts = 0, .paramIns = 0, diff --git a/source/native-plugins/lfo.c b/source/native-plugins/lfo.c index f3d39f4b1..c55faf555 100644 --- a/source/native-plugins/lfo.c +++ b/source/native-plugins/lfo.c @@ -272,6 +272,8 @@ static const NativePluginDescriptor lfoDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_NOTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 0, .midiOuts = 0, .paramIns = PARAM_COUNT-1, diff --git a/source/native-plugins/midi-channel-ab.c b/source/native-plugins/midi-channel-ab.c index bb8c4a4f0..ea1bf82c1 100644 --- a/source/native-plugins/midi-channel-ab.c +++ b/source/native-plugins/midi-channel-ab.c @@ -161,6 +161,8 @@ static const NativePluginDescriptor midichanabDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 2, .paramIns = 0, diff --git a/source/native-plugins/midi-channel-filter.c b/source/native-plugins/midi-channel-filter.c index 2d66053a3..b9cce5da6 100644 --- a/source/native-plugins/midi-channel-filter.c +++ b/source/native-plugins/midi-channel-filter.c @@ -152,6 +152,8 @@ static const NativePluginDescriptor midichanfilterDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 1, .paramIns = 0, diff --git a/source/native-plugins/midi-channelize.c b/source/native-plugins/midi-channelize.c index bc993c72b..f3bf6d653 100644 --- a/source/native-plugins/midi-channelize.c +++ b/source/native-plugins/midi-channelize.c @@ -160,6 +160,8 @@ static const NativePluginDescriptor midichannelizeDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 1, .paramIns = 1, diff --git a/source/native-plugins/midi-gain.c b/source/native-plugins/midi-gain.c index 0ef3ca8a8..a163011ed 100644 --- a/source/native-plugins/midi-gain.c +++ b/source/native-plugins/midi-gain.c @@ -222,6 +222,8 @@ static const NativePluginDescriptor midigainDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 1, .paramIns = 0, diff --git a/source/native-plugins/midi-join.c b/source/native-plugins/midi-join.c index df44e89e8..21f17f642 100644 --- a/source/native-plugins/midi-join.c +++ b/source/native-plugins/midi-join.c @@ -99,6 +99,8 @@ static const NativePluginDescriptor midijoinDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = MAX_MIDI_CHANNELS, .midiOuts = 1, .paramIns = 0, diff --git a/source/native-plugins/midi-split.c b/source/native-plugins/midi-split.c index 2ccb80e60..0d508af98 100644 --- a/source/native-plugins/midi-split.c +++ b/source/native-plugins/midi-split.c @@ -92,6 +92,8 @@ static const NativePluginDescriptor midisplitDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = MAX_MIDI_CHANNELS, .paramIns = 0, diff --git a/source/native-plugins/midi-through.c b/source/native-plugins/midi-through.c index 4f3a33485..3accf5350 100644 --- a/source/native-plugins/midi-through.c +++ b/source/native-plugins/midi-through.c @@ -73,6 +73,8 @@ static const NativePluginDescriptor midithroughDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 1, .paramIns = 0, diff --git a/source/native-plugins/midi-transpose.c b/source/native-plugins/midi-transpose.c index bf10eb326..ea13db88a 100644 --- a/source/native-plugins/midi-transpose.c +++ b/source/native-plugins/midi-transpose.c @@ -185,6 +185,8 @@ static const NativePluginDescriptor miditransposeDesc = { .supports = NATIVE_PLUGIN_SUPPORTS_EVERYTHING, .audioIns = 0, .audioOuts = 0, + .cvIns = 0, + .cvOuts = 0, .midiIns = 1, .midiOuts = 1, .paramIns = 2,