diff --git a/Readme.md b/Readme.md index d3a86b3..1b501ad 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,5 @@ ![language](https://img.shields.io/badge/Language-C%2B%2B11%2C%20QML-green.svg) ![dependencies](https://img.shields.io/badge/Dependencies-OpenVR%2C%20Qt5-green.svg) ![license_gpl3](https://img.shields.io/badge/License-GPL%203.0-green.svg) [![Build status](https://ci.appveyor.com/api/projects/status/8oivf5xws6vsq2x3/branch/master?svg=true)](https://ci.appveyor.com/project/icewind1991/openvr-advancedsettings/branch/master) - # OpenVR Advanced Settings Overlay Adds an overlay to the OpenVR dashboard that allows access to advanced settings. @@ -32,15 +31,16 @@ Adds an overlay to the OpenVR dashboard that allows access to advanced settings. ## Installer -Download the newest installer from the [release section](https://github.com/icewind1991/OpenVR-AdvancedSettings/releases) and execute it. +Download the newest installer from the [release section](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/releases) and execute it. If you have an older standalone version installed, delete the old application folder first. ## Standalone +I am not currently providing standalone Archives if you want a standalone version you can: -Download the newest standalone archive from the [release section](https://github.com/icewind1991/OpenVR-AdvancedSettings/releases) and unpack the archive. +Download the newest standalone archive from the [release section](https://github.com/OpenVR-Advanced-Settings/OpenVR-AdvancedSettings/releases)and unpack the archive. -To install for the first time simply start AdvancedSettings.exe once while SteamVRis running. It will register with SteamVR and automatically starts whenever SteamVR starts (Can be disabled in the settings). +To install for the first time simply start AdvancedSettings.exe once while SteamVR is running. It will register with SteamVR and automatically starts whenever SteamVR starts (Can be disabled in the settings). To upgrade an existing installation first stop SteamVR and delete the old application folder (or override it). Then start SteamVR and run AdvancedSettings.exe once. @@ -50,9 +50,7 @@ Executing startdesktopmode.bat from the application folder shows a window on the ## Preview builds -If you want to try latest and greatest unreleased features, you can download the latest [automated build](https://ci.appveyor.com/project/icewind1991/openvr-advancedsettings/branch/master/artifacts). - -Note that these unreleased builds often only get minimal testing and might be broken. +If you want to try latest and greatest unreleased features, you can download latest changes in the alpha branches of the repository. # Documentation @@ -136,7 +134,8 @@ Allows to temporarily move and rotate the center of the playspace. This allows t - **Right Controller**: Configure the right controller for push-to-talk. - **Show Notification**: Shows a notification icon in the headset when push-to-talk is enabled a configured button is pressed. - **Push-to-Mute**: Inverse push-to-talk. The Microphone is unmuted by default and muted when any of the configured buttons is pressed. -- **Profile**: Allows to apply/define/delete push-to-talk profiles that save buttons, controller and notification settings. +- **PTT Profile**: Allows you to apply/define/delete push-to-talk profiles that save buttons, controller and notification settings. +- **Audio Profile**: Allows you to apply/define/delete audio profiles that save playback devices, mute state, and volume. ## - Revive Page: diff --git a/advancedSettings.pro b/advancedSettings.pro index e6961cf..dacff55 100644 --- a/advancedSettings.pro +++ b/advancedSettings.pro @@ -27,7 +27,37 @@ SOURCES += src/main.cpp\ src/tabcontrollers/AccessibilityTabController.cpp \ src/utils/ChaperoneUtils.cpp \ src/tabcontrollers/audiomanager/AudioManagerDummy.cpp \ - src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp + src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp \ + release/moc_AccessibilityTabController.cpp \ + release/moc_AudioTabController.cpp \ + release/moc_ChaperoneTabController.cpp \ + release/moc_FixFloorTabController.cpp \ + release/moc_MoveCenterTabController.cpp \ + release/moc_overlaycontroller.cpp \ + release/moc_PttController.cpp \ + release/moc_ReviveTabController.cpp \ + release/moc_SettingsTabController.cpp \ + release/moc_StatisticsTabController.cpp \ + release/moc_SteamVRTabController.cpp \ + release/moc_UtilitiesTabController.cpp \ + src/tabcontrollers/audiomanager/AudioManagerDummy.cpp \ + src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \ + src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp \ + src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp \ + src/tabcontrollers/AccessibilityTabController.cpp \ + src/tabcontrollers/AudioTabController.cpp \ + src/tabcontrollers/ChaperoneTabController.cpp \ + src/tabcontrollers/FixFloorTabController.cpp \ + src/tabcontrollers/MoveCenterTabController.cpp \ + src/tabcontrollers/PttController.cpp \ + src/tabcontrollers/ReviveTabController.cpp \ + src/tabcontrollers/SettingsTabController.cpp \ + src/tabcontrollers/StatisticsTabController.cpp \ + src/tabcontrollers/SteamVRTabController.cpp \ + src/tabcontrollers/UtilitiesTabController.cpp \ + src/utils/ChaperoneUtils.cpp \ + src/main.cpp \ + src/overlaycontroller.cpp HEADERS += src/overlaycontroller.h \ src/logging.h \ @@ -47,7 +77,37 @@ HEADERS += src/overlaycontroller.h \ src/utils/Matrix.h \ src/utils/ChaperoneUtils.h \ src/tabcontrollers/audiomanager/AudioManagerDummy.h \ - src/tabcontrollers/keyboardinput/KeyboardInputDummy.h + src/tabcontrollers/keyboardinput/KeyboardInputDummy.h \ + release/moc_predefs.h \ + src/tabcontrollers/audiomanager/AudioManagerDummy.h \ + src/tabcontrollers/audiomanager/AudioManagerWindows.h \ + src/tabcontrollers/audiomanager/IPolicyConfig.h \ + src/tabcontrollers/keyboardinput/KeyboardInputDummy.h \ + src/tabcontrollers/keyboardinput/KeyboardInputWindows.h \ + src/tabcontrollers/AccessibilityTabController.h \ + src/tabcontrollers/AudioManager.h \ + src/tabcontrollers/AudioTabController.h \ + src/tabcontrollers/ChaperoneTabController.h \ + src/tabcontrollers/FixFloorTabController.h \ + src/tabcontrollers/KeyboardInput.h \ + src/tabcontrollers/MoveCenterTabController.h \ + src/tabcontrollers/PttController.h \ + src/tabcontrollers/ReviveTabController.h \ + src/tabcontrollers/SettingsTabController.h \ + src/tabcontrollers/StatisticsTabController.h \ + src/tabcontrollers/SteamVRTabController.h \ + src/tabcontrollers/UtilitiesTabController.h \ + src/utils/ChaperoneUtils.h \ + src/utils/Matrix.h \ + src/logging.h \ + src/overlaycontroller.h \ + third-party/easylogging++/easylogging++.h \ + third-party/openvr/bin/osx64/OpenVR.framework/Versions/A/Headers/openvr.h \ + third-party/openvr/bin/osx64/OpenVR.framework/Versions/A/Headers/openvr_capi.h \ + third-party/openvr/bin/osx64/OpenVR.framework/Versions/A/Headers/openvr_driver.h \ + third-party/openvr/headers/openvr.h \ + third-party/openvr/headers/openvr_capi.h \ + third-party/openvr/headers/openvr_driver.h win32 { SOURCES += src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \ @@ -65,3 +125,47 @@ LIBS += -lopenvr_api win32:DESTDIR = bin/win64/AdvancedSettings unix:DESTDIR = bin/linux/AdvancedSettings + +DISTFILES += \ + src/res/sounds/alarm01.wav \ + src/res/qml/ptt_notification.png \ + src/res/battery_0.png \ + src/res/battery_1.png \ + src/res/battery_2.png \ + src/res/battery_3.png \ + src/res/battery_4.png \ + src/res/battery_5.png \ + src/res/thumbicon.png \ + src/res/qml/backarrow.svg \ + src/res/qml/check.svg \ + src/res/qml/mic_off.svg \ + src/res/qml/mic_on.svg \ + src/res/qml/ptt_notification.svg \ + src/res/qml/speaker_off.svg \ + src/res/qml/speaker_on.svg \ + src/res/qml/qmldir \ + src/res/qml/AccessibilityPage.qml \ + src/res/qml/AudioPage.qml \ + src/res/qml/ChaperonePage.qml \ + src/res/qml/ChaperoneWarningsPage.qml \ + src/res/qml/FixFloorPage.qml \ + src/res/qml/mainwidget.qml \ + src/res/qml/MyComboBox.qml \ + src/res/qml/MyDialogOkCancelPopup.qml \ + src/res/qml/MyDialogOkPopup.qml \ + src/res/qml/MyPushButton.qml \ + src/res/qml/MyPushButton2.qml \ + src/res/qml/MyResources.qml \ + src/res/qml/MySlider.qml \ + src/res/qml/MyStackViewPage.qml \ + src/res/qml/MyText.qml \ + src/res/qml/MyTextField.qml \ + src/res/qml/MyToggleButton.qml \ + src/res/qml/PlayspacePage.qml \ + src/res/qml/PttControllerConfigDialog.qml \ + src/res/qml/RevivePage.qml \ + src/res/qml/RootPage.qml \ + src/res/qml/SettingsPage.qml \ + src/res/qml/StatisticsPage.qml \ + src/res/qml/SteamVRPage.qml \ + src/res/qml/UtilitiesPage.qml diff --git a/docs/screenshots/AudioPage.png b/docs/screenshots/AudioPage.png index 8c1f177..9b3bd13 100644 Binary files a/docs/screenshots/AudioPage.png and b/docs/screenshots/AudioPage.png differ diff --git a/docs/screenshots/PlayspacePage.png b/docs/screenshots/PlayspacePage.png index a4750e8..a412395 100644 Binary files a/docs/screenshots/PlayspacePage.png and b/docs/screenshots/PlayspacePage.png differ diff --git a/src/main.cpp b/src/main.cpp index 646d59f..922bcc6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -110,58 +110,71 @@ public: }; -int main(int argc, char *argv[]) { - - bool desktopMode = false; - bool noSound = false; - bool noManifest = false; - // Parse command line arguments - for (int i = 1; i < argc; i++) { - if (std::string(argv[i]).compare("-desktop") == 0) { - desktopMode = true; - } else if (std::string(argv[i]).compare("-nosound") == 0) { - noSound = true; - } else if (std::string(argv[i]).compare("-nomanifest") == 0) { - noManifest = true; - } else if (std::string(argv[i]).compare("-installmanifest") == 0) { - int exitcode = 0; - QCoreApplication coreApp(argc, argv); - auto initError = vr::VRInitError_None; - vr::VR_Init(&initError, vr::VRApplication_Utility); - if (initError == vr::VRInitError_None) { - try { - installManifest(true); - } catch (std::exception& e) { - exitcode = -1; - std::cerr << e.what() << std::endl; - } - } else { - exitcode = -2; - std::cerr << std::string("Failed to initialize OpenVR: " + std::string(vr::VR_GetVRInitErrorAsEnglishDescription(initError))) << std::endl; - } - vr::VR_Shutdown(); - exit(exitcode); - } else if (std::string(argv[i]).compare("-removemanifest") == 0) { - int exitcode = 0; - QCoreApplication coreApp(argc, argv); - auto initError = vr::VRInitError_None; - vr::VR_Init(&initError, vr::VRApplication_Utility); - if (initError == vr::VRInitError_None) { - try { - removeManifest(); - } catch (std::exception& e) { - exitcode = -1; - std::cerr << e.what() << std::endl; - } - } else { - exitcode = -2; - std::cerr << std::string("Failed to initialize OpenVR: " + std::string(vr::VR_GetVRInitErrorAsEnglishDescription(initError))) << std::endl; - } - vr::VR_Shutdown(); - exit(exitcode); - } - } +namespace argument { + // Checks whether a specific string was passed as a launch argument. + bool CheckCommandLineArgument(int argc, char *argv[], const std::string parameter) { + // The old way was one giant loop that tested every single parameter. + // Having an individual loop for all args most likely has a very small performance + // penalty compared to the original solution, + // but the gains in readability and ease of extension of not having a hundred line+ for loop are worth it. + for (int i = 0; i < argc; i++) { + if (std::string(argv[i]) == parameter) { + return true; + } + } + return false; + } + + constexpr auto DESKTOP_MODE = "-desktop"; + constexpr auto NO_SOUND = "-nosound"; + constexpr auto NO_MANIFEST = "-nomanifest"; + constexpr auto INSTALL_MANIFEST= "-installmanifest"; + constexpr auto REMOVE_MANIFEST= "-removemanifest"; +} + +enum ReturnErrorCode { + SUCCESS = 0, + GENERAL_FAILURE = -1, + OPENVR_INIT_ERROR = -2, +}; + +int main(int argc, char *argv[]) { + + const bool desktop_mode = argument::CheckCommandLineArgument(argc, argv, argument::DESKTOP_MODE); + const bool no_sound = argument::CheckCommandLineArgument(argc, argv, argument::NO_SOUND); + const bool no_manifest = argument::CheckCommandLineArgument(argc, argv, argument::NO_MANIFEST); + const bool install_manifest = argument::CheckCommandLineArgument(argc, argv, argument::INSTALL_MANIFEST); + const bool remove_manifest = argument::CheckCommandLineArgument(argc, argv, argument::REMOVE_MANIFEST); + + if (install_manifest || remove_manifest) { + int exit_code = ReturnErrorCode::SUCCESS; + QCoreApplication coreApp(argc, argv); + auto openvr_init_status = vr::VRInitError_None; + vr::VR_Init(&openvr_init_status, vr::VRApplication_Utility); + + if (openvr_init_status == vr::VRInitError_None) { + try { + if (install_manifest) { + installManifest(true); + } + else if (remove_manifest) { + removeManifest(); + } + } + catch (std::exception& e) { + exit_code = ReturnErrorCode::GENERAL_FAILURE; + std::cerr << e.what() << std::endl; + } + } + else { + exit_code = ReturnErrorCode::OPENVR_INIT_ERROR; + std::cerr << std::string("Failed to initialize OpenVR: " + std::string(vr::VR_GetVRInitErrorAsEnglishDescription(openvr_init_status))) << std::endl; + } + + vr::VR_Shutdown(); + exit(exit_code); + } try { MyQApplication a(argc, argv); @@ -195,13 +208,13 @@ int main(int argc, char *argv[]) { LOG(INFO) << "Log File: " << logFilePath; } - if (desktopMode) { + if (desktop_mode) { LOG(INFO) << "Desktop mode enabled."; } - if (noSound) { + if (no_sound) { LOG(INFO) << "Sound effects disabled."; } - if (noManifest) { + if (no_manifest) { LOG(INFO) << "vrmanifest disabled."; } @@ -211,7 +224,7 @@ int main(int argc, char *argv[]) { QQmlEngine qmlEngine; - advsettings::OverlayController* controller = advsettings::OverlayController::createInstance(desktopMode, noSound); + advsettings::OverlayController* controller = advsettings::OverlayController::createInstance(desktop_mode, no_sound); controller->Init(&qmlEngine); QQmlComponent component(&qmlEngine, QUrl::fromLocalFile("res/qml/mainwidget.qml")); @@ -222,7 +235,7 @@ int main(int argc, char *argv[]) { auto quickObj = component.create(); controller->SetWidget(qobject_cast(quickObj), advsettings::OverlayController::applicationName, advsettings::OverlayController::applicationKey); - if (!desktopMode && !noManifest) { + if (!desktop_mode && !no_manifest) { try { installManifest(); } catch (std::exception& e) { @@ -230,7 +243,7 @@ int main(int argc, char *argv[]) { } } - if (desktopMode) { + if (desktop_mode) { auto m_pWindow = new QQuickWindow(); qobject_cast(quickObj)->setParentItem(m_pWindow->contentItem()); m_pWindow->setGeometry(0, 0, qobject_cast(quickObj)->width(), qobject_cast(quickObj)->height()); @@ -241,7 +254,7 @@ int main(int argc, char *argv[]) { } catch (const std::exception& e) { LOG(FATAL) << e.what(); - return -1; + return ReturnErrorCode::GENERAL_FAILURE; } - return 0; + return ReturnErrorCode::SUCCESS; } diff --git a/src/res/qml/AudioPage.qml b/src/res/qml/AudioPage.qml index b499c24..774ef91 100644 --- a/src/res/qml/AudioPage.qml +++ b/src/res/qml/AudioPage.qml @@ -24,7 +24,7 @@ MyStackViewPage { id: pttDeleteProfileDialog property int profileIndex: -1 dialogTitle: "Delete Profile" - dialogText: "Do you really want to delete this profile?" + dialogText: "Do you really want to delete this ptt profile?" onClosed: { if (okClicked) { AudioTabController.deletePttProfile(profileIndex) @@ -32,6 +32,18 @@ MyStackViewPage { } } + MyDialogOkCancelPopup { + id: audioDeleteProfileDialog + property int profileIndex: -1 + dialogTitle: "Delete Profile" + dialogText: "Do you really want to delete this audio profile?" + onClosed: { + if (okClicked) { + AudioTabController.deleteAudioProfile(profileIndex) + } + } + } + PttControllerConfigDialog { id: pttControllerConfigDialog pttControllerConfigClass: AudioTabController @@ -39,7 +51,7 @@ MyStackViewPage { MyDialogOkCancelPopup { id: pttNewProfileDialog - dialogTitle: "Create New Profile" + dialogTitle: "Create New PTT Profile" dialogWidth: 600 dialogHeight: 220 dialogContentItem: ColumnLayout { @@ -78,6 +90,48 @@ MyStackViewPage { } } + + MyDialogOkCancelPopup { + id: audioNewProfileDialog + dialogTitle: "Create New Audio Profile" + dialogWidth: 600 + dialogHeight: 220 + dialogContentItem: ColumnLayout { + RowLayout { + Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + MyText { + text: "Name: " + } + MyTextField { + id: audioNewProfileName + keyBoardUID: 590 + color: "#cccccc" + text: "" + Layout.fillWidth: true + font.pointSize: 20 + function onInputEvent(input) { + audioNewProfileName.text = input + } + } + } + } + onClosed: { + if (okClicked) { + if (audioNewProfileName.text != "") { + AudioTabController.addAudioProfile(audioNewProfileName.text) + } else { + audioMessageDialog.showMessage("Create New Profile", "ERROR: No name given.") + } + } + } + function openPopup() { + audioNewProfileName.text = "" + open() + } + } + content: ColumnLayout { spacing: 24 @@ -329,16 +383,50 @@ MyStackViewPage { } } RowLayout { - spacing: 18 + spacing: 10 MyText { - Layout.leftMargin: 270 - text: "Profile:" + Layout.preferredWidth: 150 + text: "Audio Profile:" + + } + + MyComboBox { + id: audioProfileComboBox + Layout.preferredWidth: 250 + model: [""] + onCurrentIndexChanged: { + if (currentIndex > 0) { + audioApplyProfileButton.enabled = true + audioDeleteProfileButton.enabled = true + } else { + audioApplyProfileButton.enabled = false + audioDeleteProfileButton.enabled = false + } + } + } + + MyPushButton { + id: audioApplyProfileButton + enabled: true + Layout.preferredWidth: 150 + text: "Apply" + onClicked: { + if (audioProfileComboBox.currentIndex > 0) { + AudioTabController.applyAudioProfile(audioProfileComboBox.currentIndex - 1) + audioProfileComboBox.currentIndex = 0 + } + } + } + + MyText { + text: "PTT Profile:" + Layout.preferredWidth: 150 } MyComboBox { id: pttProfileComboBox - Layout.fillWidth: true + Layout.preferredWidth: 250 model: [""] onCurrentIndexChanged: { if (currentIndex > 0) { @@ -354,7 +442,7 @@ MyStackViewPage { MyPushButton { id: pttApplyProfileButton enabled: true - Layout.preferredWidth: 200 + Layout.preferredWidth: 150 text: "Apply" onClicked: { if (pttProfileComboBox.currentIndex > 0) { @@ -366,6 +454,26 @@ MyStackViewPage { } RowLayout { spacing: 18 + + MyPushButton { + id: audioDeleteProfileButton + enabled: true + Layout.preferredWidth: 200 + text: "Delete Profile" + onClicked: { + if (audioProfileComboBox.currentIndex > 0) { + audioDeleteProfileDialog.profileIndex = audioProfileComboBox.currentIndex - 1 + audioDeleteProfileDialog.open() + } + } + } + MyPushButton { + Layout.preferredWidth: 200 + text: "New Profile" + onClicked: { + audioNewProfileDialog.openPopup() + } + } Item { Layout.fillWidth: true } @@ -444,6 +552,7 @@ MyStackViewPage { audioMicNameCombo.currentIndex = AudioTabController.micDeviceIndex } reloadPttProfiles() + reloadAudioProfiles() audioPttEnabledToggle.checked = AudioTabController.pttEnabled audioPttLeftControllerToggle.checked = AudioTabController.pttLeftControllerEnabled audioPttRightControllerToggle.checked = AudioTabController.pttRightControllerEnabled @@ -523,6 +632,10 @@ MyStackViewPage { onPttProfilesUpdated: { reloadPttProfiles() } + onAudioProfilesUpdated:{ + reloadAudioProfiles() + } + onPlaybackDeviceListChanged: { var devs1 = [] var devs2 = [""] @@ -587,4 +700,14 @@ MyStackViewPage { pttProfileComboBox.currentIndex = 0 pttProfileComboBox.model = profiles } + + function reloadAudioProfiles(){ + var profiles = [""] + var profileCount = AudioTabController.getAudioProfileCount() + for (var i = 0; i < profileCount; i++) { + profiles.push(AudioTabController.getAudioProfileName(i)) + } + audioProfileComboBox.currentIndex = 0 + audioProfileComboBox.model = profiles + } } diff --git a/src/res/qml/PlayspacePage.qml b/src/res/qml/PlayspacePage.qml index 9795983..49cb301 100644 --- a/src/res/qml/PlayspacePage.qml +++ b/src/res/qml/PlayspacePage.qml @@ -92,6 +92,7 @@ MyStackViewPage { } MyToggleButton { + Layout.preferredWidth: 240 id: lockXToggle text: "Lock X" onCheckedChanged: { @@ -141,6 +142,7 @@ MyStackViewPage { MyToggleButton { + Layout.preferredWidth: 240 id: lockYToggle text: "Lock Y" onCheckedChanged: { @@ -190,6 +192,7 @@ MyStackViewPage { MyToggleButton { + Layout.preferredWidth: 240 id: lockZToggle text: "Lock Z" onCheckedChanged: { @@ -286,6 +289,15 @@ MyStackViewPage { } } } + MyPushButton { + id: playSpaceRotationApplyButton + Layout.preferredWidth: 145 + text:"Apply" + onClicked: { + MoveCenterTabController.applyRotation() + } + + } } } } diff --git a/src/tabcontrollers/AudioTabController.cpp b/src/tabcontrollers/AudioTabController.cpp index fd82dc7..788abdb 100644 --- a/src/tabcontrollers/AudioTabController.cpp +++ b/src/tabcontrollers/AudioTabController.cpp @@ -38,6 +38,7 @@ namespace advsettings { m_micMuted = audioManager->getMicMuted(); reloadPttProfiles(); reloadPttConfig(); + reloadAudioProfiles(); reloadAudioSettings(); eventLoopTick(); } @@ -347,6 +348,7 @@ namespace advsettings { if (index != m_playbackDeviceIndex) { if (index < m_playbackDevices.size() && index != m_mirrorDeviceIndex) { vr::EVRSettingsError vrSettingsError; + //Applys Audio Switch IN VR vr::VRSettings()->SetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String, m_playbackDevices[index].first.c_str(), &vrSettingsError); if (vrSettingsError != vr::VRSettingsError_None) { LOG(WARNING) << "Could not write \"" << vr::k_pch_audio_OnPlaybackDevice_String << "\" setting: " << vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError); @@ -460,4 +462,249 @@ namespace advsettings { } } + + /*AUDIO PROFILE FUNCTIONS + The following section includes the code required to save and load Audio Profiles. + + Saved Settings Include: + Playback Device + Mirror Device + Mirror Vol + Microphone + Microphone Volume + Profile Name + + */ + + /* + Name: reloadAudioProfiles + + Inputs: args: none + other: Reads audioProfiles setting from file + + + Output: return:none + other:none + + Description: Clears working copy, and reloads from Settings file. + + */ + void AudioTabController::reloadAudioProfiles() { + audioProfiles.clear(); + auto settings = OverlayController::appSettings(); + settings->beginGroup(getSettingsName()); + auto profileCount = settings->beginReadArray("audioProfiles"); + for (int i = 0; i < profileCount; i++) { + settings->setArrayIndex(i); + audioProfiles.emplace_back(); + auto& entry = audioProfiles[i]; + entry.profileName = settings->value("profileName").toString().toStdString(); + entry.playbackName = settings->value("playbackName").toString().toStdString(); + entry.micName = settings->value("micName").toString().toStdString(); + entry.mirrorName = settings->value("mirrorName").toString().toStdString(); + entry.micMute = settings->value("micMute", false).toBool(); + entry.mirrorMute = settings->value("mirrorMute", false).toBool(); + entry.mirrorVol = settings->value("mirrorVol", 0.0).toFloat(); + entry.micVol = settings->value("micVol", 1.0).toFloat(); + } + settings->endArray(); + settings->endGroup(); + } + + /* + Name: saveAudioProfile + + Inputs: args: none + other: none + + + Output: return: none + other: Writes audioProfiles setting to file + + Description: saves a copy of the audio profiles from working to Settings file. + + */ + void AudioTabController::saveAudioProfiles() { + auto settings = OverlayController::appSettings(); + settings->beginGroup(getSettingsName()); + settings->beginWriteArray("audioProfiles"); + unsigned i = 0; + for (auto& p : audioProfiles) { + settings->setArrayIndex(i); + settings->setValue("profileName", QString::fromStdString(p.profileName)); + settings->setValue("playbackName", QString::fromStdString(p.playbackName)); + settings->setValue("micName", QString::fromStdString(p.micName)); + settings->setValue("mirrorName", QString::fromStdString(p.mirrorName)); + settings->setValue("micMute", p.micMute); + settings->setValue("mirrorMute", p.mirrorMute); + settings->setValue("micVol", p.micVol); + settings->setValue("mirrorVol", p.mirrorVol); + i++; + } + settings->endArray(); + settings->endGroup(); + } + + + + /* + Name: addAudioProfile + + Inputs: args: Qstring name - the name of the audio profile + other: none + + + Output: return: none + other: audioProfile to audioProfiles array + + Description: Creates an audioProfile, and adds it to the working copy of audioProfiles[] + + */ + + void AudioTabController::addAudioProfile(QString name) { + AudioProfile* profile = nullptr; + for (auto& p : audioProfiles) { + if (p.profileName.compare(name.toStdString()) == 0) { + profile = &p; + break; + } + } + if (!profile) { + auto i = audioProfiles.size(); + audioProfiles.emplace_back(); + profile = &audioProfiles[i]; + } + profile->profileName = name.toStdString(); + profile->playbackName = getPlaybackDeviceName(m_playbackDeviceIndex).toStdString(); + profile->mirrorName = getPlaybackDeviceName(m_mirrorDeviceIndex).toStdString(); + profile->micName = getRecordingDeviceName(m_recordingDeviceIndex).toStdString(); + profile->micMute = m_micMuted; + profile->mirrorMute = m_mirrorMuted; + profile->mirrorVol = m_mirrorVolume; + profile->micVol = m_micVolume; + + saveAudioProfiles(); + OverlayController::appSettings()->sync(); + emit audioProfilesUpdated(); + } + + + /* + Name: applyAudioProfile + + Inputs: args: index - index of audioProfile in audioProfiles[] + other: audioProfile based on index + + + Output: return: none + other: none + + Description: Applies the required logic to activate the audio profile. + + */ + //TODO Remembers Mirror Volume when switching to main volume. + void AudioTabController::applyAudioProfile(unsigned index) { + if (index < audioProfiles.size()) { + auto& profile = audioProfiles[index]; + int mInd = getMirrorIndex(profile.mirrorName); + int pInd = getPlaybackIndex(profile.playbackName); + + //Needed to keep remembering when swtiching from mirror/main etc. + setMicMuted(false, false); + setMirrorMuted(false, false); + + if ((m_playbackDeviceIndex == mInd) && (m_mirrorDeviceIndex == pInd)) { + setMirrorDeviceIndex(-1, true); + } + if (m_playbackDeviceIndex == mInd) { + setPlaybackDeviceIndex(pInd, true); + setMirrorDeviceIndex(mInd, true); + } + else { + setMirrorDeviceIndex(mInd, true); + setPlaybackDeviceIndex(pInd, true); + } + setMicDeviceIndex(getRecordingIndex(profile.micName), true); + setMicMuted(profile.micMute, true); + setMirrorMuted(profile.mirrorMute, true); + setMicVolume(profile.micVol, true); + setMirrorVolume(profile.mirrorVol, true); + + } + } + + /* + Name: deleteAudioProfile + + Inputs: args: index - index of audioProfile in audioProfiles[] + other: audioProfile based on index + + + Output: return: none + other: none + + Description: Removes selected Audio Profile + + */ + void AudioTabController::deleteAudioProfile(unsigned index) { + if (index < audioProfiles.size()) { + auto pos = audioProfiles.begin() + index; + audioProfiles.erase(pos); + saveAudioProfiles(); + OverlayController::appSettings()->sync(); + emit audioProfilesUpdated(); + } + } + + + unsigned AudioTabController::getAudioProfileCount() { + return (unsigned)audioProfiles.size(); + } + + QString AudioTabController::getAudioProfileName(unsigned index) { + if (index < audioProfiles.size()) { + return QString::fromStdString(audioProfiles[index].profileName); + } + return ""; + } + + /* + Name: getPlaybackIndex, getRecordingIndex, and getMirrorIndex + + input: string, of microphone/playback device name + output: integer for use In: setMicDeviceIndex(int,bool), setMirrorDeviceIndex(int,bool) setPlayBackDeviceIndex(int,bool) + + description: Gets proper index value for selecting specific devices. + */ + int AudioTabController::getPlaybackIndex(std::string str) { + for (int i = 0; i < m_playbackDevices.size(); i++) { + if (str.compare(m_playbackDevices[i].second)==0) { + return i; + } + } + return m_playbackDeviceIndex; + } + + int AudioTabController::getRecordingIndex(std::string str) { + for (int i = 0; i < m_recordingDevices.size(); i++) { + if (str.compare(m_recordingDevices[i].second) == 0) { + return i; + } + } + return m_recordingDeviceIndex; + } + + int AudioTabController::getMirrorIndex(std::string str) { + for (int i = 0; i < m_playbackDevices.size(); i++) { + if (str.compare(m_playbackDevices[i].second) == 0) { + return i; + } + } + return -1; + } + + /* ---------------------------*/ + + /*----------------*/ + } // namespace advconfig diff --git a/src/tabcontrollers/AudioTabController.h b/src/tabcontrollers/AudioTabController.h index ee916a6..acad6fa 100644 --- a/src/tabcontrollers/AudioTabController.h +++ b/src/tabcontrollers/AudioTabController.h @@ -3,6 +3,7 @@ #include "AudioManager.h" #include "PttController.h" +//#include "AudioProfileController.h" #include class QQuickWindow; @@ -12,6 +13,17 @@ namespace advsettings { // forward declaration class OverlayController; + struct AudioProfile { + std::string profileName; + std::string playbackName; + std::string mirrorName; + std::string micName; + float mirrorVol = 0.0; + float micVol = 0.0; + bool micMute = false; + bool mirrorMute = false; + }; + class AudioTabController : public PttController { Q_OBJECT @@ -55,6 +67,7 @@ namespace advsettings { std::string lastMirrorDevId; QString getSettingsName() override { return "audioSettings"; } + //QString getSettingsNameAudio() override { return "audioSettingsTest"; } void onPttStart() override; void onPttStop() override; void onPttEnabled() override; @@ -66,7 +79,17 @@ namespace advsettings { void findMirrorDeviceIndex(std::string id, bool notify = true); void findMicDeviceIndex(std::string id, bool notify = true); + int getPlaybackIndex(std::string str); + int getRecordingIndex(std::string str); + int getMirrorIndex(std::string str); + //void setPlaybackDeviceControl(int index, bool notify = true); + + std::vector audioProfiles; + //std::recursive_mutex eventLoopMutexAudio; + public: + + void initStage1(); void initStage2(OverlayController* parent, QQuickWindow* widget); @@ -87,12 +110,19 @@ namespace advsettings { bool micProximitySensorCanMute() const; bool micReversePtt() const; + void reloadAudioProfiles(); + void saveAudioProfiles(); + Q_INVOKABLE int getPlaybackDeviceCount(); Q_INVOKABLE QString getPlaybackDeviceName(int index); Q_INVOKABLE int getRecordingDeviceCount(); Q_INVOKABLE QString getRecordingDeviceName(int index); + //TODO check if needed? + Q_INVOKABLE unsigned getAudioProfileCount(); + Q_INVOKABLE QString getAudioProfileName(unsigned index); + void onNewRecordingDevice(); void onNewPlaybackDevice(); void onNewMirrorDevice(); @@ -111,6 +141,10 @@ namespace advsettings { void setMirrorDeviceIndex(int value, bool notify = true); void setMicDeviceIndex(int value, bool notify = true); + void addAudioProfile(QString name); + void applyAudioProfile(unsigned index); + void deleteAudioProfile(unsigned index); + signals: void playbackDeviceIndexChanged(int index); @@ -126,6 +160,8 @@ namespace advsettings { void playbackDeviceListChanged(); void recordingDeviceListChanged(); + + void audioProfilesUpdated(); }; } // namespace advsettings diff --git a/src/tabcontrollers/MoveCenterTabController.cpp b/src/tabcontrollers/MoveCenterTabController.cpp index f1f5ec6..8641185 100644 --- a/src/tabcontrollers/MoveCenterTabController.cpp +++ b/src/tabcontrollers/MoveCenterTabController.cpp @@ -113,15 +113,23 @@ int MoveCenterTabController::rotation() const { void MoveCenterTabController::setRotation(int value, bool notify) { if (m_rotation != value) { - float angle = (value - m_rotation) * 2 * M_PI / 360.0; - parent->RotateUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, angle, m_adjustChaperone); + //float angle = (value - m_rotation) * 2 * M_PI / 360.0; + //parent->RotateUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, angle, m_adjustChaperone); m_rotation = value; - if (notify) { + if (notify) { emit rotationChanged(m_rotation); } } } +void MoveCenterTabController::applyRotation() { + if (m_rotation != m_rotationOld) { + float angle = (m_rotationOld - m_rotation) * 2 * M_PI / 360.0; + parent->RotateUniverseCenter((vr::TrackingUniverseOrigin)m_trackingUniverse, angle, m_adjustChaperone); + m_rotationOld = m_rotation; + } +} + bool MoveCenterTabController::adjustChaperone() const { return m_adjustChaperone; } diff --git a/src/tabcontrollers/MoveCenterTabController.h b/src/tabcontrollers/MoveCenterTabController.h index 1d39007..0768e51 100644 --- a/src/tabcontrollers/MoveCenterTabController.h +++ b/src/tabcontrollers/MoveCenterTabController.h @@ -19,7 +19,7 @@ class MoveCenterTabController : public QObject { Q_PROPERTY(float offsetX READ offsetX WRITE setOffsetX NOTIFY offsetXChanged) Q_PROPERTY(float offsetY READ offsetY WRITE setOffsetY NOTIFY offsetYChanged) Q_PROPERTY(float offsetZ READ offsetZ WRITE setOffsetZ NOTIFY offsetZChanged) - Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged) + Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged ) Q_PROPERTY(bool adjustChaperone READ adjustChaperone WRITE setAdjustChaperone NOTIFY adjustChaperoneChanged) Q_PROPERTY(bool moveShortcutRight READ moveShortcutRight WRITE setMoveShortcutRight NOTIFY moveShortcutRightChanged) Q_PROPERTY(bool moveShortcutLeft READ moveShortcutLeft WRITE setMoveShortcutLeft NOTIFY moveShortcutLeftChanged) @@ -37,6 +37,7 @@ private: float m_offsetY = 0.0f; float m_offsetZ = 0.0f; int m_rotation = 0; + int m_rotationOld = 0; bool m_adjustChaperone = true; bool m_moveShortcutRightPressed = false; bool m_moveShortcutLeftPressed = false; @@ -80,7 +81,7 @@ public slots: void setOffsetY(float value, bool notify = true); void setOffsetZ(float value, bool notify = true); - void setRotation(int value, bool notify = true); + void setRotation(int value , bool notify = true); void setAdjustChaperone(bool value, bool notify = true); @@ -96,6 +97,7 @@ public slots: void setLockY(bool value, bool notify = true); void setLockZ(bool value, bool notify = true); + void applyRotation(); void reset(); signals: