File indexing completed on 2024-04-21 04:51:04

0001 /*
0002     SPDX-FileCopyrightText: 2019 Jean-Baptiste Mardelle
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "mixerwidget.hpp"
0007 
0008 #include "audiolevelwidget.hpp"
0009 #include "capture/mediacapture.h"
0010 #include "core.h"
0011 #include "iecscale.h"
0012 #include "kdenlivesettings.h"
0013 #include "mixermanager.hpp"
0014 #include "mlt++/MltEvent.h"
0015 #include "mlt++/MltFilter.h"
0016 #include "mlt++/MltProfile.h"
0017 #include "mlt++/MltTractor.h"
0018 
0019 #include <KDualAction>
0020 #include <KLocalizedString>
0021 #include <KSqueezedTextLabel>
0022 #include <QCheckBox>
0023 #include <QDial>
0024 #include <QDoubleSpinBox>
0025 #include <QFontDatabase>
0026 #include <QGridLayout>
0027 #include <QLabel>
0028 #include <QMouseEvent>
0029 #include <QSlider>
0030 #include <QSpinBox>
0031 #include <QStyle>
0032 #include <QToolButton>
0033 
0034 void MixerWidget::property_changed(mlt_service, MixerWidget *widget, mlt_event_data data)
0035 {
0036     if (widget && !strcmp(Mlt::EventData(data).to_string(), "_position")) {
0037         mlt_properties filter_props = MLT_FILTER_PROPERTIES(widget->m_monitorFilter->get_filter());
0038         int pos = mlt_properties_get_int(filter_props, "_position");
0039         if (!widget->m_levels.contains(pos)) {
0040             QVector<double> levels;
0041             for (int i = 0; i < widget->m_channels; i++) {
0042                 // NOTE: this is an approximation. To get the real peak level, we need version 2 of audiolevel MLT filter, see property_changedV2
0043                 levels << log10(mlt_properties_get_double(filter_props, QString("_audio_level.%1").arg(i).toUtf8().constData()) / 1.18) * 20;
0044             }
0045             widget->m_levels[pos] = std::move(levels);
0046             if (widget->m_levels.size() > widget->m_maxLevels) {
0047                 widget->m_levels.erase(widget->m_levels.begin());
0048             }
0049         }
0050     }
0051 }
0052 
0053 void MixerWidget::property_changedV2(mlt_service, MixerWidget *widget, mlt_event_data data)
0054 {
0055     if (widget && !strcmp(Mlt::EventData(data).to_string(), "_position")) {
0056         mlt_properties filter_props = MLT_FILTER_PROPERTIES(widget->m_monitorFilter->get_filter());
0057         int pos = mlt_properties_get_int(filter_props, "_position");
0058         if (!widget->m_levels.contains(pos)) {
0059             QVector<double> levels;
0060             for (int i = 0; i < widget->m_channels; i++) {
0061                 levels << mlt_properties_get_double(filter_props, QString("_audio_level.%1").arg(i).toUtf8().constData());
0062             }
0063             widget->m_levels[pos] = std::move(levels);
0064             if (widget->m_levels.size() > widget->m_maxLevels) {
0065                 widget->m_levels.erase(widget->m_levels.begin());
0066             }
0067         }
0068     }
0069 }
0070 
0071 MixerWidget::MixerWidget(int tid, Mlt::Tractor *service, QString trackTag, const QString &trackName, int sliderHandle, MixerManager *parent)
0072     : QWidget(parent)
0073     , m_manager(parent)
0074     , m_tid(tid)
0075     , m_levelFilter(nullptr)
0076     , m_monitorFilter(nullptr)
0077     , m_balanceFilter(nullptr)
0078     , m_channels(pCore->audioChannels())
0079     , m_balanceSpin(nullptr)
0080     , m_balanceSlider(nullptr)
0081     , m_maxLevels(qMax(30, int(service->get_fps() * 1.5)))
0082     , m_solo(nullptr)
0083     , m_collapse(nullptr)
0084     , m_monitor(nullptr)
0085     , m_lastVolume(0)
0086     , m_listener(nullptr)
0087     , m_recording(false)
0088     , m_trackTag(std::move(trackTag))
0089     , m_sliderHandleSize(sliderHandle)
0090 {
0091     buildUI(service, trackName);
0092 }
0093 
0094 MixerWidget::~MixerWidget()
0095 {
0096     if (m_listener) {
0097         delete m_listener;
0098     }
0099 }
0100 
0101 void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackName)
0102 {
0103     setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
0104     // Build audio meter widget
0105     m_audioMeterWidget.reset(new AudioLevelWidget(width(), m_sliderHandleSize, this));
0106     // initialize for stereo display
0107     for (int i = 0; i < m_channels; i++) {
0108         m_audioData << -100;
0109     }
0110     m_audioMeterWidget->setAudioValues(m_audioData);
0111 
0112     // Build volume widget
0113     m_volumeSlider = new QSlider(Qt::Vertical, this);
0114     m_volumeSlider->setRange(0, 10000);
0115     m_volumeSlider->setValue(6000);
0116     m_volumeSlider->setSingleStep(50);
0117     m_volumeSlider->setToolTip(i18n("Volume"));
0118     m_volumeSlider->setWhatsThis(xi18nc("@info:whatsthis", "Adjusts the output volume of the audio track (affects all audio clips equally)."));
0119     m_volumeSpin = new QDoubleSpinBox(this);
0120     m_volumeSpin->setRange(-50, 24);
0121     m_volumeSpin->setSuffix(i18n("dB"));
0122     m_volumeSpin->setFrame(false);
0123 
0124     connect(m_volumeSpin, &QDoubleSpinBox::editingFinished, this, [&]() {
0125         double val = m_volumeSpin->value();
0126         if (m_monitor && m_monitor->isChecked()) {
0127             m_volumeSlider->setValue(val * 100.);
0128         } else {
0129             m_volumeSlider->setValue(fromDB(val) * 100.);
0130         }
0131     });
0132 
0133     QLabel *labelLeft = nullptr;
0134     QLabel *labelRight = nullptr;
0135     if (m_channels == 2) {
0136         m_balanceSlider = new QSlider(Qt::Horizontal, this);
0137         m_balanceSlider->setRange(-50, 50);
0138         m_balanceSlider->setValue(0);
0139         m_balanceSlider->setTickPosition(QSlider::TicksBelow);
0140         m_balanceSlider->setTickInterval(50);
0141         m_balanceSlider->setToolTip(i18n("Balance"));
0142         m_balanceSlider->setWhatsThis(xi18nc("@info:whatsthis", "Adjusts the output balance of the track. Negative values move the output towards the left, "
0143                                                                 "positive values to the right. Affects all audio clips equally."));
0144 
0145         labelLeft = new QLabel(i18nc("Left", "L"), this);
0146         labelLeft->setAlignment(Qt::AlignHCenter);
0147         labelRight = new QLabel(i18nc("Right", "R"), this);
0148         labelRight->setAlignment(Qt::AlignHCenter);
0149 
0150         m_balanceSpin = new QSpinBox(this);
0151         m_balanceSpin->setRange(-50, 50);
0152         m_balanceSpin->setValue(0);
0153         m_balanceSpin->setFrame(false);
0154         m_balanceSpin->setToolTip(i18n("Balance"));
0155         m_balanceSpin->setWhatsThis(xi18nc("@info:whatsthis", "Adjusts the output balance of the track. Negative values move the output towards the left, "
0156                                                               "positive values to the right. Affects all audio clips equally."));
0157     }
0158 
0159     // Check if we already have built-in filters for this tractor
0160     int max = service->filter_count();
0161     for (int i = 0; i < max; i++) {
0162         std::shared_ptr<Mlt::Filter> fl(service->filter(i));
0163         if (!fl->is_valid()) {
0164             continue;
0165         }
0166         const QString filterService = fl->get("mlt_service");
0167         if (filterService == QLatin1String("audiolevel")) {
0168             m_monitorFilter = fl;
0169             m_monitorFilter->set("disable", 0);
0170         } else if (filterService == QLatin1String("volume")) {
0171             m_levelFilter = fl;
0172             double volume = m_levelFilter->get_double("level");
0173             m_volumeSpin->setValue(volume);
0174             m_volumeSlider->setValue(fromDB(volume) * 100.);
0175         } else if (m_channels == 2 && filterService == QLatin1String("panner")) {
0176             m_balanceFilter = fl;
0177             int val = int(m_balanceFilter->get_double("start") * 100) - 50;
0178             m_balanceSpin->setValue(val);
0179             m_balanceSlider->setValue(val);
0180         }
0181     }
0182     // Build default filters if not found
0183     if (m_levelFilter == nullptr) {
0184         m_levelFilter.reset(new Mlt::Filter(service->get_profile(), "volume"));
0185         if (m_levelFilter->is_valid()) {
0186             m_levelFilter->set("internal_added", 237);
0187             m_levelFilter->set("disable", 1);
0188             service->attach(*m_levelFilter.get());
0189         }
0190     }
0191     if (m_balanceFilter == nullptr && m_channels == 2) {
0192         m_balanceFilter.reset(new Mlt::Filter(service->get_profile(), "panner"));
0193         if (m_balanceFilter->is_valid()) {
0194             m_balanceFilter->set("internal_added", 237);
0195             m_balanceFilter->set("start", 0.5);
0196             m_balanceFilter->set("disable", 1);
0197             service->attach(*m_balanceFilter.get());
0198         }
0199     }
0200     // Monitoring should be appended last so that other effects are reflected in audio monitor
0201     if (m_monitorFilter == nullptr && m_tid != -1) {
0202         m_monitorFilter.reset(new Mlt::Filter(service->get_profile(), "audiolevel"));
0203         if (m_monitorFilter->is_valid()) {
0204             m_monitorFilter->set("iec_scale", 0);
0205             if (m_manager->audioLevelV2()) {
0206                 m_monitorFilter->set("dbpeak", 1);
0207             }
0208             service->attach(*m_monitorFilter.get());
0209         }
0210     }
0211 
0212     m_trackLabel = new KSqueezedTextLabel(this);
0213     m_trackLabel->setAutoFillBackground(true);
0214     m_trackLabel->setAlignment(Qt::AlignHCenter);
0215     m_trackLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
0216     m_trackLabel->setTextElideMode(Qt::ElideRight);
0217     setTrackName(trackName);
0218     m_muteAction = new KDualAction(i18n("Mute track"), i18n("Unmute track"), this);
0219     m_muteAction->setWhatsThis(xi18nc("@info:whatsthis", "Mutes/un-mutes the audio track."));
0220     m_muteAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-hide-audio")));
0221     m_muteAction->setInactiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-show-audio")));
0222 
0223     if (m_balanceSlider) {
0224         connect(m_balanceSlider, &QSlider::valueChanged, m_balanceSpin, &QSpinBox::setValue);
0225     }
0226 
0227     connect(m_muteAction, &KDualAction::activeChangedByUser, this, [&](bool active) {
0228         if (m_tid == -1) {
0229             // Muting master, special case
0230             if (m_levelFilter) {
0231                 if (active) {
0232                     m_lastVolume = m_levelFilter->get_double("level");
0233                     m_levelFilter->set("level", -1000);
0234                     m_levelFilter->set("disable", 0);
0235                 } else {
0236                     m_levelFilter->set("level", m_lastVolume);
0237                     m_levelFilter->set("disable", qFuzzyIsNull(m_lastVolume) ? 1 : 0);
0238                 }
0239             }
0240         } else {
0241             Q_EMIT muteTrack(m_tid, !active);
0242             reset();
0243         }
0244         pCore->setDocumentModified();
0245         updateLabel();
0246     });
0247 
0248     auto *mute = new QToolButton(this);
0249     mute->setDefaultAction(m_muteAction);
0250     mute->setAutoRaise(true);
0251 
0252     QToolButton *showEffects = nullptr;
0253 
0254     // Setup default width
0255     setFixedWidth(3 * mute->sizeHint().width());
0256 
0257     if (m_tid > -1) {
0258         // Solo / rec button only on tracks (not on master)
0259         m_solo = new QToolButton(this);
0260         m_solo->setCheckable(true);
0261         m_solo->setIcon(QIcon::fromTheme("headphones"));
0262         m_solo->setToolTip(i18n("Solo mode"));
0263         m_solo->setWhatsThis(xi18nc("@info:whatsthis", "When selected mutes all other audio tracks."));
0264         m_solo->setAutoRaise(true);
0265         connect(m_solo, &QToolButton::toggled, this, [&](bool toggled) {
0266             Q_EMIT toggleSolo(m_tid, toggled);
0267             updateLabel();
0268         });
0269 
0270         m_monitor = new QToolButton(this);
0271         m_monitor->setIcon(QIcon::fromTheme("audio-input-microphone"));
0272         m_monitor->setToolTip(i18n("Record audio"));
0273         m_monitor->setWhatsThis(xi18nc("@info:whatsthis", "Puts the audio track into recording mode."));
0274         m_monitor->setCheckable(true);
0275         m_monitor->setAutoRaise(true);
0276         connect(m_monitor, &QToolButton::toggled, this, [&](bool toggled) {
0277             if (!toggled && (m_recording || pCore->isMediaCapturing())) {
0278                 // Abort recording if in progress
0279                 Q_EMIT pCore->recordAudio(m_tid, false);
0280             }
0281             m_manager->monitorAudio(m_tid, toggled);
0282         });
0283     } else {
0284         m_collapse = new QToolButton(this);
0285         m_collapse->setIcon(KdenliveSettings::mixerCollapse() ? QIcon::fromTheme("arrow-left") : QIcon::fromTheme("arrow-right"));
0286         m_collapse->setToolTip(i18n("Show channels"));
0287         m_collapse->setWhatsThis(xi18nc("@info:whatsthis", "Toggles the display of the audio track controls in the audio mixer view."));
0288         m_collapse->setCheckable(true);
0289         m_collapse->setAutoRaise(true);
0290         m_collapse->setChecked(KdenliveSettings::mixerCollapse());
0291         connect(m_collapse, &QToolButton::clicked, this, [&]() {
0292             KdenliveSettings::setMixerCollapse(m_collapse->isChecked());
0293             m_collapse->setIcon(m_collapse->isChecked() ? QIcon::fromTheme("arrow-left") : QIcon::fromTheme("arrow-right"));
0294             m_manager->collapseMixers();
0295         });
0296     }
0297     showEffects = new QToolButton(this);
0298     showEffects->setIcon(QIcon::fromTheme("autocorrection"));
0299     showEffects->setToolTip(i18n("Open Effect Stack"));
0300     if (m_tid > -1) {
0301         showEffects->setWhatsThis(xi18nc("@info:whatsthis", "Opens the effect stack for the audio track."));
0302     } else {
0303         showEffects->setWhatsThis(xi18nc("@info:whatsthis", "Opens the effect stack for the audio master."));
0304     }
0305     showEffects->setAutoRaise(true);
0306     connect(showEffects, &QToolButton::clicked, this, [&]() { Q_EMIT m_manager->showEffectStack(m_tid); });
0307 
0308     connect(m_volumeSlider, &QSlider::valueChanged, this, [&](int value) {
0309         QSignalBlocker bk(m_volumeSpin);
0310         if (m_recording || (m_monitor && m_monitor->isChecked())) {
0311             m_volumeSpin->setValue(value / 100);
0312             KdenliveSettings::setAudiocapturevolume(value / 100);
0313             Q_EMIT m_manager->updateRecVolume();
0314             // TODO update capture volume
0315         } else if (m_levelFilter != nullptr) {
0316             double dbValue = 0;
0317             if (value > 6000) {
0318                 // increase volume
0319                 dbValue = 24 * (1 - log10((100 - value / 100.) * 0.225 + 1));
0320             } else if (value < 6000) {
0321                 dbValue = -50 * (1 - log10(10 - (value / 100. - 59) * (-0.11395)));
0322             }
0323             m_volumeSpin->setValue(dbValue);
0324             m_levelFilter->set("level", dbValue);
0325             m_levelFilter->set("disable", value == 60 ? 1 : 0);
0326             m_levels.clear();
0327             Q_EMIT m_manager->purgeCache();
0328             pCore->setDocumentModified();
0329         }
0330     });
0331     if (m_balanceSlider) {
0332         connect(m_balanceSpin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0333             QSignalBlocker bk(m_balanceSlider);
0334             m_balanceSlider->setValue(value);
0335             if (m_balanceFilter != nullptr) {
0336                 m_balanceFilter->set("start", (value + 50) / 100.);
0337                 m_balanceFilter->set("disable", value == 0 ? 1 : 0);
0338                 m_levels.clear();
0339                 Q_EMIT m_manager->purgeCache();
0340                 pCore->setDocumentModified();
0341             }
0342         });
0343     }
0344     auto *lay = new QVBoxLayout;
0345     setContentsMargins(0, 0, 0, 0);
0346     lay->setContentsMargins(0, 0, 0, 0);
0347     lay->addWidget(m_trackLabel);
0348     auto *buttonslay = new QHBoxLayout;
0349     buttonslay->setSpacing(0);
0350     buttonslay->setContentsMargins(0, 0, 0, 0);
0351     if (m_collapse) {
0352         buttonslay->addWidget(m_collapse);
0353     }
0354     buttonslay->addWidget(mute);
0355     if (m_solo) {
0356         buttonslay->addWidget(m_solo);
0357     }
0358     if (m_monitor) {
0359         buttonslay->addWidget(m_monitor);
0360     }
0361     if (showEffects) {
0362         buttonslay->addWidget(showEffects);
0363     }
0364     lay->addLayout(buttonslay);
0365     if (m_balanceSlider) {
0366         auto *balancelay = new QGridLayout;
0367         balancelay->addWidget(m_balanceSlider, 0, 0, 1, 3);
0368         balancelay->addWidget(labelLeft, 1, 0, 1, 1);
0369         balancelay->addWidget(m_balanceSpin, 1, 1, 1, 1);
0370         balancelay->addWidget(labelRight, 1, 2, 1, 1);
0371         lay->addLayout(balancelay);
0372     }
0373     auto *hlay = new QHBoxLayout;
0374     hlay->setSpacing(0);
0375     hlay->setContentsMargins(0, 0, 0, 0);
0376     hlay->addWidget(m_audioMeterWidget.get());
0377     hlay->addWidget(m_volumeSlider);
0378     lay->addLayout(hlay);
0379     lay->addWidget(m_volumeSpin);
0380     lay->setStretch(4, 10);
0381     setLayout(lay);
0382     if (service->get_int("hide") > 1) {
0383         setMute(true);
0384     }
0385 }
0386 
0387 void MixerWidget::mousePressEvent(QMouseEvent *event)
0388 {
0389     if (event->button() == Qt::RightButton) {
0390         QWidget *child = childAt(event->pos());
0391         if (child == m_balanceSlider) {
0392             m_balanceSpin->setValue(0);
0393         } else if (child == m_volumeSlider) {
0394             m_volumeSlider->setValue(6000);
0395         }
0396     } else {
0397         QWidget::mousePressEvent(event);
0398     }
0399 }
0400 
0401 void MixerWidget::setTrackName(const QString &name)
0402 {
0403     // Show only tag on master or if name is empty
0404     if (name.isEmpty() || m_tid == -1) {
0405         m_trackLabel->setText(m_trackTag);
0406     } else {
0407         m_trackLabel->setText(QString("%1 - %2").arg(m_trackTag, name));
0408     }
0409 }
0410 
0411 void MixerWidget::setMute(bool mute)
0412 {
0413     m_muteAction->setActive(mute);
0414     m_volumeSlider->setEnabled(!mute);
0415     m_volumeSpin->setEnabled(!mute);
0416     m_audioMeterWidget->setEnabled(!mute);
0417     if (m_balanceSlider) {
0418         m_balanceSpin->setEnabled(!mute);
0419         m_balanceSlider->setEnabled(!mute);
0420     }
0421     updateLabel();
0422 }
0423 
0424 void MixerWidget::updateLabel()
0425 {
0426     if (m_recording) {
0427         QPalette pal = m_trackLabel->palette();
0428         pal.setColor(QPalette::Window, Qt::red);
0429         m_trackLabel->setPalette(pal);
0430     } else if (m_monitor && m_monitor->isChecked()) {
0431         QPalette pal = m_trackLabel->palette();
0432         pal.setColor(QPalette::Window, Qt::darkBlue);
0433         m_trackLabel->setPalette(pal);
0434     } else if (m_muteAction->isActive()) {
0435         QPalette pal = m_trackLabel->palette();
0436         pal.setColor(QPalette::Window, QColor(0xff8c00));
0437         m_trackLabel->setPalette(pal);
0438     } else if (m_solo && m_solo->isChecked()) {
0439         QPalette pal = m_trackLabel->palette();
0440         pal.setColor(QPalette::Window, Qt::darkGreen);
0441         m_trackLabel->setPalette(pal);
0442     } else {
0443         QPalette pal = palette();
0444         m_trackLabel->setPalette(pal);
0445     }
0446 }
0447 
0448 void MixerWidget::updateAudioLevel(int pos)
0449 {
0450     QMutexLocker lk(&m_storeMutex);
0451     if (m_levels.contains(pos)) {
0452         m_audioMeterWidget->setAudioValues(m_levels.value(pos));
0453         // m_levels.remove(pos);
0454     } else {
0455         m_audioMeterWidget->setAudioValues(m_audioData);
0456     }
0457 }
0458 
0459 void MixerWidget::reset()
0460 {
0461     QMutexLocker lk(&m_storeMutex);
0462     m_levels.clear();
0463     m_audioMeterWidget->setAudioValues(m_audioData);
0464 }
0465 
0466 void MixerWidget::clear()
0467 {
0468     QMutexLocker lk(&m_storeMutex);
0469     m_levels.clear();
0470 }
0471 
0472 bool MixerWidget::isMute() const
0473 {
0474     return m_muteAction->isActive();
0475 }
0476 
0477 void MixerWidget::unSolo()
0478 {
0479     if (m_solo) {
0480         QSignalBlocker bl(m_solo);
0481         m_solo->setChecked(false);
0482     }
0483 }
0484 
0485 void MixerWidget::gotRecLevels(QVector<qreal> levels)
0486 {
0487     switch (levels.size()) {
0488     case 0:
0489         m_audioMeterWidget->setAudioValues({-100, -100});
0490         break;
0491     case 1:
0492         m_audioMeterWidget->setAudioValues({levels[0]});
0493         break;
0494     default:
0495         m_audioMeterWidget->setAudioValues({levels[0], levels[1]});
0496         break;
0497     }
0498 }
0499 
0500 void MixerWidget::updateMonitorState()
0501 {
0502     QSignalBlocker bk(m_volumeSpin);
0503     QSignalBlocker bk2(m_volumeSlider);
0504     if (m_monitor && m_monitor->isChecked()) {
0505         connect(pCore->getAudioDevice(), &MediaCapture::audioLevels, this, &MixerWidget::gotRecLevels);
0506         if (m_balanceSlider) {
0507             m_balanceSlider->setEnabled(false);
0508             m_balanceSpin->setEnabled(false);
0509         }
0510         m_volumeSpin->setRange(0, 100);
0511         m_volumeSpin->setSuffix(QStringLiteral("%"));
0512         m_volumeSpin->setValue(KdenliveSettings::audiocapturevolume());
0513         m_volumeSlider->setValue(KdenliveSettings::audiocapturevolume() * 100);
0514     } else {
0515         disconnect(pCore->getAudioDevice(), &MediaCapture::audioLevels, this, &MixerWidget::gotRecLevels);
0516         if (m_balanceSlider) {
0517             m_balanceSlider->setEnabled(true);
0518             m_balanceSpin->setEnabled(true);
0519         }
0520         int level = m_levelFilter->get_int("level");
0521         m_volumeSpin->setRange(-100, 60);
0522         m_volumeSpin->setSuffix(i18n("dB"));
0523         m_volumeSpin->setValue(level);
0524         m_volumeSlider->setValue(fromDB(level) * 100.);
0525     }
0526     updateLabel();
0527 }
0528 
0529 void MixerWidget::monitorAudio(bool monitor)
0530 {
0531     QSignalBlocker bk(m_monitor);
0532     qDebug() << ":::: MONIOTORING AUDIO: " << monitor;
0533     if (monitor) {
0534         m_monitor->setChecked(true);
0535         updateMonitorState();
0536     } else {
0537         m_monitor->setChecked(false);
0538         updateMonitorState();
0539         reset();
0540     }
0541 }
0542 
0543 void MixerWidget::setRecordState(bool recording)
0544 {
0545     m_recording = recording;
0546     updateMonitorState();
0547 }
0548 
0549 void MixerWidget::connectMixer(bool doConnect)
0550 {
0551     if (doConnect) {
0552         if (m_tid == -1) {
0553             // Master level
0554             connect(pCore.get(), &Core::audioLevelsAvailable, m_audioMeterWidget.get(), &AudioLevelWidget::setAudioValues);
0555         } else if (m_listener == nullptr) {
0556             m_listener = m_monitorFilter->listen("property-changed", this,
0557                                                  m_manager->audioLevelV2() ? reinterpret_cast<mlt_listener>(property_changedV2)
0558                                                                            : reinterpret_cast<mlt_listener>(property_changed));
0559         }
0560     } else {
0561         if (m_tid == -1) {
0562             disconnect(pCore.get(), &Core::audioLevelsAvailable, m_audioMeterWidget.get(), &AudioLevelWidget::setAudioValues);
0563         } else {
0564             delete m_listener;
0565             m_listener = nullptr;
0566         }
0567     }
0568     pauseMonitoring(!doConnect);
0569 }
0570 
0571 void MixerWidget::pauseMonitoring(bool pause)
0572 {
0573     if (m_monitorFilter) {
0574         m_monitorFilter->set("disable", pause ? 1 : 0);
0575     }
0576 }