| @@ -151,7 +151,6 @@ AudioDeviceManager::AudioDeviceManager() | |||
| : numInputChansNeeded (0), | |||
| numOutputChansNeeded (2), | |||
| listNeedsScanning (true), | |||
| inputLevel (0), | |||
| cpuUsageMs (0), | |||
| timeToCpuScale (0) | |||
| { | |||
| @@ -761,31 +760,8 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| { | |||
| const ScopedLock sl (audioCallbackLock); | |||
| if (inputLevelMeasurementEnabledCount.get() > 0 && numInputChannels > 0) | |||
| { | |||
| for (int j = 0; j < numSamples; ++j) | |||
| { | |||
| float s = 0; | |||
| for (int i = 0; i < numInputChannels; ++i) | |||
| s += std::abs (inputChannelData[i][j]); | |||
| s /= numInputChannels; | |||
| const double decayFactor = 0.99992; | |||
| if (s > inputLevel) | |||
| inputLevel = s; | |||
| else if (inputLevel > 0.001f) | |||
| inputLevel *= decayFactor; | |||
| else | |||
| inputLevel = 0; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| inputLevel = 0; | |||
| } | |||
| inputLevelMeter.updateLevel (inputChannelData, numInputChannels, numSamples); | |||
| outputLevelMeter.updateLevel (const_cast<const float**> (outputChannelData), numOutputChannels, numSamples); | |||
| if (callbacks.size() > 0) | |||
| { | |||
| @@ -1141,18 +1117,51 @@ void AudioDeviceManager::playTestSound() | |||
| } | |||
| //============================================================================== | |||
| void AudioDeviceManager::enableInputLevelMeasurement (const bool enableMeasurement) | |||
| AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {} | |||
| void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelData, int numChannels, int numSamples) noexcept | |||
| { | |||
| if (enableMeasurement) | |||
| ++inputLevelMeasurementEnabledCount; | |||
| if (enabled.get() != 0 && numChannels > 0) | |||
| { | |||
| for (int j = 0; j < numSamples; ++j) | |||
| { | |||
| float s = 0; | |||
| for (int i = 0; i < numChannels; ++i) | |||
| s += std::abs (channelData[i][j]); | |||
| s /= numChannels; | |||
| const double decayFactor = 0.99992; | |||
| if (s > level) | |||
| level = s; | |||
| else if (level > 0.001f) | |||
| level *= decayFactor; | |||
| else | |||
| level = 0; | |||
| } | |||
| } | |||
| else | |||
| --inputLevelMeasurementEnabledCount; | |||
| { | |||
| level = 0; | |||
| } | |||
| } | |||
| inputLevel = 0; | |||
| void AudioDeviceManager::LevelMeter::setEnabled (bool shouldBeEnabled) noexcept | |||
| { | |||
| enabled.set (shouldBeEnabled ? 1 : 0); | |||
| level = 0; | |||
| } | |||
| double AudioDeviceManager::getCurrentInputLevel() const | |||
| double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept | |||
| { | |||
| jassert (inputLevelMeasurementEnabledCount.get() > 0); // you need to call enableInputLevelMeasurement() before using this! | |||
| return inputLevel; | |||
| jassert (enabled.get() != 0); // you need to call setEnabled (true) before using this! | |||
| return level; | |||
| } | |||
| 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); } | |||
| @@ -456,26 +456,27 @@ public: | |||
| bool playOnAllOutputChannels = false); | |||
| //============================================================================== | |||
| /** Turns on level-measuring. | |||
| When enabled, the device manager will measure the peak input level | |||
| across all channels, and you can get this level by calling getCurrentInputLevel(). | |||
| This is mainly intended for audio setup UI panels to use to create a mic | |||
| level display, so that the user can check that they've selected the right | |||
| device. | |||
| /** Turns on level-measuring for input channels. | |||
| @see getCurrentInputLevel() | |||
| */ | |||
| void enableInputLevelMeasurement (bool enableMeasurement) noexcept; | |||
| A simple filter is used to make the level decay smoothly, but this is | |||
| only intended for giving rough feedback, and not for any kind of accurate | |||
| measurement. | |||
| /** Turns on level-measuring for output channels. | |||
| @see getCurrentOutputLevel() | |||
| */ | |||
| void enableInputLevelMeasurement (bool enableMeasurement); | |||
| void enableOutputLevelMeasurement (bool enableMeasurement) noexcept; | |||
| /** Returns the current input level. | |||
| To use this, you must first enable it by calling enableInputLevelMeasurement(). | |||
| See enableInputLevelMeasurement() for more info. | |||
| @see enableInputLevelMeasurement() | |||
| */ | |||
| double getCurrentInputLevel() const noexcept; | |||
| /** Returns the current output level. | |||
| To use this, you must first enable it by calling enableOutputLevelMeasurement(). | |||
| @see enableOutputLevelMeasurement() | |||
| */ | |||
| double getCurrentInputLevel() const; | |||
| double getCurrentOutputLevel() const noexcept; | |||
| /** 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 | |||
| @@ -502,8 +503,6 @@ private: | |||
| BigInteger inputChannels, outputChannels; | |||
| ScopedPointer<XmlElement> lastExplicitSettings; | |||
| mutable bool listNeedsScanning; | |||
| Atomic<int> inputLevelMeasurementEnabledCount; | |||
| double inputLevel; | |||
| AudioSampleBuffer tempBuffer; | |||
| struct MidiCallbackInfo | |||
| @@ -522,6 +521,19 @@ private: | |||
| double cpuUsageMs, timeToCpuScale; | |||
| 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; | |||
| double level; | |||
| }; | |||
| LevelMeter inputLevelMeter, outputLevelMeter; | |||
| //============================================================================== | |||
| class CallbackHandler; | |||
| friend class CallbackHandler; | |||