diff --git a/resources/ui/carla_settings_driver.ui b/resources/ui/carla_settings_driver.ui index 784d9c111..37b5d410c 100644 --- a/resources/ui/carla_settings_driver.ui +++ b/resources/ui/carla_settings_driver.ui @@ -37,7 +37,7 @@ - 1 + 40 1 @@ -61,6 +61,9 @@ Qt::Horizontal + + QSizePolicy::Fixed + 40 @@ -94,10 +97,13 @@ Qt::Horizontal + + QSizePolicy::Fixed + 40 - 20 + 1 diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 143bf8ad6..6b7064859 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -837,8 +837,16 @@ public: */ virtual void clearXruns() const noexcept; + /*! + * Dynamically change buffer size and/or sample rate while engine is running. + * @see ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE + * @see ENGINE_DRIVER_DEVICE_VARIABLE_SAMPLE_RATE + */ + virtual bool setBufferSizeAndSampleRate(const uint bufferSize, const double sampleRate); + /*! * Show the custom control panel for the current engine device. + * @see ENGINE_DRIVER_DEVICE_HAS_CONTROL_PANEL */ virtual bool showDeviceControlPanel() const noexcept; diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index fd6cb52c3..85430e9df 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -427,8 +427,16 @@ CARLA_EXPORT const CarlaRuntimeEngineInfo* carla_get_runtime_engine_info(); */ CARLA_EXPORT const CarlaRuntimeEngineDriverDeviceInfo* carla_get_runtime_engine_driver_device_info(); +/*! + * Dynamically change buffer size and/or sample rate while engine is running. + * @see ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE + * @see ENGINE_DRIVER_DEVICE_VARIABLE_SAMPLE_RATE + */ +CARLA_EXPORT bool carla_set_engine_buffer_size_and_sample_rate(uint bufferSize, double sampleRate); + /*! * Show the custom control panel for the current engine device. + * @see ENGINE_DRIVER_DEVICE_HAS_CONTROL_PANEL */ CARLA_EXPORT bool carla_show_engine_device_control_panel(); diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index 4ee276e5b..a2ea3d409 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -541,6 +541,14 @@ const CarlaRuntimeEngineDriverDeviceInfo* carla_get_runtime_engine_driver_device return &retInfo; } +bool carla_set_engine_buffer_size_and_sample_rate(uint bufferSize, double sampleRate) +{ + CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, false); + carla_debug("carla_set_engine_buffer_size_and_sample_rate(%u, %f)", bufferSize, sampleRate); + + return gStandalone.engine->setBufferSizeAndSampleRate(bufferSize, sampleRate); +} + bool carla_show_engine_device_control_panel() { CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, false); diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 79efa21f0..7c05310e0 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -410,6 +410,11 @@ bool CarlaEngine::showDeviceControlPanel() const noexcept return false; } +bool CarlaEngine::setBufferSizeAndSampleRate(const uint, const double) +{ + return false; +} + // ----------------------------------------------------------------------- // Plugin management diff --git a/source/backend/engine/CarlaEngineJack.cpp b/source/backend/engine/CarlaEngineJack.cpp index f63decb02..a3fb81c37 100644 --- a/source/backend/engine/CarlaEngineJack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -1191,6 +1191,16 @@ public: } #endif + bool setBufferSizeAndSampleRate(const uint bufferSize, const double sampleRate) override + { + CARLA_SAFE_ASSERT_RETURN(carla_isEqual(pData->sampleRate, sampleRate), false); + CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false); + + try { + return jackbridge_set_buffer_size(fClient, bufferSize); + } CARLA_SAFE_EXCEPTION_RETURN("setBufferSizeAndSampleRate", false); + } + EngineTimeInfo getTimeInfo() const noexcept override { if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) diff --git a/source/backend/engine/CarlaEngineJuce.cpp b/source/backend/engine/CarlaEngineJuce.cpp index 5299afcb2..17c35ec21 100644 --- a/source/backend/engine/CarlaEngineJuce.cpp +++ b/source/backend/engine/CarlaEngineJuce.cpp @@ -352,6 +352,69 @@ public: pData->xruns = xruns > 0 ? static_cast(xruns) : 0; } + bool setBufferSizeAndSampleRate(const uint bufferSize, const double sampleRate) override + { + CARLA_SAFE_ASSERT_RETURN(fDevice != nullptr, false); + + juce::StringArray inputNames(fDevice->getInputChannelNames()); + juce::StringArray outputNames(fDevice->getOutputChannelNames()); + + if (inputNames.size() < 0 || outputNames.size() <= 0) + { + setLastError("Selected device does not have any outputs"); + return false; + } + + juce::BigInteger inputChannels; + inputChannels.setRange(0, inputNames.size(), true); + + juce::BigInteger outputChannels; + outputChannels.setRange(0, outputNames.size(), true); + + // stop stream first + if (fDevice->isPlaying()) + fDevice->stop(); + if (fDevice->isOpen()) + fDevice->close(); + + juce::String error = fDevice->open(inputChannels, outputChannels, sampleRate, static_cast(bufferSize)); + + if (error.isNotEmpty()) + { + setLastError(error.toUTF8()); + + // try to roll back + error = fDevice->open(inputChannels, outputChannels, pData->sampleRate, static_cast(pData->bufferSize)); + + // if we failed, we are screwed... + if (error.isNotEmpty()) + { + fDevice = nullptr; + close(); + } + + return false; + } + + const uint32_t newBufferSize = static_cast(fDevice->getCurrentBufferSizeSamples()); + const double newSampleRate = fDevice->getCurrentSampleRate(); + + if (carla_isNotEqual(pData->sampleRate, newSampleRate)) + { + pData->sampleRate = newSampleRate; + sampleRateChanged(newSampleRate); + } + + if (pData->bufferSize != newBufferSize) + { + pData->bufferSize = newBufferSize; + bufferSizeChanged(newBufferSize); + } + + fDevice->start(this); + return true; + } + bool showDeviceControlPanel() const noexcept override { try { diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 6bd1c766d..f84c8047a 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -2738,6 +2738,7 @@ uint CarlaEngine::getJuceApiCount() { return 0; const char* CarlaEngine::getJuceApiName(const uint) { return nullptr; } const char* const* CarlaEngine::getJuceApiDeviceNames(const uint) { return nullptr; } const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const uint, const char* const) { return nullptr; } +bool CarlaEngine::showJuceDeviceControlPanel(const uint, const char* const) { return false; } # else CarlaEngine* CarlaEngine::newRtAudio(const AudioApi) { return nullptr; } uint CarlaEngine::getRtAudioApiCount() { return 0; } diff --git a/source/frontend/carla_backend.py b/source/frontend/carla_backend.py index 8ff16d45b..cb1ac2eb4 100644 --- a/source/frontend/carla_backend.py +++ b/source/frontend/carla_backend.py @@ -1508,7 +1508,14 @@ class CarlaHostMeta(object): def get_runtime_engine_driver_device_info(self): raise NotImplementedError + # Dynamically change buffer size and/or sample rate while engine is running. + # @see ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE + # @see ENGINE_DRIVER_DEVICE_VARIABLE_SAMPLE_RATE + def set_engine_buffer_size_and_sample_rate(self, bufferSize, sampleRate): + raise NotImplementedError + # Show the custom control panel for the current engine device. + # @see ENGINE_DRIVER_DEVICE_HAS_CONTROL_PANEL def show_engine_device_control_panel(self): raise NotImplementedError @@ -2168,6 +2175,9 @@ class CarlaHostNull(CarlaHostMeta): def get_runtime_engine_driver_device_info(self): return PyCarlaRuntimeEngineDriverDeviceInfo + def set_engine_buffer_size_and_sample_rate(self, bufferSize, sampleRate): + return False + def show_engine_device_control_panel(self): return False @@ -2477,6 +2487,9 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_get_runtime_engine_driver_device_info.argtypes = None self.lib.carla_get_runtime_engine_driver_device_info.restype = POINTER(CarlaRuntimeEngineDriverDeviceInfo) + self.lib.carla_set_engine_buffer_size_and_sample_rate.argtypes = [c_uint, c_double] + self.lib.carla_set_engine_buffer_size_and_sample_rate.restype = c_bool + self.lib.carla_show_engine_device_control_panel.argtypes = None self.lib.carla_show_engine_device_control_panel.restype = c_bool @@ -2776,6 +2789,9 @@ class CarlaHostDLL(CarlaHostMeta): def get_runtime_engine_driver_device_info(self): return structToDict(self.lib.carla_get_runtime_engine_driver_device_info().contents) + def set_engine_buffer_size_and_sample_rate(self, bufferSize, sampleRate): + return bool(self.lib.carla_set_engine_buffer_size_and_sample_rate(bufferSize, sampleRate)) + def show_engine_device_control_panel(self): return bool(self.lib.carla_show_engine_device_control_panel()) @@ -3166,6 +3182,9 @@ class CarlaHostPlugin(CarlaHostMeta): def get_runtime_engine_driver_device_info(self): return PyCarlaRuntimeEngineDriverDeviceInfo + def set_engine_buffer_size_and_sample_rate(self, bufferSize, sampleRate): + return False + def show_engine_device_control_panel(self): return False diff --git a/source/frontend/carla_host.py b/source/frontend/carla_host.py index ccf1df6d5..236b2d456 100644 --- a/source/frontend/carla_host.py +++ b/source/frontend/carla_host.py @@ -877,6 +877,9 @@ class HostWindow(QMainWindow): QMessageBox.warning(self, self.tr("Warning"), self.tr("Engine was stopped while configuring settings, all changes have been ignored")) return + bufferSize, sampleRate = dialog.getValues() + self.host.set_engine_buffer_size_and_sample_rate(bufferSize, sampleRate) + @pyqtSlot() def slot_engineStopTryAgain(self): if self.host.is_engine_running() and not self.host.set_engine_about_to_close(): diff --git a/source/frontend/carla_settings.py b/source/frontend/carla_settings.py index f48c4831c..af8738186 100755 --- a/source/frontend/carla_settings.py +++ b/source/frontend/carla_settings.py @@ -281,9 +281,9 @@ class RuntimeDriverSettingsW(QDialog): bufferSize = self.ui.cb_buffersize.currentText() sampleRate = self.ui.cb_samplerate.currentText() - if bufferSize == self.AUTOMATIC_OPTION: + if bufferSize == DriverSettingsW.AUTOMATIC_OPTION: bufferSize = "0" - if sampleRate == self.AUTOMATIC_OPTION: + if sampleRate == DriverSettingsW.AUTOMATIC_OPTION: sampleRate = "0" return (int(bufferSize), int(sampleRate))