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 }