@@ -684,8 +684,8 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||||
{ | { | ||||
const ScopedLock sl (audioCallbackLock); | const ScopedLock sl (audioCallbackLock); | ||||
inputLevelMeter.updateLevel (inputChannelData, numInputChannels, numSamples); | |||||
outputLevelMeter.updateLevel (const_cast<const float**> (outputChannelData), numOutputChannels, numSamples); | |||||
inputLevelGetter->updateLevel (inputChannelData, numInputChannels, numSamples); | |||||
outputLevelGetter->updateLevel (const_cast<const float**> (outputChannelData), numOutputChannels, numSamples); | |||||
if (callbacks.size() > 0) | 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 | void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelData, int numChannels, int numSamples) noexcept | ||||
{ | { | ||||
if (getReferenceCount() <= 1) | |||||
return; | |||||
auto localLevel = level.get(); | auto localLevel = level.get(); | ||||
if (enabled.get() != 0 && numChannels > 0) | |||||
if (numChannels > 0) | |||||
{ | { | ||||
for (int j = 0; j < numSamples; ++j) | for (int j = 0; j < numSamples; ++j) | ||||
{ | { | ||||
@@ -943,15 +946,9 @@ void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelDat | |||||
level = localLevel; | level = localLevel; | ||||
} | } | ||||
void AudioDeviceManager::LevelMeter::setEnabled (bool shouldBeEnabled) noexcept | |||||
{ | |||||
enabled.set (shouldBeEnabled ? 1 : 0); | |||||
level = 0; | |||||
} | |||||
double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept | 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(); | return level.get(); | ||||
} | } | ||||
@@ -997,10 +994,4 @@ int AudioDeviceManager::getXRunCount() const noexcept | |||||
return (deviceXRuns >= 0 ? deviceXRuns : xruns); | 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 | } // namespace juce |
@@ -403,28 +403,45 @@ public: | |||||
void playTestSound(); | 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<LevelMeter> Ptr; | |||||
LevelMeter() noexcept; | |||||
double getCurrentLevel() const noexcept; | |||||
private: | |||||
friend class AudioDeviceManager; | |||||
Atomic<float> 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. | /** 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 | 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. | it must only be used for very brief periods when absolutely necessary. | ||||
@@ -481,18 +498,8 @@ private: | |||||
double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0; | double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0; | ||||
int xruns = 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<int> enabled; | |||||
Atomic<float> level; | |||||
}; | |||||
LevelMeter inputLevelMeter, outputLevelMeter; | |||||
LevelMeter::Ptr inputLevelGetter { new LevelMeter() }, | |||||
outputLevelGetter { new LevelMeter() }; | |||||
//============================================================================== | //============================================================================== | ||||
class CallbackHandler; | class CallbackHandler; | ||||
@@ -33,19 +33,18 @@ struct SimpleDeviceManagerInputLevelMeter : public Component, | |||||
SimpleDeviceManagerInputLevelMeter (AudioDeviceManager& m) : manager (m) | SimpleDeviceManagerInputLevelMeter (AudioDeviceManager& m) : manager (m) | ||||
{ | { | ||||
startTimerHz (20); | startTimerHz (20); | ||||
manager.enableInputLevelMeasurement (true); | |||||
inputLevelGetter = manager.getInputLevelGetter(); | |||||
} | } | ||||
~SimpleDeviceManagerInputLevelMeter() | ~SimpleDeviceManagerInputLevelMeter() | ||||
{ | { | ||||
manager.enableInputLevelMeasurement (false); | |||||
} | } | ||||
void timerCallback() override | void timerCallback() override | ||||
{ | { | ||||
if (isShowing()) | if (isShowing()) | ||||
{ | { | ||||
auto newLevel = (float) manager.getCurrentInputLevel(); | |||||
auto newLevel = (float) inputLevelGetter->getCurrentLevel(); | |||||
if (std::abs (level - newLevel) > 0.005f) | if (std::abs (level - newLevel) > 0.005f) | ||||
{ | { | ||||
@@ -66,6 +65,7 @@ struct SimpleDeviceManagerInputLevelMeter : public Component, | |||||
} | } | ||||
AudioDeviceManager& manager; | AudioDeviceManager& manager; | ||||
AudioDeviceManager::LevelMeter::Ptr inputLevelGetter; | |||||
float level = 0; | float level = 0; | ||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleDeviceManagerInputLevelMeter) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimpleDeviceManagerInputLevelMeter) | ||||