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 }