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, | |||