瀏覽代碼

UI: Add advanced audio properties dialog

This dialog gives options such as increasing audio past 100%, forcing
the audio of a source to mono, and setting the audio sync offset of a
source (which was an oft-requested feature)
jp9000 11 年之前
父節點
當前提交
6fc52dfb16

+ 4 - 0
obs/CMakeLists.txt

@@ -96,6 +96,7 @@ set(obs_SOURCES
 	window-basic-source-select.cpp
 	window-license-agreement.cpp
 	window-basic-status-bar.cpp
+	window-basic-adv-audio.cpp
 	window-basic-transform.cpp
 	window-basic-preview.cpp
 	window-namedialog.cpp
@@ -103,6 +104,7 @@ set(obs_SOURCES
 	window-remux.cpp
 	properties-view.cpp
 	volume-control.cpp
+	adv-audio-control.cpp
 	qt-wrappers.cpp)
 
 set(obs_HEADERS
@@ -116,6 +118,7 @@ set(obs_HEADERS
 	window-basic-source-select.hpp
 	window-license-agreement.hpp
 	window-basic-status-bar.hpp
+	window-basic-adv-audio.hpp
 	window-basic-transform.hpp
 	window-basic-preview.hpp
 	window-namedialog.hpp
@@ -124,6 +127,7 @@ set(obs_HEADERS
 	properties-view.hpp
 	display-helpers.hpp
 	volume-control.hpp
+	adv-audio-control.hpp
 	qt-display.hpp
 	qt-wrappers.hpp)
 

+ 253 - 0
obs/adv-audio-control.cpp

@@ -0,0 +1,253 @@
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QSpinBox>
+#include <QCheckBox>
+#include <QSlider>
+#include "qt-wrappers.hpp"
+#include "adv-audio-control.hpp"
+
+#ifndef NSEC_PER_MSEC
+#define NSEC_PER_MSEC 1000000
+#endif
+
+OBSAdvAudioCtrl::OBSAdvAudioCtrl(obs_source_t *source_)
+	: source(source_)
+{
+	QWidget *forceMonoContainer;
+	QWidget *mediaChannelContainer;
+	QWidget *panningContainer;
+	QHBoxLayout *hlayout;
+	QLabel  *labelL, *labelR;
+	signal_handler_t *handler = obs_source_get_signal_handler(source);
+	const char *sourceName = obs_source_get_name(source);
+	float vol = obs_source_get_volume(source);
+	uint32_t flags = obs_source_get_flags(source);
+
+	forceMonoContainer             = new QWidget();
+	mediaChannelContainer          = new QWidget();
+	panningContainer               = new QWidget();
+	labelL                         = new QLabel();
+	labelR                         = new QLabel();
+	nameLabel                      = new QLabel();
+	volume                         = new QSpinBox();
+	forceMono                      = new QCheckBox();
+	panning                        = new QSlider(Qt::Horizontal);
+	syncOffset                     = new QSpinBox();
+	mediaChannel1                  = new QCheckBox();
+	mediaChannel2                  = new QCheckBox();
+	mediaChannel3                  = new QCheckBox();
+	mediaChannel4                  = new QCheckBox();
+
+	volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged,
+			this);
+	syncOffsetSignal.Connect(handler, "audio_sync", OBSSourceSyncChanged,
+			this);
+	flagsSignal.Connect(handler, "update_flags", OBSSourceFlagsChanged,
+			this);
+
+	hlayout = new QHBoxLayout();
+	hlayout->setContentsMargins(0, 0, 0, 0);
+	forceMonoContainer->setLayout(hlayout);
+	hlayout = new QHBoxLayout();
+	hlayout->setContentsMargins(0, 0, 0, 0);
+	mediaChannelContainer->setLayout(hlayout);
+	hlayout = new QHBoxLayout();
+	hlayout->setContentsMargins(0, 0, 0, 0);
+	panningContainer->setLayout(hlayout);
+
+	labelL->setText("L");
+
+	labelR->setText("R");
+
+	nameLabel->setMinimumWidth(170);
+	nameLabel->setText(QT_UTF8(sourceName));
+	nameLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+
+	volume->setMinimum(0);
+	volume->setMaximum(2000);
+	volume->setMinimumWidth(130);
+	volume->setMaximumWidth(130);
+	volume->setValue(int(vol * 100.0f));
+
+	forceMono->setChecked((flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0);
+
+	forceMonoContainer->setMinimumWidth(130);
+	forceMonoContainer->setMaximumWidth(130);
+	forceMonoContainer->layout()->addWidget(forceMono);
+	forceMonoContainer->layout()->setAlignment(forceMono,
+			Qt::AlignHCenter | Qt::AlignVCenter);
+
+	panning->setMinimum(0);
+	panning->setMaximum(100);
+	panning->setTickPosition(QSlider::TicksAbove);
+	panning->setEnabled(false);
+	panning->setValue(50); /* XXX */
+
+	int64_t cur_sync = obs_source_get_sync_offset(source);
+	syncOffset->setMinimum(-20000);
+	syncOffset->setMaximum(20000);
+	syncOffset->setMinimumWidth(130);
+	syncOffset->setMaximumWidth(130);
+	syncOffset->setValue(int(cur_sync / NSEC_PER_MSEC));
+
+	mediaChannel1->setChecked(true);
+	mediaChannel1->setText("1");
+	mediaChannel1->setEnabled(false);
+	mediaChannel2->setText("2");
+	mediaChannel2->setEnabled(false);
+	mediaChannel3->setText("3");
+	mediaChannel3->setEnabled(false);
+	mediaChannel4->setText("4");
+	mediaChannel4->setEnabled(false);
+
+	panningContainer->setMinimumWidth(140);
+	panningContainer->setMaximumWidth(140);
+	panningContainer->layout()->addWidget(labelL);
+	panningContainer->layout()->addWidget(panning);
+	panningContainer->layout()->addWidget(labelR);
+
+	mediaChannelContainer->setMinimumWidth(160);
+	mediaChannelContainer->setMaximumWidth(160);
+	mediaChannelContainer->layout()->addWidget(mediaChannel1);
+	mediaChannelContainer->layout()->addWidget(mediaChannel2);
+	mediaChannelContainer->layout()->addWidget(mediaChannel3);
+	mediaChannelContainer->layout()->addWidget(mediaChannel4);
+
+	QWidget::connect(volume, SIGNAL(valueChanged(int)),
+			this, SLOT(volumeChanged(int)));
+	QWidget::connect(forceMono, SIGNAL(clicked(bool)),
+			this, SLOT(downmixMonoChanged(bool)));
+	QWidget::connect(panning, SIGNAL(valueChanged(int)),
+			this, SLOT(panningChanged(int)));
+	QWidget::connect(syncOffset, SIGNAL(valueChanged(int)),
+			this, SLOT(syncOffsetChanged(int)));
+	QWidget::connect(mediaChannel1, SIGNAL(clicked(bool)),
+			this, SLOT(mediaChannel1Changed(bool)));
+	QWidget::connect(mediaChannel2, SIGNAL(clicked(bool)),
+			this, SLOT(mediaChannel2Changed(bool)));
+	QWidget::connect(mediaChannel3, SIGNAL(clicked(bool)),
+			this, SLOT(mediaChannel3Changed(bool)));
+	QWidget::connect(mediaChannel4, SIGNAL(clicked(bool)),
+			this, SLOT(mediaChannel4Changed(bool)));
+
+	hlayout = new QHBoxLayout;
+	hlayout->setContentsMargins(0, 0, 0, 0);
+	hlayout->addWidget(nameLabel);
+	hlayout->addWidget(volume);
+	hlayout->addWidget(forceMonoContainer);
+	hlayout->addWidget(panningContainer);
+	hlayout->addWidget(syncOffset);
+	hlayout->addWidget(mediaChannelContainer);
+	setLayout(hlayout);
+	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
+}
+
+/* ------------------------------------------------------------------------- */
+/* OBS source callbacks */
+
+void OBSAdvAudioCtrl::OBSSourceFlagsChanged(void *param, calldata_t *calldata)
+{
+	uint32_t flags = (uint32_t)calldata_int(calldata, "flags");
+	QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
+			"SourceFlagsChanged", Q_ARG(uint32_t, flags));
+
+}
+
+void OBSAdvAudioCtrl::OBSSourceVolumeChanged(void *param, calldata_t *calldata)
+{
+	float volume = (float)calldata_float(calldata, "volume");
+	QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
+			"SourceVolumeChanged", Q_ARG(float, volume));
+}
+
+void OBSAdvAudioCtrl::OBSSourceSyncChanged(void *param, calldata_t *calldata)
+{
+	int64_t offset = calldata_int(calldata, "offset");
+	QMetaObject::invokeMethod(reinterpret_cast<OBSAdvAudioCtrl*>(param),
+			"SourceSyncChanged", Q_ARG(int64_t, offset));
+}
+
+/* ------------------------------------------------------------------------- */
+/* Qt event queue source callbacks */
+
+void OBSAdvAudioCtrl::SourceFlagsChanged(uint32_t flags)
+{
+	bool forceMonoVal = (flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0;
+
+	if (forceMono->isChecked() != forceMonoVal)
+		forceMono->setChecked(forceMonoVal);
+}
+
+void OBSAdvAudioCtrl::SourceVolumeChanged(float value)
+{
+	volume->setValue(int(value * 100));
+}
+
+void OBSAdvAudioCtrl::SourceSyncChanged(int64_t offset)
+{
+	syncOffset->setValue(offset / NSEC_PER_MSEC);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Qt control callbacks */
+
+void OBSAdvAudioCtrl::volumeChanged(int percentage)
+{
+	float val = float(percentage) / 100.0f;
+	if (!close_float(val, obs_source_get_volume(source), 0.01f))
+		obs_source_set_volume(source, val);
+}
+
+void OBSAdvAudioCtrl::downmixMonoChanged(bool checked)
+{
+	uint32_t flags = obs_source_get_flags(source);
+	bool forceMonoActive = (flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0;
+
+	if (forceMonoActive != checked) {
+		if (checked)
+			flags |= OBS_SOURCE_FLAG_FORCE_MONO;
+		else
+			flags &= ~OBS_SOURCE_FLAG_FORCE_MONO;
+
+		obs_source_set_flags(source, flags);
+	}
+}
+
+void OBSAdvAudioCtrl::panningChanged(int val)
+{
+	/* TODO */
+	UNUSED_PARAMETER(val);
+}
+
+void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds)
+{
+	int64_t cur_val = obs_source_get_sync_offset(source);
+
+	if (cur_val / NSEC_PER_MSEC != milliseconds)
+		obs_source_set_sync_offset(source,
+				int64_t(milliseconds) * NSEC_PER_MSEC);
+}
+
+void OBSAdvAudioCtrl::mediaChannel1Changed(bool checked)
+{
+	/* TODO */
+	UNUSED_PARAMETER(checked);
+}
+
+void OBSAdvAudioCtrl::mediaChannel2Changed(bool checked)
+{
+	/* TODO */
+	UNUSED_PARAMETER(checked);
+}
+
+void OBSAdvAudioCtrl::mediaChannel3Changed(bool checked)
+{
+	/* TODO */
+	UNUSED_PARAMETER(checked);
+}
+
+void OBSAdvAudioCtrl::mediaChannel4Changed(bool checked)
+{
+	/* TODO */
+	UNUSED_PARAMETER(checked);
+}

+ 52 - 0
obs/adv-audio-control.hpp

@@ -0,0 +1,52 @@
+#pragma once
+
+#include <obs.hpp>
+#include <QWidget>
+
+class QLabel;
+class QSpinBox;
+class QCheckBox;
+class QSlider;
+
+class OBSAdvAudioCtrl : public QWidget {
+	Q_OBJECT
+
+private:
+	OBSSource              source;
+	QLabel                 *nameLabel              = nullptr;
+	QSpinBox               *volume                 = nullptr;
+	QCheckBox              *forceMono              = nullptr;
+	QSlider                *panning                = nullptr;
+	QSpinBox               *syncOffset             = nullptr;
+	QCheckBox              *mediaChannel1          = nullptr;
+	QCheckBox              *mediaChannel2          = nullptr;
+	QCheckBox              *mediaChannel3          = nullptr;
+	QCheckBox              *mediaChannel4          = nullptr;
+
+	OBSSignal              volChangedSignal;
+	OBSSignal              syncOffsetSignal;
+	OBSSignal              flagsSignal;
+
+	static void OBSSourceFlagsChanged(void *param, calldata_t *calldata);
+	static void OBSSourceVolumeChanged(void *param, calldata_t *calldata);
+	static void OBSSourceSyncChanged(void *param, calldata_t *calldata);
+
+public:
+	OBSAdvAudioCtrl(obs_source_t *source_);
+
+	inline obs_source_t *GetSource() const {return source;}
+
+public slots:
+	void SourceFlagsChanged(uint32_t flags);
+	void SourceVolumeChanged(float volume);
+	void SourceSyncChanged(int64_t offset);
+
+	void volumeChanged(int percentage);
+	void downmixMonoChanged(bool checked);
+	void panningChanged(int val);
+	void syncOffsetChanged(int milliseconds);
+	void mediaChannel1Changed(bool checked);
+	void mediaChannel2Changed(bool checked);
+	void mediaChannel3Changed(bool checked);
+	void mediaChannel4Changed(bool checked);
+};

+ 10 - 0
obs/data/locale/en-US.ini

@@ -189,6 +189,7 @@ Basic.MainMenu.Edit.Order.MoveUp="Move &Up"
 Basic.MainMenu.Edit.Order.MoveDown="Move &Down"
 Basic.MainMenu.Edit.Order.MoveToTop="Move to &Top"
 Basic.MainMenu.Edit.Order.MoveToBottom="Move to &Bottom"
+Basic.MainMenu.Edit.AdvAudio="&Advanced Audio Properties"
 
 # basic mode help menu
 Basic.MainMenu.Help="&Help"
@@ -258,3 +259,12 @@ Basic.Settings.Audio.DesktopDevice2="Desktop Audio Device 2"
 Basic.Settings.Audio.AuxDevice="Mic/Auxiliary Audio Device"
 Basic.Settings.Audio.AuxDevice2="Mic/Auxiliary Audio Device 2"
 Basic.Settings.Audio.AuxDevice3="Mic/Auxiliary Audio Device 3"
+
+# advanced audio properties
+Basic.AdvAudio="Advanced Audio Properties"
+Basic.AdvAudio.Name="Name"
+Basic.AdvAudio.Volume="Volume (%)"
+Basic.AdvAudio.Mono="Downmix to Mono"
+Basic.AdvAudio.Panning="Panning"
+Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
+Basic.AdvAudio.MediaChannel="Media Channel"

+ 10 - 3
obs/forms/OBSBasic.ui

@@ -28,7 +28,7 @@
   </property>
   <property name="windowIcon">
    <iconset resource="obs.qrc">
-   <normaloff>:/res/images/obs.png</normaloff>:/res/images/obs.png</iconset>
+    <normaloff>:/res/images/obs.png</normaloff>:/res/images/obs.png</iconset>
   </property>
   <widget class="QWidget" name="centralwidget">
    <layout class="QVBoxLayout" name="verticalLayout">
@@ -338,7 +338,7 @@
               <rect>
                <x>0</x>
                <y>0</y>
-               <width>233</width>
+               <width>216</width>
                <height>16</height>
               </rect>
              </property>
@@ -452,7 +452,7 @@
      <x>0</x>
      <y>0</y>
      <width>927</width>
-     <height>24</height>
+     <height>26</height>
     </rect>
    </property>
    <widget class="QMenu" name="menu_File">
@@ -521,6 +521,8 @@
     <addaction name="separator"/>
     <addaction name="transformMenu"/>
     <addaction name="orderMenu"/>
+    <addaction name="separator"/>
+    <addaction name="actionAdvAudioProperties"/>
    </widget>
    <addaction name="menu_File"/>
    <addaction name="menuBasic_MainMenu_Edit"/>
@@ -817,6 +819,11 @@
     <string>Interact</string>
    </property>
   </action>
+  <action name="actionAdvAudioProperties">
+   <property name="text">
+    <string>Basic.MainMenu.Edit.AdvAudio</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>

+ 160 - 0
obs/window-basic-adv-audio.cpp

@@ -0,0 +1,160 @@
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QScrollArea>
+#include <QLabel>
+#include "window-basic-adv-audio.hpp"
+#include "adv-audio-control.hpp"
+#include "obs-app.hpp"
+#include "qt-wrappers.hpp"
+
+Q_DECLARE_METATYPE(OBSSource);
+
+OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
+	: QDialog(parent),
+	  sourceAddedSignal(obs_get_signal_handler(), "source_activate",
+			  OBSSourceAdded, this),
+	  sourceRemovedSignal(obs_get_signal_handler(), "source_deactivate",
+			  OBSSourceRemoved, this)
+{
+	QScrollArea *scrollArea;
+	QVBoxLayout *vlayout;
+	QHBoxLayout *hlayout;
+	QWidget *widget;
+	QLabel *label;
+
+	hlayout = new QHBoxLayout;
+	hlayout->setContentsMargins(0, 0, 0, 0);
+	label = new QLabel(QTStr("Basic.AdvAudio.Name"));
+	label->setMinimumWidth(170);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	label = new QLabel(QTStr("Basic.AdvAudio.Volume"));
+	label->setMinimumWidth(130);
+	label->setMaximumWidth(130);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	label = new QLabel(QTStr("Basic.AdvAudio.Mono"));
+	label->setMinimumWidth(130);
+	label->setMaximumWidth(130);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	label = new QLabel(QTStr("Basic.AdvAudio.Panning"));
+	label->setMinimumWidth(140);
+	label->setMaximumWidth(140);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	label = new QLabel(QTStr("Basic.AdvAudio.SyncOffset"));
+	label->setMinimumWidth(130);
+	label->setMaximumWidth(130);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	label = new QLabel(QTStr("Basic.AdvAudio.MediaChannel"));
+	label->setMinimumWidth(160);
+	label->setMaximumWidth(160);
+	label->setAlignment(Qt::AlignHCenter);
+	hlayout->addWidget(label);
+	widget = new QWidget;
+	widget->setLayout(hlayout);
+
+	vlayout = new QVBoxLayout;
+	vlayout->setContentsMargins(0, 0, 0, 10);
+	vlayout->addWidget(widget);
+	controlArea = new QWidget;
+	controlArea->setLayout(vlayout);
+	controlArea->setSizePolicy(QSizePolicy::Preferred,
+			QSizePolicy::Preferred);
+
+	vlayout = new QVBoxLayout;
+	vlayout->addWidget(controlArea);
+	//vlayout->setAlignment(controlArea, Qt::AlignTop);
+	widget = new QWidget;
+	widget->setLayout(vlayout);
+	widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+
+	scrollArea = new QScrollArea;
+	scrollArea->setWidget(widget);
+	scrollArea->setWidgetResizable(true);
+
+	vlayout = new QVBoxLayout;
+	vlayout->setContentsMargins(11, 11, 11, 11);
+	vlayout->addWidget(scrollArea);
+	setLayout(vlayout);
+
+	/* get global audio sources */
+	for (uint32_t i = 1; i <= 10; i++) {
+		obs_source_t *source = obs_get_output_source(i);
+		if (source) {
+			AddAudioSource(source);
+			obs_source_release(source);
+		}
+	}
+
+	/* enum user scene/sources */
+	obs_enum_sources(EnumSources, this);
+
+	resize(1000, 340);
+	setWindowTitle(QTStr("Basic.AdvAudio"));
+	setSizeGripEnabled(true);
+	setWindowModality(Qt::NonModal);
+	setAttribute(Qt::WA_DeleteOnClose, true);
+}
+
+bool OBSBasicAdvAudio::EnumSources(void *param, obs_source_t *source)
+{
+	OBSBasicAdvAudio *dialog = reinterpret_cast<OBSBasicAdvAudio*>(param);
+	uint32_t flags = obs_source_get_output_flags(source);
+
+	if ((flags & OBS_SOURCE_AUDIO) != 0 && obs_source_active(source))
+		dialog->AddAudioSource(source);
+
+	return true;
+}
+
+void OBSBasicAdvAudio::OBSSourceAdded(void *param, calldata_t *calldata)
+{
+	OBSSource source((obs_source_t*)calldata_ptr(calldata, "source"));
+
+	QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param),
+			"SourceAdded", Q_ARG(OBSSource, source));
+}
+
+void OBSBasicAdvAudio::OBSSourceRemoved(void *param, calldata_t *calldata)
+{
+	OBSSource source((obs_source_t*)calldata_ptr(calldata, "source"));
+
+	QMetaObject::invokeMethod(reinterpret_cast<OBSBasicAdvAudio*>(param),
+			"SourceRemoved", Q_ARG(OBSSource, source));
+}
+
+inline void OBSBasicAdvAudio::AddAudioSource(obs_source_t *source)
+{
+	OBSAdvAudioCtrl *control = new OBSAdvAudioCtrl(source);
+	controlArea->layout()->addWidget(control);
+	controls.push_back(control);
+}
+
+void OBSBasicAdvAudio::SourceAdded(OBSSource source)
+{
+	uint32_t flags = obs_source_get_output_flags(source);
+
+	if ((flags & OBS_SOURCE_AUDIO) == 0)
+		return;
+
+	AddAudioSource(source);
+}
+
+void OBSBasicAdvAudio::SourceRemoved(OBSSource source)
+{
+	uint32_t flags = obs_source_get_output_flags(source);
+
+	if ((flags & OBS_SOURCE_AUDIO) == 0)
+		return;
+
+	for (size_t i = 0; i < controls.size(); i++) {
+		if (controls[i]->GetSource() == source) {
+			delete controls[i];
+			controls.erase(controls.begin() + i);
+			break;
+		}
+	}
+}

+ 34 - 0
obs/window-basic-adv-audio.hpp

@@ -0,0 +1,34 @@
+#pragma once
+
+#include <obs.hpp>
+#include <QDialog>
+#include <vector>
+
+class OBSAdvAudioCtrl;
+
+// "Basic advanced audio"?  ...
+
+class OBSBasicAdvAudio : public QDialog {
+	Q_OBJECT
+
+private:
+	QWidget *controlArea;
+	OBSSignal sourceAddedSignal;
+	OBSSignal sourceRemovedSignal;
+
+	std::vector<OBSAdvAudioCtrl*> controls;
+
+	inline void AddAudioSource(obs_source_t *source);
+
+	static bool EnumSources(void *param, obs_source_t *source);
+
+	static void OBSSourceAdded(void *param, calldata_t *calldata);
+	static void OBSSourceRemoved(void *param, calldata_t *calldata);
+
+public slots:
+	void SourceAdded(OBSSource source);
+	void SourceRemoved(OBSSource source);
+
+public:
+	OBSBasicAdvAudio(QWidget *parent);
+};

+ 10 - 0
obs/window-basic-main.cpp

@@ -619,6 +619,9 @@ OBSBasic::~OBSBasic()
 	if (transformWindow)
 		delete transformWindow;
 
+	if (advAudioWindow)
+		delete advAudioWindow;
+
 	ClearVolumeControls();
 	ui->sources->clear();
 	ui->scenes->clear();
@@ -1561,6 +1564,13 @@ void OBSBasic::on_action_Settings_triggered()
 	settings.exec();
 }
 
