File indexing completed on 2024-05-19 04:54:24

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #pragma once
0007 
0008 #include "abstractmodel/abstracttreemodel.hpp"
0009 #include "definitions.h"
0010 #include "undohelper.hpp"
0011 
0012 #include <QReadWriteLock>
0013 #include <QUuid>
0014 #include <memory>
0015 #include <mlt++/Mlt.h>
0016 #include <unordered_set>
0017 
0018 /** @brief This class an effect stack as viewed by the back-end.
0019    It is responsible for planting and managing effects into the list of producer it holds a pointer to.
0020    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,
0021    ...)
0022  */
0023 class AbstractEffectItem;
0024 class AssetParameterModel;
0025 class DocUndoStack;
0026 class EffectItemModel;
0027 class TreeItem;
0028 class KeyframeModel;
0029 
0030 class EffectStackModel : public AbstractTreeModel
0031 {
0032     Q_OBJECT
0033 
0034 public:
0035     /** @brief Constructs an effect stack and returns a shared ptr to the constructed object
0036        @param service is the mlt object on which we will plant the effects
0037        @param ownerId is some information about the actual object to which the effects are applied
0038     */
0039     static std::shared_ptr<EffectStackModel> construct(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack);
0040 
0041 protected:
0042     EffectStackModel(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack);
0043 
0044 public:
0045     /** @brief Add an effect at the bottom of the stack */
0046     bool appendEffect(const QString &effectId, bool makeCurrent = false, stringMap params = {});
0047     bool appendEffectWithUndo(const QString &effectId, Fun &undo, Fun &redo);
0048     /** @brief Copy an existing effect and append it at the bottom of the stack
0049      */
0050     bool copyEffect(const std::shared_ptr<AbstractEffectItem> &sourceItem, PlaylistState::ClipState state, bool logUndo = true);
0051     bool copyXmlEffect(const QDomElement &effect);
0052     bool copyXmlEffectWithUndo(const QDomElement &effect, Fun &undo, Fun &redo);
0053     /** @brief Import all effects from the given effect stack
0054      */
0055     bool importEffects(const std::shared_ptr<EffectStackModel> &sourceStack, PlaylistState::ClipState state);
0056     void importEffects(const std::weak_ptr<Mlt::Service> &service, PlaylistState::ClipState state, bool alreadyExist = false,
0057                        const QString &originalDecimalPoint = QString(), const QUuid &uuid = QUuid());
0058     bool removeFade(bool fromStart);
0059 
0060     /** @brief This function change the global (timeline-wise) enabled state of the effects
0061      */
0062     void setEffectStackEnabled(bool enabled);
0063 
0064     /** @brief Returns an effect or group from the stack (at the given row) */
0065     std::shared_ptr<AbstractEffectItem> getEffectStackRow(int row, const std::shared_ptr<TreeItem> &parentItem = nullptr);
0066     std::shared_ptr<AssetParameterModel> getAssetModelById(const QString &effectId);
0067 
0068     /** @brief Move an effect in the stack */
0069     void moveEffect(int destRow, const std::shared_ptr<AbstractEffectItem> &item);
0070 
0071     /** @brief Set effect in row as current one */
0072     void setActiveEffect(int ix);
0073     /** @brief Get currently active effect row */
0074     int getActiveEffect() const;
0075     /** @brief Adjust an effect duration (useful for fades) */
0076     bool adjustFadeLength(int duration, bool fromStart, bool audioFade, bool videoFade, bool logUndo);
0077     bool adjustStackLength(bool adjustFromEnd, int oldIn, int oldDuration, int newIn, int duration, int offset, Fun &undo, Fun &redo, bool logUndo);
0078 
0079     void slotCreateGroup(const std::shared_ptr<EffectItemModel> &childEffect);
0080 
0081     /** @brief Returns the id of the owner of the stack */
0082     ObjectId getOwnerId() const;
0083 
0084     int getFadePosition(bool fromStart);
0085     Q_INVOKABLE void adjust(const QString &effectId, const QString &effectName, double value);
0086 
0087     /** @brief Returns true if the stack contains an effect with the given Id */
0088     Q_INVOKABLE bool hasFilter(const QString &effectId) const;
0089     // TODO: this break the encapsulation, remove
0090     Q_INVOKABLE double getFilterParam(const QString &effectId, const QString &paramName);
0091     /** @brief get the active effect's keyframe model */
0092     Q_INVOKABLE KeyframeModel *getEffectKeyframeModel();
0093     /** Add a keyframe in all model parameters */
0094     bool addEffectKeyFrame(int frame, double normalisedVal);
0095     /** @brief Remove a keyframe in all model parameters */
0096     bool removeKeyFrame(int frame);
0097     /** Update a keyframe in all model parameters (with value updated only in first parameter)*/
0098     bool updateKeyFrame(int oldFrame, int newFrame, QVariant normalisedVal);
0099     /** @brief Returns true if active effect has a keyframe at pos p*/
0100     bool hasKeyFrame(int frame);
0101     /** @brief Remove unwanted fade effects, mostly after a cut operation */
0102     void cleanFadeEffects(bool outEffects, Fun &undo, Fun &redo);
0103 
0104     /** @brief Remove all the services associated with this stack and replace them with the given one */
0105     void resetService(std::weak_ptr<Mlt::Service> service);
0106 
0107     /** @brief Append a new service to be managed by this stack */
0108     void addService(std::weak_ptr<Mlt::Service> service);
0109     /** @brief Append an existing service to be managed by this stack (on document load)*/
0110     void loadService(std::weak_ptr<Mlt::Service> service);
0111 
0112     /** @brief Remove a service from those managed by this stack */
0113     void removeService(const std::shared_ptr<Mlt::Service> &service);
0114 
0115     /** @brief Returns a comma separated list of effect names */
0116     const QString effectNames() const;
0117 
0118     /** @brief Returns a list of external file urls used by the effects (e.g. LUTs) */
0119     QStringList externalFiles() const;
0120 
0121     bool isStackEnabled() const;
0122 
0123     /** @brief Returns an XML representation of the effect stack with all parameters */
0124     QDomElement toXml(QDomDocument &document);
0125     /** @brief Returns an XML representation of one of the effect in the stack with all parameters */
0126     QDomElement rowToXml(const QUuid &uuid, int row, QDomDocument &document);
0127     /** @brief Load an effect stack from an XML representation */
0128     bool fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo);
0129     /** @brief Delete active effect from stack */
0130     void removeCurrentEffect();
0131 
0132     /** @brief This is a convenience function that helps check if the tree is in a valid state */
0133     bool checkConsistency() override;
0134 
0135     /** @brief Return true if an asset id is already added to this effect stack */
0136     bool hasEffect(const QString &assetId) const;
0137 
0138     /** @brief Remove all effects for this stack */
0139     void removeAllEffects(Fun &undo, Fun &redo);
0140 
0141     /** @brief Returns a list of zones for all effects */
0142     QVariantList getEffectZones() const;
0143 
0144     /** @brief Copy all Kdenlive effects of this track on a producer */
0145     void passEffects(Mlt::Producer *producer, const QString &exception = QString());
0146 
0147 public Q_SLOTS:
0148     /** @brief Delete an effect from the stack */
0149     void removeEffect(const std::shared_ptr<EffectItemModel> &effect);
0150     /** @brief Move an effect in the stack */
0151     void moveEffectByRow(int destRow, int srcRow);
0152 
0153 protected:
0154     /** @brief Register the existence of a new element
0155      */
0156     void registerItem(const std::shared_ptr<TreeItem> &item) override;
0157     /** @brief Deregister the existence of a new element*/
0158     void deregisterItem(int id, TreeItem *item) override;
0159 
0160     std::weak_ptr<Mlt::Service> m_masterService;
0161     std::vector<std::weak_ptr<Mlt::Service>> m_childServices;
0162     bool m_effectStackEnabled;
0163     ObjectId m_ownerId;
0164 
0165     std::weak_ptr<DocUndoStack> m_undoStack;
0166 
0167 private:
0168     mutable QReadWriteLock m_lock;
0169     std::unordered_set<int> m_fadeIns;
0170     std::unordered_set<int> m_fadeOuts;
0171 
0172     /** @brief: When loading a project, we load filters/effects that are already planted
0173      *          in the producer, so we shouldn't plant them again. Setting this value to
0174      *          true will prevent planting in the producer */
0175     bool m_loadingExisting;
0176     bool doAppendEffect(const QString &effectId, bool makeCurrent, stringMap params, Fun &undo, Fun &redo);
0177 
0178 private Q_SLOTS:
0179     /** @brief: Some effects do not support dynamic changes like sox, and need to be unplugged / replugged on each param change
0180      */
0181     void replugEffect(const std::shared_ptr<AssetParameterModel> &asset);
0182     /** @brief: Some effect zones changed, ensure to update master effect zones
0183      */
0184     void updateEffectZones();
0185 
0186 Q_SIGNALS:
0187     /** @brief: This signal is connected to the project clip for bin clips and activates the reload of effects on child (timeline) producers
0188      */
0189     void modelChanged();
0190     void enabledStateChanged();
0191     /** @brief: The master effect stack zones changed, update */
0192     void updateMasterZones();
0193     /** @brief: Currently active effect changed */
0194     void currentChanged(QModelIndex ix, bool active);
0195 };