From d1cc36cb780e2dbe4639fb19c6fe3b00b321bb1e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 26 Sep 2019 19:53:35 +1000 Subject: [PATCH] audio preferences --- app/CMakeLists.txt | 1 + app/audio/CMakeLists.txt | 22 ++++ app/audio/audiomanager.cpp | 111 ++++++++++++++++++ app/audio/audiomanager.h | 90 ++++++++++++++ app/core.cpp | 5 + .../preferences/tabs/preferencesaudiotab.cpp | 102 +++++++++++----- .../preferences/tabs/preferencesaudiotab.h | 8 ++ 7 files changed, 308 insertions(+), 31 deletions(-) create mode 100644 app/audio/CMakeLists.txt create mode 100644 app/audio/audiomanager.cpp create mode 100644 app/audio/audiomanager.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1fc0c766b..48d7c6438 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -21,6 +21,7 @@ set(OLIVE_SOURCES main.cpp ) +add_subdirectory(audio) add_subdirectory(common) add_subdirectory(config) add_subdirectory(decoder) diff --git a/app/audio/CMakeLists.txt b/app/audio/CMakeLists.txt new file mode 100644 index 000000000..72ceaba7c --- /dev/null +++ b/app/audio/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + audio/audiomanager.h + audio/audiomanager.cpp + PARENT_SCOPE +) diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp new file mode 100644 index 000000000..a03faf166 --- /dev/null +++ b/app/audio/audiomanager.cpp @@ -0,0 +1,111 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "audiomanager.h" + +AudioManager* AudioManager::audio_ = nullptr; + +void AudioManager::CreateInstance() +{ + if (audio_ == nullptr) { + audio_ = new AudioManager(); + } +} + +void AudioManager::DestroyInstance() +{ + delete audio_; + audio_ = nullptr; +} + +AudioManager *AudioManager::instance() +{ + return audio_; +} + +void AudioManager::RefreshDevices() +{ + if (refreshing_devices_) { + return; + } + + input_devices_.clear(); + output_devices_.clear(); + + refreshing_devices_ = true; + + refresh_thread_.start(QThread::LowPriority); +} + +bool AudioManager::IsRefreshing() +{ + return refreshing_devices_; +} + +const QList &AudioManager::ListInputDevices() +{ + return input_devices_; +} + +const QList &AudioManager::ListOutputDevices() +{ + return output_devices_; +} + +AudioManager::AudioManager() : + output_(nullptr), + refreshing_devices_(false) +{ + RefreshDevices(); + + connect(&refresh_thread_, SIGNAL(ListsReady()), this, SLOT(RefreshThreadDone())); +} + +void AudioManager::RefreshThreadDone() +{ + output_devices_ = refresh_thread_.output_devices(); + input_devices_ = refresh_thread_.input_devices(); + + refreshing_devices_ = false; + + emit DeviceListReady(); +} + +AudioRefreshDevicesThread::AudioRefreshDevicesThread() +{ +} + +void AudioRefreshDevicesThread::run() +{ + output_devices_ = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + input_devices_ = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); + + emit ListsReady(); +} + +const QList& AudioRefreshDevicesThread::input_devices() +{ + return input_devices_; +} + +const QList& AudioRefreshDevicesThread::output_devices() +{ + return output_devices_; +} diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h new file mode 100644 index 000000000..75778ee61 --- /dev/null +++ b/app/audio/audiomanager.h @@ -0,0 +1,90 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef AUDIOMANAGER_H +#define AUDIOMANAGER_H + +#include +#include +#include + +/** + * @brief A thread for refreshing the total list of devices on the system + * + * Refreshing devices causes a noticeable pause in execution. Doing it another thread is intended to avoid this. + */ +class AudioRefreshDevicesThread : public QThread { + Q_OBJECT +public: + AudioRefreshDevicesThread(); + + virtual void run() override; + + const QList& input_devices(); + const QList& output_devices(); + +signals: + void ListsReady(); + +private: + QList input_devices_; + QList output_devices_; +}; + +class AudioManager : public QObject +{ + Q_OBJECT +public: + static void CreateInstance(); + static void DestroyInstance(); + + static AudioManager* instance(); + + void RefreshDevices(); + + bool IsRefreshing(); + + const QList& ListInputDevices(); + const QList& ListOutputDevices(); + +signals: + void DeviceListReady(); + +private: + AudioManager(); + + QList input_devices_; + + QList output_devices_; + + static AudioManager* audio_; + + std::unique_ptr output_; + + bool refreshing_devices_; + + AudioRefreshDevicesThread refresh_thread_; + +private slots: + void RefreshThreadDone(); + +}; + +#endif // AUDIOMANAGER_H diff --git a/app/core.cpp b/app/core.cpp index d4f735110..6f7f1c9a0 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -29,6 +29,7 @@ #include #include +#include "audio/audiomanager.h" #include "config/config.h" #include "dialog/about/about.h" #include "dialog/sequence/sequence.h" @@ -384,6 +385,10 @@ void Core::StartGUI(bool full_screen) // Initialize color service ColorService::Init(); + + // Initialize audio service + AudioManager::CreateInstance(); + } Project *Core::GetActiveProject() diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index f5ddfacff..4723ce284 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -3,10 +3,13 @@ #include #include #include +#include +#include "audio/audiomanager.h" #include "config/config.h" -PreferencesAudioTab::PreferencesAudioTab() +PreferencesAudioTab::PreferencesAudioTab() : + has_devices_(false) { QGridLayout* audio_tab_layout = new QGridLayout(this); audio_tab_layout->setMargin(0); @@ -14,47 +17,17 @@ PreferencesAudioTab::PreferencesAudioTab() int row = 0; // Audio -> Output Device - audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); audio_output_devices = new QComboBox(); - audio_output_devices->addItem(tr("Default"), ""); - - // list all available audio output devices - QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); - bool found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == Config::Current()["AudioOutput"]) { - audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); - found_preferred_device = true; - } - } - audio_tab_layout->addWidget(audio_output_devices, row, 1); row++; // Audio -> Input Device - audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); audio_input_devices = new QComboBox(); - audio_input_devices->addItem(tr("Default"), ""); - - // list all available audio input devices - devs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); - found_preferred_device = false; - for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName()); - if (!found_preferred_device - && devs.at(i).deviceName() == Config::Current()["AudioInput"]) { - audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); - found_preferred_device = true; - } - } - audio_tab_layout->addWidget(audio_input_devices, row, 1); row++; @@ -86,9 +59,76 @@ PreferencesAudioTab::PreferencesAudioTab() audio_tab_layout->addWidget(recordingComboBox, row, 1); row++; + + QPushButton* refresh_devices = new QPushButton(tr("Refresh Devices")); + audio_tab_layout->addWidget(refresh_devices, row, 1); + + row++; + + RetrieveDeviceLists(); + + connect(refresh_devices, SIGNAL(clicked(bool)), this, SLOT(RefreshDevices())); + connect(AudioManager::instance(), SIGNAL(DeviceListReady()), this, SLOT(RetrieveDeviceLists())); } void PreferencesAudioTab::Accept() { + // If we don't have the device list, we can't set it + if (!has_devices_) { + return; + } +} +void PreferencesAudioTab::RefreshDevices() +{ + AudioManager::instance()->RefreshDevices(); + + RetrieveDeviceLists(); +} + +void PreferencesAudioTab::RetrieveDeviceLists() +{ + has_devices_ = false; + + audio_input_devices->clear(); + audio_output_devices->clear(); + + if (AudioManager::instance()->IsRefreshing()) { + audio_output_devices->addItem(tr("Please wait...")); + audio_input_devices->addItem(tr("Please wait...")); + audio_output_devices->setEnabled(false); + audio_input_devices->setEnabled(false); + return; + } + + audio_output_devices->setEnabled(true); + audio_input_devices->setEnabled(true); + + // list all available audio output devices + bool found_preferred_device = false; + audio_output_devices->addItem(tr("Default"), ""); + for (int i=0;iListOutputDevices().size();i++) { + audio_output_devices->addItem(AudioManager::instance()->ListOutputDevices().at(i).deviceName(), + AudioManager::instance()->ListOutputDevices().at(i).deviceName()); + if (!found_preferred_device + && AudioManager::instance()->ListOutputDevices().at(i).deviceName() == Config::Current()["AudioOutput"]) { + audio_output_devices->setCurrentIndex(audio_output_devices->count()-1); + found_preferred_device = true; + } + } + + // list all available audio input devices + found_preferred_device = false; + audio_input_devices->addItem(tr("Default"), ""); + for (int i=0;iListInputDevices().size();i++) { + audio_input_devices->addItem(AudioManager::instance()->ListInputDevices().at(i).deviceName(), + AudioManager::instance()->ListInputDevices().at(i).deviceName()); + if (!found_preferred_device + && AudioManager::instance()->ListInputDevices().at(i).deviceName() == Config::Current()["AudioInput"]) { + audio_input_devices->setCurrentIndex(audio_input_devices->count()-1); + found_preferred_device = true; + } + } + + has_devices_ = true; } diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index a7b4fde6b..8b3bcde32 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -34,6 +34,14 @@ private: */ QComboBox* recordingComboBox; +private slots: + void RefreshDevices(); + + void RetrieveDeviceLists(); + +private: + bool has_devices_; + }; #endif // PREFERENCESAUDIOTAB_H