mixermanager.cpp 8.87 KB
Newer Older
1
/*
2
    SPDX-FileCopyrightText: 2019 Jean-Baptiste Mardelle
Camille Moulin's avatar
Camille Moulin committed
3
    SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4
*/
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
5
6

#include "mixermanager.hpp"
7
#include "core.h"
8
#include "kdenlivesettings.h"
9
#include "mainwindow.h"
10
#include "mixerwidget.hpp"
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
11
#include "timeline2/model/timelineitemmodel.hpp"
12
#include "effects/effectsrepository.hpp"
13
14
#include "capture/mediacapture.h"

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
15
16
17
18

#include "mlt++/MltService.h"
#include "mlt++/MltTractor.h"

19
#include <QApplication>
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
20
21
#include <QHBoxLayout>
#include <QModelIndex>
22
#include <QScreen>
23
#include <QScrollArea>
24
#include <QTimer>
25
#include <klocalizedstring.h>
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
26
27
28
29
30

const double log_factor = 1.0 / log10(1.0 / 127);

MixerManager::MixerManager(QWidget *parent)
    : QWidget(parent)
31
    , m_masterMixer(nullptr)
32
    , m_visibleMixerManager(false)
33
    , m_expandedWidth(-1)
Yuri Chornoivan's avatar
Yuri Chornoivan committed
34
    , m_recommendedWidth(300)
35
    , m_monitorTrack(-1)
36
    , m_filterIsV2(false)
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
37
{
38
    m_masterBox = new QHBoxLayout;
39
    setContentsMargins(0, 0, 0, 0);
40
    m_channelsBox = new QScrollArea(this);
41
    m_channelsBox->setContentsMargins(0, 0, 0, 0);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
42
    m_box = new QHBoxLayout;
43
    m_box->setSpacing(0);
44
    auto *channelsBoxContainer = new QWidget(this);
45
46
47
48
49
50
    m_channelsBox->setWidget(channelsBoxContainer);
    m_channelsBox->setWidgetResizable(true);
    m_channelsBox->setFrameShape(QFrame::NoFrame);
    m_box->addWidget(m_channelsBox);
    m_channelsLayout = new QHBoxLayout;
    m_channelsLayout->setContentsMargins(0, 0, 0, 0);
51
    m_masterBox->setContentsMargins(0, 0, 0, 0);
52
    m_channelsLayout->setSpacing(4);
53
54
    channelsBoxContainer->setLayout(m_channelsLayout);
    m_channelsLayout->addStretch(10);
55
    m_box->addLayout(m_masterBox);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
56
57
58
    setLayout(m_box);
}

59
60
61
62
63
void MixerManager::checkAudioLevelVersion()
{
    m_filterIsV2 = EffectsRepository::get()->exists(QStringLiteral("audiolevel")) && EffectsRepository::get()->getVersion(QStringLiteral("audiolevel")) > 100;
}

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
void MixerManager::monitorAudio(int tid, bool monitor)
{
    if (!monitor) {
        if (m_mixers.count(tid) > 0) {
            m_mixers[tid]->monitorAudio(false);
        }
        m_monitorTrack = -1;
        pCore->getAudioDevice()->switchMonitorState(false);
        return;
    }
    // We want to monitor audio
    if (m_monitorTrack > -1) {
        // Another track is monitoring
        if (m_mixers.count(m_monitorTrack) > 0) {
            m_mixers[m_monitorTrack]->monitorAudio(false);
        }
        m_monitorTrack = -1;
    } else {
        pCore->getAudioDevice()->switchMonitorState(true);
    }
    if (m_mixers.count(tid) > 0) {
        m_mixers[tid]->monitorAudio(true);
    } else {
        return;
    }
    m_monitorTrack = tid;
}

Julius Künzel's avatar
Julius Künzel committed
92
void MixerManager::registerTrack(int tid, std::shared_ptr<Mlt::Tractor> service, const QString &trackTag, const QString &trackName)
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
93
94
95
96
97
{
    if (m_mixers.count(tid) > 0) {
        // Track already registered
        return;
    }
Julius Künzel's avatar
Julius Künzel committed
98
    std::shared_ptr<MixerWidget> mixer(new MixerWidget(tid, service, trackTag, trackName, this));
Vincent Pinon's avatar
Vincent Pinon committed
99
    connect(mixer.get(), &MixerWidget::muteTrack, this, [&](int id, bool mute) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
100
101
        m_model->setTrackProperty(id, "hide", mute ? QStringLiteral("1") : QStringLiteral("3"));
    });
