effectstackmodel.hpp 8.86 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/***************************************************************************
 *   Copyright (C) 2017 by Nicolas Carion                                  *
 *   This file is part of Kdenlive. See www.kdenlive.org.                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) version 3 or any later version accepted by the       *
 *   membership of KDE e.V. (or its successor approved  by the membership  *
 *   of KDE e.V.), which shall act as a proxy defined in Section 14 of     *
 *   version 3 of the license.                                             *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

#ifndef EFFECTSTACKMODEL_H
#define EFFECTSTACKMODEL_H

#include "abstractmodel/abstracttreemodel.hpp"
26
#include "definitions.h"
Nicolas Carion's avatar
Nicolas Carion committed
27
#include "undohelper.hpp"
28
29

#include <QReadWriteLock>
30
31
#include <memory>
#include <mlt++/Mlt.h>
32
#include <unordered_set>
33
34

/* @brief This class an effect stack as viewed by the back-end.
35
36
37
   It is responsible for planting and managing effects into the list of producer it holds a pointer to.
   It can contains more than one producer for example if it represents the effect stack of a projectClip: this clips contains several producers (audio, video,
   ...)
38
 */
39
class AbstractEffectItem;
40
class AssetParameterModel;
41
42
43
class DocUndoStack;
class EffectItemModel;
class TreeItem;
44
class KeyframeModel;
45

46
47
class EffectStackModel : public AbstractTreeModel
{
48
    Q_OBJECT
49
50

public:
51
    /* @brief Constructs an effect stack and returns a shared ptr to the constructed object
52
53
54
       @param service is the mlt object on which we will plant the effects
       @param ownerId is some information about the actual object to which the effects are applied
    */
55
    static std::shared_ptr<EffectStackModel> construct(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack);
56

57
protected:
58
    EffectStackModel(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack);
59
60

public:
61
    /* @brief Add an effect at the bottom of the stack */
62
    bool appendEffect(const QString &effectId, bool makeCurrent = false);
63
64
    /* @brief Copy an existing effect and append it at the bottom of the stack
     */
65
    bool copyEffect(const std::shared_ptr<AbstractEffectItem> &sourceItem, PlaylistState::ClipState state, bool logUndo = true);
66
    bool copyXmlEffect(QDomElement effect);
67
68
    /* @brief Import all effects from the given effect stack
     */
Nicolas Carion's avatar
Nicolas Carion committed
69
    bool importEffects(const std::shared_ptr<EffectStackModel> &sourceStack, PlaylistState::ClipState state);
70
    void importEffects(const std::weak_ptr<Mlt::Service> &service, PlaylistState::ClipState state, bool alreadyExist = false, QString originalDecimalPoint = QString());
71
    bool removeFade(bool fromStart);
72

73
74
    /* @brief This function change the global (timeline-wise) enabled state of the effects
     */
75
    void setEffectStackEnabled(bool enabled);
76

77
    /* @brief Returns an effect or group from the stack (at the given row) */
Nicolas Carion's avatar
Nicolas Carion committed
78
    std::shared_ptr<AbstractEffectItem> getEffectStackRow(int row, const std::shared_ptr<TreeItem> &parentItem = nullptr);
79
    std::shared_ptr<AssetParameterModel> getAssetModelById(const QString &effectId);
80
81

    /* @brief Move an effect in the stack */
Nicolas Carion's avatar
Nicolas Carion committed
82
    void moveEffect(int destRow, const std::shared_ptr<AbstractEffectItem> &item);
83

84
    /* @brief Set effect in row as current one */
85
    void setActiveEffect(int ix);
86
    /* @brief Get currently active effect row */
87
    int getActiveEffect() const;
88
    /* @brief Adjust an effect duration (useful for fades) */
89
    bool adjustFadeLength(int duration, bool fromStart, bool audioFade, bool videoFade, bool logUndo);
90
    bool adjustStackLength(bool adjustFromEnd, int oldIn, int oldDuration, int newIn, int duration, int offset, Fun &undo, Fun &redo, bool logUndo);
91

Nicolas Carion's avatar
Nicolas Carion committed
92
    void slotCreateGroup(const std::shared_ptr<EffectItemModel> &childEffect);
93
94
95

    /* @brief Returns the id of the owner of the stack */
    ObjectId getOwnerId() const;
96

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
97
    int getFadePosition(bool fromStart);
98
    Q_INVOKABLE void adjust(const QString &effectId, const QString &effectName, double value);
99
100
101
102
103

