From d2875c2c4fa0e430e81f4d017e515a1786daee67 Mon Sep 17 00:00:00 2001 From: Kalila L Date: Tue, 9 Feb 2021 00:44:01 -0500 Subject: [PATCH] Add manual mode to noise reduction + add noise reduction threshold --- interface/src/scripting/Audio.cpp | 50 ++++++++++++++++++++++ interface/src/scripting/Audio.h | 26 +++++++++++ libraries/audio-client/src/AudioClient.cpp | 32 +++++++++++++- libraries/audio-client/src/AudioClient.h | 12 ++++++ 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 43958188e3..36045bd8ec 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -25,6 +25,8 @@ QString Audio::DESKTOP { "Desktop" }; QString Audio::HMD { "VR" }; Setting::Handle enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true }; +Setting::Handle enableNoiseReductionAutomaticSetting { QStringList { Audio::AUDIO, "NoiseReductionAutomatic" }, false }; +Setting::Handle setNoiseReductionThresholdSetting { QStringList { Audio::AUDIO, "NoiseReductionThreshold" }, 0.2f }; Setting::Handle enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true }; Setting::Handle enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true }; @@ -40,6 +42,8 @@ Audio::Audio() : _devices(_contextIsHMD) { auto client = DependencyManager::get().data(); connect(client, &AudioClient::muteToggled, this, &Audio::setMuted); connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction); + connect(client, &AudioClient::noiseReductionAutomaticChanged, this, &Audio::enableNoiseReductionAutomatic); + connect(client, &AudioClient::noiseReductionThresholdChanged, this, &Audio::setNoiseReductionThreshold); connect(client, &AudioClient::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted); connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); @@ -47,6 +51,8 @@ Audio::Audio() : _devices(_contextIsHMD) { connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk); enableNoiseReduction(enableNoiseReductionSetting.get()); + enableNoiseReductionAutomatic(enableNoiseReductionAutomaticSetting.get()); + setNoiseReductionThreshold(setNoiseReductionThresholdSetting.get()); enableWarnWhenMuted(enableWarnWhenMutedSetting.get()); enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get()); onContextChanged(); @@ -286,6 +292,50 @@ void Audio::enableNoiseReduction(bool enable) { } } +bool Audio::noiseReductionAutomatic() const { + return resultWithReadLock([&] { + return _noiseReductionAutomatic; + }); +} + +void Audio::enableNoiseReductionAutomatic(bool enable) { + bool changed = false; + withWriteLock([&] { + if (_noiseReductionAutomatic != enable) { + _noiseReductionAutomatic = enable; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setNoiseReductionAutomatic", Q_ARG(bool, enable), Q_ARG(bool, false)); + enableNoiseReductionAutomaticSetting.set(enable); + changed = true; + } + }); + if (changed) { + emit noiseReductionAutomaticChanged(enable); + } +} + +float Audio::getNoiseReductionThreshold() const { + return resultWithReadLock([&] { + return _noiseReductionThreshold; + }); +} + +void Audio::setNoiseReductionThreshold(float threshold) { + bool changed = false; + withWriteLock([&] { + if (_noiseReductionThreshold != threshold) { + _noiseReductionThreshold = threshold; + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setNoiseReductionThreshold", Q_ARG(float, threshold), Q_ARG(bool, false)); + setNoiseReductionThresholdSetting.set(threshold); + changed = true; + } + }); + if (changed) { + emit noiseReductionAutomaticChanged(threshold); + } +} + bool Audio::warnWhenMutedEnabled() const { return resultWithReadLock([&] { return _enableWarnWhenMuted; diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 74d85f0107..3addd6d5a4 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -92,6 +92,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged) + Q_PROPERTY(bool noiseReductionAutomatic READ noiseReductionAutomatic WRITE enableNoiseReductionAutomatic NOTIFY noiseReductionAutomaticChanged) + Q_PROPERTY(float noiseReductionThreshold READ getNoiseReductionThreshold WRITE setNoiseReductionThreshold NOTIFY noiseReductionThresholdChanged) Q_PROPERTY(bool warnWhenMuted READ warnWhenMutedEnabled WRITE enableWarnWhenMuted NOTIFY warnWhenMutedChanged) Q_PROPERTY(bool acousticEchoCancellation READ acousticEchoCancellationEnabled WRITE enableAcousticEchoCancellation NOTIFY acousticEchoCancellationChanged) @@ -124,6 +126,8 @@ public: bool isMuted() const; bool noiseReductionEnabled() const; + bool noiseReductionAutomatic() const; + float getNoiseReductionThreshold() const; bool warnWhenMutedEnabled() const; bool acousticEchoCancellationEnabled() const; float getInputVolume() const; @@ -398,6 +402,24 @@ signals: * @returns {Signal} */ void noiseReductionChanged(bool isEnabled); + + /**jsdoc + * Triggered when the audio input noise reduction mode is changed. + * @function Audio.noiseReductionAutomaticChanged + * @param {boolean} isEnabled - true if audio input noise reduction automatic mode is enabled, otherwise false. + * This means the mode is set to 'manual'. + * @returns {Signal} + */ + void noiseReductionAutomaticChanged(bool isEnabled); + + /**jsdoc + * Triggered when audio input noise reduction threshold is changed. + * @function Audio.noiseReductionThresholdChanged + * @param {number} threshold - The threshold for the audio input noise reduction, range 0.0 (open the gate completely) – 1.0 + * (close the gate completely). + * @returns {Signal} + */ + void noiseReductionThresholdChanged(float threshold); /**jsdoc * Triggered when "warn when muted" is enabled or disabled. @@ -512,6 +534,8 @@ public slots: private slots: void setMuted(bool muted); void enableNoiseReduction(bool enable); + void enableNoiseReductionAutomatic(bool enable); + void setNoiseReductionThreshold(float threshold); void enableWarnWhenMuted(bool enable); void enableAcousticEchoCancellation(bool enable); void setInputVolume(float volume); @@ -533,8 +557,10 @@ private: float _localInjectorGain { 0.0f }; // in dB float _systemInjectorGain { 0.0f }; // in dB float _pttOutputGainDesktop { 0.0f }; // in dB + float _noiseReductionThreshold { 0.2f }; // Match default value of AudioClient::_noiseReductionThreshold. bool _isClipping { false }; bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled. + bool _noiseReductionAutomatic { true }; // Match default value of AudioClient::_noiseReductionAutomatic. bool _enableWarnWhenMuted { true }; bool _enableAcousticEchoCancellation { true }; // AudioClient::_isAECEnabled bool _contextIsHMD { false }; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 2600097c3b..a3d2568b6d 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1342,6 +1342,13 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { } } +float AudioClient::loudnessToLevel(float loudness) { + float level = loudness * (1 / 32768.0f); // level in [0, 1] + level = 6.02059991f * fastLog2f(level); // convert to dBFS + level = (level + 48.0f) * (1 / 42.0f); // map [-48, -6] dBFS to [0, 1] + return glm::clamp(level, 0.0f, 1.0f); +} + void AudioClient::handleAudioInput(QByteArray& audioBuffer) { if (!_audioPaused) { @@ -1352,9 +1359,14 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) { int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE; int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO); - if (_isNoiseGateEnabled) { + if (_isNoiseGateEnabled && _isNoiseReductionAutomatic) { // The audio gate includes DC removal audioGateOpen = _audioGate->render(samples, samples, numFrames); + } else if (_isNoiseGateEnabled && !_isNoiseReductionAutomatic && + loudnessToLevel(_lastSmoothedRawInputLoudness) >= _noiseReductionThreshold) { + audioGateOpen = _audioGate->removeDC(samples, samples, numFrames); + } else if (_isNoiseGateEnabled && !_isNoiseReductionAutomatic) { + audioGateOpen = false; } else { audioGateOpen = _audioGate->removeDC(samples, samples, numFrames); } @@ -1750,6 +1762,24 @@ void AudioClient::setNoiseReduction(bool enable, bool emitSignal) { } } +void AudioClient::setNoiseReductionAutomatic(bool enable, bool emitSignal) { + if (_isNoiseReductionAutomatic != enable) { + _isNoiseReductionAutomatic = enable; + if (emitSignal) { + emit noiseReductionAutomaticChanged(_isNoiseReductionAutomatic); + } + } +} + +void AudioClient::setNoiseReductionThreshold(float threshold, bool emitSignal) { + if (_noiseReductionThreshold != threshold) { + _noiseReductionThreshold = threshold; + if (emitSignal) { + emit noiseReductionThresholdChanged(_noiseReductionThreshold); + } + } +} + void AudioClient::setWarnWhenMuted(bool enable, bool emitSignal) { if (_warnWhenMuted != enable) { _warnWhenMuted = enable; diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 09abb2c356..f101d68a0e 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -217,6 +217,12 @@ public slots: void setNoiseReduction(bool isNoiseGateEnabled, bool emitSignal = true); bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } + + void setNoiseReductionAutomatic(bool isNoiseGateAutomatic, bool emitSignal = true); + bool isNoiseReductionAutomatic() const { return _isNoiseReductionAutomatic; } + + void setNoiseReductionThreshold(float noiseReductionThreshold, bool emitSignal = true); + float noiseReductionThreshold() const { return _noiseReductionThreshold; } void setWarnWhenMuted(bool isNoiseGateEnabled, bool emitSignal = true); bool isWarnWhenMutedEnabled() const { return _warnWhenMuted; } @@ -265,6 +271,8 @@ signals: void inputVolumeChanged(float volume); void muteToggled(bool muted); void noiseReductionChanged(bool noiseReductionEnabled); + void noiseReductionAutomaticChanged(bool noiseReductionAutomatic); + void noiseReductionThresholdChanged(bool noiseReductionThreshold); void warnWhenMutedChanged(bool warnWhenMutedEnabled); void acousticEchoCancellationChanged(bool acousticEchoCancellationEnabled); void mutedByMixer(); @@ -310,6 +318,8 @@ private: friend class CheckDevicesThread; friend class LocalInjectorsThread; + float loudnessToLevel(float loudness); + // background tasks void checkDevices(); void checkPeakValues(); @@ -397,6 +407,8 @@ private: bool _shouldEchoLocally{ false }; bool _shouldEchoToServer{ false }; bool _isNoiseGateEnabled{ true }; + bool _isNoiseReductionAutomatic{ true }; + float _noiseReductionThreshold{ 0.2f }; bool _warnWhenMuted; bool _isAECEnabled{ true };