102
    if (m_visibleMixerManager) {
103
        mixer->connectMixer(!KdenliveSettings::mixerCollapse(), m_filterIsV2);
104
    }
105
    connect(pCore.get(), &Core::updateMixerLevels, mixer.get(), &MixerWidget::updateAudioLevel);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
106
    connect(this, &MixerManager::clearMixers, mixer.get(), &MixerWidget::clear);
Vincent Pinon's avatar
Vincent Pinon committed
107
    connect(mixer.get(), &MixerWidget::toggleSolo, this, [&](int trid, bool solo) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
108
109
        if (!solo) {
            // unmute
Vincent Pinon's avatar
Vincent Pinon committed
110
            for (int id : qAsConst(m_soloMuted)) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
111
112
113
114
115
116
117
118
                if (m_mixers.count(id) > 0) {
                    m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
                }
            }
            m_soloMuted.clear();
        } else {
            if (!m_soloMuted.isEmpty()) {
                // Another track was solo, discard first
Vincent Pinon's avatar
Vincent Pinon committed
119
                for (int id : qAsConst(m_soloMuted)) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
120
121
122
123
124
125
                    if (m_mixers.count(id) > 0) {
                        m_model->setTrackProperty(id, "hide", QStringLiteral("1"));
                    }
                }
                m_soloMuted.clear();
            }
Vincent Pinon's avatar
Vincent Pinon committed
126
            for (const auto &item : m_mixers) {
127
                if (item.first != trid && !item.second->isMute()) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
128
129
130
131
132
133
134
135
                    m_model->setTrackProperty(item.first, "hide", QStringLiteral("3"));
                    m_soloMuted << item.first;
                    item.second->unSolo();
                }
            }
        }
    });
    m_mixers[tid] = mixer;
136
137
138
139
    QFrame *line = new QFrame(this);
    line->setFrameShape(QFrame::VLine);
    line->setFrameShadow(QFrame::Sunken);
    m_channelsLayout->insertWidget(0, line);
140
    m_channelsLayout->insertWidget(0, mixer.get());
Yuri Chornoivan's avatar
Yuri Chornoivan committed
141
    m_recommendedWidth = (mixer->minimumWidth() + 12 + line->minimumWidth()) * (qMin(2, int(m_mixers.size())));
142
143
144
    if (!KdenliveSettings::mixerCollapse()) {
        m_channelsBox->setMinimumWidth(m_recommendedWidth);
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
145
146
147
148
149
150
151
152
153
154
}

void MixerManager::deregisterTrack(int tid)
{
    Q_ASSERT(m_mixers.count(tid) > 0);
    m_mixers.erase(tid);
}

void MixerManager::cleanup()
{
155
156
157
158
159
    while (QLayoutItem* item = m_channelsLayout->takeAt(0)) {
        if (QWidget* widget = item->widget()) {
            widget->deleteLater();
        }
        delete item;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
160
    }
161
    m_channelsLayout->addStretch(10);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
162
    m_mixers.clear();
163
    if (m_masterMixer) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
164
        m_masterMixer->reset();
165
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
166
167
}

168
169
170
171
172
void MixerManager::unsetModel()
{
    m_model.reset();
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
173
174
175
176
void MixerManager::setModel(std::shared_ptr<TimelineItemModel> model)
{
    // Insert master mixer
    m_model = model;
Vincent Pinon's avatar
Vincent Pinon committed
177
    connect(m_model.get(), &TimelineItemModel::dataChanged, this, [&](const QModelIndex &topLeft, const QModelIndex &, const QVector<int> &roles) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
178
        if (roles.contains(TimelineModel::IsDisabledRole)) {
179
            int id = int(topLeft.internalId());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
180
181
182
183
184
            if (m_mixers.count(id) > 0) {
                m_mixers[id]->setMute(m_model->data(topLeft, TimelineModel::IsDisabledRole).toBool());
            } else {
                qDebug()<<"=== MODEL DATA CHANGED: MUTE DONE TRACK NOT FOUND!!!";
            }
Julius Künzel's avatar
Julius Künzel committed
185
        } else if (roles.contains(TimelineModel::NameRole)) {
186
            int id = int(topLeft.internalId());
Julius Künzel's avatar
Julius Künzel committed
187
188
189
190
191
192
            if (m_mixers.count(id) > 0) {
                qDebug()<<"=== MODEL DATA CHANGED: CHANGED";
                m_mixers[id]->setTrackName(m_model->data(topLeft, TimelineModel::NameRole).toString());
            } else {
                qDebug()<<"=== MODEL DATA CHANGED: CHANGE NAME DONE TRACK NOT FOUND!!!";
            }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
193
194
195
196
        }
    });

    Mlt::Tractor *service = model->tractor();
197
    if (m_masterMixer != nullptr) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
198
        // delete previous master mixer
199
        m_masterBox->removeWidget(m_masterMixer.get());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
200
    }