    /* @brief Returns true if the stack contains an effect with the given Id */
    Q_INVOKABLE bool hasFilter(const QString &effectId) const;
    // TODO: this break the encapsulation, remove
    Q_INVOKABLE double getFilterParam(const QString &effectId, const QString &paramName);
104
105
    /** get the active effect's keyframe model */
    Q_INVOKABLE KeyframeModel *getEffectKeyframeModel();
106
107
108
109
110
    /** Add a keyframe in all model parameters */
    bool addEffectKeyFrame(int frame, double normalisedVal);
    /** Remove a keyframe in all model parameters */
    bool removeKeyFrame(int frame);
    /** Update a keyframe in all model parameters (with value updated only in first parameter)*/
111
    bool updateKeyFrame(int oldFrame, int newFrame, QVariant normalisedVal);
112
113
    /** Returns true if active effect has a keyframe at pos p*/
    bool hasKeyFrame(int frame);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
114
115
    /** Remove unwanted fade effects, mostly after a cut operation */
    void cleanFadeEffects(bool outEffects, Fun &undo, Fun &redo);
116

117
118
119
120
121
    /* Remove all the services associated with this stack and replace them with the given one */
    void resetService(std::weak_ptr<Mlt::Service> service);

    /* @brief Append a new service to be managed by this stack */
    void addService(std::weak_ptr<Mlt::Service> service);
122
123
    /* @brief Append an existing service to be managed by this stack (on document load)*/
    void loadService(std::weak_ptr<Mlt::Service> service);
124

125
    /* @brief Remove a service from those managed by this stack */
Nicolas Carion's avatar
Nicolas Carion committed
126
    void removeService(const std::shared_ptr<Mlt::Service> &service);
127

128
129
130
    /* @brief Returns a comma separated list of effect names */
    const QString effectNames() const;

131
    bool isStackEnabled() const;
132

133
134
    /* @brief Returns an XML representation of the effect stack with all parameters */
    QDomElement toXml(QDomDocument &document);
135
136
    /* @brief Returns an XML representation of one of the effect in the stack with all parameters */
    QDomElement rowToXml(int row, QDomDocument &document);
137
    /* @brief Load an effect stack from an XML representation */
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
138
    bool fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo);
139
140
    /* @brief Delete active effect from stack */
    void removeCurrentEffect();
141

142
143
144
    /* @brief This is a convenience function that helps check if the tree is in a valid state */
    bool checkConsistency() override;

145
146
    /* @brief Return true if an asset id is already added to this effect stack */
    bool hasEffect(const QString &assetId) const;
147
148
149
    
    /* @brief Remove all effects for this stack */
    void removeAllEffects(Fun &undo, Fun & redo);
150

151
152
public slots:
    /* @brief Delete an effect from the stack */
Nicolas Carion's avatar
Nicolas Carion committed
153
    void removeEffect(const std::shared_ptr<EffectItemModel> &effect);
154

155
protected:
156
157
158
159
160
161
    /* @brief Register the existence of a new element
     */
    void registerItem(const std::shared_ptr<TreeItem> &item) override;
    /* @brief Deregister the existence of a new element*/
    void deregisterItem(int id, TreeItem *item) override;

162
163
    std::weak_ptr<Mlt::Service> m_masterService;
    std::vector<std::weak_ptr<Mlt::Service>> m_childServices;
164
    bool m_effectStackEnabled;
165
    ObjectId m_ownerId;
166

167
    std::weak_ptr<DocUndoStack> m_undoStack;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
168

169
170
private:
    mutable QReadWriteLock m_lock;
Nicolas Carion's avatar
Nicolas Carion committed
171
172
    std::unordered_set<int> m_fadeIns;
    std::unordered_set<int> m_fadeOuts;
173

174
175
176
177
    /** @brief: When loading a project, we load filters/effects that are already planted
     *          in the producer, so we shouldn't plant them again. Setting this value to
     *          true will prevent planting in the producer */
    bool m_loadingExisting;
178
179
180
private slots:
    /** @brief: Some effects do not support dynamic changes like sox, and need to be unplugged / replugged on each param change
     */
Nicolas Carion's avatar
Nicolas Carion committed
181
    void replugEffect(const std::shared_ptr<AssetParameterModel> &asset);
182
183

signals:
184
185
    /** @brief: This signal is connected to the project clip for bin clips and activates the reload of effects on child (timeline) producers
     */
186
    void modelChanged();
187
    void enabledStateChanged();
188
189
190
};

#endif