diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index 84d090a375..eb172f469c 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -684,8 +684,8 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat { const ScopedLock sl (audioCallbackLock); - inputLevelMeter.updateLevel (inputChannelData, numInputChannels, numSamples); - outputLevelMeter.updateLevel (const_cast (outputChannelData), numOutputChannels, numSamples); + inputLevelGetter->updateLevel (inputChannelData, numInputChannels, numSamples); + outputLevelGetter->updateLevel (const_cast (outputChannelData), numOutputChannels, numSamples); if (callbacks.size() > 0) { @@ -912,9 +912,12 @@ AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {} void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelData, int numChannels, int numSamples) noexcept { + if (getReferenceCount() <= 1) + return; + auto localLevel = level.get(); - if (enabled.get() != 0 && numChannels > 0) + if (numChannels > 0) { for (int j = 0; j < numSamples; ++j) { @@ -943,15 +946,9 @@ void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelDat level = localLevel; } -void AudioDeviceManager::LevelMeter::setEnabled (bool shouldBeEnabled) noexcept -{ - enabled.set (shouldBeEnabled ? 1 : 0); - level = 0; -} - double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept { - jassert (enabled.get() != 0); // you need to call setEnabled (true) before using this! + jassert (getReferenceCount() > 1); return level.get(); } @@ -997,10 +994,4 @@ int AudioDeviceManager::getXRunCount() const noexcept return (deviceXRuns >= 0 ? deviceXRuns : xruns); } -double AudioDeviceManager::getCurrentInputLevel() const noexcept { return inputLevelMeter.getCurrentLevel(); } -double AudioDeviceManager::getCurrentOutputLevel() const noexcept { return outputLevelMeter.getCurrentLevel(); } - -void AudioDeviceManager::enableInputLevelMeasurement (bool enable) noexcept { inputLevelMeter.setEnabled (enable); } -void AudioDeviceManager::enableOutputLevelMeasurement (bool enable) noexcept { outputLevelMeter.setEnabled (enable); } - } // namespace juce diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h index 460fb04c92..e9da12ef56 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h @@ -403,28 +403,45 @@ public: void playTestSound(); //============================================================================== - /** Turns on level-measuring for input channels. - @see getCurrentInputLevel() - */ - void enableInputLevelMeasurement (bool enableMeasurement) noexcept; + /** + A simple reference-counted struct that holds a level-meter value that can be read + using getCurrentLevel(). + + This is used to ensure that the level processing code is only executed when something + holds a reference to one of these objects and will be bypassed otherwise. - /** Turns on level-measuring for output channels. - @see getCurrentOutputLevel() + @see getInputLevelGetter, getOutputLevelGetter */ - void enableOutputLevelMeasurement (bool enableMeasurement) noexcept; + struct LevelMeter : public ReferenceCountedObject + { + typedef ReferenceCountedObjectPtr Ptr; + + LevelMeter() noexcept; + + double getCurrentLevel() const noexcept; + + private: + friend class AudioDeviceManager; + + Atomic level { 0 }; + void updateLevel (const float* const*, int numChannels, int numSamples) noexcept; + }; + + /** Returns a reference-counted object that can be used to get the current input level. - /** Returns the current input level. - To use this, you must first enable it by calling enableInputLevelMeasurement(). - @see enableInputLevelMeasurement() + You need to store this object locally to ensure that the reference count is incremented + and decremented properly. The current input level value can be read using getCurrentLevel(). */ - double getCurrentInputLevel() const noexcept; + LevelMeter::Ptr getInputLevelGetter() noexcept { return inputLevelGetter; } + + /** Returns a reference-counted object that can be used to get the current input level. - /** Returns the current output level. - To use this, you must first enable it by calling enableOutputLevelMeasurement(). - @see enableOutputLevelMeasurement() + You need to store this object locally to ensure that the reference count is incremented + and decremented properly. The current input level value can be read using getCurrentLevel(). */ - double getCurrentOutputLevel() const noexcept; + LevelMeter::Ptr getOutputLevelGetter() noexcept { return outputLevelGetter; } + //============================================================================== /** Returns the a lock that can be used to synchronise access to the audio callback. Obviously while this is locked, you're blocking the audio thread from running, so it must only be used for very brief periods when absolutely necessary. @@ -481,18 +498,8 @@ private: double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0; int xruns = 0; - struct LevelMeter - { - LevelMeter() noexcept; - void updateLevel (const float* const*, int numChannels, int numSamples) noexcept; - void setEnabled (bool) noexcept; - double getCurrentLevel() const noexcept; - - Atomic enabled; - Atomic level; - }; - - LevelMeter inputLevelMeter, outputLevelMeter; + LevelMeter::Ptr inputLevelGetter { new LevelMeter() }, + outputLevelGetter { new LevelMeter() }; //============================================================================== class CallbackHandler; diff --git a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp index 8f05eda479..3a174dcd33 100644 --- a/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp +++ b/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp @@ -33,19 +33,18 @@ struct SimpleDeviceManagerInputLevelMeter : public Component, SimpleDeviceManagerInputLevelMeter (AudioDeviceManager& m) : manager (m) { startTimerHz (20); - manager.enableInputLevelMeasurement (true); + inputLevelGetter = manager.getInputLevelGetter(); } ~SimpleDeviceManagerInputLevelMeter() { - manager.enableInputLevelMeasurement (false); } void timerCallback() override { if (isShowing()) { - auto newLevel = (float) manager.getCurrentInputLevel(); + auto newLevel = (float) inputLevelGetter->getCurrentLevel(); if (std::abs (level - newLevel) > 0.005f) { @@ -66,6 +65,7 @@ struct SimpleDeviceManagerInputLevelMeter : public Component, } AudioDeviceManager& manager; + AudioDeviceManager::LevelMeter::Ptr inputLevelGetter; float level = 0; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleDeviceManagerInputLevelMeter)