mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 23:12:36 +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.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import stylesUit 1.0
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
|
@ -104,6 +105,11 @@ Rectangle {
|
|||
AudioScriptingInterface.setSystemInjectorGain(sliderValue);
|
||||
}
|
||||
}
|
||||
function updateNoiseReductionThresholdFromQML(sliderValue) {
|
||||
if (AudioScriptingInterface.getNoiseReductionThreshold() !== sliderValue) {
|
||||
AudioScriptingInterface.setNoiseReductionThreshold(sliderValue);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
enablePeakValues();
|
||||
|
@ -164,7 +170,7 @@ Rectangle {
|
|||
x: 2 * margins.paddings;
|
||||
width: parent.width;
|
||||
// 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.topMargin: 10;
|
||||
|
||||
|
@ -175,6 +181,7 @@ Rectangle {
|
|||
height: parent.height;
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left;
|
||||
|
||||
HifiControlsUit.Switch {
|
||||
id: muteMic;
|
||||
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 {
|
||||
id: pttSwitch
|
||||
height: root.switchHeight;
|
||||
switchWidth: root.switchWidth;
|
||||
anchors.top: acousticEchoCancellationSwitch.bottom;
|
||||
anchors.top: muteMic.bottom;
|
||||
anchors.topMargin: 24
|
||||
anchors.left: parent.left
|
||||
labelTextOn: (bar.currentIndex === 0) ? qsTr("Push To Talk (T)") : qsTr("Push To Talk");
|
||||
|
@ -254,6 +227,7 @@ Rectangle {
|
|||
height: parent.height;
|
||||
anchors.top: parent.top
|
||||
anchors.left: switchContainer.right;
|
||||
|
||||
HifiControlsUit.Switch {
|
||||
id: warnMutedSwitch
|
||||
height: root.switchHeight;
|
||||
|
@ -271,7 +245,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
HifiControlsUit.Switch {
|
||||
id: audioLevelSwitch
|
||||
height: root.switchHeight;
|
||||
|
@ -519,13 +492,264 @@ Rectangle {
|
|||
anchors.top: systemInjectorGainContainer.bottom;
|
||||
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 {
|
||||
id: inputDeviceHeader
|
||||
x: margins.paddings;
|
||||
width: parent.width - margins.paddings*2;
|
||||
height: 36;
|
||||
anchors.top: secondSeparator.bottom;
|
||||
anchors.top: thirdSeparator.bottom;
|
||||
anchors.topMargin: 10;
|
||||
|
||||
HiFiGlyphs {
|
||||
|
@ -597,19 +821,19 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
AudioControls.InputPeak {
|
||||
id: inputLevel
|
||||
anchors.right: parent.right
|
||||
peak: model.peak;
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: ((bar.currentIndex === 1 && isVR) ||
|
||||
(bar.currentIndex === 0 && !isVR)) &&
|
||||
AudioScriptingInterface.devices.input.peakValuesAvailable;
|
||||
id: inputLevel
|
||||
anchors.right: parent.right
|
||||
peak: model.peak;
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: ((bar.currentIndex === 1 && isVR) ||
|
||||
(bar.currentIndex === 0 && !isVR)) &&
|
||||
AudioScriptingInterface.devices.input.peakValuesAvailable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Separator {
|
||||
id: thirdSeparator;
|
||||
id: fourthSeparator;
|
||||
anchors.top: inputView.bottom;
|
||||
anchors.topMargin: 10;
|
||||
}
|
||||
|
@ -617,7 +841,7 @@ Rectangle {
|
|||
Item {
|
||||
id: outputDeviceHeader;
|
||||
anchors.topMargin: 10;
|
||||
anchors.top: thirdSeparator.bottom;
|
||||
anchors.top: fourthSeparator.bottom;
|
||||
x: margins.paddings;
|
||||
width: parent.width - margins.paddings*2
|
||||
height: 36
|
||||
|
@ -684,4 +908,4 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ QString Audio::DESKTOP { "Desktop" };
|
|||
QString Audio::HMD { "VR" };
|
||||
|
||||
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> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true };
|
||||
|
||||
|
@ -40,6 +42,8 @@ Audio::Audio() : _devices(_contextIsHMD) {
|
|||
auto client = DependencyManager::get<AudioClient>().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<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 {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
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
|
||||
* enabled, the input audio signal is blocked (fully attenuated) when it falls below an adaptive threshold set just
|
||||
* 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>.
|
||||
* 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>.
|
||||
|
@ -92,6 +97,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 +131,7 @@ public:
|
|||
|
||||
bool isMuted() const;
|
||||
bool noiseReductionEnabled() const;
|
||||
bool noiseReductionAutomatic() const;
|
||||
bool warnWhenMutedEnabled() const;
|
||||
bool acousticEchoCancellationEnabled() const;
|
||||
float getInputVolume() const;
|
||||
|
@ -270,6 +278,20 @@ public:
|
|||
* @returns {number} The injector gain (dB) in the client.
|
||||
*/
|
||||
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
|
||||
* Starts making an audio recording of the audio being played in-world (i.e., not local-only audio) to a file in WAV format.
|
||||
|
@ -398,6 +420,23 @@ signals:
|
|||
* @returns {Signal}
|
||||
*/
|
||||
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
|
||||
* Triggered when "warn when muted" is enabled or disabled.
|
||||
|
@ -512,6 +551,7 @@ public slots:
|
|||
private slots:
|
||||
void setMuted(bool muted);
|
||||
void enableNoiseReduction(bool enable);
|
||||
void enableNoiseReductionAutomatic(bool enable);
|
||||
void enableWarnWhenMuted(bool enable);
|
||||
void enableAcousticEchoCancellation(bool enable);
|
||||
void setInputVolume(float volume);
|
||||
|
@ -533,8 +573,10 @@ private:
|
|||
float _localInjectorGain { 0.0f }; // in dB
|
||||
float _systemInjectorGain { 0.0f }; // in dB
|
||||
float _pttOutputGainDesktop { 0.0f }; // in dB
|
||||
float _noiseReductionThreshold { 0.1f }; // 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 };
|
||||
|
|
|
@ -1266,7 +1266,7 @@ void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numC
|
|||
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.
|
||||
bool hasReverb = _reverb || _receivedAudioStream.hasReverb();
|
||||
if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb)) {
|
||||
if ((_muted && !_shouldEchoLocally) || !_audioOutput || (!_shouldEchoLocally && !hasReverb) || !_audioGateOpen) {
|
||||
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) {
|
||||
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;
|
||||
|
|
|
@ -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.1f };
|
||||
bool _warnWhenMuted;
|
||||
bool _isAECEnabled{ true };
|
||||
|
||||
|
|
Loading…
Reference in a new issue