mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 13:49:12 +02:00
Merge pull request #1007 from digisomni/feature/manual-noise-reduction-gate
Add manual mode to noise reduction + add noise reduction threshold
This commit is contained in:
commit
672bceee1c
5 changed files with 408 additions and 50 deletions
|
@ -15,6 +15,7 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
import QtQuick.Controls 2.2
|
import QtQuick.Controls 2.2
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
import stylesUit 1.0
|
import stylesUit 1.0
|
||||||
import controlsUit 1.0 as HifiControlsUit
|
import controlsUit 1.0 as HifiControlsUit
|
||||||
|
@ -104,6 +105,11 @@ Rectangle {
|
||||||
AudioScriptingInterface.setSystemInjectorGain(sliderValue);
|
AudioScriptingInterface.setSystemInjectorGain(sliderValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function updateNoiseReductionThresholdFromQML(sliderValue) {
|
||||||
|
if (AudioScriptingInterface.getNoiseReductionThreshold() !== sliderValue) {
|
||||||
|
AudioScriptingInterface.setNoiseReductionThreshold(sliderValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
enablePeakValues();
|
enablePeakValues();
|
||||||
|
@ -164,7 +170,7 @@ Rectangle {
|
||||||
x: 2 * margins.paddings;
|
x: 2 * margins.paddings;
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
// switch heights + 2 * top margins
|
// switch heights + 2 * top margins
|
||||||
height: (root.switchHeight) * 6 + 48;
|
height: (bar.currentIndex === 0) ? (root.switchHeight) * 2 + 48 : (root.switchHeight) * 4 + 48;
|
||||||
anchors.top: firstSeparator.bottom;
|
anchors.top: firstSeparator.bottom;
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
|
|
||||||
|
@ -175,6 +181,7 @@ Rectangle {
|
||||||
height: parent.height;
|
height: parent.height;
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: muteMic;
|
id: muteMic;
|
||||||
height: root.switchHeight;
|
height: root.switchHeight;
|
||||||
|
@ -193,45 +200,11 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
|
||||||
id: noiseReductionSwitch;
|
|
||||||
height: root.switchHeight;
|
|
||||||
switchWidth: root.switchWidth;
|
|
||||||
anchors.top: muteMic.bottom;
|
|
||||||
anchors.topMargin: 24
|
|
||||||
anchors.left: parent.left
|
|
||||||
labelTextOn: "Noise Reduction";
|
|
||||||
labelTextSize: 16;
|
|
||||||
backgroundOnColor: "#E3E3E3";
|
|
||||||
checked: AudioScriptingInterface.noiseReduction;
|
|
||||||
onCheckedChanged: {
|
|
||||||
AudioScriptingInterface.noiseReduction = checked;
|
|
||||||
checked = Qt.binding(function() { return AudioScriptingInterface.noiseReduction; }); // restore binding
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
|
||||||
id: acousticEchoCancellationSwitch;
|
|
||||||
height: root.switchHeight;
|
|
||||||
switchWidth: root.switchWidth;
|
|
||||||
anchors.top: noiseReductionSwitch.bottom
|
|
||||||
anchors.topMargin: 24
|
|
||||||
anchors.left: parent.left
|
|
||||||
labelTextOn: "Echo Cancellation";
|
|
||||||
labelTextSize: 16;
|
|
||||||
backgroundOnColor: "#E3E3E3";
|
|
||||||
checked: AudioScriptingInterface.acousticEchoCancellation;
|
|
||||||
onCheckedChanged: {
|
|
||||||
AudioScriptingInterface.acousticEchoCancellation = checked;
|
|
||||||
checked = Qt.binding(function() { return AudioScriptingInterface.acousticEchoCancellation; });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: pttSwitch
|
id: pttSwitch
|
||||||
height: root.switchHeight;
|
height: root.switchHeight;
|
||||||
switchWidth: root.switchWidth;
|
switchWidth: root.switchWidth;
|
||||||
anchors.top: acousticEchoCancellationSwitch.bottom;
|
anchors.top: muteMic.bottom;
|
||||||
anchors.topMargin: 24
|
anchors.topMargin: 24
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
||||||
|
@ -254,6 +227,7 @@ Rectangle {
|
||||||
height: parent.height;
|
height: parent.height;
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: switchContainer.right;
|
anchors.left: switchContainer.right;
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: warnMutedSwitch
|
id: warnMutedSwitch
|
||||||
height: root.switchHeight;
|
height: root.switchHeight;
|
||||||
|
@ -271,7 +245,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HifiControlsUit.Switch {
|
HifiControlsUit.Switch {
|
||||||
id: audioLevelSwitch
|
id: audioLevelSwitch
|
||||||
height: root.switchHeight;
|
height: root.switchHeight;
|
||||||
|
@ -520,12 +493,263 @@ Rectangle {
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noiseReductionHeader
|
||||||
|
x: margins.paddings;
|
||||||
|
width: parent.width - margins.paddings * 2;
|
||||||
|
height: 36;
|
||||||
|
anchors.top: secondSeparator.bottom;
|
||||||
|
anchors.topMargin: 10;
|
||||||
|
|
||||||
|
HiFiGlyphs {
|
||||||
|
width: margins.sizeCheckBox;
|
||||||
|
text: hifi.glyphs.mic;
|
||||||
|
color: hifi.colors.white;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: -size / 4; // The glyph has empty space at left about 25%
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
size: 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewayRegular {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
width: margins.sizeText + margins.sizeLevel;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: margins.sizeCheckBox;
|
||||||
|
size: 22;
|
||||||
|
color: hifi.colors.white;
|
||||||
|
text: qsTr("Noise Reduction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noiseReductionSwitches;
|
||||||
|
x: 2 * margins.paddings;
|
||||||
|
width: parent.width;
|
||||||
|
// switch heights + 2 * top margins
|
||||||
|
height: (root.switchHeight) * 5 + 48;
|
||||||
|
anchors.top: noiseReductionHeader.bottom;
|
||||||
|
anchors.topMargin: 0;
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noiseReductionSwitchContainer;
|
||||||
|
x: margins.paddings;
|
||||||
|
width: parent.width / 2;
|
||||||
|
height: parent.height;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
|
||||||
|
HifiControlsUit.Switch {
|
||||||
|
id: acousticEchoCancellationSwitch;
|
||||||
|
height: root.switchHeight;
|
||||||
|
switchWidth: root.switchWidth;
|
||||||
|
anchors.top: noiseReductionSwitchContainer.top
|
||||||
|
anchors.topMargin: 24
|
||||||
|
anchors.left: parent.left
|
||||||
|
labelTextOn: "Echo Cancellation";
|
||||||
|
labelTextSize: 16;
|
||||||
|
backgroundOnColor: "#E3E3E3";
|
||||||
|
checked: AudioScriptingInterface.acousticEchoCancellation;
|
||||||
|
onCheckedChanged: {
|
||||||
|
AudioScriptingInterface.acousticEchoCancellation = checked;
|
||||||
|
checked = Qt.binding(function () { return AudioScriptingInterface.acousticEchoCancellation; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.Switch {
|
||||||
|
id: noiseReductionSwitch;
|
||||||
|
height: root.switchHeight;
|
||||||
|
switchWidth: root.switchWidth;
|
||||||
|
anchors.top: acousticEchoCancellationSwitch.bottom;
|
||||||
|
anchors.topMargin: 24
|
||||||
|
anchors.left: parent.left
|
||||||
|
labelTextOn: "Noise Reduction";
|
||||||
|
labelTextSize: 16;
|
||||||
|
backgroundOnColor: "#E3E3E3";
|
||||||
|
checked: AudioScriptingInterface.noiseReduction;
|
||||||
|
onCheckedChanged: {
|
||||||
|
AudioScriptingInterface.noiseReduction = checked;
|
||||||
|
checked = Qt.binding(function () { return AudioScriptingInterface.noiseReduction; }); // restore binding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControlsUit.Switch {
|
||||||
|
id: noiseReductionAutomaticSwitch;
|
||||||
|
height: root.switchHeight;
|
||||||
|
switchWidth: root.switchWidth;
|
||||||
|
anchors.top: noiseReductionSwitch.bottom;
|
||||||
|
anchors.topMargin: 24;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
labelTextOn: "Manual Noise Reduction";
|
||||||
|
labelTextSize: 16;
|
||||||
|
backgroundOnColor: "#E3E3E3";
|
||||||
|
checked: !AudioScriptingInterface.noiseReductionAutomatic;
|
||||||
|
visible: AudioScriptingInterface.noiseReduction;
|
||||||
|
onCheckedChanged: {
|
||||||
|
AudioScriptingInterface.noiseReductionAutomatic = !checked;
|
||||||
|
checked = Qt.binding(function () { return !AudioScriptingInterface.noiseReductionAutomatic; }); // restore binding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noiseReductionThresholdContainer
|
||||||
|
x: margins.paddings;
|
||||||
|
anchors.top: noiseReductionSwitches.bottom;
|
||||||
|
anchors.topMargin: 16;
|
||||||
|
width: parent.width - margins.paddings * 2;
|
||||||
|
height: avatarGainSliderTextMetrics.height + 10;
|
||||||
|
visible: AudioScriptingInterface.noiseReduction && !AudioScriptingInterface.noiseReductionAutomatic;
|
||||||
|
|
||||||
|
HifiControlsUit.Slider {
|
||||||
|
id: noiseReductionThresholdSlider
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: noiseReductionThresholdSliderTextMetrics.height
|
||||||
|
width: 200
|
||||||
|
minimumValue: 0.0
|
||||||
|
maximumValue: 1.0
|
||||||
|
stepSize: 0.05
|
||||||
|
value: AudioScriptingInterface.getNoiseReductionThreshold()
|
||||||
|
onValueChanged: {
|
||||||
|
updateNoiseReductionThresholdFromQML(value);
|
||||||
|
}
|
||||||
|
onPressedChanged: {
|
||||||
|
if (!pressed) {
|
||||||
|
updateNoiseReductionThresholdFromQML(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onWheel: {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
onDoubleClicked: {
|
||||||
|
noiseReductionThresholdSlider.value = 0.0;
|
||||||
|
}
|
||||||
|
onPressed: {
|
||||||
|
// Pass through to Slider
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
// the above mouse.accepted seems to make this
|
||||||
|
// never get called, nonetheless...
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextMetrics {
|
||||||
|
id: noiseReductionThresholdSliderTextMetrics
|
||||||
|
text: noiseReductionThresholdSliderText.text
|
||||||
|
font: noiseReductionThresholdSliderText.font
|
||||||
|
}
|
||||||
|
RalewayRegular {
|
||||||
|
// The slider for my card is special, it controls the master gain
|
||||||
|
id: noiseReductionThresholdSliderText;
|
||||||
|
text: "Audio input threshold";
|
||||||
|
size: 16;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
color: hifi.colors.white;
|
||||||
|
horizontalAlignment: Text.AlignLeft;
|
||||||
|
verticalAlignment: Text.AlignTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noisePeak
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 5;
|
||||||
|
anchors.top: noiseReductionThresholdSlider.bottom;
|
||||||
|
|
||||||
|
width: noiseReductionThresholdSlider.width - 10;
|
||||||
|
height: 8;
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: status;
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter;
|
||||||
|
verticalCenter: parent.verticalCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
visible: AudioScriptingInterface.muted;
|
||||||
|
color: "#E2334D";
|
||||||
|
|
||||||
|
text: "MUTED";
|
||||||
|
font.pointSize: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noiseBar;
|
||||||
|
|
||||||
|
property bool gated: false;
|
||||||
|
property var level: AudioScriptingInterface.inputLevel;
|
||||||
|
|
||||||
|
width: parent.width;
|
||||||
|
height: parent.height;
|
||||||
|
|
||||||
|
anchors { fill: parent }
|
||||||
|
|
||||||
|
visible: !status.visible;
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
AudioScriptingInterface.noiseGateOpened.connect(function () { noiseBar.gated = false; });
|
||||||
|
AudioScriptingInterface.noiseGateClosed.connect(function () { noiseBar.gated = true; });
|
||||||
|
AudioScriptingInterface.inputLevelChanged.connect(function () { noiseBar.level = AudioScriptingInterface.inputLevel; });
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle { // base
|
||||||
|
radius: 4;
|
||||||
|
anchors { fill: parent }
|
||||||
|
color: colors.gutter;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle { // noiseMask
|
||||||
|
id: noiseMask;
|
||||||
|
width: parent.width * noiseBar.level;
|
||||||
|
radius: 5;
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom;
|
||||||
|
bottomMargin: 0;
|
||||||
|
top: parent.top;
|
||||||
|
topMargin: 0;
|
||||||
|
left: parent.left;
|
||||||
|
leftMargin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearGradient {
|
||||||
|
anchors { fill: noiseMask }
|
||||||
|
source: noiseMask
|
||||||
|
start: Qt.point(0, 0);
|
||||||
|
end: Qt.point(noiseBar.width, 0);
|
||||||
|
gradient: Gradient {
|
||||||
|
GradientStop {
|
||||||
|
position: 0;
|
||||||
|
color: noiseBar.gated ? "#E2334D" : "#39A38F";
|
||||||
|
}
|
||||||
|
GradientStop {
|
||||||
|
position: 1;
|
||||||
|
color: noiseBar.gated ? "#E2334D" : "#39A38F";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
id: thirdSeparator;
|
||||||
|
anchors.top: noiseReductionThresholdContainer.bottom;
|
||||||
|
anchors.topMargin: 14;
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: inputDeviceHeader
|
id: inputDeviceHeader
|
||||||
x: margins.paddings;
|
x: margins.paddings;
|
||||||
width: parent.width - margins.paddings*2;
|
width: parent.width - margins.paddings*2;
|
||||||
height: 36;
|
height: 36;
|
||||||
anchors.top: secondSeparator.bottom;
|
anchors.top: thirdSeparator.bottom;
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
|
|
||||||
HiFiGlyphs {
|
HiFiGlyphs {
|
||||||
|
@ -597,19 +821,19 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AudioControls.InputPeak {
|
AudioControls.InputPeak {
|
||||||
id: inputLevel
|
id: inputLevel
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
peak: model.peak;
|
peak: model.peak;
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: ((bar.currentIndex === 1 && isVR) ||
|
visible: ((bar.currentIndex === 1 && isVR) ||
|
||||||
(bar.currentIndex === 0 && !isVR)) &&
|
(bar.currentIndex === 0 && !isVR)) &&
|
||||||
AudioScriptingInterface.devices.input.peakValuesAvailable;
|
AudioScriptingInterface.devices.input.peakValuesAvailable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
id: thirdSeparator;
|
id: fourthSeparator;
|
||||||
anchors.top: inputView.bottom;
|
anchors.top: inputView.bottom;
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
}
|
}
|
||||||
|
@ -617,7 +841,7 @@ Rectangle {
|
||||||
Item {
|
Item {
|
||||||
id: outputDeviceHeader;
|
id: outputDeviceHeader;
|
||||||
anchors.topMargin: 10;
|
anchors.topMargin: 10;
|
||||||
anchors.top: thirdSeparator.bottom;
|
anchors.top: fourthSeparator.bottom;
|
||||||
x: margins.paddings;
|
x: margins.paddings;
|
||||||
width: parent.width - margins.paddings*2
|
width: parent.width - margins.paddings*2
|
||||||
height: 36
|
height: 36
|
||||||
|
|
|
@ -25,6 +25,8 @@ QString Audio::DESKTOP { "Desktop" };
|
||||||
QString Audio::HMD { "VR" };
|
QString Audio::HMD { "VR" };
|
||||||
|
|
||||||
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
|
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
|
||||||
|
Setting::Handle<bool> enableNoiseReductionAutomaticSetting { QStringList { Audio::AUDIO, "NoiseReductionAutomatic" }, true };
|
||||||
|
Setting::Handle<float> setNoiseReductionThresholdSetting { QStringList { Audio::AUDIO, "NoiseReductionThreshold" }, 0.1f };
|
||||||
Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true };
|
Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true };
|
||||||
Setting::Handle<bool> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true };
|
Setting::Handle<bool> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true };
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ Audio::Audio() : _devices(_contextIsHMD) {
|
||||||
auto client = DependencyManager::get<AudioClient>().data();
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
|
connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
|
||||||
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction);
|
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::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted);
|
||||||
connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation);
|
connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation);
|
||||||
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
|
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::contextChanged, &_devices, &AudioDevices::onContextChanged);
|
||||||
connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk);
|
connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk);
|
||||||
enableNoiseReduction(enableNoiseReductionSetting.get());
|
enableNoiseReduction(enableNoiseReductionSetting.get());
|
||||||
|
enableNoiseReductionAutomatic(enableNoiseReductionAutomaticSetting.get());
|
||||||
|
setNoiseReductionThreshold(setNoiseReductionThresholdSetting.get());
|
||||||
enableWarnWhenMuted(enableWarnWhenMutedSetting.get());
|
enableWarnWhenMuted(enableWarnWhenMutedSetting.get());
|
||||||
enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get());
|
enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get());
|
||||||
onContextChanged();
|
onContextChanged();
|
||||||
|
@ -286,6 +292,50 @@ void Audio::enableNoiseReduction(bool enable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Audio::noiseReductionAutomatic() const {
|
||||||
|
return resultWithReadLock<bool>([&] {
|
||||||
|
return _noiseReductionAutomatic;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::enableNoiseReductionAutomatic(bool enable) {
|
||||||
|
bool changed = false;
|
||||||
|
withWriteLock([&] {
|
||||||
|
if (_noiseReductionAutomatic != enable) {
|
||||||
|
_noiseReductionAutomatic = enable;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().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() {
|
||||||
|
return resultWithReadLock<float>([&] {
|
||||||
|
return _noiseReductionThreshold;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::setNoiseReductionThreshold(float threshold) {
|
||||||
|
bool changed = false;
|
||||||
|
withWriteLock([&] {
|
||||||
|
if (_noiseReductionThreshold != threshold) {
|
||||||
|
_noiseReductionThreshold = threshold;
|
||||||
|
auto client = DependencyManager::get<AudioClient>().data();
|
||||||
|
QMetaObject::invokeMethod(client, "setNoiseReductionThreshold", Q_ARG(float, threshold), Q_ARG(bool, false));
|
||||||
|
setNoiseReductionThresholdSetting.set(threshold);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (changed) {
|
||||||
|
emit noiseReductionThresholdChanged(threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Audio::warnWhenMutedEnabled() const {
|
bool Audio::warnWhenMutedEnabled() const {
|
||||||
return resultWithReadLock<bool>([&] {
|
return resultWithReadLock<bool>([&] {
|
||||||
return _enableWarnWhenMuted;
|
return _enableWarnWhenMuted;
|
||||||
|
|
|
@ -50,6 +50,11 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
* @property {boolean} noiseReduction - <code>true</code> if noise reduction is enabled, otherwise <code>false</code>. When
|
||||||
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||||
* above the noise floor.
|
* above the noise floor.
|
||||||
|
* @property {boolean} noiseReductionAutomatic - <code>true</code> if audio input noise reduction automatic mode is enabled,
|
||||||
|
* <code>false</code> if in manual mode. Manual mode allows you to use <code>Audio.noiseReductionThreshold</code>
|
||||||
|
* to set a manual sensitivity for the noise gate.
|
||||||
|
* @property {number} noiseReductionThreshold - Sets the noise gate threshold before your mic audio is transmitted.
|
||||||
|
* (Applies only if <code>Audio.noiseReductionAutomatic</code> is <code>false</code>.)
|
||||||
* @property {number} inputVolume - Adjusts the volume of the input audio, range <code>0.0</code> – <code>1.0</code>.
|
* @property {number} inputVolume - Adjusts the volume of the input audio, range <code>0.0</code> – <code>1.0</code>.
|
||||||
* If set to a value, the resulting value depends on the input device: for example, the volume can't be changed on some
|
* If set to a value, the resulting value depends on the input device: for example, the volume can't be changed on some
|
||||||
* devices, and others might only support values of <code>0.0</code> and <code>1.0</code>.
|
* devices, and others might only support values of <code>0.0</code> and <code>1.0</code>.
|
||||||
|
@ -92,6 +97,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
|
||||||
|
|
||||||
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
|
||||||
Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY noiseReductionChanged)
|
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 warnWhenMuted READ warnWhenMutedEnabled WRITE enableWarnWhenMuted NOTIFY warnWhenMutedChanged)
|
||||||
Q_PROPERTY(bool acousticEchoCancellation
|
Q_PROPERTY(bool acousticEchoCancellation
|
||||||
READ acousticEchoCancellationEnabled WRITE enableAcousticEchoCancellation NOTIFY acousticEchoCancellationChanged)
|
READ acousticEchoCancellationEnabled WRITE enableAcousticEchoCancellation NOTIFY acousticEchoCancellationChanged)
|
||||||
|
@ -124,6 +131,7 @@ public:
|
||||||
|
|
||||||
bool isMuted() const;
|
bool isMuted() const;
|
||||||
bool noiseReductionEnabled() const;
|
bool noiseReductionEnabled() const;
|
||||||
|
bool noiseReductionAutomatic() const;
|
||||||
bool warnWhenMutedEnabled() const;
|
bool warnWhenMutedEnabled() const;
|
||||||
bool acousticEchoCancellationEnabled() const;
|
bool acousticEchoCancellationEnabled() const;
|
||||||
float getInputVolume() const;
|
float getInputVolume() const;
|
||||||
|
@ -271,6 +279,20 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE float getSystemInjectorGain();
|
Q_INVOKABLE float getSystemInjectorGain();
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Sets the noise gate threshold before your mic audio is transmitted. (Applies only if <code>Audio.noiseReductionAutomatic</code> is <code>false</code>.)
|
||||||
|
* @function Audio.setNoiseReductionThreshold
|
||||||
|
* @param {number} threshold - The level that your input must surpass to be transmitted. <code>0.0</code> (open the gate completely) – <code>1.0</code>
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void setNoiseReductionThreshold(float threshold);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Gets the noise reduction threshold.
|
||||||
|
* @function Audio.getNoiseReductionThreshold
|
||||||
|
* @returns {number} The noise reduction threshold. <code>0.0</code> – <code>1.0</code>
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE float getNoiseReductionThreshold();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format.
|
* Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format.
|
||||||
* @function Audio.startRecording
|
* @function Audio.startRecording
|
||||||
|
@ -399,6 +421,23 @@ signals:
|
||||||
*/
|
*/
|
||||||
void noiseReductionChanged(bool isEnabled);
|
void noiseReductionChanged(bool isEnabled);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Triggered when the audio input noise reduction mode is changed.
|
||||||
|
* @function Audio.noiseReductionAutomaticChanged
|
||||||
|
* @param {boolean} isEnabled - <code>true</code> if audio input noise reduction automatic mode is enabled, <code>false</code> if in manual mode.
|
||||||
|
* @returns {Signal}
|
||||||
|
*/
|
||||||
|
void noiseReductionAutomaticChanged(bool isEnabled);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Triggered when the audio input noise reduction threshold is changed.
|
||||||
|
* @function Audio.noiseReductionThresholdChanged
|
||||||
|
* @param {number} threshold - The threshold for the audio input noise reduction, range <code>0.0</code> (open the gate completely) – <code>1.0</code>
|
||||||
|
* (close the gate completely).
|
||||||
|
* @returns {Signal}
|
||||||
|
*/
|
||||||
|
void noiseReductionThresholdChanged(float threshold);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Triggered when "warn when muted" is enabled or disabled.
|
* Triggered when "warn when muted" is enabled or disabled.
|
||||||
* @function Audio.warnWhenMutedChanged
|
* @function Audio.warnWhenMutedChanged
|
||||||
|
@ -512,6 +551,7 @@ public slots:
|
||||||
private slots:
|
private slots:
|
||||||
void setMuted(bool muted);
|
void setMuted(bool muted);
|
||||||
void enableNoiseReduction(bool enable);
|
void enableNoiseReduction(bool enable);
|
||||||
|
void enableNoiseReductionAutomatic(bool enable);
|
||||||
void enableWarnWhenMuted(bool enable);
|
void enableWarnWhenMuted(bool enable);
|
||||||
void enableAcousticEchoCancellation(bool enable);
|
void enableAcousticEchoCancellation(bool enable);
|
||||||
void setInputVolume(float volume);
|
void setInputVolume(float volume);
|
||||||
|
@ -533,8 +573,10 @@ private:
|
||||||
float _localInjectorGain { 0.0f }; // in dB
|
float _localInjectorGain { 0.0f }; // in dB
|
||||||
float _systemInjectorGain { 0.0f }; // in dB
|
float _systemInjectorGain { 0.0f }; // in dB
|
||||||
float _pttOutputGainDesktop { 0.0f }; // in dB
|
float _pttOutputGainDesktop { 0.0f }; // in dB
|
||||||
|
float _noiseReductionThreshold { 0.1f }; // Match default value of AudioClient::_noiseReductionThreshold.
|
||||||
bool _isClipping { false };
|
bool _isClipping { false };
|
||||||
bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled.
|
bool _enableNoiseReduction { true }; // Match default value of AudioClient::_isNoiseGateEnabled.
|
||||||
|
bool _noiseReductionAutomatic { true }; // Match default value of AudioClient::_noiseReductionAutomatic.
|
||||||
bool _enableWarnWhenMuted { true };
|
bool _enableWarnWhenMuted { true };
|
||||||
bool _enableAcousticEchoCancellation { true }; // AudioClient::_isAECEnabled
|
bool _enableAcousticEchoCancellation { true }; // AudioClient::_isAECEnabled
|
||||||
bool _contextIsHMD { false };
|
bool _contextIsHMD { false };
|
||||||
|
|
|
@ -1266,7 +1266,7 @@ void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numC
|
||||||
void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
// If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
|
// If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
|
||||||
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
|
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
|
||||||
if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb)) {
|
if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb) || !_audioGateOpen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
if (!_audioPaused) {
|
if (!_audioPaused) {
|
||||||
|
|
||||||
|
@ -1352,9 +1359,14 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
|
|
||||||
if (_isNoiseGateEnabled) {
|
if (_isNoiseGateEnabled && _isNoiseReductionAutomatic) {
|
||||||
// The audio gate includes DC removal
|
// The audio gate includes DC removal
|
||||||
audioGateOpen = _audioGate->render(samples, samples, numFrames);
|
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 {
|
} else {
|
||||||
audioGateOpen = _audioGate->removeDC(samples, samples, numFrames);
|
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) {
|
void AudioClient::setWarnWhenMuted(bool enable, bool emitSignal) {
|
||||||
if (_warnWhenMuted != enable) {
|
if (_warnWhenMuted != enable) {
|
||||||
_warnWhenMuted = enable;
|
_warnWhenMuted = enable;
|
||||||
|
|
|
@ -218,6 +218,12 @@ public slots:
|
||||||
void setNoiseReduction(bool isNoiseGateEnabled, bool emitSignal = true);
|
void setNoiseReduction(bool isNoiseGateEnabled, bool emitSignal = true);
|
||||||
bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; }
|
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);
|
void setWarnWhenMuted(bool isNoiseGateEnabled, bool emitSignal = true);
|
||||||
bool isWarnWhenMutedEnabled() const { return _warnWhenMuted; }
|
bool isWarnWhenMutedEnabled() const { return _warnWhenMuted; }
|
||||||
|
|
||||||
|
@ -265,6 +271,8 @@ signals:
|
||||||
void inputVolumeChanged(float volume);
|
void inputVolumeChanged(float volume);
|
||||||
void muteToggled(bool muted);
|
void muteToggled(bool muted);
|
||||||
void noiseReductionChanged(bool noiseReductionEnabled);
|
void noiseReductionChanged(bool noiseReductionEnabled);
|
||||||
|
void noiseReductionAutomaticChanged(bool noiseReductionAutomatic);
|
||||||
|
void noiseReductionThresholdChanged(bool noiseReductionThreshold);
|
||||||
void warnWhenMutedChanged(bool warnWhenMutedEnabled);
|
void warnWhenMutedChanged(bool warnWhenMutedEnabled);
|
||||||
void acousticEchoCancellationChanged(bool acousticEchoCancellationEnabled);
|
void acousticEchoCancellationChanged(bool acousticEchoCancellationEnabled);
|
||||||
void mutedByMixer();
|
void mutedByMixer();
|
||||||
|
@ -310,6 +318,8 @@ private:
|
||||||
friend class CheckDevicesThread;
|
friend class CheckDevicesThread;
|
||||||
friend class LocalInjectorsThread;
|
friend class LocalInjectorsThread;
|
||||||
|
|
||||||
|
float loudnessToLevel(float loudness);
|
||||||
|
|
||||||
// background tasks
|
// background tasks
|
||||||
void checkDevices();
|
void checkDevices();
|
||||||
void checkPeakValues();
|
void checkPeakValues();
|
||||||
|
@ -397,6 +407,8 @@ private:
|
||||||
bool _shouldEchoLocally{ false };
|
bool _shouldEchoLocally{ false };
|
||||||
bool _shouldEchoToServer{ false };
|
bool _shouldEchoToServer{ false };
|
||||||
bool _isNoiseGateEnabled{ true };
|
bool _isNoiseGateEnabled{ true };
|
||||||
|
bool _isNoiseReductionAutomatic{ true };
|
||||||
|
float _noiseReductionThreshold{ 0.1f };
|
||||||
bool _warnWhenMuted;
|
bool _warnWhenMuted;
|
||||||
bool _isAECEnabled{ true };
|
bool _isAECEnabled{ true };
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue