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 "mixermanager.hpp"
0007 #include "capture/mediacapture.h"
0008 #include "core.h"
0009 #include "effects/effectsrepository.hpp"
0010 #include "kdenlivesettings.h"
0011 #include "mainwindow.h"
0012 #include "mixerwidget.hpp"
0013 #include "timeline2/model/timelineitemmodel.hpp"
0014 
0015 #include "mlt++/MltService.h"
0016 #include "mlt++/MltTractor.h"
0017 
0018 #include <KLocalizedString>
0019 #include <QApplication>
0020 #include <QHBoxLayout>
0021 #include <QModelIndex>
0022 #include <QScreen>
0023 #include <QScrollArea>
0024 #include <QStyle>
0025 #include <QStyleOptionSlider>
0026 #include <QTimer>
0027 
0028 MySlider::MySlider(QWidget *parent)
0029     : QSlider(parent)
0030 {
0031 }
0032 
0033 int MySlider::getHandleHeight()
0034 {
0035     // Get slider handle size
0036     QStyleOptionSlider opt;
0037     initStyleOption(&opt);
0038     return style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle).height();
0039 }
0040 
0041 MixerManager::MixerManager(QWidget *parent)
0042     : QWidget(parent)
0043     , m_masterMixer(nullptr)
0044     , m_visibleMixerManager(false)
0045     , m_expandedWidth(-1)
0046     , m_recommendedWidth(300)
0047     , m_monitorTrack(-1)
0048     , m_filterIsV2(false)
0049 {
0050     m_masterBox = new QHBoxLayout;
0051     setContentsMargins(0, 0, 0, 0);
0052     m_channelsBox = new QScrollArea(this);
0053     m_channelsBox->setContentsMargins(0, 0, 0, 0);
0054     m_box = new QHBoxLayout;
0055     m_box->setSpacing(0);
0056     auto *channelsBoxContainer = new QWidget(this);
0057     m_channelsBox->setWidget(channelsBoxContainer);
0058     m_channelsBox->setWidgetResizable(true);
0059     m_channelsBox->setFrameShape(QFrame::NoFrame);
0060     m_box->addWidget(m_channelsBox);
0061     m_channelsLayout = new QHBoxLayout;
0062     m_channelsLayout->setContentsMargins(0, 0, 0, 0);
0063     m_masterBox->setContentsMargins(0, 0, 0, 0);
0064     // m_channelsLayout->setSpacing(4);
0065     m_channelsLayout->setSpacing(1);
0066     channelsBoxContainer->setLayout(m_channelsLayout);
0067     m_channelsLayout->addStretch(10);
0068     QFrame *line = new QFrame(this);
0069     line->setFrameShape(QFrame::VLine);
0070     line->setFrameShadow(QFrame::Sunken);
0071     line->setFixedWidth(3);
0072     m_box->addWidget(line);
0073     m_box->addLayout(m_masterBox);
0074     setLayout(m_box);
0075     MySlider slider;
0076     m_sliderHandle = slider.getHandleHeight();
0077 }
0078 
0079 void MixerManager::checkAudioLevelVersion()
0080 {
0081     m_filterIsV2 = EffectsRepository::get()->exists(QStringLiteral("audiolevel")) && EffectsRepository::get()->getVersion(QStringLiteral("audiolevel")) > 100;
0082 }
0083 
0084 void MixerManager::monitorAudio(int tid, bool monitor)
0085 {
0086     if (!monitor) {
0087         if (m_mixers.count(tid) > 0) {
0088             m_mixers[tid]->monitorAudio(false);
0089         }
0090         m_monitorTrack = -1;
0091         pCore->getAudioDevice()->switchMonitorState(false);
0092         pCore->monitorAudio(tid, false);
0093         return;
0094     }
0095     // We want to monitor audio
0096     if (m_monitorTrack > -1) {
0097         // Another track is monitoring
0098         if (m_mixers.count(m_monitorTrack) > 0) {
0099             m_mixers[m_monitorTrack]->monitorAudio(false);
0100             pCore->monitorAudio(m_monitorTrack, false);
0101         }
0102         m_monitorTrack = -1;
0103     } else {
0104         pCore->displayMessage(i18n("Monitoring audio. Press <b>Space</b> to start/pause recording, <b>Esc</b> to end."), InformationMessage, 8000);
0105         pCore->getAudioDevice()->switchMonitorState(true);
0106     }
0107     if (m_mixers.count(tid) > 0) {
0108         m_mixers[tid]->monitorAudio(true);
0109         pCore->monitorAudio(tid, true);
0110     } else {
0111         return;
0112     }
0113     m_monitorTrack = tid;
0114 }
0115 
0116 void MixerManager::registerTrack(int tid, Mlt::Tractor *service, const QString &trackTag, const QString &trackName)
0117 {
0118     if (m_mixers.count(tid) > 0) {
0119         // Track already registered
0120         return;
0121     }
0122     std::shared_ptr<MixerWidget> mixer(new MixerWidget(tid, service, trackTag, trackName, m_sliderHandle, this));
0123     connect(mixer.get(), &MixerWidget::muteTrack, this,
0124             [&](int id, bool mute) { m_model->setTrackProperty(id, "hide", mute ? QStringLiteral("1") : QStringLiteral("3")); });
0125     if (m_visibleMixerManager) {
0126         mixer->connectMixer(!KdenliveSettings::mixerCollapse());
0127     }
0128     connect(pCore.get(), &Core::updateMixerLevels, mixer.get(), &MixerWidget::updateAudioLevel);
0129     connect(this, &MixerManager::clearMixers, mixer.get(), &MixerWidget::clear);
0130     connect(mixer.get(), &MixerWidget::toggleSolo, this, [&](int trid, bool solo) {
0131         if (!solo) {
0132             // unmute
0133             for (int id : qAsConst(m_soloMuted)) {
0134                 if (m_mixers.count(id) > 0) {
0135                     m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
0136                 }
0137             }
0138             m_soloMuted.clear();
0139         } else {
0140             if (!m_soloMuted.isEmpty()) {
0141                 // Another track was solo, discard first
0142                 for (int id : qAsConst(m_soloMuted)) {
0143                     if (m_mixers.count(id) > 0) {
0144                         m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
0145                     }
0146                 }
0147                 m_soloMuted.clear();
0148             }
0149             for (const auto &item : m_mixers) {
0150                 if (item.first != trid && !item.second->isMute()) {
0151                     m_model->setTrackProperty(item.first, "hide", QStringLiteral("3"));
0152                     m_soloMuted << item.first;
0153                     item.second->unSolo();
0154                 }
0155             }
0156         }
0157     });
0158     m_mixers[tid] = mixer;
0159     m_channelsLayout->insertWidget(0, mixer.get());
0160     m_recommendedWidth = (mixer->minimumWidth() + 1) * (qMin(2, int(m_mixers.size()))) + 3;
0161     if (!KdenliveSettings::mixerCollapse()) {
0162         m_channelsBox->setMinimumWidth(m_recommendedWidth);
0163     }
0164 }
0165 
0166 void MixerManager::deregisterTrack(int tid)
0167 {
0168     Q_ASSERT(m_mixers.count(tid) > 0);
0169     m_mixers.erase(tid);
0170 }
0171 
0172 void MixerManager::cleanup()
0173 {
0174     while (QLayoutItem *item = m_channelsLayout->takeAt(0)) {
0175         if (QWidget *widget = item->widget()) {
0176             widget->deleteLater();
0177         }
0178         delete item;
0179     }
0180     m_channelsLayout->addStretch(10);
0181     m_mixers.clear();
0182     if (m_masterMixer) {
0183         m_masterMixer->reset();
0184     }
0185 }
0186 
0187 void MixerManager::unsetModel()
0188 {
0189     m_model.reset();
0190 }
0191 
0192 void MixerManager::setModel(std::shared_ptr<TimelineItemModel> model)
0193 {
0194     // Insert master mixer
0195     m_model = model;
0196     connect(m_model.get(), &TimelineItemModel::dataChanged, this, [&](const QModelIndex &topLeft, const QModelIndex &, const QVector<int> &roles) {
0197         if (roles.contains(TimelineModel::IsDisabledRole)) {
0198             int id = int(topLeft.internalId());
0199             if (m_mixers.count(id) > 0) {
0200                 m_mixers[id]->setMute(m_model->data(topLeft, TimelineModel::IsDisabledRole).toBool());
0201             } else {
0202                 qDebug() << "=== MODEL DATA CHANGED: MUTE DONE TRACK NOT FOUND!!!";
0203             }
0204         } else if (roles.contains(TimelineModel::NameRole)) {
0205             int id = int(topLeft.internalId());
0206             if (m_mixers.count(id) > 0) {
0207                 qDebug() << "=== MODEL DATA CHANGED: CHANGED";
0208                 m_mixers[id]->setTrackName(m_model->data(topLeft, TimelineModel::NameRole).toString());
0209             } else {
0210                 qDebug() << "=== MODEL DATA CHANGED: CHANGE NAME DONE TRACK NOT FOUND!!!";
0211             }
0212         }
0213     });
0214 
0215     Mlt::Tractor *service = model->tractor();
0216     if (m_masterMixer != nullptr) {
0217         // delete previous master mixer
0218         m_masterBox->removeWidget(m_masterMixer.get());
0219     }
0220     m_masterMixer.reset(new MixerWidget(-1, service, i18n("Master"), QString(), m_sliderHandle, this));
0221     connect(m_masterMixer.get(), &MixerWidget::muteTrack, this, [&](int /*id*/, bool mute) { m_model->tractor()->set("hide", mute ? 3 : 1); });
0222     if (m_visibleMixerManager) {
0223         m_masterMixer->connectMixer(true);
0224     }
0225     connect(this, &MixerManager::clearMixers, m_masterMixer.get(), &MixerWidget::clear);
0226     m_masterBox->addWidget(m_masterMixer.get());
0227     if (KdenliveSettings::mixerCollapse()) {
0228         collapseMixers();
0229     }
0230 }
0231 
0232 void MixerManager::recordStateChanged(int tid, bool recording)
0233 {
0234     if (m_mixers.count(tid) > 0) {
0235         m_mixers[tid]->setRecordState(recording);
0236     }
0237     Q_EMIT pCore->switchTimelineRecord(recording);
0238 }
0239 
0240 void MixerManager::connectMixer(bool doConnect)
0241 {
0242     m_visibleMixerManager = doConnect;
0243     for (const auto &item : m_mixers) {
0244         item.second->connectMixer(m_visibleMixerManager && !KdenliveSettings::mixerCollapse());
0245     }
0246     if (m_masterMixer != nullptr) {
0247         m_masterMixer->connectMixer(m_visibleMixerManager);
0248     }
0249 }
0250 
0251 void MixerManager::collapseMixers()
0252 {
0253     connectMixer(m_visibleMixerManager);
0254     if (KdenliveSettings::mixerCollapse()) {
0255         m_expandedWidth = width();
0256         m_channelsBox->setFixedWidth(0);
0257         // m_line->setMaximumWidth(0);
0258         if (!pCore->window()->isMixedTabbed()) {
0259             setFixedWidth(m_masterMixer->width() + 2 * m_box->contentsMargins().left());
0260         }
0261     } else {
0262         // m_line->setMaximumWidth(QWIDGETSIZE_MAX);
0263         m_channelsBox->setMaximumWidth(QWIDGETSIZE_MAX);
0264         m_channelsBox->setMinimumWidth(m_recommendedWidth);
0265         setFixedWidth(m_expandedWidth);
0266         QMetaObject::invokeMethod(this, "resetSizePolicy", Qt::QueuedConnection);
0267     }
0268 }
0269 
0270 void MixerManager::resetSizePolicy()
0271 {
0272     setMaximumWidth(QWIDGETSIZE_MAX);
0273     setMinimumWidth(0);
0274 }
0275 
0276 QSize MixerManager::sizeHint() const
0277 {
0278     return QSize(m_recommendedWidth, 0);
0279 }
0280 
0281 void MixerManager::pauseMonitoring(bool pause)
0282 {
0283     for (const auto &item : m_mixers) {
0284         item.second->pauseMonitoring(pause);
0285     }
0286     if (m_masterMixer != nullptr) {
0287         m_masterMixer->pauseMonitoring(pause);
0288     }
0289 }
0290 
0291 int MixerManager::recordTrack() const
0292 {
0293     return m_monitorTrack;
0294 }
0295 
0296 bool MixerManager::audioLevelV2() const
0297 {
0298     return m_filterIsV2;
0299 }