Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-rc1
| @@ -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. | |||
| */ | |||
| @@ -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)) | |||
| { | |||
| @@ -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<int>(bufferSize)); | |||
| graph.setPlayConfigDetails(numAudioIns, numAudioOuts, | |||
| numCVIns, numCVOuts, | |||
| 1, 1, | |||
| sampleRate, static_cast<int>(bufferSize)); | |||
| graph.prepareToPlay(sampleRate, static_cast<int>(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<int>(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(); i<count; ++i) | |||
| audioBuffer.clear(i, 0, frames); | |||
| for (uint32_t j=numAudioIns, count=audioBuffer.getNumChannels(); j < count; ++j) | |||
| audioBuffer.clear(j, 0, frames); | |||
| for (uint32_t j=0; j < numCVOuts; ++j) | |||
| cvOutBuffer.clear(j, 0, frames); | |||
| } | |||
| // ready to go! | |||
| graph.processBlock(audioBuffer, midiBuffer); | |||
| graph.processBlockWithCV(audioBuffer, cvInBuffer, cvOutBuffer, midiBuffer); | |||
| // put water audio in carla buffer | |||
| // put water audio and cv in carla buffer | |||
| { | |||
| for (uint32_t i=0; i < outputs; ++i) | |||
| uint32_t i=0; | |||
| for (; i < numAudioOuts; ++i) | |||
| carla_copyFloats(outBuf[i], audioBuffer.getReadPointer(i), frames); | |||
| for (uint32_t j=0; j < numCVOuts; ++j, ++i) | |||
| carla_copyFloats(outBuf[i], cvOutBuffer.getReadPointer(j), frames); | |||
| } | |||
| // put water events in carla buffer | |||
| @@ -2245,19 +2309,20 @@ EngineInternalGraph::~EngineInternalGraph() noexcept | |||
| CARLA_SAFE_ASSERT(fRack == nullptr); | |||
| } | |||
| void EngineInternalGraph::create(const uint32_t inputs, const uint32_t outputs) | |||
| void EngineInternalGraph::create(const uint32_t audioIns, const uint32_t audioOuts, | |||
| const uint32_t cvIns, const uint32_t cvOuts) | |||
| { | |||
| fIsRack = (kEngine->getOptions().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; | |||
| @@ -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; | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -218,7 +218,9 @@ public: | |||
| pData->sampleRate = fDevice->getCurrentSampleRate(); | |||
| pData->initTime(pData->options.transportExtra); | |||
| pData->graph.create(static_cast<uint32_t>(inputNames.size()), static_cast<uint32_t>(outputNames.size())); | |||
| pData->graph.create(static_cast<uint32_t>(inputNames.size()), | |||
| static_cast<uint32_t>(outputNames.size()), | |||
| 0, 0); | |||
| fDevice->start(this); | |||
| @@ -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<NativePluginHints>(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<NativePluginSupports>(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 | |||
| @@ -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(); | |||
| @@ -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<const float**>(fAudioInBuffers), fAudioOutBuffers, frames, | |||
| const_cast<const float**>(fAudioAndCvInBuffers), fAudioAndCvOutBuffers, frames, | |||
| fMidiInEvents, fMidiEventInCount); | |||
| } | |||
| else | |||
| { | |||
| fDescriptor->process(fHandle, | |||
| (pData->audioIn.count > 0) ? const_cast<const float**>(&fAudioInBuffers[0]) : nullptr, | |||
| (pData->audioOut.count > 0) ? &fAudioOutBuffers[0] : nullptr, | |||
| (fAudioAndCvInBuffers != nullptr) ? const_cast<const float**>(&fAudioAndCvInBuffers[0]) : nullptr, | |||
| (fAudioAndCvOutBuffers != nullptr) ? &fAudioAndCvOutBuffers[0] : nullptr, | |||
| frames, fMidiInEvents, fMidiEventInCount); | |||
| fDescriptor->process(fHandle2, | |||
| (pData->audioIn.count > 0) ? const_cast<const float**>(&fAudioInBuffers[1]) : nullptr, | |||
| (pData->audioOut.count > 0) ? &fAudioOutBuffers[1] : nullptr, | |||
| (fAudioAndCvInBuffers != nullptr) ? const_cast<const float**>(&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]; | |||
| @@ -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<uint32_t>(desc->numInputChannels); | |||
| info.audioOuts = static_cast<uint32_t>(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; | |||
| @@ -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); | |||
| @@ -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'] | |||
| @@ -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, | |||
| @@ -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; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -577,7 +577,8 @@ public: \ | |||
| ClassName::_get_state, \ | |||
| ClassName::_set_state, \ | |||
| ClassName::_dispatcher, \ | |||
| ClassName::_render_inline_display | |||
| ClassName::_render_inline_display, \ | |||
| 0, 0 | |||
| // ----------------------------------------------------------------------- | |||
| @@ -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. | |||
| @@ -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) | |||
| @@ -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. */ | |||
| @@ -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<int>(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 | |||
| @@ -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<Node> nodes; | |||
| @@ -373,7 +381,7 @@ private: | |||
| friend class AudioGraphIOProcessor; | |||
| struct AudioProcessorGraphBufferHelpers; | |||
| ScopedPointer<AudioProcessorGraphBufferHelpers> audioBuffers; | |||
| ScopedPointer<AudioProcessorGraphBufferHelpers> audioAndCVBuffers; | |||
| MidiBuffer* currentMidiInputBuffer; | |||
| MidiBuffer currentMidiOutputBuffer; | |||
| @@ -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<NativePluginHints>(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<NativePluginSupports>(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 | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||
| @@ -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, | |||