File indexing completed on 2024-04-28 08:43:21

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