+void OBSBasic::on_actionAdvAudioProperties_triggered()
+{
+	advAudioWindow = new OBSBasicAdvAudio(this);
+	advAudioWindow->show();
+	advAudioWindow->setAttribute(Qt::WA_DeleteOnClose, true);
+}
+
 void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
 		QListWidgetItem *prev)
 {

+ 3 - 0
obs/window-basic-main.hpp

@@ -28,6 +28,7 @@
 #include "window-basic-interaction.hpp"
 #include "window-basic-properties.hpp"
 #include "window-basic-transform.hpp"
+#include "window-basic-adv-audio.hpp"
 
 #include <util/platform.h>
 #include <util/util.hpp>
@@ -61,6 +62,7 @@ private:
 	QPointer<OBSBasicInteraction> interaction;
 	QPointer<OBSBasicProperties> properties;
 	QPointer<OBSBasicTransform> transformWindow;
+	QPointer<OBSBasicAdvAudio> advAudioWindow;
 
 	QNetworkAccessManager networkManager;
 
@@ -230,6 +232,7 @@ private slots:
 	void on_actionShow_Recordings_triggered();
 	void on_actionRemux_triggered();
 	void on_action_Settings_triggered();
+	void on_actionAdvAudioProperties_triggered();
 	void on_actionShowLogs_triggered();
 	void on_actionUploadCurrentLog_triggered();
 	void on_actionUploadLastLog_triggered();