diff --git a/src/audiomixer/mixermanager.cpp b/src/audiomixer/mixermanager.cpp
index 65ddc457f..780ebfeff 100644
--- a/src/audiomixer/mixermanager.cpp
+++ b/src/audiomixer/mixermanager.cpp
@@ -1,215 +1,215 @@
/***************************************************************************
* Copyright (C) 2019 by Jean-Baptiste Mardelle *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* 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) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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 "mixermanager.hpp"
#include "mixerwidget.hpp"
#include "timeline2/model/timelineitemmodel.hpp"
#include "kdenlivesettings.h"
#include "mlt++/MltService.h"
#include "mlt++/MltTractor.h"
#include
#include
#include
#include
#include
const double log_factor = 1.0 / log10(1.0 / 127);
static inline double levelToDB(double level)
{
if (level <= 0) {
return -100;
}
return 100 * (1.0 - log10(level) * log_factor);
}
MixerManager::MixerManager(QWidget *parent)
: QWidget(parent)
, m_masterMixer(nullptr)
, m_connectedWidgets(false)
, m_expandedWidth(-1)
{
m_masterBox = new QHBoxLayout;
m_channelsBox = new QScrollArea(this);
m_box = new QHBoxLayout;
m_box->setSpacing(0);
auto *channelsBoxContainer = new QWidget;
channelsBoxContainer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
m_channelsBox->setWidget(channelsBoxContainer);
m_channelsBox->setWidgetResizable(true);
m_channelsBox->setFrameShape(QFrame::NoFrame);
m_box->addWidget(m_channelsBox);
m_channelsLayout = new QHBoxLayout;
m_channelsLayout->setContentsMargins(0, 0, 0, 0);
m_channelsLayout->setSpacing(0);
channelsBoxContainer->setLayout(m_channelsLayout);
m_channelsLayout->addStretch(10);
m_line = new QFrame(this);
m_line->setFrameShape(QFrame::VLine);
m_line->setFrameShadow(QFrame::Sunken);
m_box->addWidget(m_line);
m_box->addLayout(m_masterBox);
setLayout(m_box);
}
void MixerManager::registerTrack(int tid, std::shared_ptr service, const QString &trackTag)
{
if (m_mixers.count(tid) > 0) {
// Track already registered
return;
}
std::shared_ptr mixer(new MixerWidget(tid, service, trackTag, this));
connect(mixer.get(), &MixerWidget::muteTrack, [&](int id, bool mute) {
m_model->setTrackProperty(id, "hide", mute ? QStringLiteral("1") : QStringLiteral("3"));
});
if (m_connectedWidgets) {
mixer->connectMixer(true);
}
connect(this, &MixerManager::updateLevels, mixer.get(), &MixerWidget::updateAudioLevel);
connect(this, &MixerManager::clearMixers, mixer.get(), &MixerWidget::clear);
connect(mixer.get(), &MixerWidget::toggleSolo, [&](int trid, bool solo) {
if (!solo) {
// unmute
for (int id : m_soloMuted) {
if (m_mixers.count(id) > 0) {
m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
}
}
m_soloMuted.clear();
} else {
if (!m_soloMuted.isEmpty()) {
// Another track was solo, discard first
for (int id : m_soloMuted) {
if (m_mixers.count(id) > 0) {
m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
}
}
m_soloMuted.clear();
}
for (auto item : m_mixers) {
if (item.first != trid && !item.second->isMute()) {
m_model->setTrackProperty(item.first, "hide", QStringLiteral("3"));
m_soloMuted << item.first;
item.second->unSolo();
}
}
}
});
m_mixers[tid] = mixer;
m_channelsLayout->insertWidget(0, mixer.get());
}
void MixerManager::deregisterTrack(int tid)
{
Q_ASSERT(m_mixers.count(tid) > 0);
m_mixers.erase(tid);
}
void MixerManager::cleanup()
{
for (auto item : m_mixers) {
m_channelsLayout->removeWidget(item.second.get());
}
m_mixers.clear();
if (m_masterMixer) {
- m_masterMixer->clear(true);
+ m_masterMixer->reset();
}
}
void MixerManager::setModel(std::shared_ptr model)
{
// Insert master mixer
m_model = model;
connect(m_model.get(), &TimelineItemModel::dataChanged, [&](const QModelIndex &topLeft, const QModelIndex &, const QVector &roles) {
if (roles.contains(TimelineModel::IsDisabledRole)) {
int id = (int) topLeft.internalId();
if (m_mixers.count(id) > 0) {
m_mixers[id]->setMute(m_model->data(topLeft, TimelineModel::IsDisabledRole).toBool());
} else {
qDebug()<<"=== MODEL DATA CHANGED: MUTE DONE TRACK NOT FOUND!!!";
}
}
});
Mlt::Tractor *service = model->tractor();
if (m_masterMixer != nullptr) {
// delete previous master mixer
m_masterBox->removeWidget(m_masterMixer.get());
}
m_masterMixer.reset(new MixerWidget(-1, service, i18n("Master"), this));
connect(m_masterMixer.get(), &MixerWidget::muteTrack, [&](int /*id*/, bool mute) {
m_model->tractor()->set("hide", mute ? 3 : 1);
});
if (m_connectedWidgets) {
m_masterMixer->connectMixer(true);
}
connect(this, &MixerManager::updateLevels, m_masterMixer.get(), &MixerWidget::updateAudioLevel);
connect(this, &MixerManager::clearMixers, m_masterMixer.get(), &MixerWidget::clear);
m_masterBox->addWidget(m_masterMixer.get());
collapseMixers();
}
void MixerManager::recordStateChanged(int tid, bool recording)
{
if (m_mixers.count(tid) > 0) {
m_mixers[tid]->setRecordState(recording);
}
}
void MixerManager::connectMixer(bool doConnect, bool channelsOnly)
{
m_connectedWidgets = doConnect;
for (auto item : m_mixers) {
item.second->connectMixer(m_connectedWidgets);
}
if (!channelsOnly && m_masterMixer != nullptr) {
m_masterMixer->connectMixer(m_connectedWidgets);
}
}
void MixerManager::collapseMixers()
{
if (KdenliveSettings::mixerCollapse()) {
m_expandedWidth = width();
m_channelsBox->setFixedWidth(0);
m_line->setMaximumWidth(0);
connectMixer(false, true);
setFixedWidth(m_masterMixer->width() + 2 * m_box->contentsMargins().left());
} else {
m_line->setMaximumWidth(QWIDGETSIZE_MAX);
m_channelsBox->setMaximumWidth(QWIDGETSIZE_MAX);
m_channelsBox->setMinimumWidth(m_masterMixer->width() + 2 * m_box->contentsMargins().left());
setMaximumWidth(QWIDGETSIZE_MAX);
if (m_expandedWidth > 0) {
setFixedWidth(m_expandedWidth);
}
connectMixer(true, true);
QTimer::singleShot(500, this, &MixerManager::resetSizePolicy);
}
}
void MixerManager::resetSizePolicy()
{
setMaximumWidth(QWIDGETSIZE_MAX);
setMinimumWidth(0);
}
diff --git a/src/audiomixer/mixerwidget.cpp b/src/audiomixer/mixerwidget.cpp
index ff45ee34c..035c2b629 100644
--- a/src/audiomixer/mixerwidget.cpp
+++ b/src/audiomixer/mixerwidget.cpp
@@ -1,480 +1,486 @@
/***************************************************************************
* Copyright (C) 2019 by Jean-Baptiste Mardelle *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* 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) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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 "mixerwidget.hpp"
#include "mlt++/MltFilter.h"
#include "mlt++/MltTractor.h"
#include "mlt++/MltEvent.h"
#include "mlt++/MltProfile.h"
#include "core.h"
#include "kdenlivesettings.h"
#include "mixermanager.hpp"
#include "audiolevelwidget.hpp"
#include "capture/mediacapture.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static inline double IEC_Scale(double dB)
{
dB = log10(dB) * 20.0;
double fScale = 1.0f;
if (dB < -70.0f)
fScale = 0.0f;
else if (dB < -60.0f)
fScale = (dB + 70.0f) * 0.0025f;
else if (dB < -50.0f)
fScale = (dB + 60.0f) * 0.005f + 0.025f;
else if (dB < -40.0)
fScale = (dB + 50.0f) * 0.0075f + 0.075f;
else if (dB < -30.0f)
fScale = (dB + 40.0f) * 0.015f + 0.15f;
else if (dB < -20.0f)
fScale = (dB + 30.0f) * 0.02f + 0.3f;
else if (dB < -0.001f || dB > 0.001f) /* if (dB < 0.0f) */
fScale = (dB + 20.0f) * 0.025f + 0.5f;
return fScale;
}
static inline int fromDB(double level)
{
int value = 60;
if (level > 0.) {
// increase volume
value = 100 - ((pow(10, 1. - level/24) - 1) / .225);
} else if (level < 0.) {
value = (10 - pow(10, 1. - level/-50)) / -0.11395 + 59;
}
return value;
}
void MixerWidget::property_changed( mlt_service , MixerWidget *widget, char *name )
{
if (widget && !strcmp(name, "_position")) {
mlt_properties filter_props = MLT_FILTER_PROPERTIES( widget->m_monitorFilter->get_filter());
int pos = mlt_properties_get_int(filter_props, "_position");
if (!widget->m_levels.contains(pos)) {
widget->m_levels[pos] = {IEC_Scale(mlt_properties_get_double(filter_props, "_audio_level.0")), IEC_Scale(mlt_properties_get_double(filter_props, "_audio_level.1"))};
if (widget->m_levels.size() > widget->m_maxLevels) {
widget->m_levels.erase(widget->m_levels.begin());
}
}
}
}
MixerWidget::MixerWidget(int tid, std::shared_ptr service, const QString &trackTag, MixerManager *parent)
: QWidget(parent)
, m_manager(parent)
, m_tid(tid)
, m_levelFilter(nullptr)
, m_monitorFilter(nullptr)
, m_balanceFilter(nullptr)
, m_maxLevels(qMax(30, (int)(service->get_fps() * 1.5)))
, m_solo(nullptr)
, m_record(nullptr)
, m_collapse(nullptr)
, m_lastVolume(0)
, m_listener(nullptr)
, m_recording(false)
{
buildUI(service.get(), trackTag);
}
MixerWidget::MixerWidget(int tid, Mlt::Tractor *service, const QString &trackTag, MixerManager *parent)
: QWidget(parent)
, m_manager(parent)
, m_tid(tid)
, m_levelFilter(nullptr)
, m_monitorFilter(nullptr)
, m_balanceFilter(nullptr)
, m_maxLevels(qMax(30, (int)(service->get_fps() * 1.5)))
, m_solo(nullptr)
, m_record(nullptr)
, m_collapse(nullptr)
, m_lastVolume(0)
, m_listener(nullptr)
, m_recording(false)
{
buildUI(service, trackTag);
}
MixerWidget::~MixerWidget()
{
if (m_listener) {
delete m_listener;
}
}
void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
{
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
// Build audio meter widget
m_audioMeterWidget.reset(new AudioLevelWidget(width(), this));
// intialize for stereo display
m_audioMeterWidget->setAudioValues({-100, -100});
// Build volume widget
m_volumeSlider = new QSlider(Qt::Vertical, this);
m_volumeSlider->setRange(0, 100);
m_volumeSlider->setValue(60);
m_volumeSlider->setToolTip(i18n("Volume"));
m_volumeSpin = new QDoubleSpinBox(this);
m_volumeSpin->setRange(-50, 24);
m_volumeSpin->setSuffix(i18n("dB"));
m_volumeSpin->setFrame(false);
connect(m_volumeSpin, static_cast(&QDoubleSpinBox::valueChanged), [&](double val) {
m_volumeSlider->setValue(fromDB(val));
});
m_balanceDial = new QDial(this);
m_balanceDial->setRange(-50, 50);
m_balanceDial->setValue(0);
m_balanceSpin = new QSpinBox(this);
m_balanceSpin->setRange(-50, 50);
m_balanceSpin->setValue(0);
m_balanceSpin->setFrame(false);
m_balanceSpin->setToolTip(i18n("Balance"));
// Check if we already have build-in filters for this tractor
int max = service->filter_count();
for (int i = 0; i < max; i++) {
std::shared_ptr fl(service->filter(i));
if (!fl->is_valid()) {
continue;
}
const QString filterService = fl->get("mlt_service");
if (filterService == QLatin1String("audiolevel")) {
m_monitorFilter = fl;
} else if (filterService == QLatin1String("volume")) {
m_levelFilter = fl;
int volume = m_levelFilter->get_int("level");
m_volumeSpin->setValue(volume);
m_volumeSlider->setValue(fromDB(volume));
} else if (filterService == QLatin1String("panner")) {
m_balanceFilter = fl;
int val = m_balanceFilter->get_double("start") * 100 - 50;
m_balanceSpin->setValue(val);
m_balanceDial->setValue(val);
}
}
// Build default filters if not found
if (m_levelFilter == nullptr) {
m_levelFilter.reset(new Mlt::Filter(service->get_profile(), "volume"));
if (m_levelFilter->is_valid()) {
m_levelFilter->set("internal_added", 237);
m_levelFilter->set("disable", 1);
service->attach(*m_levelFilter.get());
}
}
if (m_balanceFilter == nullptr) {
m_balanceFilter.reset(new Mlt::Filter(service->get_profile(), "panner"));
if (m_balanceFilter->is_valid()) {
m_balanceFilter->set("internal_added", 237);
m_balanceFilter->set("start", 0.5);
m_balanceFilter->set("disable", 1);
service->attach(*m_balanceFilter.get());
}
}
// Monitoring should be appended last so that other effects are reflected in audio monitor
if (m_monitorFilter == nullptr) {
m_monitorFilter.reset(new Mlt::Filter(service->get_profile(), "audiolevel"));
if (m_monitorFilter->is_valid()) {
m_monitorFilter->set("iec_scale", 0);
service->attach(*m_monitorFilter.get());
}
}
m_trackLabel = new QLabel(trackTag, this);
m_trackLabel->setAutoFillBackground(true);
m_trackLabel->setAlignment(Qt::AlignHCenter);
m_trackLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
m_muteAction = new KDualAction(i18n("Mute track"), i18n("Unmute track"), this);
m_muteAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-hide-audio")));
m_muteAction->setInactiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-show-audio")));
connect(m_balanceDial, &QDial::valueChanged, m_balanceSpin, &QSpinBox::setValue);
connect(m_muteAction, &KDualAction::activeChangedByUser, [&](bool active) {
if (m_tid == -1) {
// Muting master, special case
if (m_levelFilter) {
if (active) {
m_lastVolume = m_levelFilter->get_int("level");
m_levelFilter->set("level", -1000);
} else {
m_levelFilter->set("level", m_lastVolume);
}
}
} else {
emit muteTrack(m_tid, !active);
- clear(true);
+ reset();
}
updateLabel();
});
QToolButton *mute = new QToolButton(this);
mute->setDefaultAction(m_muteAction);
mute->setAutoRaise(true);
// Setup default width
QFontMetrics fm(font());
setFixedWidth(3 * mute->sizeHint().width());
if (m_tid > -1) {
// No solo / rec button on master
m_solo = new QToolButton(this);
m_solo->setCheckable(true);
m_solo->setIcon(QIcon::fromTheme("headphones"));
m_solo->setToolTip(i18n("Solo mode"));
m_solo->setAutoRaise(true);
connect(m_solo, &QToolButton::toggled, [&](bool toggled) {
emit toggleSolo(m_tid, toggled);
updateLabel();
});
m_record = new QToolButton(this);
m_record->setIcon(QIcon::fromTheme("media-record"));
m_record->setToolTip(i18n("Record"));
m_record->setCheckable(true);
m_record->setAutoRaise(true);
connect(m_record, &QToolButton::clicked, [&]() {
m_manager->recordAudio(m_tid);
});
} else {
m_collapse = new QToolButton(this);
m_collapse->setIcon(QIcon::fromTheme("arrow-left"));
m_collapse->setToolTip(i18n("Show Channels"));
m_collapse->setCheckable(true);
m_collapse->setAutoRaise(true);
connect(m_collapse, &QToolButton::clicked, [&]() {
KdenliveSettings::setMixerCollapse(m_collapse->isChecked());
m_manager->collapseMixers();
});
}
connect(m_volumeSlider, &QSlider::valueChanged, [&](int value) {
QSignalBlocker bk(m_volumeSpin);
if (m_recording) {
m_volumeSpin->setValue(value);
KdenliveSettings::setAudiocapturevolume(value);
//TODO update capture volume
} else if (m_levelFilter != nullptr) {
double dbValue = 0;
if (value > 60) {
// increase volume
dbValue = 24 * (1 - log10((100 - value)*0.225 + 1));
} else if (value < 60) {
dbValue = -50 * (1 - log10(10 - (value - 59)*(-0.11395)));
}
m_volumeSpin->setValue(dbValue);
m_levelFilter->set("level", dbValue);
m_levelFilter->set("disable", value == 60 ? 1 : 0);
m_levels.clear();
m_manager->purgeCache();
}
});
connect(m_balanceSpin, static_cast(&QSpinBox::valueChanged), [&](int value) {
QSignalBlocker bk(m_balanceDial);
m_balanceDial->setValue(value);
if (m_balanceFilter != nullptr) {
m_balanceFilter->set("start", (value + 50) / 100.);
m_balanceFilter->set("disable", value == 0 ? 1 : 0);
m_levels.clear();
m_manager->purgeCache();
}
});
QVBoxLayout *lay = new QVBoxLayout;
setContentsMargins(0, 0, 0, 0);
lay->setMargin(0);
lay->addWidget(m_trackLabel);
QHBoxLayout *buttonslay = new QHBoxLayout;
buttonslay->setSpacing(0);
buttonslay->setContentsMargins(0, 0, 0, 0);
if (m_collapse) {
buttonslay->addWidget(m_collapse);
}
buttonslay->addWidget(mute);
if (m_solo) {
buttonslay->addWidget(m_solo);
}
if (m_record) {
buttonslay->addWidget(m_record);
}
lay->addLayout(buttonslay);
lay->addWidget(m_balanceDial);
lay->addWidget(m_balanceSpin);
QHBoxLayout *hlay = new QHBoxLayout;
hlay->addWidget(m_audioMeterWidget.get());
hlay->addWidget(m_volumeSlider);
lay->addLayout(hlay);
lay->addWidget(m_volumeSpin);
lay->setStretch(4, 10);
setLayout(lay);
if (service->get_int("hide") > 1) {
setMute(true);
}
}
void MixerWidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::RightButton) {
QWidget *child = childAt(event->pos());
if (child == m_balanceDial) {
m_balanceSpin->setValue(0);
} else if (child == m_volumeSlider) {
m_volumeSlider->setValue(60);
}
} else {
QWidget::mousePressEvent(event);
}
}
void MixerWidget::setMute(bool mute)
{
m_muteAction->setActive(mute);
m_volumeSlider->setEnabled(!mute);
m_volumeSpin->setEnabled(!mute);
m_audioMeterWidget->setEnabled(!mute);
m_balanceSpin->setEnabled(!mute);
m_balanceDial->setEnabled(!mute);
updateLabel();
}
void MixerWidget::updateLabel()
{
if (m_recording) {
QPalette pal = m_trackLabel->palette();
pal.setColor(QPalette::Window, Qt::red);
m_trackLabel->setPalette(pal);
} else if (m_muteAction->isActive()) {
QPalette pal = m_trackLabel->palette();
pal.setColor(QPalette::Window, QColor("#ff8c00"));
m_trackLabel->setPalette(pal);
} else if (m_solo && m_solo->isChecked()) {
QPalette pal = m_trackLabel->palette();
pal.setColor(QPalette::Window, Qt::darkGreen);
m_trackLabel->setPalette(pal);
} else {
QPalette pal = palette();
m_trackLabel->setPalette(pal);
}
}
void MixerWidget::updateAudioLevel(int pos)
{
QMutexLocker lk(&m_storeMutex);
if (m_levels.contains(pos)) {
m_audioMeterWidget->setAudioValues({m_levels.value(pos).first, m_levels.value(pos).second});
//m_levels.remove(pos);
} else {
m_audioMeterWidget->setAudioValues({-100, -100});
}
}
-void MixerWidget::clear(bool reset)
+
+void MixerWidget::reset()
+{
+ QMutexLocker lk(&m_storeMutex);
+ m_levels.clear();
+ m_audioMeterWidget->setAudioValues({-100, -100});
+}
+
+void MixerWidget::clear()
{
- if (reset) {
- m_audioMeterWidget->setAudioValues({-100, -100});
- }
QMutexLocker lk(&m_storeMutex);
m_levels.clear();
}
+
bool MixerWidget::isMute() const
{
return m_muteAction->isActive();
}
void MixerWidget::unSolo()
{
if (m_solo) {
QSignalBlocker bl(m_solo);
m_solo->setChecked(false);
}
}
void MixerWidget::gotRecLevels(QVectorlevels)
{
switch (levels.size()) {
case 0:
m_audioMeterWidget->setAudioValues({-100, -100});
break;
case 1:
m_audioMeterWidget->setAudioValues({IEC_Scale(levels[0]), -100});
break;
default:
m_audioMeterWidget->setAudioValues({IEC_Scale(levels[0]), IEC_Scale(levels[1])});
break;
}
}
void MixerWidget::setRecordState(bool recording)
{
m_recording = recording;
m_record->setChecked(m_recording);
QSignalBlocker bk(m_volumeSpin);
QSignalBlocker bk2(m_volumeSlider);
if (m_recording) {
connect(pCore->getAudioDevice(), &MediaCapture::audioLevels, this, &MixerWidget::gotRecLevels);
m_balanceDial->setEnabled(false);
m_balanceSpin->setEnabled(false);
m_volumeSpin->setRange(0, 100);
m_volumeSpin->setSuffix(QStringLiteral("%"));
m_volumeSpin->setValue(KdenliveSettings::audiocapturevolume());
m_volumeSlider->setValue(KdenliveSettings::audiocapturevolume());
} else {
m_balanceDial->setEnabled(true);
m_balanceSpin->setEnabled(true);
int level = m_levelFilter->get_int("level");
disconnect(pCore->getAudioDevice(), &MediaCapture::audioLevels, this, &MixerWidget::gotRecLevels);
m_volumeSpin->setRange(-100, 60);
m_volumeSpin->setSuffix(i18n("dB"));
m_volumeSpin->setValue(level);
m_volumeSlider->setValue(fromDB(level));
}
updateLabel();
}
void MixerWidget::connectMixer(bool doConnect)
{
if (doConnect) {
if (m_listener == nullptr) {
m_listener = m_monitorFilter->listen("property-changed", this, (mlt_listener)property_changed);
}
} else {
delete m_listener;
m_listener = nullptr;
}
}
diff --git a/src/audiomixer/mixerwidget.hpp b/src/audiomixer/mixerwidget.hpp
index e992db225..a041eec6f 100644
--- a/src/audiomixer/mixerwidget.hpp
+++ b/src/audiomixer/mixerwidget.hpp
@@ -1,114 +1,116 @@
/***************************************************************************
* Copyright (C) 2019 by Jean-Baptiste Mardelle *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* 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) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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 MIXERWIDGET_H
#define MIXERWIDGET_H
#include "definitions.h"
#include "mlt++/MltService.h"
#include
#include
#include
#include
class KDualAction;
class AudioLevelWidget;
class QSlider;
class QDial;
class QSpinBox;
class QDoubleSpinBox;
class QLabel;
class QToolButton;
class MixerManager;
namespace Mlt {
class Tractor;
class Event;
}
class MixerWidget : public QWidget
{
Q_OBJECT
public:
MixerWidget(int tid, std::shared_ptr service, const QString &trackTag, MixerManager *parent = nullptr);
MixerWidget(int tid, Mlt::Tractor *service, const QString &trackTag, MixerManager *parent = nullptr);
virtual ~MixerWidget();
void buildUI(Mlt::Tractor *service, const QString &trackTag);
/** @brief discard stored audio values and reset vu-meter to 0 if requested */
- void clear(bool reset = false);
+ void reset();
+ /** @brief discard stored audio values */
+ void clear();
static void property_changed( mlt_service , MixerWidget *self, char *name );
void setMute(bool mute);
/** @brief Returs true if track is muted
* */
bool isMute() const;
/** @brief Uncheck the solo button
* */
void unSolo();
/** @brief Connect the mixer widgets to the correspondant filters */
void connectMixer(bool doConnect);
protected:
void mousePressEvent(QMouseEvent *event) override;
public slots:
void updateAudioLevel(int pos);
void setRecordState(bool recording);
private slots:
void gotRecLevels(QVectorlevels);
protected:
MixerManager *m_manager;
int m_tid;
std::shared_ptr m_levelFilter;
std::shared_ptr m_monitorFilter;
std::shared_ptr m_balanceFilter;
QMap> m_levels;
KDualAction *m_muteAction;
QSpinBox *m_balanceSpin;
QDial *m_balanceDial;
QDoubleSpinBox *m_volumeSpin;
int m_maxLevels;
private:
std::shared_ptr m_audioMeterWidget;
QSlider *m_volumeSlider;
QToolButton *m_solo;
QToolButton *m_record;
QToolButton *m_collapse;
QLabel *m_trackLabel;
QMutex m_storeMutex;
int m_lastVolume;
Mlt::Event *m_listener;
bool m_recording;
/** @Update track label to reflect state */
void updateLabel();
signals:
void gotLevels(QPair );
void muteTrack(int tid, bool mute);
void toggleSolo(int tid, bool toggled);
};
#endif