diff --git a/src/engine/bufferscalers/enginebufferscalerubberband.cpp b/src/engine/bufferscalers/enginebufferscalerubberband.cpp index fc84498a937..dc84f2a1f54 100644 --- a/src/engine/bufferscalers/enginebufferscalerubberband.cpp +++ b/src/engine/bufferscalers/enginebufferscalerubberband.cpp @@ -97,7 +97,6 @@ void EngineBufferScaleRubberBand::onSignalChanged() { // TODO: Resetting the sample rate will cause internal // memory allocations that may block the real-time thread. // When is this function actually invoked?? - m_rubberBand.clear(); if (!getOutputSignal().isValid()) { return; } diff --git a/src/preferences/dialog/dlgprefsound.cpp b/src/preferences/dialog/dlgprefsound.cpp index eaf86a07d14..b785fb11583 100644 --- a/src/preferences/dialog/dlgprefsound.cpp +++ b/src/preferences/dialog/dlgprefsound.cpp @@ -334,6 +334,14 @@ void DlgPrefSound::slotApply() { ScopedWaitCursor cursor; const auto keylockEngine = keylockComboBox->currentData().value(); + + // Temporary set an empty config to force the audio thread to stop and + // stay off while we are swapping the keylock settings. This is + // necessary because the audio thread doesn't have any synchronisation + // mechanism due to its realtime nature and editing the RubberBand + // config while it is running leads to race conditions. + m_pSoundManager->closeActiveConfig(); + m_pKeylockEngine.set(static_cast(keylockEngine)); m_pSettings->set(kKeylockEngingeCfgkey, ConfigValue(static_cast(keylockEngine))); diff --git a/src/soundio/soundmanager.cpp b/src/soundio/soundmanager.cpp index 8e2b5cdf30a..572133020a4 100644 --- a/src/soundio/soundmanager.cpp +++ b/src/soundio/soundmanager.cpp @@ -553,22 +553,20 @@ SoundManagerConfig SoundManager::getConfig() const { return m_config; } -SoundDeviceStatus SoundManager::setConfig(const SoundManagerConfig& config) { - SoundDeviceStatus status = SoundDeviceStatus::Ok; - m_config = config; - checkConfig(); - +void SoundManager::closeActiveConfig() { // Close open devices. After this call we will not get any more // onDeviceOutputCallback() or pushBuffer() calls because all the // SoundDevices are closed. closeDevices() blocks and can take a while. const bool sleepAfterClosing = true; closeDevices(sleepAfterClosing); +} + +SoundDeviceStatus SoundManager::setConfig(const SoundManagerConfig& config) { + SoundDeviceStatus status = SoundDeviceStatus::Ok; + m_config = config; + checkConfig(); - // certain parts of mixxx rely on this being here, for the time being, just - // letting those be -- bkgood - // Do this first so vinyl control gets the right samplerate -- Owen W. - m_pConfig->set(ConfigKey("[Soundcard]", "Samplerate"), - ConfigValue(static_cast(m_config.getSampleRate().value()))); + closeActiveConfig(); status = setupDevices(); if (status == SoundDeviceStatus::Ok) { diff --git a/src/soundio/soundmanager.h b/src/soundio/soundmanager.h index 42fdd1e11aa..205909535f4 100644 --- a/src/soundio/soundmanager.h +++ b/src/soundio/soundmanager.h @@ -74,6 +74,7 @@ class SoundManager : public QObject { QList getHostAPIList() const; SoundManagerConfig getConfig() const; SoundDeviceStatus setConfig(const SoundManagerConfig& config); + void closeActiveConfig(); void checkConfig(); void onDeviceOutputCallback(const SINT iFramesPerBuffer);