Files
obs-studio/frontend/widgets/OBSBasic_VolControl.cpp

318 lines
10 KiB
C++

/******************************************************************************
Copyright (C) 2023 by Lain Bailey <lain@obsproject.com>
Zachary Lund <admin@computerquip.com>
Philippe Groarke <philippe.groarke@gmail.com>
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 2 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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "OBSBasic.hpp"
#include <widgets/VolControl.hpp>
using namespace std;
void OBSBasic::UpdateVolumeControlsDecayRate()
{
double meterDecayRate = config_get_double(activeConfiguration, "Audio", "MeterDecayRate");
for (size_t i = 0; i < volumes.size(); i++) {
volumes[i]->SetMeterDecayRate(meterDecayRate);
}
}
void OBSBasic::UpdateVolumeControlsPeakMeterType()
{
uint32_t peakMeterTypeIdx = config_get_uint(activeConfiguration, "Audio", "PeakMeterType");
enum obs_peak_meter_type peakMeterType;
switch (peakMeterTypeIdx) {
case 0:
peakMeterType = SAMPLE_PEAK_METER;
break;
case 1:
peakMeterType = TRUE_PEAK_METER;
break;
default:
peakMeterType = SAMPLE_PEAK_METER;
break;
}
for (size_t i = 0; i < volumes.size(); i++) {
volumes[i]->setPeakMeterType(peakMeterType);
}
}
void OBSBasic::ClearVolumeControls()
{
for (VolControl *vol : volumes)
delete vol;
volumes.clear();
}
void OBSBasic::RefreshVolumeColors()
{
for (VolControl *vol : volumes) {
vol->refreshColors();
}
}
void OBSBasic::HideAudioControl()
{
QAction *action = reinterpret_cast<QAction *>(sender());
VolControl *vol = action->property("volControl").value<VolControl *>();
obs_source_t *source = vol->GetSource();
if (!SourceMixerHidden(source)) {
SetSourceMixerHidden(source, true);
DeactivateAudioSource(source);
}
}
void OBSBasic::UnhideAllAudioControls()
{
auto UnhideAudioMixer = [this](obs_source_t *source) /* -- */
{
if (!obs_source_active(source))
return true;
if (!SourceMixerHidden(source))
return true;
SetSourceMixerHidden(source, false);
ActivateAudioSource(source);
return true;
};
using UnhideAudioMixer_t = decltype(UnhideAudioMixer);
auto PreEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
return (*reinterpret_cast<UnhideAudioMixer_t *>(data))(source);
};
obs_enum_sources(PreEnum, &UnhideAudioMixer);
}
void OBSBasic::ToggleHideMixer()
{
OBSSceneItem item = GetCurrentSceneItem();
OBSSource source = obs_sceneitem_get_source(item);
if (!SourceMixerHidden(source)) {
SetSourceMixerHidden(source, true);
DeactivateAudioSource(source);
} else {
SetSourceMixerHidden(source, false);
ActivateAudioSource(source);
}
}
void OBSBasic::LockVolumeControl(bool lock)
{
QAction *action = reinterpret_cast<QAction *>(sender());
VolControl *vol = action->property("volControl").value<VolControl *>();
obs_source_t *source = vol->GetSource();
OBSDataAutoRelease priv_settings = obs_source_get_private_settings(source);
obs_data_set_bool(priv_settings, "volume_locked", lock);
vol->EnableSlider(!lock);
}
void OBSBasic::VolControlContextMenu()
{
VolControl *vol = reinterpret_cast<VolControl *>(sender());
/* ------------------- */
QAction lockAction(QTStr("LockVolume"), this);
lockAction.setCheckable(true);
lockAction.setChecked(SourceVolumeLocked(vol->GetSource()));
QAction hideAction(QTStr("Hide"), this);
QAction unhideAllAction(QTStr("UnhideAll"), this);
QAction mixerRenameAction(QTStr("Rename"), this);
QAction copyFiltersAction(QTStr("Copy.Filters"), this);
QAction pasteFiltersAction(QTStr("Paste.Filters"), this);
QAction filtersAction(QTStr("Filters"), this);
QAction propertiesAction(QTStr("Properties"), this);
QAction advPropAction(QTStr("Basic.MainMenu.Edit.AdvAudio"), this);
QAction toggleControlLayoutAction(QTStr("VerticalLayout"), this);
toggleControlLayoutAction.setCheckable(true);
toggleControlLayoutAction.setChecked(
config_get_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl"));
/* ------------------- */
connect(&hideAction, &QAction::triggered, this, &OBSBasic::HideAudioControl, Qt::DirectConnection);
connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection);
connect(&lockAction, &QAction::toggled, this, &OBSBasic::LockVolumeControl, Qt::DirectConnection);
connect(&mixerRenameAction, &QAction::triggered, this, &OBSBasic::MixerRenameSource, Qt::DirectConnection);
connect(&copyFiltersAction, &QAction::triggered, this, &OBSBasic::AudioMixerCopyFilters, Qt::DirectConnection);
connect(&pasteFiltersAction, &QAction::triggered, this, &OBSBasic::AudioMixerPasteFilters,
Qt::DirectConnection);
connect(&filtersAction, &QAction::triggered, this, &OBSBasic::GetAudioSourceFilters, Qt::DirectConnection);
connect(&propertiesAction, &QAction::triggered, this, &OBSBasic::GetAudioSourceProperties,
Qt::DirectConnection);
connect(&advPropAction, &QAction::triggered, this, &OBSBasic::on_actionAdvAudioProperties_triggered,
Qt::DirectConnection);
/* ------------------- */
connect(&toggleControlLayoutAction, &QAction::changed, this, &OBSBasic::ToggleVolControlLayout,
Qt::DirectConnection);
/* ------------------- */
hideAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
lockAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
mixerRenameAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
copyFiltersAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
pasteFiltersAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
filtersAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
propertiesAction.setProperty("volControl", QVariant::fromValue<VolControl *>(vol));
/* ------------------- */
copyFiltersAction.setEnabled(obs_source_filter_count(vol->GetSource()) > 0);
pasteFiltersAction.setEnabled(!obs_weak_source_expired(copyFiltersSource));
QMenu popup;
vol->SetContextMenu(&popup);
popup.addAction(&lockAction);
popup.addSeparator();
popup.addAction(&unhideAllAction);
popup.addAction(&hideAction);
popup.addAction(&mixerRenameAction);
popup.addSeparator();
popup.addAction(&copyFiltersAction);
popup.addAction(&pasteFiltersAction);
popup.addSeparator();
popup.addAction(&toggleControlLayoutAction);
popup.addSeparator();
popup.addAction(&filtersAction);
popup.addAction(&propertiesAction);
popup.addAction(&advPropAction);
// toggleControlLayoutAction deletes and re-creates the volume controls
// meaning that "vol" would be pointing to freed memory.
if (popup.exec(QCursor::pos()) != &toggleControlLayoutAction)
vol->SetContextMenu(nullptr);
}
void OBSBasic::on_hMixerScrollArea_customContextMenuRequested()
{
StackedMixerAreaContextMenuRequested();
}
void OBSBasic::on_vMixerScrollArea_customContextMenuRequested()
{
StackedMixerAreaContextMenuRequested();
}
void OBSBasic::StackedMixerAreaContextMenuRequested()
{
QAction unhideAllAction(QTStr("UnhideAll"), this);
QAction advPropAction(QTStr("Basic.MainMenu.Edit.AdvAudio"), this);
QAction toggleControlLayoutAction(QTStr("VerticalLayout"), this);
toggleControlLayoutAction.setCheckable(true);
toggleControlLayoutAction.setChecked(
config_get_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl"));
/* ------------------- */
connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection);
connect(&advPropAction, &QAction::triggered, this, &OBSBasic::on_actionAdvAudioProperties_triggered,
Qt::DirectConnection);
/* ------------------- */
connect(&toggleControlLayoutAction, &QAction::changed, this, &OBSBasic::ToggleVolControlLayout,
Qt::DirectConnection);
/* ------------------- */
QMenu popup;
popup.addAction(&unhideAllAction);
popup.addSeparator();
popup.addAction(&toggleControlLayoutAction);
popup.addSeparator();
popup.addAction(&advPropAction);
popup.exec(QCursor::pos());
}
void OBSBasic::ToggleMixerLayout(bool vertical)
{
if (vertical) {
ui->stackedMixerArea->setMinimumSize(180, 220);
ui->stackedMixerArea->setCurrentIndex(1);
} else {
ui->stackedMixerArea->setMinimumSize(220, 0);
ui->stackedMixerArea->setCurrentIndex(0);
}
}
void OBSBasic::ToggleVolControlLayout()
{
bool vertical = !config_get_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl");
config_set_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl", vertical);
ToggleMixerLayout(vertical);
// We need to store it so we can delete current and then add
// at the right order
vector<OBSSource> sources;
for (size_t i = 0; i != volumes.size(); i++)
sources.emplace_back(volumes[i]->GetSource());
ClearVolumeControls();
for (const auto &source : sources)
ActivateAudioSource(source);
}
void OBSBasic::on_actionMixerToolbarAdvAudio_triggered()
{
on_actionAdvAudioProperties_triggered();
}
void OBSBasic::on_actionMixerToolbarMenu_triggered()
{
QAction unhideAllAction(QTStr("UnhideAll"), this);
connect(&unhideAllAction, &QAction::triggered, this, &OBSBasic::UnhideAllAudioControls, Qt::DirectConnection);
QAction toggleControlLayoutAction(QTStr("VerticalLayout"), this);
toggleControlLayoutAction.setCheckable(true);
toggleControlLayoutAction.setChecked(
config_get_bool(App()->GetUserConfig(), "BasicWindow", "VerticalVolControl"));
connect(&toggleControlLayoutAction, &QAction::changed, this, &OBSBasic::ToggleVolControlLayout,
Qt::DirectConnection);
QMenu popup;
popup.addAction(&unhideAllAction);
popup.addSeparator();
popup.addAction(&toggleControlLayoutAction);
popup.exec(QCursor::pos());
}