| @@ -662,7 +662,8 @@ public: | |||
| /*! | |||
| * Plugin process call. | |||
| */ | |||
| virtual void process(float** const inBuffer, float** const outBuffer, const uint32_t frames) = 0; | |||
| virtual void process(const float** const audioIn, float** const audioOut, | |||
| const float** const cvIn, float** const cvOut, const uint32_t frames) = 0; | |||
| /*! | |||
| * Tell the plugin the current buffer size changed. | |||
| @@ -553,7 +553,7 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
| // safe copy | |||
| float inBuf0[frames]; | |||
| float inBuf1[frames]; | |||
| float* inBuf[2] = { inBuf0, inBuf1 }; | |||
| const float* inBuf[2] = { inBuf0, inBuf1 }; | |||
| // initialize audio inputs | |||
| FloatVectorOperations::copy(inBuf0, inBufReal[0], iframes); | |||
| @@ -613,7 +613,7 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
| // process | |||
| plugin->initBuffers(); | |||
| plugin->process(inBuf, outBuf, frames); | |||
| plugin->process(inBuf, outBuf, nullptr, nullptr, frames); | |||
| plugin->unlock(); | |||
| // if plugin has no audio inputs, add input buffer | |||
| @@ -985,6 +985,8 @@ public: | |||
| midi.clear(); | |||
| // TODO - CV support | |||
| const uint32_t bufferSize(static_cast<uint32_t>(audio.getNumSamples())); | |||
| if (const int numChan = audio.getNumChannels()) | |||
| @@ -1011,7 +1013,7 @@ public: | |||
| } | |||
| } | |||
| fPlugin->process(audioBuffers, audioBuffers, bufferSize); | |||
| fPlugin->process(const_cast<const float**>(audioBuffers), audioBuffers, nullptr, nullptr, bufferSize); | |||
| for (int i=0; i<numChan; ++i) | |||
| { | |||
| @@ -1028,7 +1030,7 @@ public: | |||
| } | |||
| else | |||
| { | |||
| fPlugin->process(nullptr, nullptr, bufferSize); | |||
| fPlugin->process(nullptr, nullptr, nullptr, nullptr, bufferSize); | |||
| } | |||
| midi.clear(); | |||
| @@ -1955,45 +1955,61 @@ private: | |||
| void processPlugin(CarlaPlugin* const plugin, const uint32_t nframes) | |||
| { | |||
| const uint32_t inCount(plugin->getAudioInCount()); | |||
| const uint32_t outCount(plugin->getAudioOutCount()); | |||
| const uint32_t audioInCount(plugin->getAudioInCount()); | |||
| const uint32_t audioOutCount(plugin->getAudioOutCount()); | |||
| const uint32_t cvInCount(plugin->getCVInCount()); | |||
| const uint32_t cvOutCount(plugin->getCVOutCount()); | |||
| float* inBuffer[inCount]; | |||
| float* outBuffer[outCount]; | |||
| const float* audioIn[audioInCount]; | |||
| /* */ float* audioOut[audioOutCount]; | |||
| const float* cvIn[cvInCount]; | |||
| /* */ float* cvOut[cvOutCount]; | |||
| float inPeaks[2] = { 0.0f }; | |||
| float outPeaks[2] = { 0.0f }; | |||
| for (uint32_t i=0; i < inCount; ++i) | |||
| for (uint32_t i=0; i < audioInCount; ++i) | |||
| { | |||
| CarlaEngineAudioPort* const port(plugin->getAudioInPort(i)); | |||
| inBuffer[i] = port->getBuffer(); | |||
| audioIn[i] = port->getBuffer(); | |||
| } | |||
| for (uint32_t i=0; i < outCount; ++i) | |||
| for (uint32_t i=0; i < audioOutCount; ++i) | |||
| { | |||
| CarlaEngineAudioPort* const port(plugin->getAudioOutPort(i)); | |||
| outBuffer[i] = port->getBuffer(); | |||
| audioOut[i] = port->getBuffer(); | |||
| } | |||
| for (uint32_t i=0; i < cvInCount; ++i) | |||
| { | |||
| CarlaEngineCVPort* const port(plugin->getCVInPort(i)); | |||
| cvIn[i] = port->getBuffer(); | |||
| } | |||
| for (uint32_t i=0; i < inCount && i < 2; ++i) | |||
| for (uint32_t i=0; i < cvOutCount; ++i) | |||
| { | |||
| CarlaEngineCVPort* const port(plugin->getCVOutPort(i)); | |||
| cvOut[i] = port->getBuffer(); | |||
| } | |||
| float inPeaks[2] = { 0.0f }; | |||
| float outPeaks[2] = { 0.0f }; | |||
| for (uint32_t i=0; i < audioInCount && i < 2; ++i) | |||
| { | |||
| for (uint32_t j=0; j < nframes; ++j) | |||
| { | |||
| const float absV(std::abs(inBuffer[i][j])); | |||
| const float absV(std::abs(audioIn[i][j])); | |||
| if (absV > inPeaks[i]) | |||
| inPeaks[i] = absV; | |||
| } | |||
| } | |||
| plugin->process(inBuffer, outBuffer, nframes); | |||
| plugin->process(audioIn, audioOut, cvIn, cvOut, nframes); | |||
| for (uint32_t i=0; i < outCount && i < 2; ++i) | |||
| for (uint32_t i=0; i < audioOutCount && i < 2; ++i) | |||
| { | |||
| for (uint32_t j=0; j < nframes; ++j) | |||
| { | |||
| const float absV(std::abs(outBuffer[i][j])); | |||
| const float absV(std::abs(audioOut[i][j])); | |||
| if (absV > outPeaks[i]) | |||
| outPeaks[i] = absV; | |||
| @@ -345,6 +345,7 @@ public: | |||
| fLastPongCounter(-1), | |||
| fBridgeBinary(), | |||
| fShmAudioPool(), | |||
| fShmCVPool(), | |||
| fShmRtControl(), | |||
| fShmNonRtControl(), | |||
| fInfo(), | |||
| @@ -923,7 +924,7 @@ public: | |||
| fTimedOut = false; | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, 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 | |||
| @@ -932,7 +933,9 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -1158,20 +1161,28 @@ public: | |||
| } // End of Event Input | |||
| processSingle(inBuffer, outBuffer, frames); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames); | |||
| } | |||
| bool processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames) | |||
| bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(frames > 0, false); | |||
| if (pData->audioIn.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(inBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); | |||
| } | |||
| if (pData->audioOut.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(outBuffer != nullptr, false); | |||
| 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); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| @@ -1184,17 +1195,20 @@ public: | |||
| else if (! pData->singleMutex.tryLock()) | |||
| { | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return false; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Reset audio buffers | |||
| //std::memset(fShmAudioPool.data, 0, fShmAudioPool.size); | |||
| for (uint32_t i=0; i < fInfo.aIns; ++i) | |||
| FloatVectorOperations::copy(fShmAudioPool.data + (i * frames), inBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(fShmAudioPool.data + (i * frames), audioIn[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < fInfo.cvIns; ++i) | |||
| FloatVectorOperations::copy(fShmCVPool.data + (i * frames), cvIn[i], static_cast<int>(frames)); | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // TimeInfo | |||
| @@ -1236,7 +1250,10 @@ public: | |||
| } | |||
| for (uint32_t i=0; i < fInfo.aOuts; ++i) | |||
| FloatVectorOperations::copy(outBuffer[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < fInfo.cvOuts; ++i) | |||
| FloatVectorOperations::copy(cvOut[i], fShmCVPool.data + ((i + fInfo.cvIns) * frames), static_cast<int>(frames)); | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Post-processing (dry/wet, volume and balance) | |||
| @@ -1256,8 +1273,8 @@ public: | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| { | |||
| bufValue = inBuffer[(pData->audioIn.count == 1) ? 0 : i][k]; | |||
| outBuffer[i][k] = (outBuffer[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | |||
| bufValue = audioIn[(pData->audioIn.count == 1) ? 0 : i][k]; | |||
| audioOut[i][k] = (audioOut[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | |||
| } | |||
| } | |||
| @@ -1269,7 +1286,7 @@ public: | |||
| if (isPair) | |||
| { | |||
| CARLA_ASSERT(i+1 < pData->audioOut.count); | |||
| FloatVectorOperations::copy(oldBufLeft, outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(oldBufLeft, audioOut[i], static_cast<int>(frames)); | |||
| } | |||
| float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; | |||
| @@ -1280,14 +1297,14 @@ public: | |||
| if (isPair) | |||
| { | |||
| // left | |||
| outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL); | |||
| outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR); | |||
| audioOut[i][k] = oldBufLeft[k] * (1.0f - balRangeL); | |||
| audioOut[i][k] += audioOut[i+1][k] * (1.0f - balRangeR); | |||
| } | |||
| else | |||
| { | |||
| // right | |||
| outBuffer[i][k] = outBuffer[i][k] * balRangeR; | |||
| outBuffer[i][k] += oldBufLeft[k] * balRangeL; | |||
| audioOut[i][k] = audioOut[i][k] * balRangeR; | |||
| audioOut[i][k] += oldBufLeft[k] * balRangeL; | |||
| } | |||
| } | |||
| } | |||
| @@ -1296,7 +1313,7 @@ public: | |||
| if (doVolume) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k] *= pData->postProc.volume; | |||
| audioOut[i][k] *= pData->postProc.volume; | |||
| } | |||
| } | |||
| @@ -1310,7 +1327,7 @@ public: | |||
| void bufferSizeChanged(const uint32_t newBufferSize) override | |||
| { | |||
| resizeAudioPool(newBufferSize); | |||
| resizeAudioAndCVPool(newBufferSize); | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtControl.mutex); | |||
| @@ -2126,11 +2143,13 @@ private: | |||
| CarlaString fBridgeBinary; | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeAudioPool fShmCVPool; | |||
| BridgeRtControl fShmRtControl; | |||
| BridgeNonRtControl fShmNonRtControl; | |||
| struct Info { | |||
| uint32_t aIns, aOuts; | |||
| uint32_t cvIns, cvOuts; | |||
| uint32_t mIns, mOuts; | |||
| PluginCategory category; | |||
| uint optionsAvailable; | |||
| @@ -2144,6 +2163,8 @@ private: | |||
| Info() | |||
| : aIns(0), | |||
| aOuts(0), | |||
| cvIns(0), | |||
| cvOuts(0), | |||
| mIns(0), | |||
| mOuts(0), | |||
| category(PLUGIN_CATEGORY_NONE), | |||
| @@ -2158,12 +2179,17 @@ private: | |||
| BridgeParamInfo* fParams; | |||
| void resizeAudioPool(const uint32_t bufferSize) | |||
| void resizeAudioAndCVPool(const uint32_t bufferSize) | |||
| { | |||
| fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts); | |||
| fShmCVPool.resize(bufferSize, fInfo.cvIns+fInfo.cvOuts); | |||
| fShmRtControl.writeOpcode(kPluginBridgeRtSetAudioPool); | |||
| fShmRtControl.writeLong(static_cast<int64_t>(fShmAudioPool.size)); | |||
| fShmRtControl.writeOpcode(kPluginBridgeRtSetCVPool); | |||
| fShmRtControl.writeLong(static_cast<int64_t>(fShmCVPool.size)); | |||
| fShmRtControl.commitWrite(); | |||
| waitForServer(); | |||
| @@ -2216,9 +2242,29 @@ CarlaPlugin* CarlaPlugin::newBridge(const Initializer& init, BinaryType btype, P | |||
| plugin->reload(); | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && ! plugin->canRunInRack()) | |||
| bool canRun = true; | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| if (! plugin->canRunInRack()) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Stereo Bridged plugins, sorry!"); | |||
| canRun = false; | |||
| } | |||
| else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
| canRun = false; | |||
| } | |||
| } | |||
| else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) | |||
| { | |||
| init.engine->setLastError("CV ports in patchbay mode is still TODO"); | |||
| canRun = false; | |||
| } | |||
| if (! canRun) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Stereo Bridged plugins, sorry!"); | |||
| delete plugin; | |||
| return nullptr; | |||
| } | |||
| @@ -1076,7 +1076,7 @@ public: | |||
| } | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, 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 | |||
| @@ -1085,7 +1085,9 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -1196,7 +1198,7 @@ public: | |||
| if (isSampleAccurate && event.time > timeOffset) | |||
| { | |||
| if (processSingle(inBuffer, outBuffer, event.time - timeOffset, timeOffset, midiEventCount)) | |||
| if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset, midiEventCount)) | |||
| { | |||
| startTime = 0; | |||
| timeOffset = event.time; | |||
| @@ -1507,7 +1509,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset, midiEventCount); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset, midiEventCount); | |||
| } // End of Event Input and Processing | |||
| @@ -1516,7 +1518,7 @@ public: | |||
| else | |||
| { | |||
| processSingle(inBuffer, outBuffer, frames, 0, midiEventCount); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0, midiEventCount); | |||
| } // End of Plugin processing (no events) | |||
| @@ -1535,7 +1537,7 @@ public: | |||
| if (pData->latency <= frames) | |||
| { | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], inBuffer[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], audioIn[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| } | |||
| else | |||
| { | |||
| @@ -1544,7 +1546,7 @@ public: | |||
| for (k=0; k < pData->latency-frames; ++k) | |||
| pData->latencyBuffers[i][k] = pData->latencyBuffers[i][k+frames]; | |||
| for (j=0; k < pData->latency; ++j, ++k) | |||
| pData->latencyBuffers[i][k] = inBuffer[i][j]; | |||
| pData->latencyBuffers[i][k] = audioIn[i][j]; | |||
| } | |||
| } | |||
| } | |||
| @@ -1578,17 +1580,25 @@ public: | |||
| #endif | |||
| } | |||
| bool processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset, const ulong midiEventCount) | |||
| bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames, const uint32_t timeOffset, const ulong midiEventCount) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(frames > 0, false); | |||
| if (pData->audioIn.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(inBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); | |||
| } | |||
| if (pData->audioOut.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(outBuffer != nullptr, false); | |||
| 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); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| @@ -1603,21 +1613,37 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = 0.0f; | |||
| 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; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Reset audio buffers | |||
| // Set audio buffers | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], inBuffer[i]+timeOffset, static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(fAudioOutBuffers[i], static_cast<int>(frames)); | |||
| #if 0 | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Set CV buffers | |||
| for (uint32_t i=0; i < pData->cvIn.count; ++i) | |||
| FloatVectorOperations::copy(fCvInBuffers[i], cvIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(fCvOutBuffers[i], static_cast<int>(frames)); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Run plugin | |||
| @@ -1710,7 +1736,7 @@ public: | |||
| // Volume (and buffer copy) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| } | |||
| } | |||
| @@ -1720,7 +1746,15 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| #if 0 | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| cvOut[i][k+timeOffset] = fCvOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| @@ -2310,9 +2344,29 @@ CarlaPlugin* CarlaPlugin::newDSSI(const Initializer& init) | |||
| plugin->reload(); | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && ! plugin->canRunInRack()) | |||
| bool canRun = true; | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| if (! plugin->canRunInRack()) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo DSSI plugins, sorry!"); | |||
| canRun = false; | |||
| } | |||
| else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
| canRun = false; | |||
| } | |||
| } | |||
| else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) | |||
| { | |||
| init.engine->setLastError("CV ports in patchbay mode is still TODO"); | |||
| canRun = false; | |||
| } | |||
| if (! canRun) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo DSSI plugins, sorry!"); | |||
| delete plugin; | |||
| return nullptr; | |||
| } | |||
| @@ -1002,7 +1002,7 @@ public: | |||
| // ------------------------------------------------------------------- | |||
| // Plugin processing | |||
| void process(float** const, float** const outBuffer, const uint32_t frames) override | |||
| void process(const float** const, float** const audioOut, const float** const, float** const, const uint32_t frames) override | |||
| { | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Check if active | |||
| @@ -1011,7 +1011,7 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -1093,7 +1093,7 @@ public: | |||
| if (time > timeOffset) | |||
| { | |||
| if (processSingle(outBuffer, time - timeOffset, timeOffset)) | |||
| if (processSingle(audioOut, time - timeOffset, timeOffset)) | |||
| { | |||
| timeOffset = time; | |||
| @@ -1330,7 +1330,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(outBuffer, frames - timeOffset, timeOffset); | |||
| processSingle(audioOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| @@ -568,7 +568,7 @@ public: | |||
| } catch(...) {} | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, const uint32_t frames) override | |||
| void process(const float** const audioIn, float** const audioOut, const float** const, float** const, const uint32_t frames) override | |||
| { | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Check if active | |||
| @@ -577,7 +577,7 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -877,7 +877,7 @@ public: | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Process | |||
| processSingle(inBuffer, outBuffer, frames); | |||
| processSingle(audioIn, audioOut, frames); | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // MIDI Output | |||
| @@ -946,7 +946,7 @@ public: | |||
| } | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, 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 | |||
| @@ -955,7 +955,9 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -999,7 +1001,7 @@ public: | |||
| if (isSampleAccurate && event.time > timeOffset) | |||
| { | |||
| if (processSingle(inBuffer, outBuffer, event.time - timeOffset, timeOffset)) | |||
| if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset)) | |||
| timeOffset = event.time; | |||
| } | |||
| @@ -1118,7 +1120,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| @@ -1127,7 +1129,7 @@ public: | |||
| else | |||
| { | |||
| processSingle(inBuffer, outBuffer, frames, 0); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0); | |||
| } // End of Plugin processing (no events) | |||
| @@ -1146,7 +1148,7 @@ public: | |||
| if (pData->latency <= frames) | |||
| { | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], inBuffer[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], audioIn[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| } | |||
| else | |||
| { | |||
| @@ -1155,7 +1157,7 @@ public: | |||
| for (k=0; k < pData->latency-frames; ++k) | |||
| pData->latencyBuffers[i][k] = pData->latencyBuffers[i][k+frames]; | |||
| for (j=0; k < pData->latency; ++j, ++k) | |||
| pData->latencyBuffers[i][k] = inBuffer[i][j]; | |||
| pData->latencyBuffers[i][k] = audioIn[i][j]; | |||
| } | |||
| } | |||
| } | |||
| @@ -1189,17 +1191,25 @@ public: | |||
| #endif | |||
| } | |||
| bool processSingle(float** const inBuffer, float** const outBuffer, 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) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(inBuffer != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); | |||
| } | |||
| if (pData->audioOut.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(outBuffer != nullptr, false); | |||
| 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); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| @@ -1214,21 +1224,37 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = 0.0f; | |||
| 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; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Reset audio buffers | |||
| // Set audio buffers | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], inBuffer[i]+timeOffset, static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(fAudioOutBuffers[i], static_cast<int>(frames)); | |||
| #if 0 | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Set CV buffers | |||
| for (uint32_t i=0; i < pData->cvIn.count; ++i) | |||
| FloatVectorOperations::copy(fCvInBuffers[i], cvIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(fCvOutBuffers[i], static_cast<int>(frames)); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Run plugin | |||
| @@ -1307,7 +1333,7 @@ public: | |||
| // Volume (and buffer copy) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| } | |||
| } | |||
| @@ -1317,7 +1343,15 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| #if 0 | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| cvOut[i][k+timeOffset] = fCvOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| @@ -1724,9 +1758,29 @@ CarlaPlugin* CarlaPlugin::newLADSPA(const Initializer& init, const LADSPA_RDF_De | |||
| plugin->reload(); | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && ! plugin->canRunInRack()) | |||
| bool canRun = true; | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| if (! plugin->canRunInRack()) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LADSPA plugins, sorry!"); | |||
| canRun = false; | |||
| } | |||
| else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
| canRun = false; | |||
| } | |||
| } | |||
| else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) | |||
| { | |||
| init.engine->setLastError("CV ports in patchbay mode is still TODO"); | |||
| canRun = false; | |||
| } | |||
| if (! canRun) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LADSPA plugins, sorry!"); | |||
| delete plugin; | |||
| return nullptr; | |||
| } | |||
| @@ -730,7 +730,7 @@ public: | |||
| } | |||
| #endif | |||
| void process(float** const, float** const outBuffer, const uint32_t frames) override | |||
| void process(const float** const, float** const audioOut, const float** const, float** const, const uint32_t frames) override | |||
| { | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Check if active | |||
| @@ -739,7 +739,7 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -812,7 +812,7 @@ public: | |||
| if (event.time > timeOffset && sampleAccurate) | |||
| { | |||
| if (processSingle(outBuffer, event.time - timeOffset, timeOffset)) | |||
| if (processSingle(audioOut, event.time - timeOffset, timeOffset)) | |||
| { | |||
| startTime = 0; | |||
| timeOffset = event.time; | |||
| @@ -1024,7 +1024,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(outBuffer, frames - timeOffset, timeOffset); | |||
| processSingle(audioOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| } | |||
| @@ -2450,7 +2450,7 @@ public: | |||
| } | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, 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 | |||
| @@ -2459,7 +2459,9 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -2726,24 +2728,6 @@ public: | |||
| carla_copyStruct<EngineTimeInfo>(fLastTimeInfo, timeInfo); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // CV ports | |||
| float* cvInBuf[pData->cvIn.count /*> 0 ? pData->cvIn.count : 1*/]; | |||
| float* cvOutBuf[pData->cvOut.count /*> 0 ? pData->cvOut.count : 1*/]; | |||
| for (uint32_t i=0; i < pData->cvIn.count; ++i) | |||
| { | |||
| CARLA_SAFE_ASSERT_CONTINUE(pData->cvIn.ports[i].port != nullptr); | |||
| cvInBuf[i] = pData->cvIn.ports[i].port->getBuffer(); | |||
| } | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| { | |||
| CARLA_SAFE_ASSERT_CONTINUE(pData->cvOut.ports[i].port != nullptr); | |||
| cvOutBuf[i] = pData->cvOut.ports[i].port->getBuffer(); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Event Input and Processing | |||
| @@ -2850,7 +2834,7 @@ public: | |||
| if (isSampleAccurate && event.time > timeOffset) | |||
| { | |||
| if (processSingle(inBuffer, outBuffer, cvInBuf, cvOutBuf, event.time - timeOffset, timeOffset)) | |||
| if (processSingle(audioIn, audioOut, cvIn, cvOut, event.time - timeOffset, timeOffset)) | |||
| { | |||
| startTime = 0; | |||
| timeOffset = event.time; | |||
| @@ -3127,7 +3111,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(inBuffer, outBuffer, cvInBuf, cvOutBuf, frames - timeOffset, timeOffset); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| @@ -3136,7 +3120,7 @@ public: | |||
| else | |||
| { | |||
| processSingle(inBuffer, outBuffer, cvInBuf, cvOutBuf, frames, 0); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0); | |||
| } // End of Plugin processing (no events) | |||
| @@ -3155,7 +3139,7 @@ public: | |||
| if (pData->latency <= frames) | |||
| { | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], inBuffer[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| FloatVectorOperations::copy(pData->latencyBuffers[i], audioIn[i]+(frames-pData->latency), static_cast<int>(pData->latency)); | |||
| } | |||
| else | |||
| { | |||
| @@ -3164,7 +3148,7 @@ public: | |||
| for (k=0; k < pData->latency-frames; ++k) | |||
| pData->latencyBuffers[i][k] = pData->latencyBuffers[i][k+frames]; | |||
| for (j=0; k < pData->latency; ++j, ++k) | |||
| pData->latencyBuffers[i][k] = inBuffer[i][j]; | |||
| pData->latencyBuffers[i][k] = audioIn[i][j]; | |||
| } | |||
| } | |||
| } | |||
| @@ -3306,25 +3290,25 @@ public: | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| } | |||
| bool processSingle(float** const audioInBuf, float** const audioOutBuf, float** const cvInBuf, float** const cvOutBuf, 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) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(audioInBuf != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); | |||
| } | |||
| if (pData->audioOut.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(audioOutBuf != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false); | |||
| } | |||
| if (pData->cvIn.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(cvInBuf != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(cvIn != nullptr, false); | |||
| } | |||
| if (pData->cvOut.count > 0) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(cvOutBuf != nullptr, false); | |||
| CARLA_SAFE_ASSERT_RETURN(cvOut != nullptr, false); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| @@ -3339,7 +3323,12 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| audioOutBuf[i][k+timeOffset] = 0.0f; | |||
| 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; | |||
| @@ -3349,7 +3338,7 @@ public: | |||
| // Set audio buffers | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], audioInBuf[i]+timeOffset, static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(fAudioOutBuffers[i], static_cast<int>(frames)); | |||
| @@ -3358,7 +3347,7 @@ public: | |||
| // Set CV buffers | |||
| for (uint32_t i=0; i < pData->cvIn.count; ++i) | |||
| FloatVectorOperations::copy(fCvInBuffers[i], cvInBuf[i]+timeOffset, static_cast<int>(frames)); | |||
| FloatVectorOperations::copy(fCvInBuffers[i], cvIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(fCvOutBuffers[i], static_cast<int>(frames)); | |||
| @@ -3455,7 +3444,7 @@ public: | |||
| // Volume (and buffer copy) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| audioOutBuf[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| } | |||
| } | |||
| } // End of Post-processing | |||
| @@ -3464,10 +3453,16 @@ public: | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| audioOutBuf[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| cvOut[i][k+timeOffset] = fCvOutBuffers[i][k]; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| pData->singleMutex.unlock(); | |||
| @@ -5888,9 +5883,29 @@ CarlaPlugin* CarlaPlugin::newLV2(const Initializer& init) | |||
| plugin->reload(); | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && ! plugin->canRunInRack()) | |||
| bool canRun = true; | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| if (! plugin->canRunInRack()) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LV2 plugins, sorry!"); | |||
| canRun = false; | |||
| } | |||
| else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
| canRun = false; | |||
| } | |||
| } | |||
| else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) | |||
| { | |||
| init.engine->setLastError("CV ports in patchbay mode is still TODO"); | |||
| canRun = false; | |||
| } | |||
| if (! canRun) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo LV2 plugins, sorry!"); | |||
| delete plugin; | |||
| return nullptr; | |||
| } | |||
| @@ -1277,7 +1277,7 @@ public: | |||
| } | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, 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 | |||
| @@ -1286,8 +1286,9 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(cvOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -1419,7 +1420,7 @@ public: | |||
| if (time > timeOffset && sampleAccurate) | |||
| { | |||
| if (processSingle(inBuffer, outBuffer, time - timeOffset, timeOffset)) | |||
| if (processSingle(audioIn, audioOut, cvIn, cvOut, time - timeOffset, timeOffset)) | |||
| { | |||
| startTime = 0; | |||
| timeOffset = time; | |||
| @@ -1670,7 +1671,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| @@ -1679,7 +1680,7 @@ public: | |||
| else | |||
| { | |||
| processSingle(inBuffer, outBuffer, frames, 0); | |||
| processSingle(audioIn, audioOut, cvIn, cvOut, frames, 0); | |||
| } // End of Plugin processing (no events) | |||
| @@ -1725,27 +1726,26 @@ public: | |||
| } // End of Control and MIDI Output | |||
| } | |||
| bool processSingle(float** const inBuffer, float** const outBuffer, 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_ASSERT(frames > 0); | |||
| if (frames == 0) | |||
| return false; | |||
| CARLA_SAFE_ASSERT_RETURN(frames > 0, false); | |||
| if (pData->audioIn.count > 0) | |||
| { | |||
| CARLA_ASSERT(inBuffer != nullptr); | |||
| if (inBuffer == nullptr) | |||
| return false; | |||
| CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false); | |||
| } | |||
| if (pData->audioOut.count > 0) | |||
| { | |||
| CARLA_ASSERT(outBuffer != nullptr); | |||
| if (outBuffer == nullptr) | |||
| return false; | |||
| 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); | |||
| } | |||
| uint32_t i, k; | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Try lock, silence otherwise | |||
| @@ -1756,24 +1756,40 @@ public: | |||
| } | |||
| else if (! pData->singleMutex.tryLock()) | |||
| { | |||
| for (i=0; i < pData->audioOut.count; ++i) | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = 0.0f; | |||
| 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; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Reset audio buffers | |||
| // Set audio buffers | |||
| for (i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], inBuffer[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| FloatVectorOperations::copy(fAudioInBuffers[i], audioIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (i=0; i < pData->audioOut.count; ++i) | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(fAudioOutBuffers[i], static_cast<int>(frames)); | |||
| #if 0 | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Set CV buffers | |||
| for (uint32_t i=0; i < pData->cvIn.count; ++i) | |||
| FloatVectorOperations::copy(fCvInBuffers[i], cvIn[i]+timeOffset, static_cast<int>(frames)); | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| FloatVectorOperations::clear(fCvOutBuffers[i], static_cast<int>(frames)); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Run plugin | |||
| @@ -1810,12 +1826,12 @@ public: | |||
| bool isPair; | |||
| float bufValue, oldBufLeft[doBalance ? frames : 1]; | |||
| for (i=0; i < pData->audioOut.count; ++i) | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| // Dry/Wet | |||
| if (doDryWet) | |||
| { | |||
| for (k=0; k < frames; ++k) | |||
| 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)); | |||
| @@ -1836,7 +1852,7 @@ public: | |||
| float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f; | |||
| float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f; | |||
| for (k=0; k < frames; ++k) | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| { | |||
| if (isPair) | |||
| { | |||
| @@ -1855,17 +1871,25 @@ public: | |||
| // Volume (and buffer copy) | |||
| { | |||
| for (k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume; | |||
| } | |||
| } | |||
| } // End of Post-processing | |||
| #else | |||
| for (i=0; i < pData->audioOut.count; ++i) | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| { | |||
| for (k=0; k < frames; ++k) | |||
| outBuffer[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| #if 0 | |||
| for (uint32_t i=0; i < pData->cvOut.count; ++i) | |||
| { | |||
| for (uint32_t k=0; k < frames; ++k) | |||
| cvOut[i][k+timeOffset] = fCvOutBuffers[i][k]; | |||
| } | |||
| #endif | |||
| @@ -2434,9 +2458,29 @@ CarlaPlugin* CarlaPlugin::newNative(const Initializer& init) | |||
| plugin->reload(); | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && ! plugin->canRunInRack()) | |||
| bool canRun = true; | |||
| if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| if (! plugin->canRunInRack()) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo Internal plugins, sorry!"); | |||
| canRun = false; | |||
| } | |||
| else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
| canRun = false; | |||
| } | |||
| } | |||
| else if (init.engine->getProccessMode() == ENGINE_PROCESS_MODE_PATCHBAY && (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0)) | |||
| { | |||
| init.engine->setLastError("CV ports in patchbay mode is still TODO"); | |||
| canRun = false; | |||
| } | |||
| if (! canRun) | |||
| { | |||
| init.engine->setLastError("Carla's rack mode can only work with Mono or Stereo Internal plugins, sorry!"); | |||
| delete plugin; | |||
| return nullptr; | |||
| } | |||
| @@ -1052,7 +1052,7 @@ public: | |||
| } catch(...) {} | |||
| } | |||
| void process(float** const inBuffer, float** const outBuffer, const uint32_t frames) override | |||
| void process(const float** const audioIn, float** const audioOut, const float** const, float** const, const uint32_t frames) override | |||
| { | |||
| fProcThread = pthread_self(); | |||
| @@ -1063,7 +1063,7 @@ public: | |||
| { | |||
| // disable any output sound | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| FloatVectorOperations::clear(outBuffer[i], static_cast<int>(frames)); | |||
| FloatVectorOperations::clear(audioOut[i], static_cast<int>(frames)); | |||
| return; | |||
| } | |||
| @@ -1228,7 +1228,7 @@ public: | |||
| if (isSampleAccurate && event.time > timeOffset) | |||
| { | |||
| if (processSingle(inBuffer, outBuffer, event.time - timeOffset, timeOffset)) | |||
| if (processSingle(audioIn, audioOut, event.time - timeOffset, timeOffset)) | |||
| { | |||
| startTime = 0; | |||
| timeOffset = event.time; | |||
| @@ -1472,7 +1472,7 @@ public: | |||
| pData->postRtEvents.trySplice(); | |||
| if (frames > timeOffset) | |||
| processSingle(inBuffer, outBuffer, frames - timeOffset, timeOffset); | |||
| processSingle(audioIn, audioOut, frames - timeOffset, timeOffset); | |||
| } // End of Event Input and Processing | |||
| @@ -1481,7 +1481,7 @@ public: | |||
| else | |||
| { | |||
| processSingle(inBuffer, outBuffer, frames, 0); | |||
| processSingle(audioIn, audioOut, frames, 0); | |||
| } // End of Plugin processing (no events) | |||
| @@ -1513,7 +1513,7 @@ public: | |||
| } // End of MIDI Output | |||
| } | |||
| bool processSingle(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) | |||
| bool processSingle(const float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(frames > 0, false); | |||
| @@ -1551,7 +1551,7 @@ public: | |||
| float* vstOutBuffer[pData->audioOut.count]; | |||
| for (uint32_t i=0; i < pData->audioIn.count; ++i) | |||
| vstInBuffer[i] = inBuffer[i]+timeOffset; | |||
| vstInBuffer[i] = const_cast<float*>(inBuffer[i]+timeOffset); | |||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | |||
| vstOutBuffer[i] = outBuffer[i]+timeOffset; | |||
| @@ -55,6 +55,7 @@ enum PluginBridgeOscInfoType { | |||
| enum PluginBridgeRtOpcode { | |||
| kPluginBridgeRtNull = 0, | |||
| kPluginBridgeRtSetAudioPool, // ulong/ptr | |||
| kPluginBridgeRtSetCVPool, // ulong/ptr | |||
| kPluginBridgeRtControlEventParameter, // uint/frame, byte/chan, ushort, float | |||
| kPluginBridgeRtControlEventMidiBank, // uint/frame, byte/chan, ushort | |||
| kPluginBridgeRtControlEventMidiProgram, // uint/frame, byte/chan, ushort | |||
| @@ -208,6 +209,8 @@ const char* PluginBridgeRtOpcode2str(const PluginBridgeRtOpcode opcode) noexcept | |||
| return "kPluginBridgeRtNull"; | |||
| case kPluginBridgeRtSetAudioPool: | |||
| return "kPluginBridgeRtSetAudioPool"; | |||
| case kPluginBridgeRtSetCVPool: | |||
| return "kPluginBridgeRtSetCVPool"; | |||
| case kPluginBridgeRtControlEventParameter: | |||
| return "kPluginBridgeRtControlEventParameter"; | |||
| case kPluginBridgeRtControlEventMidiBank: | |||