[multimedia/kdenlive] /: Add support for MLT autoduck transition (requires latest MLT git)

Jean-Baptiste Mardelle <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 0f02a2f3bbc3f9d04637ddb151d6f708766f1312 by Jean-Baptiste Mardelle.
Committed on 07/08/2026 at 14:32.
Pushed by mardelle into branch 'master'.

Add support for MLT autoduck transition (requires latest MLT git)

M  +1    -0    data/transitions/CMakeLists.txt
A  +20   -0    data/transitions/autoduck.xml
M  +10   -7    src/timeline2/model/timelinemodel.cpp
M  +6    -9    src/timeline2/view/qml/Timeline.qml
M  +15   -3    src/timeline2/view/timelinecontroller.cpp
M  +1    -1    src/transitions/transitionsrepository.cpp

https://invent.kde.org/multimedia/kdenlive/-/commit/0f02a2f3bbc3f9d04637ddb151d6f708766f1312

diff --git a/data/transitions/CMakeLists.txt b/data/transitions/CMakeLists.txt
index 85421692cf..8b1382b54b 100644
--- a/data/transitions/CMakeLists.txt
+++ b/data/transitions/CMakeLists.txt
@@ -3,6 +3,7 @@
 
 INSTALL (FILES 
 affine.xml
+autoduck.xml
 composite.xml
 dissolve.xml
 luma.xml
diff --git a/data/transitions/autoduck.xml b/data/transitions/autoduck.xml
new file mode 100644
index 0000000000..b7de412212
--- /dev/null
+++ b/data/transitions/autoduck.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE kpartgui>
+<transition tag="mix" id="autoduck" type="audiotransition">
+    <name>Auto Duck</name>
+    <description>Applies a volume change on the lower track depending on the volume of the upper track.</description>
+    <author>Dan Dennedy</author>
+    <parameter type="constant" name="duck_threshold" max="0" min="-20" default="-15" decimals="1">
+        <name>Ducking Threshold</name>
+    </parameter>
+    <parameter type="constant" name="duck_attenuation" max="0" min="-60" default="-18" decimals="1">
+        <name>Ducking Attenuation</name>
+    </parameter>
+    <parameter type="constant" name="duck_fade_in" max="5000" min="0" default="1500" suffix="ms">
+        <name>Ducking Fade In</name>
+    </parameter>
+    <parameter type="constant" name="duck_fade_out" max="5000" min="0" default="250" suffix="ms">
+        <name>Ducking Fade Out</name>
+    </parameter>
+    <parameter type="fixed" name="sum" max="1" min="1" default="1"/>
+</transition>
diff --git a/src/timeline2/model/timelinemodel.cpp b/src/timeline2/model/timelinemodel.cpp
index 0e3ced23ad..78e4fae2b4 100644
--- a/src/timeline2/model/timelinemodel.cpp
+++ b/src/timeline2/model/timelinemodel.cpp
@@ -1855,7 +1855,7 @@ QVariantList TimelineModel::suggestCompositionMove(int compoId, int trackId, int
     Q_ASSERT(isTrack(trackId));
     int currentPos = getCompositionPosition(compoId);
     int currentTrack = getCompositionTrackId(compoId);
-    if (getTrackById_const(trackId)->isAudioTrack()) {
+    if (getTrackById_const(trackId)->isAudioTrack() != getTrackById_const(currentTrack)->isAudioTrack()) {
         // Trying move on incompatible track type, stay on same track
         trackId = currentTrack;
     }
@@ -6528,7 +6528,12 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
     Q_ASSERT(isComposition(compoId));
     Q_ASSERT(isTrack(trackId));
     if (compositionTrack == -1 || (compositionTrack > 0 && trackId == getTrackIndexFromPosition(compositionTrack - 1))) {
-        compositionTrack = getPreviousVideoTrackPos(trackId);
+        int previousTrack = getPreviousTrackId(trackId);
+        if (previousTrack == trackId) {
+            compositionTrack = 0;
+        } else {
+            compositionTrack = getTrackMltIndex(previousTrack);
+        }
     }
     if (compositionTrack == -1) {
         // it doesn't make sense to insert a composition on the last track
@@ -6658,11 +6663,9 @@ bool TimelineModel::replantCompositions(int currentCompo, bool updateView)
         resource = transition.get("mlt_service");
         int internal = transition.get_int("internal_added");
         if (internal > 0) {
-            if (resource != QLatin1String("mix")) {
-                trackCompositions << new Mlt::Transition(transition);
-                field->disconnect_service(transition);
-                transition.disconnect_all_producers();
-            }
+            trackCompositions << new Mlt::Transition(transition);
+            field->disconnect_service(transition);
+            transition.disconnect_all_producers();
         }
 
         if (nextservice == nullptr) {
diff --git a/src/timeline2/view/qml/Timeline.qml b/src/timeline2/view/qml/Timeline.qml
index 7ecf022c12..d2b8f6c4cd 100644
--- a/src/timeline2/view/qml/Timeline.qml
+++ b/src/timeline2/view/qml/Timeline.qml
@@ -707,7 +707,7 @@ function getTrackColor(audio, header) {
                 var track = Logic.getTrackIdFromPos(drag.y + voffset + scrollView.contentY - subtitleTrack.height)
                 if (track !== -1) {
                     var frame = Math.floor((drag.x + scrollView.contentX + offset) / root.timeScale)
-                    if (root.controller.isAudioTrack(track) != isAudioDrag) {
+                    if (root.controller.isAudioTrack(track) != compoArea.isAudioDrag) {
                         // Don't allow moving composition to an audio track
                         track = root.controller.getCompositionTrackId(root.clipBeingDroppedId)
                     }
@@ -717,7 +717,7 @@ function getTrackColor(audio, header) {
                     sameCutPos = root.timeline.isOnCut(root.clipBeingDroppedId)
                     if (sameCutPos > -1) {
                         var sourceTrack = Logic.getTrackById(fakeTrack)
-                        if ((drag.y < sourceTrack.y + sourceTrack.height / 2) || isAudioDrag) {
+                        if ((drag.y < sourceTrack.y + sourceTrack.height / 2) || compoArea.isAudioDrag) {
                             sameTrackIndicator.x = sameCutPos * root.timeScale - sameTrackIndicator.width / 2
                             sameTrackIndicator.y = sourceTrack.y
                             sameTrackIndicator.height = sourceTrack.height
@@ -746,8 +746,8 @@ function getTrackColor(audio, header) {
                 var track = Logic.getTrackIdFromPos(drag.y + scrollView.contentY - yOffset)
                 var frame = Math.round((drag.x + scrollView.contentX) / root.timeScale)
                 root.droppedPosition = frame
-                isAudioDrag = drag.getDataAsString('type') == "audio"
-                if (track >= 0 && root.controller.isAudioTrack(track) == isAudioDrag) {
+                compoArea.isAudioDrag = drag.getDataAsString('type') == "audio"
+                if (track >= 0 && root.controller.isAudioTrack(track) == compoArea.isAudioDrag) {
                     root.clipBeingDroppedData = drag.getDataAsString('kdenlive/composition')
                     root.clipBeingDroppedId = root.timeline.insertComposition(track, frame, root.clipBeingDroppedData, false)
                     root.continuousScrolling(drag.x + scrollView.contentX, drag.y + scrollView.contentY, upMove)
@@ -777,7 +777,7 @@ function getTrackColor(audio, header) {
                         yOffset = subtitleTrack.height
                     }
                     var track = Logic.getTrackIdFromPos(drag.y + scrollView.contentY - yOffset)
-                    if (track !== -1 && root.controller.isAudioTrack(track) == isAudioDrag) {
+                    if (track !== -1 && root.controller.isAudioTrack(track) == compoArea.isAudioDrag) {
                         frame = root.controller.suggestSnapPoint(frame, root.snapping)
                         root.clipBeingDroppedData = drag.getDataAsString('kdenlive/composition')
                         root.clipBeingDroppedId = root.timeline.insertComposition(track, frame, root.clipBeingDroppedData , false)
@@ -808,11 +808,8 @@ function getTrackColor(audio, header) {
                 if (sameTrackIndicator.visible) {
                     // We want a same track composition
                     root.timeline.insertNewMix(track, sameCutPos, root.clipBeingDroppedData)
-                } else if (!isAudioDrag) {
-                    root.timeline.insertNewCompositionAtPos(track, frame, root.clipBeingDroppedData)
                 } else {
-                    // Cannot insert an audio mix composition
-                    // TODO: show warning
+                    root.timeline.insertNewCompositionAtPos(track, frame, root.clipBeingDroppedData)
                 }
             }
             root.clearDropData()
diff --git a/src/timeline2/view/timelinecontroller.cpp b/src/timeline2/view/timelinecontroller.cpp
index ec70542bcd..f63b1ab072 100644
--- a/src/timeline2/view/timelinecontroller.cpp
+++ b/src/timeline2/view/timelinecontroller.cpp
@@ -552,7 +552,11 @@ int TimelineController::insertNewCompositionAtPos(int tid, int position, const Q
     if (topCid > 0) {
         return addCompositionToClip(transitionId, topCid, 0);
     } else {
-        int lowerVideoTrackId = m_model->getPreviousVideoTrackIndex(tid);
+        int previousTrack = m_model->getPreviousTrackId(tid);
+        int lowerVideoTrackId = 0;
+        if (previousTrack != tid) {
+            lowerVideoTrackId = m_model->getTrackMltIndex(previousTrack);
+        }
         if (lowerVideoTrackId > 0) {
             int lowerCid = m_model->getTrackById_const(lowerVideoTrackId)->getClipByStartPosition(position);
             if (lowerCid > 0) {
@@ -594,7 +598,11 @@ int TimelineController::insertNewComposition(int tid, int clipId, int offset, QS
     int endPos = minimumPos + clip_duration;
     int position = minimumPos;
     int duration = qMin(clip_duration, pCore->getDurationFromString(KdenliveSettings::transition_duration()));
-    int lowerVideoTrackId = m_model->getPreviousVideoTrackIndex(tid);
+    int previousTrack = m_model->getPreviousTrackId(tid);
+    int lowerVideoTrackId = 0;
+    if (previousTrack != tid) {
+        lowerVideoTrackId = m_model->getTrackMltIndex(previousTrack);
+    }
     bool revert = offset > clip_duration / 2;
     int bottomId = 0;
     if (lowerVideoTrackId > 0) {
@@ -691,7 +699,11 @@ int TimelineController::insertComposition(int tid, int position, QString transit
         duration = pCore->getDurationFromString(KdenliveSettings::transition_duration());
     }
     // Check if composition should be reversed (top clip at beginning, bottom at end)
-    int a_track = m_model->getPreviousVideoTrackPos(tid);
+    int previousTrack = m_model->getPreviousTrackId(tid);
+    int a_track = 0;
+    if (previousTrack != tid) {
+        a_track = m_model->getTrackMltIndex(previousTrack);
+    }
     int topClip = m_model->getTrackById_const(tid)->getClipByPosition(position);
     int bottomClip = -1;
     if (a_track > 0) {
diff --git a/src/transitions/transitionsrepository.cpp b/src/transitions/transitionsrepository.cpp
index 28440effb4..0a1f4474ae 100644
--- a/src/transitions/transitionsrepository.cpp
+++ b/src/transitions/transitionsrepository.cpp
@@ -111,7 +111,7 @@ void TransitionsRepository::parseCustomAssetFile(const QString &file_name, std::
         if (customAssets.count(result.id) > 0) {
             // qDebug() << "duplicate transition" << result.id;
         }
-        if (m_hiddenList.contains(result.mltId)) {
+        if (m_hiddenList.contains(result.id)) {
             result.type = AssetListType::AssetType::Hidden;
         }
         customAssets[result.id] = result;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.