Julius Künzel's avatar
Julius Künzel committed
201
    m_masterMixer.reset(new MixerWidget(-1, service, i18n("Master"), QString(), this));
Vincent Pinon's avatar
Vincent Pinon committed
202
    connect(m_masterMixer.get(), &MixerWidget::muteTrack, this, [&](int /*id*/, bool mute) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
203
204
        m_model->tractor()->set("hide", mute ? 3 : 1);
    });
205
    if (m_visibleMixerManager) {
206
        m_masterMixer->connectMixer(true, m_filterIsV2);
207
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
208
    connect(this, &MixerManager::clearMixers, m_masterMixer.get(), &MixerWidget::clear);
209
    m_masterBox->addWidget(m_masterMixer.get());
210
211
212
    if (KdenliveSettings::mixerCollapse()) {
        collapseMixers();
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
213
214
}

215
216
217
218
219
void MixerManager::recordStateChanged(int tid, bool recording)
{
    if (m_mixers.count(tid) > 0) {
        m_mixers[tid]->setRecordState(recording);
    }
220
    emit pCore->switchTimelineRecord(recording);
221
}
222

223
void MixerManager::connectMixer(bool doConnect)
224
{
225
    m_visibleMixerManager = doConnect;
Vincent Pinon's avatar
Vincent Pinon committed
226
    for (const auto &item : m_mixers) {
227
        item.second->connectMixer(m_visibleMixerManager && !KdenliveSettings::mixerCollapse(), m_filterIsV2);
228
    }
229
    if (m_masterMixer != nullptr) {
230
        m_masterMixer->connectMixer(m_visibleMixerManager, m_filterIsV2);
231
232
    }
}
233

234
void MixerManager::collapseMixers()
235
{
236
    connectMixer(m_visibleMixerManager);
237
    if (KdenliveSettings::mixerCollapse()) {
238
        m_expandedWidth = width();
239
        m_channelsBox->setFixedWidth(0);
240
        //m_line->setMaximumWidth(0);
241
242
243
        if (!pCore->window()->isMixedTabbed()) {
            setFixedWidth(m_masterMixer->width() + 2 * m_box->contentsMargins().left());
        }
244
    } else {
245
        //m_line->setMaximumWidth(QWIDGETSIZE_MAX);
246
        m_channelsBox->setMaximumWidth(QWIDGETSIZE_MAX);
Yuri Chornoivan's avatar
Yuri Chornoivan committed
247
        m_channelsBox->setMinimumWidth(m_recommendedWidth);
248
249
        setFixedWidth(m_expandedWidth);
        QMetaObject::invokeMethod(this, "resetSizePolicy", Qt::QueuedConnection);
250
251
252
253
254
255
256
257
    }
}

void MixerManager::resetSizePolicy()
{
    setMaximumWidth(QWIDGETSIZE_MAX);
    setMinimumWidth(0);
}
258
259
260

QSize MixerManager::sizeHint() const
{
Yuri Chornoivan's avatar
Yuri Chornoivan committed
261
    return QSize(m_recommendedWidth, 0);
262
}
263
264
265

void MixerManager::pauseMonitoring(bool pause)
{
Vincent Pinon's avatar
Vincent Pinon committed
266
    for (const auto &item : m_mixers) {
267
268
269
270
271
272
        item.second->pauseMonitoring(pause);
    }
    if (m_masterMixer != nullptr) {
        m_masterMixer->pauseMonitoring(pause);
    }
}