From b37a0239b07220c3f7c5730fe33c12d6aeb1425c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 12 Jun 2017 18:00:52 -0400 Subject: [PATCH] up to reverb (needs cherry-picking) --- .../resources/qml/controls-uit/CheckBox.qml | 3 +- .../qml/dialogs/PreferencesDialog.qml | 3 - interface/resources/qml/hifi/Audio.qml | 279 ------------------ interface/resources/qml/hifi/audio/Audio.qml | 146 +++++++++ .../resources/qml/hifi/audio/CheckBox.qml | 18 ++ .../qml/hifi/components/AudioCheckbox.qml | 30 -- .../resources/qml/hifi/dialogs/Audio.qml | 37 ++- .../resources/qml/hifi/tablet/TabletRoot.qml | 2 +- .../resources/qml/hifi/tablet/WindowRoot.qml | 2 +- interface/resources/qml/hifi/tester.sh | 2 +- .../resources/qml/styles-uit/Separator.qml | 3 + interface/src/Application.cpp | 36 ++- interface/src/Application.h | 2 - interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 3 - interface/src/scripting/Audio.cpp | 91 +++++- interface/src/scripting/Audio.h | 43 ++- interface/src/scripting/AudioDevices.cpp | 39 ++- interface/src/scripting/AudioDevices.h | 9 +- interface/src/ui/AvatarInputs.cpp | 16 +- interface/src/ui/AvatarInputs.h | 2 +- libraries/audio-client/src/AudioClient.h | 7 +- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 1 + scripts/system/audio.js | 2 +- 24 files changed, 386 insertions(+), 392 deletions(-) delete mode 100644 interface/resources/qml/hifi/Audio.qml create mode 100644 interface/resources/qml/hifi/audio/Audio.qml create mode 100644 interface/resources/qml/hifi/audio/CheckBox.qml delete mode 100644 interface/resources/qml/hifi/components/AudioCheckbox.qml diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 916a7d4889..d6dc5d2736 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -18,6 +18,7 @@ Original.CheckBox { id: checkBox property int colorScheme: hifi.colorSchemes.light + property string color: hifi.colors.lightGray readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property bool isRedCheck: false property int boxSize: 14 @@ -89,7 +90,7 @@ Original.CheckBox { label: Label { text: control.text - colorScheme: checkBox.colorScheme + color: control.color x: 2 wrapMode: Text.Wrap enabled: checkBox.enabled diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 71d1a20f85..e16f3aa12d 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -25,7 +25,6 @@ ScrollingWindow { height: 577 property var sections: [] property var showCategories: [] - property bool showFooter: true minSize: Qt.vector2d(400, 500) HifiConstants { id: hifi } @@ -95,8 +94,6 @@ ScrollingWindow { } footer: Row { - visible: root.showFooter - anchors { top: parent.top right: parent.right diff --git a/interface/resources/qml/hifi/Audio.qml b/interface/resources/qml/hifi/Audio.qml deleted file mode 100644 index 12bf0afe65..0000000000 --- a/interface/resources/qml/hifi/Audio.qml +++ /dev/null @@ -1,279 +0,0 @@ -// -// Audio.qml -// qml/hifi -// -// Audio setup -// -// Created by Vlad Stelmahovsky on 03/22/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtGraphicalEffects 1.0 - -import "../styles-uit" -import "../controls-uit" as HifiControls -import "../windows" - -import "components" - -Rectangle { - id: audio; - - HifiConstants { id: hifi; } - - property var eventBridge; - property string title: "Audio Settings" - signal sendToScript(var message); - - color: "#404040"; - - Text { - text: "ZZMP" - } - - ListView { - model: Audio.devices.input - } -} - -/* -Rectangle { - id: audio; - - //put info text here - property alias infoText: infoArea.text - - color: "#404040"; - - HifiConstants { id: hifi; } - objectName: "AudioWindow" - - property var eventBridge; - property string title: "Audio Options" - signal sendToScript(var message); - - - Component { - id: separator - LinearGradient { - start: Qt.point(0, 0) - end: Qt.point(0, 4) - gradient: Gradient { - GradientStop { position: 0.0; color: "#303030" } - GradientStop { position: 0.33; color: "#252525" } // Equivalent of darkGray0 over baseGray background. - GradientStop { position: 0.5; color: "#303030" } - GradientStop { position: 0.6; color: "#454a49" } - GradientStop { position: 1.0; color: "#454a49" } - } - cached: true - } - } - - Column { - anchors { left: parent.left; right: parent.right } - spacing: 8 - - RalewayRegular { - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - height: 45 - size: 20 - color: "white" - text: audio.title - } - - Loader { - width: parent.width - height: 5 - sourceComponent: separator - } - - //connections required to syncronize with Menu - Connections { - target: AudioDevice - onMuteToggled: { - audioMute.checkbox.checked = AudioDevice.getMuted() - } - } - - Connections { - target: AvatarInputs !== undefined ? AvatarInputs : null - onShowAudioToolsChanged: { - audioTools.checkbox.checked = showAudioTools - } - } - - AudioCheckbox { - id: audioMute - width: parent.width - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - checkbox.checked: AudioDevice.muted - text.text: qsTr("Mute microphone") - onCheckBoxClicked: { - AudioDevice.muted = checked - } - } - - AudioCheckbox { - id: audioTools - width: parent.width - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - checkbox.checked: AvatarInputs !== undefined ? AvatarInputs.showAudioTools : false - text.text: qsTr("Show audio level meter") - onCheckBoxClicked: { - if (AvatarInputs !== undefined) { - AvatarInputs.showAudioTools = checked - } - } - } - - Loader { - width: parent.width - height: 5 - sourceComponent: separator - } - - Row { - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - height: 40 - spacing: 8 - - HiFiGlyphs { - text: hifi.glyphs.mic - color: hifi.colors.primaryHighlight - anchors.verticalCenter: parent.verticalCenter - size: 32 - } - RalewayRegular { - anchors.verticalCenter: parent.verticalCenter - size: 16 - color: "#AFAFAF" - text: qsTr("CHOOSE INPUT DEVICE") - } - } - - ListView { - id: inputAudioListView - anchors { left: parent.left; right: parent.right; leftMargin: 70 } - height: 125 - spacing: 0 - clip: true - snapMode: ListView.SnapToItem - model: AudioDevice - delegate: Item { - width: parent.width - visible: devicemode === 0 - height: visible ? 36 : 0 - - AudioCheckbox { - id: cbin - anchors.verticalCenter: parent.verticalCenter - Binding { - target: cbin.checkbox - property: 'checked' - value: devicechecked - } - - width: parent.width - cbchecked: devicechecked - text.text: devicename - onCheckBoxClicked: { - if (checked) { - AudioDevice.setInputDeviceAsync(devicename) - } - } - } - } - } - - Loader { - width: parent.width - height: 5 - sourceComponent: separator - } - - Row { - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - height: 40 - spacing: 8 - - HiFiGlyphs { - text: hifi.glyphs.unmuted - color: hifi.colors.primaryHighlight - anchors.verticalCenter: parent.verticalCenter - size: 32 - } - RalewayRegular { - anchors.verticalCenter: parent.verticalCenter - size: 16 - color: "#AFAFAF" - text: qsTr("CHOOSE OUTPUT DEVICE") - } - } - - ListView { - id: outputAudioListView - anchors { left: parent.left; right: parent.right; leftMargin: 70 } - height: 250 - spacing: 0 - clip: true - snapMode: ListView.SnapToItem - model: AudioDevice - delegate: Item { - width: parent.width - visible: devicemode === 1 - height: visible ? 36 : 0 - AudioCheckbox { - id: cbout - width: parent.width - anchors.verticalCenter: parent.verticalCenter - Binding { - target: cbout.checkbox - property: 'checked' - value: devicechecked - } - text.text: devicename - onCheckBoxClicked: { - if (checked) { - AudioDevice.setOutputDeviceAsync(devicename) - } - } - } - } - } - - Loader { - id: lastSeparator - width: parent.width - height: 6 - sourceComponent: separator - } - - Row { - anchors { left: parent.left; right: parent.right; leftMargin: 30 } - height: 40 - spacing: 8 - - HiFiGlyphs { - id: infoSign - text: hifi.glyphs.info - color: "#AFAFAF" - anchors.verticalCenter: parent.verticalCenter - size: 60 - } - RalewayRegular { - id: infoArea - width: parent.width - infoSign.implicitWidth - parent.spacing - 10 - wrapMode: Text.WordWrap - anchors.verticalCenter: parent.verticalCenter - size: 12 - color: hifi.colors.baseGrayHighlight - } - } - } -} -*/ diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml new file mode 100644 index 0000000000..2bb1ea5864 --- /dev/null +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -0,0 +1,146 @@ +// +// Audio.qml +// qml/hifi/audio +// +// Audio setup +// +// Created by Vlad Stelmahovsky on 03/22/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 + +import "../../styles-uit" +import "../../controls-uit" as HifiControls +import "../../windows" +import "./" as Audio + +Rectangle { + id: audio; + + HifiConstants { id: hifi; } + + property var eventBridge; + property string title: "Audio Settings - " + Audio.context + signal sendToScript(var message); + + color: hifi.colors.baseGray; + + Column { + y: 16 // padding does not work + spacing: 16 + width: parent.width + + Grid { + columns: 2 + x: 16 // padding does not work + spacing: 16 + + Audio.CheckBox { + text: qsTr("Mute microphone"); + checked: Audio.muted + onClicked: { + Audio.muted = checked; + checked = Qt.binding(function() { return Audio.muted; }); // restore binding + } + } + Audio.CheckBox { + text: qsTr("Enable noise reduction"); + checked: Audio.noiseReduction + onClicked: { + Audio.noiseReduction = checked; + checked = Qt.binding(function() { return Audio.noiseReduction; }); // restore binding + } + } + Audio.CheckBox { + text: qsTr("Show audio level meter"); + checked: Audio.showMicMeter + onClicked: { + Audio.showMicMeter = checked; + checked = Qt.binding(function() { return Audio.showMicMeter; }); // restore binding + } + } + } + + Separator {} + + RowLayout { + HiFiGlyphs { + text: hifi.glyphs.mic + color: hifi.colors.primaryHighlight + anchors.verticalCenter: parent.verticalCenter + size: 28 + } + RalewayRegular { + anchors.verticalCenter: parent.verticalCenter + size: 16 + color: "#AFAFAF" + text: qsTr("CHOOSE INPUT DEVICE") + } + } + + ListView { + anchors { left: parent.left; right: parent.right; leftMargin: 70 } + height: 125 + spacing: 0 + snapMode: ListView.SnapToItem + clip: true + model: Audio.devices.input + delegate: Item { + width: parent.width + height: 36 + Audio.CheckBox { + text: display; + checked: selected + onClicked: { + selected = checked; + checked = Qt.binding(function() { return selected; }); // restore binding + } + } + } + } + + Separator {} + + RowLayout { + HiFiGlyphs { + text: hifi.glyphs.unmuted + color: hifi.colors.primaryHighlight + anchors.verticalCenter: parent.verticalCenter + size: 36 + } + RalewayRegular { + anchors.verticalCenter: parent.verticalCenter + size: 16 + color: "#AFAFAF" + text: qsTr("CHOOSE OUTPUT DEVICE") + } + } + + ListView { + anchors { left: parent.left; right: parent.right; leftMargin: 70 } + height: 125 + spacing: 0 + snapMode: ListView.SnapToItem + clip: true + model: Audio.devices.output + delegate: Item { + width: parent.width + height: 36 + Audio.CheckBox { + text: display; + checked: selected + onClicked: { + selected = checked; + checked = Qt.binding(function() { return selected; }); // restore binding + } + } + } + } + } +} diff --git a/interface/resources/qml/hifi/audio/CheckBox.qml b/interface/resources/qml/hifi/audio/CheckBox.qml new file mode 100644 index 0000000000..1f632ac479 --- /dev/null +++ b/interface/resources/qml/hifi/audio/CheckBox.qml @@ -0,0 +1,18 @@ +// +// CheckBox.qml +// qml/hifi/audio +// +// Created by Zach Pomerantz on 6/12/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 + +import "../../controls-uit" as HifiControls + +HifiControls.CheckBox { + color: "white" +} diff --git a/interface/resources/qml/hifi/components/AudioCheckbox.qml b/interface/resources/qml/hifi/components/AudioCheckbox.qml deleted file mode 100644 index b037fe4c7d..0000000000 --- a/interface/resources/qml/hifi/components/AudioCheckbox.qml +++ /dev/null @@ -1,30 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "../../styles-uit" -import "../../controls-uit" as HifiControls - -Row { - id: row - spacing: 16 - property alias checkbox: cb - property alias cbchecked: cb.checked - property alias text: txt - signal checkBoxClicked(bool checked) - - HifiControls.CheckBox { - id: cb - boxSize: 20 - colorScheme: hifi.colorSchemes.dark - anchors.verticalCenter: parent.verticalCenter - onClicked: checkBoxClicked(cb.checked) - } - RalewayBold { - id: txt - wrapMode: Text.WordWrap - width: parent.width - cb.boxSize - 30 - anchors.verticalCenter: parent.verticalCenter - size: 16 - color: "white" - } -} diff --git a/interface/resources/qml/hifi/dialogs/Audio.qml b/interface/resources/qml/hifi/dialogs/Audio.qml index 0b3620f12e..cd8ab5d742 100644 --- a/interface/resources/qml/hifi/dialogs/Audio.qml +++ b/interface/resources/qml/hifi/dialogs/Audio.qml @@ -1,21 +1,26 @@ -import QtQuick 2.5 -import Qt.labs.settings 1.0 +// +// Audio.qml +// +// Created by Zach Pomerantz on 6/12/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// -import "../../dialogs" -import "../" +import "../../windows" +import "../audio" -PreferencesDialog { - id: root +ScrollingWindow { + resizable: true + destroyOnHidden: true + width: 400 + height: 577 + minSize: Qt.vector2d(400, 500) + + id: audio objectName: "AudioDialog" - title: "Audio Settings" - showFooter: false - property var settings: Settings { - category: root.objectName - property alias x: root.x - property alias y: root.y - property alias width: root.width - property alias height: root.height - } + title: "Audio Settings - " + Audio.context - Audio {} + Audio { width: audio.width } } diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 33af7da1ae..fca445d5ba 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -151,7 +151,7 @@ Item { } function toggleMicEnabled() { - ApplicationInterface.toggleMuteAudio(); + Audio.mute = !Audio.mute; } function setUsername(newUsername) { diff --git a/interface/resources/qml/hifi/tablet/WindowRoot.qml b/interface/resources/qml/hifi/tablet/WindowRoot.qml index 470fd4a830..2f4b56f9cb 100644 --- a/interface/resources/qml/hifi/tablet/WindowRoot.qml +++ b/interface/resources/qml/hifi/tablet/WindowRoot.qml @@ -73,7 +73,7 @@ Windows.ScrollingWindow { } function toggleMicEnabled() { - ApplicationInterface.toggleMuteAudio(); + Audio.mute = !Audio.mute; } function setUsername(newUsername) { diff --git a/interface/resources/qml/hifi/tester.sh b/interface/resources/qml/hifi/tester.sh index 8b55fd204e..2f873445af 100644 --- a/interface/resources/qml/hifi/tester.sh +++ b/interface/resources/qml/hifi/tester.sh @@ -1,5 +1,5 @@ #!/bin/bash while sleep 5; do - cp ~/hifi/interface/resources/qml/hifi/Audio.qml ~/hifi/build/interface/Release/resources/qml/hifi/Audio.qml + cp ~/hifi/interface/resources/qml/hifi/audio/* ~/hifi/build/interface/Release/resources/qml/hifi/audio/ done diff --git a/interface/resources/qml/styles-uit/Separator.qml b/interface/resources/qml/styles-uit/Separator.qml index 5a775221f6..4134b928a7 100644 --- a/interface/resources/qml/styles-uit/Separator.qml +++ b/interface/resources/qml/styles-uit/Separator.qml @@ -14,6 +14,8 @@ import "../styles-uit" Item { // Size height: 2; + width: parent.width; + Rectangle { // Size width: parent.width; @@ -25,6 +27,7 @@ Item { // Style color: hifi.colors.baseGrayShadow; } + Rectangle { // Size width: parent.width; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0a05d85da3..297f44f87e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -725,7 +725,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start); connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit); connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater); - connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled); connect(audioIO.data(), &AudioClient::mutedByMixer, audioScriptingInterface.data(), &AudioScriptingInterface::mutedByMixer); connect(audioIO.data(), &AudioClient::receivedFirstPacket, audioScriptingInterface.data(), &AudioScriptingInterface::receivedFirstPacket); connect(audioIO.data(), &AudioClient::disconnected, audioScriptingInterface.data(), &AudioScriptingInterface::disconnected); @@ -741,6 +740,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioScriptingInterface->environmentMuted(); } }); + connect(this, &Application::activeDisplayPluginChanged, + reinterpret_cast(audioScriptingInterface.data()), &scripting::Audio::onChangedContext); audioThread->start(); @@ -824,6 +825,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); connect(this, &Application::activeDisplayPluginChanged, this, [](){ + bool isHMD = qApp->isHMDMode(); qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); }); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); @@ -1922,7 +1924,15 @@ void Application::initializeUi() { rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); - rootContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); + { + auto ai = AvatarInputs::getInstance(); + rootContext->setContextProperty("AvatarInputs", ai); + + // hook up audio + auto audio = reinterpret_cast(DependencyManager::get().data()); + connect(ai, &AvatarInputs::showAudioToolsChanged, audio, &scripting::Audio::onChangedMicMeter); + connect(audio, &scripting::Audio::changedMicMeter, ai, &AvatarInputs::setShowAudioTools); + } if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { rootContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); @@ -2221,12 +2231,6 @@ void Application::runTests() { runUnitTests(); } -void Application::audioMuteToggled() const { - QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteAudio); - Q_CHECK_PTR(muteAction); - muteAction->setChecked(DependencyManager::get()->isMuted()); -} - void Application::faceTrackerMuteToggled() { QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking); @@ -2765,6 +2769,12 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); break; + case Qt::Key_M: + if (isMeta) { + DependencyManager::get()->toggleMute(); + } + break; + case Qt::Key_N: if (!isOption && !isShifted && isMeta) { DependencyManager::get()->toggleIgnoreRadius(); @@ -4336,10 +4346,11 @@ void Application::update(float deltaTime) { } else { const quint64 MUTE_MICROPHONE_AFTER_USECS = 5000000; //5 secs Menu* menu = Menu::getInstance(); - if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !menu->isOptionChecked(MenuOption::MuteAudio)) { + auto audioClient = DependencyManager::get(); + if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { if (_lastFaceTrackerUpdate > 0 && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { - menu->triggerOption(MenuOption::MuteAudio); + audioClient->toggleMute(); _lastFaceTrackerUpdate = 0; } } else { @@ -6985,11 +6996,6 @@ void Application::updateSystemTabletMode() { } } -void Application::toggleMuteAudio() { - auto menu = Menu::getInstance(); - menu->setIsOptionChecked(MenuOption::MuteAudio, !menu->isOptionChecked(MenuOption::MuteAudio)); -} - OverlayID Application::getTabletScreenID() const { auto HMD = DependencyManager::get(); return HMD->getCurrentTabletScreenID(); diff --git a/interface/src/Application.h b/interface/src/Application.h index c567eff462..b5f96ca4af 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -390,7 +390,6 @@ public slots: void addAssetToWorldMessageClose(); - Q_INVOKABLE void toggleMuteAudio(); void loadLODToolsDialog(); void loadEntityStatisticsDialog(); void loadDomainConnectionDialog(); @@ -404,7 +403,6 @@ private slots: void resettingDomain(); - void audioMuteToggled() const; void faceTrackerMuteToggled(); void activeChanged(Qt::ApplicationState state); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 05b16bf872..e19457d484 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -290,7 +290,7 @@ Menu::Menu() { action = addActionToQMenuAndActionHash(settingsMenu, "Audio...", Qt::CTRL | Qt::Key_Z); connect(action, &QAction::triggered, [] { static const QUrl widgetUrl("hifi/dialogs/Audio.qml"); - static const QUrl tabletUrl("../../hifi/Audio.qml"); + static const QUrl tabletUrl("../../hifi/audio/Audio.qml"); static const QString name("AudioDialog"); qApp->showDialog(widgetUrl, tabletUrl, name); }); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b6d72f5446..5e597f1a0f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -36,7 +36,6 @@ namespace MenuOption { const QString AssetMigration = "ATP Asset Migration"; const QString AssetServer = "Asset Browser"; const QString Attachments = "Attachments..."; - const QString AudioNoiseReduction = "Noise Reduction"; const QString AudioScope = "Show Scope"; const QString AudioScopeFiftyFrames = "Fifty"; const QString AudioScopeFiveFrames = "Five"; @@ -44,7 +43,6 @@ namespace MenuOption { const QString AudioScopePause = "Pause Scope"; const QString AudioScopeTwentyFrames = "Twenty"; const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams"; - const QString AudioTools = "Show Level Meter"; const QString AutoMuteAudio = "Auto Mute Microphone"; const QString AvatarReceiveStats = "Show Receive Stats"; const QString AvatarBookmarks = "Avatar Bookmarks"; @@ -124,7 +122,6 @@ namespace MenuOption { const QString LogExtraTimings = "Log Extra Timing Details"; const QString LowVelocityFilter = "Low Velocity Filter"; const QString MeshVisible = "Draw Mesh"; - const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString MuteFaceTracking = "Mute Face Tracking"; const QString NamesAboveHeads = "Names Above Heads"; diff --git a/interface/src/scripting/Audio.cpp b/interface/src/scripting/Audio.cpp index 172fd00583..d7993ce468 100644 --- a/interface/src/scripting/Audio.cpp +++ b/interface/src/scripting/Audio.cpp @@ -11,11 +11,98 @@ #include "Audio.h" +#include "Application.h" +#include "AudioClient.h" +#include "ui/AvatarInputs.h" + using namespace scripting; static const QString DESKTOP_CONTEXT { "Desktop" }; static const QString HMD_CONTEXT { "VR" }; -QString Audio::getContext() { - return _contextIsHMD ? HMD_CONTEXT : DESKTOP_CONTEXT; +Audio::Audio() { + auto client = DependencyManager::get(); + connect(client.data(), &AudioClient::muteToggled, this, &Audio::onChangedMuted); + + connect(&_devices._inputs, &AudioDeviceList::deviceChanged, this, &Audio::onInputChanged); + + // TODO: make noise reduction sticky + // TODO: make mic meter sticky (need to reinitialize in AvatarInputs) +} + +void Audio::onChangedContext() { + bool isHMD = qApp->isHMDMode(); + if (_contextIsHMD != isHMD) { + _contextIsHMD = isHMD; + _devices.restoreDevices(_contextIsHMD); + emit changedContext(getContext()); + } +} + +QString Audio::getContext() const { + return _contextIsHMD ? HMD_CONTEXT : DESKTOP_CONTEXT; +} + +void Audio::onChangedMuted() { + auto client = DependencyManager::get().data(); + bool isMuted; + QMetaObject::invokeMethod(client, "isMuted", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, isMuted)); + + if (_isMuted != isMuted) { + _isMuted = isMuted; + emit changedMuted(_isMuted); + } +} + +void Audio::setMuted(bool isMuted) { + if (_isMuted != isMuted) { + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "toggleMute", Qt::BlockingQueuedConnection); + + _isMuted = isMuted; + emit changedMuted(_isMuted); + } +} + +void Audio::enableNoiseReduction(bool enable) { + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setNoiseReduction", Qt::BlockingQueuedConnection, Q_ARG(bool, enable)); + + _enableNoiseReduction = enable; + emit changedNoiseReduction(enable); +} + +void Audio::onChangedMicMeter(bool show) { + showMicMeter(show); +} + +void Audio::showMicMeter(bool show) { + if (_showMicMeter != show) { + _showMicMeter = show; + emit changedMicMeter(show); + } +} + +void Audio::setInputVolume(float volume) { + // getInputVolume will not reflect changes synchronously, so clamp beforehand + volume = glm::clamp(volume, 0.0f, 1.0f); + + if (_inputVolume != volume) { + auto client = DependencyManager::get().data(); + QMetaObject::invokeMethod(client, "setInputVolume", Qt::BlockingQueuedConnection, Q_ARG(float, volume)); + + _inputVolume = volume; + emit changedInputVolume(_inputVolume); + } +} + +void Audio::onInputChanged() { + auto client = DependencyManager::get().data(); + float volume; + QMetaObject::invokeMethod(client, "getInputVolume", Qt::BlockingQueuedConnection, Q_RETURN_ARG(float, volume)); + + if (_inputVolume != volume) { + _inputVolume = volume; + emit changedInputVolume(_inputVolume); + } } \ No newline at end of file diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index d0b5cbaf03..7daf98682e 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -21,11 +21,11 @@ class Audio : public AudioScriptingInterface { Q_OBJECT SINGLETON_DEPENDENCY - // TODO: Q_PROPERTY(bool mute) - // TODO: Q_PROPERTY(bool noiseReduction) - // TODO: Q_PROPERTY(bool reverb) - // TODO: Q_PROPERTY(float inputVolume) - // TODO: Q_PROPERTY(bool showMicLevel) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY changedMuted) + Q_PROPERTY(bool noiseReduction READ noiseReductionEnabled WRITE enableNoiseReduction NOTIFY changedNoiseReduction) + Q_PROPERTY(bool showMicMeter READ micMeterShown WRITE showMicMeter NOTIFY changedMicMeter) + // TODO: Q_PROPERTY(bool reverb READ getReverb WRITE setReverb NOTIFY changedReverb) + Q_PROPERTY(float inputVolume READ getInputVolume WRITE setInputVolume NOTIFY changedInputVolume) Q_PROPERTY(QString context READ getContext NOTIFY changedContext) Q_PROPERTY(AudioDevices* devices READ getDevices NOTIFY nop) @@ -34,18 +34,41 @@ public: signals: void nop(); + void changedMuted(bool); + void changedNoiseReduction(bool); + void changedMicMeter(bool); + void changedInputVolume(float); void changedContext(QString); -protected: - Audio() {} +public slots: + void onChangedMuted(); + void onChangedMicMeter(bool); + void onChangedContext(); + void onInputChanged(); - QString getContext(); +protected: + Audio(); private: + bool isMuted() const { return _isMuted; } + bool noiseReductionEnabled() const { return _enableNoiseReduction; } + bool micMeterShown() const { return _showMicMeter; } + float getInputVolume() const { return _inputVolume; } + QString getContext() const; + + void setMuted(bool muted); + void enableNoiseReduction(bool enable); + void showMicMeter(bool show); + void setInputVolume(float volume); + + float _inputVolume { 1.0f }; + bool _isMuted { false }; + bool _enableNoiseReduction { true }; + bool _showMicMeter { false }; + bool _contextIsHMD { false }; + AudioDevices* getDevices() { return &_devices; } AudioDevices _devices; - - bool _contextIsHMD { false }; }; }; diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 6a3fe396ef..7284383a28 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -10,6 +10,8 @@ // #include "AudioDevices.h" + +#include "Application.h" #include "AudioClient.h" using namespace scripting; @@ -75,40 +77,46 @@ bool AudioDeviceList::setData(const QModelIndex& index, const QVariant &value, i if (success) { device.selected = true; - emit dataChanged(index, index, { Qt::CheckStateRole }); + emit deviceChanged(); } } } + emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); return success; } void AudioDeviceList::setDevice(const QAudioDeviceInfo& device) { _selectedDevice = device; + QModelIndex index; for (auto i = 0; i < _devices.size(); ++i) { AudioDevice& device = _devices[i]; if (device.selected && device.info != _selectedDevice) { device.selected = false; - auto index = createIndex(i , 0); - emit dataChanged(index, index, { Qt::CheckStateRole }); - } else if (!device.selected && device.info == _selectedDevice) { + } else if (device.info == _selectedDevice) { device.selected = true; - auto index = createIndex(i , 0); - emit dataChanged(index, index, { Qt::CheckStateRole }); + index = createIndex(i, 0); } } + + emit deviceChanged(); + emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } void AudioDeviceList::populate(const QList& devices) { beginResetModel(); _devices.clear(); + _selectedDeviceIndex = QModelIndex(); + foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; - device.name = device.info.deviceName(); + device.name = device.info.deviceName() + .replace("High Definition", "HD") + .remove("Device"); device.selected = (device.info == _selectedDevice); _devices.push_back(device); } @@ -129,6 +137,10 @@ AudioDevices::AudioDevices() { _outputs.populate(client->getAudioDevices(QAudio::AudioOutput)); } +void AudioDevices::restoreDevices(bool isHMD) { + // TODO +} + void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device) { if (mode == QAudio::AudioInput) { _inputs.setDevice(device); @@ -138,9 +150,22 @@ void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& de } void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices) { + static bool initialized { false }; + auto initialize = [&]{ + if (initialized) { + restoreDevices(qApp->isHMDMode()); + } else { + initialized = true; + } + }; + if (mode == QAudio::AudioInput) { _inputs.populate(devices); + static std::once_flag inputFlag; + std::call_once(inputFlag, initialize); } else { // if (mode == QAudio::AudioOutput) _outputs.populate(devices); + static std::once_flag outputFlag; + std::call_once(outputFlag, initialize); } } \ No newline at end of file diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index 64832b9e57..9ba4a99bea 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -31,7 +31,7 @@ class AudioDeviceList : public QAbstractListModel { public: AudioDeviceList(QAudio::Mode mode); - int rowCount(const QModelIndex& parent) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role) const override; QHash roleNames() const override; Qt::ItemFlags flags(const QModelIndex& index) const override; @@ -40,12 +40,16 @@ public: void setDevice(const QAudioDeviceInfo& device); void populate(const QList& devices); +signals: + void deviceChanged(); + private: static QHash _roles; static Qt::ItemFlags _flags; QAudio::Mode _mode; QAudioDeviceInfo _selectedDevice; + QModelIndex _selectedDeviceIndex; QList _devices; }; @@ -56,6 +60,7 @@ class AudioDevices : public QObject { public: AudioDevices(); + void restoreDevices(bool isHMD); signals: void nop(); @@ -65,6 +70,8 @@ private slots: void onDevicesChanged(QAudio::Mode mode, const QList& devices); private: + friend class Audio; + AudioDeviceList* getInputList() { return &_inputs; } AudioDeviceList* getOutputList() { return &_outputs; } diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index 2b715eac9d..8236c9196f 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -43,16 +43,6 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { } \ } -#define AI_UPDATE_WRITABLE(name, src) \ - { \ - auto val = src; \ - if (_##name != val) { \ - _##name = val; \ - qDebug() << "AvatarInputs" << val; \ - emit name##Changed(val); \ - } \ - } - #define AI_UPDATE_FLOAT(name, src, epsilon) \ { \ float val = src; \ @@ -94,8 +84,6 @@ void AvatarInputs::update() { AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); AI_UPDATE(isHMD, qApp->isHMDMode()); - AI_UPDATE_WRITABLE(showAudioTools, Menu::getInstance()->isOptionChecked(MenuOption::AudioTools)); - auto audioIO = DependencyManager::get(); const float audioLevel = loudnessToAudioLevel(DependencyManager::get()->getLastInputLoudness()); @@ -122,8 +110,8 @@ void AvatarInputs::setShowAudioTools(bool showAudioTools) { if (_showAudioTools == showAudioTools) return; - Menu::getInstance()->setIsOptionChecked(MenuOption::AudioTools, showAudioTools); - update(); + _showAudioTools = showAudioTools; + emit showAudioToolsChanged(_showAudioTools); } void AvatarInputs::toggleCameraMute() { diff --git a/interface/src/ui/AvatarInputs.h b/interface/src/ui/AvatarInputs.h index bc9955a24f..ec6ff65789 100644 --- a/interface/src/ui/AvatarInputs.h +++ b/interface/src/ui/AvatarInputs.h @@ -49,7 +49,7 @@ signals: void audioClippingChanged(); void audioLevelChanged(); void isHMDChanged(); - void showAudioToolsChanged(bool showAudioTools); + void showAudioToolsChanged(bool); protected: Q_INVOKABLE void resetSensors(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index f3e429ce60..94251dffaf 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -122,8 +122,6 @@ public: float getTimeSinceLastClip() const { return _timeSinceLastClip; } float getAudioAverageInputLoudness() const { return _lastInputLoudness; } - bool isMuted() { return _muted; } - const AudioIOStats& getStats() const { return _stats; } int getOutputBufferSize() { return _outputBufferSizeFrames.get(); } @@ -172,11 +170,14 @@ public slots: void handleRecordedAudioInput(const QByteArray& audio); void reset(); void audioMixerKilled(); + void toggleMute(); + bool isMuted() { return _muted; } + virtual void setIsStereoInput(bool stereo) override; - void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; } + void setNoiseReduction(bool isNoiseGateEnabled) { _isNoiseGateEnabled = isNoiseGateEnabled; } void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; } void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 3bbd26e010..97f120447f 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -527,6 +527,7 @@ QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::functionloadUrl(qmlSource, QQmlComponent::PreferSynchronous); if (_qmlComponent->isLoading()) { diff --git a/scripts/system/audio.js b/scripts/system/audio.js index 7bc8676a2e..45900c8e50 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -46,7 +46,7 @@ function onClicked() { Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); shouldActivateButton = true; shouldActivateButton = true; - tablet.loadQMLSource("../Audio.qml"); + tablet.loadQMLSource("../audio/Audio.qml"); onAudioScreen = true; } }