diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index 69782a9ab..c8ebd4b19 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -706,8 +706,9 @@ public: step = 1.0f; stepSmall = 1.0f; stepLarge = 1.0f; - fLatencyIndex = static_cast(j); pData->param.special[j] = PARAMETER_SPECIAL_LATENCY; + CARLA_SAFE_ASSERT(fLatencyIndex == -1); + fLatencyIndex = static_cast(j); } else { diff --git a/source/backend/plugin/LadspaPlugin.cpp b/source/backend/plugin/LadspaPlugin.cpp index a1a4bf387..d6d9e51bd 100644 --- a/source/backend/plugin/LadspaPlugin.cpp +++ b/source/backend/plugin/LadspaPlugin.cpp @@ -679,8 +679,9 @@ public: step = 1.0f; stepSmall = 1.0f; stepLarge = 1.0f; - fLatencyIndex = static_cast(j); pData->param.special[j] = PARAMETER_SPECIAL_LATENCY; + CARLA_SAFE_ASSERT(fLatencyIndex == -1); + fLatencyIndex = static_cast(j); } else { diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index 9ef58d3d6..81d7afb52 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -398,6 +398,7 @@ public: fCvInBuffers(nullptr), fCvOutBuffers(nullptr), fParamBuffers(nullptr), + fLatencyIndex(-1), fFirstActive(true) { carla_debug("Lv2Plugin::Lv2Plugin(%p, %i)", engine, id); @@ -693,7 +694,7 @@ public: options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; - if (! (hasMidiIn || needsFixedBuffer())) + if (fLatencyIndex == -1 && ! (hasMidiIn || needsFixedBuffer())) options |= PLUGIN_OPTION_FIXED_BUFFERS; if (pData->engine->getProccessMode() != ENGINE_PROCESS_MODE_CONTINUOUS_RACK) @@ -1984,6 +1985,8 @@ public: stepSmall = 1.0f; stepLarge = 1.0f; pData->param.special[j] = PARAMETER_SPECIAL_LATENCY; + CARLA_SAFE_ASSERT(fLatencyIndex == -1); + fLatencyIndex = static_cast(j); } else if (LV2_IS_PORT_DESIGNATION_SAMPLE_RATE(portDesignation)) { @@ -2150,12 +2153,76 @@ public: pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; } + // check latency + if (fLatencyIndex >= 0) + { + // we need to pre-run the plugin so it can update its latency control-port + + float tmpIn[aIns][2]; + float tmpOut[aOuts][2]; + + for (uint32_t j=0; j < aIns; ++j) + { + tmpIn[j][0] = 0.0f; + tmpIn[j][1] = 0.0f; + + try { + fDescriptor->connect_port(fHandle, pData->audioIn.ports[j].rindex, tmpIn[j]); + } CARLA_SAFE_EXCEPTION("LV2 connect_port latency input"); + } + + for (uint32_t j=0; j < aOuts; ++j) + { + tmpOut[j][0] = 0.0f; + tmpOut[j][1] = 0.0f; + + try { + fDescriptor->connect_port(fHandle, pData->audioOut.ports[j].rindex, tmpOut[j]); + } CARLA_SAFE_EXCEPTION("LV2 connect_port latency output"); + } + + if (fDescriptor->activate != nullptr) + { + try { + fDescriptor->activate(fHandle); + } CARLA_SAFE_EXCEPTION("LV2 latency activate"); + } + + try { + fDescriptor->run(fHandle, 2); + } CARLA_SAFE_EXCEPTION("LV2 latency run"); + + if (fDescriptor->deactivate != nullptr) + { + try { + fDescriptor->deactivate(fHandle); + } CARLA_SAFE_EXCEPTION("LV2 latency deactivate"); + } + + const int32_t latency(static_cast(fParamBuffers[fLatencyIndex])); + + if (latency >= 0) + { + const uint32_t ulatency(static_cast(latency)); + + if (pData->latency != ulatency) + { + carla_stdout("latency = %i", latency); + + pData->latency = ulatency; + pData->client->setLatency(ulatency); +#ifndef BUILD_BRIDGE + pData->recreateLatencyBuffers(); +#endif + } + } + else + carla_safe_assert_int("latency >= 0", __FILE__, __LINE__, latency); + } + bufferSizeChanged(pData->engine->getBufferSize()); reloadPrograms(true); - // check latency - // TODO - evIns.clear(); evOuts.clear(); @@ -2167,7 +2234,7 @@ public: void reloadPrograms(const bool doInit) override { - carla_debug("DssiPlugin::reloadPrograms(%s)", bool2str(doInit)); + carla_debug("Lv2Plugin::reloadPrograms(%s)", bool2str(doInit)); const uint32_t oldCount = pData->midiprog.count; const int32_t current = pData->midiprog.current; @@ -2298,17 +2365,40 @@ public: { try { fDescriptor->activate(fHandle); - } catch(...) {} + } CARLA_SAFE_EXCEPTION("LV2 activate"); if (fHandle2 != nullptr) { try { fDescriptor->activate(fHandle2); - } catch(...) {} + } CARLA_SAFE_EXCEPTION("LV2 activate #2"); } } fFirstActive = true; + + if (fLatencyIndex < 0) + return; + + const int32_t latency(static_cast(fParamBuffers[fLatencyIndex])); + CARLA_SAFE_ASSERT_RETURN(latency >= 0,); + + const uint32_t ulatency(static_cast(latency)); + + if (pData->latency != ulatency) + { + carla_stdout("latency changed to %i", latency); + + pData->latency = ulatency; + pData->client->setLatency(ulatency); +#ifndef BUILD_BRIDGE + try { + pData->recreateLatencyBuffers(); // FIXME + } CARLA_SAFE_EXCEPTION("LADSPA recreateLatencyBuffers()"); +#endif + } + else + carla_stdout("latency still the same %i", latency); } void deactivate() noexcept override @@ -2320,13 +2410,13 @@ public: { try { fDescriptor->deactivate(fHandle); - } catch(...) {} + } CARLA_SAFE_EXCEPTION("LV2 deactivate"); if (fHandle2 != nullptr) { try { fDescriptor->deactivate(fHandle2); - } catch(...) {} + } CARLA_SAFE_EXCEPTION("LV2 deactivate #2"); } } } @@ -3022,7 +3112,27 @@ public: } // End of Plugin processing (no events) - CARLA_PROCESS_CONTINUE_CHECK; + // -------------------------------------------------------------------------------------------------------- + // Latency, save values for next callback + + if (pData->latency > 0) + { + if (pData->latency <= frames) + { + for (uint32_t i=0; i < pData->audioIn.count; ++i) + FLOAT_COPY(pData->latencyBuffers[i], inBuffer[i]+(frames-pData->latency), pData->latency); + } + else + { + for (uint32_t i=0, j, k; i < pData->audioIn.count; ++i) + { + 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]; + } + } + } // -------------------------------------------------------------------------------------------------------- // MIDI Output @@ -3141,8 +3251,6 @@ public: } } // End of Control Output - CARLA_PROCESS_CONTINUE_CHECK; - // -------------------------------------------------------------------------------------------------------- // Final work @@ -3251,6 +3359,7 @@ public: { const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && pData->postProc.dryWet != 1.0f; const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && (pData->postProc.balanceLeft != -1.0f || pData->postProc.balanceRight != 1.0f); + const bool isMono = (pData->audioIn.count == 1); bool isPair; float bufValue, oldBufLeft[doBalance ? frames : 1]; @@ -3262,11 +3371,12 @@ public: { for (uint32_t k=0; k < frames; ++k) { - // TODO - //if (k < pData->latency && pData->latency < frames) - // bufValue = (pData->audioIn.count == 1) ? pData->latencyBuffers[0][k] : pData->latencyBuffers[i][k]; - //else - // bufValue = (pData->audioIn.count == 1) ? inBuffer[0][k-m_latency] : inBuffer[i][k-m_latency]; + if (k < pData->latency) + bufValue = pData->latencyBuffers[isMono ? 0 : i][k]; + else if (pData->latency < frames) + bufValue = fAudioInBuffers[isMono ? 0 : i][k-pData->latency]; + else + bufValue = fAudioInBuffers[isMono ? 0 : i][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)); @@ -3311,6 +3421,7 @@ public: } } } // End of Post-processing + #else // BUILD_BRIDGE for (uint32_t i=0; i < pData->audioOut.count; ++i) { @@ -3620,7 +3731,7 @@ public: { if (pData->osc.data.target != nullptr) { - uint8_t midiData[4] = { 0 }; + uint8_t midiData[4] = { 0, 0, 0, 0 }; midiData[1] = static_cast(MIDI_STATUS_NOTE_ON + channel); midiData[2] = note; midiData[3] = velo; @@ -3654,7 +3765,7 @@ public: { if (pData->osc.data.target != nullptr) { - uint8_t midiData[4] = { 0 }; + uint8_t midiData[4] = { 0, 0, 0, 0 }; midiData[1] = static_cast(MIDI_STATUS_NOTE_OFF + channel); midiData[2] = note; osc_send_midi(pData->osc.data, midiData); @@ -3814,6 +3925,9 @@ public: fExt.state = nullptr; fExt.worker = nullptr; + if (fRdfDescriptor->ExtensionCount == 0 || fDescriptor->extension_data == nullptr) + return; + for (uint32_t i=0; i < fRdfDescriptor->ExtensionCount; ++i) { CARLA_SAFE_ASSERT_CONTINUE(fRdfDescriptor->Extensions[i] != nullptr); @@ -4620,7 +4734,7 @@ public: pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; - if (getMidiInCount() > 0 || needsFixedBuffer()) + if (fLatencyIndex >= 0 || getMidiInCount() > 0 || needsFixedBuffer()) pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; if (pData->engine->getOptions().forceStereo) @@ -4644,7 +4758,7 @@ public: pData->options = pData->loadSettings(pData->options, getOptionsAvailable()); // ignore settings, we need this anyway - if (getMidiInCount() > 0 || needsFixedBuffer()) + if (fLatencyIndex >= 0 || getMidiInCount() > 0 || needsFixedBuffer()) pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; #endif } @@ -5094,6 +5208,7 @@ private: float** fCvInBuffers; float** fCvOutBuffers; float* fParamBuffers; + int32_t fLatencyIndex; // -1 if invalid Lv2AtomQueue fAtomQueueIn; Lv2AtomQueue fAtomQueueOut; diff --git a/source/carla_style.py b/source/carla_style.py index f2ef54e14..5f7ee2d9f 100644 --- a/source/carla_style.py +++ b/source/carla_style.py @@ -71,18 +71,21 @@ class CarlaApplication(object): self._createApp(appName) return - # set initial Qt stuff - #customFont = QFont("DejaVu Sans [Book]") - #customFont.setBold(False) - #customFont.setItalic(False) - #customFont.setOverline(False) - #customFont.setKerning(True) - #customFont.setHintingPreference(QFont.PreferFullHinting) # TODO - 4.8 only - #customFont.setPixelSize(14) - #customFont.setWeight(QFont.Normal) - - #QApplication.setDesktopSettingsAware(False) - #QApplication.setFont(customFont) + if config_UseQt5: + # set initial Qt stuff + customFont = QFont("DejaVu Sans [Book]") + customFont.setBold(False) + customFont.setItalic(False) + customFont.setOverline(False) + customFont.setKerning(True) + customFont.setHintingPreference(QFont.PreferFullHinting) # TODO - 4.8 only + customFont.setPixelSize(12) + customFont.setWeight(QFont.Normal) + + QApplication.setDesktopSettingsAware(False) + QApplication.setFont(customFont) + + # set style QApplication.setStyle("carla") # create app