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