Files
kdenlive/tests/mixtest.cpp
Zhangzhi Hu e83354d625 QString refactor: replace QString() with QStringLiteral()
Replace `QString()` constructors with `QStringLiteral()` macro to improve
performance.
2024-10-21 06:59:47 +00:00

1214 lines
51 KiB
C++

/*
SPDX-FileCopyrightText: 2020-2022 Jean-Baptiste Mardelle <jb@kdenlive.org>
SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "catch.hpp"
#include "test_utils.hpp"
// test specific headers
#include "doc/docundostack.hpp"
#include "doc/kdenlivedoc.h"
#include <QString>
#include <cmath>
#include <iostream>
#include <tuple>
#include <unordered_set>
#include "core.h"
#include "definitions.h"
using namespace fakeit;
TEST_CASE("Simple Mix", "[SameTrackMix]")
{
// Ensure our core profile is correct
REQUIRE(pCore->timecode().fps() == 25.);
REQUIRE(pCore->getDurationFromString(KdenliveSettings::mix_duration()) == 25);
// Create timeline
auto binModel = pCore->projectItemModel();
std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
// Here we do some trickery to enable testing.
// We mock the project class so that the undoStack function returns our undoStack
KdenliveDoc document(undoStack);
pCore->projectManager()->testSetDocument(&document);
QDateTime documentDate = QDateTime::currentDateTime();
KdenliveTests::updateTimeline(false, QString(), QString(), documentDate, 0);
auto timeline = document.getTimeline(document.uuid());
pCore->projectManager()->testSetActiveTimeline(timeline);
// Create a request
int tid1 = timeline->getTrackIndexFromPosition(0);
int tid3 = timeline->getTrackIndexFromPosition(1);
int tid2 = timeline->getTrackIndexFromPosition(2);
int tid4 = timeline->getTrackIndexFromPosition(3);
// Create clip with audio
QString binId = KdenliveTests::createProducerWithSound(pCore->getProjectProfile(), binModel, 100);
// Create video clip
QString binId2 = KdenliveTests::createProducer(pCore->getProjectProfile(), "red", binModel, 50, false);
// Setup insert stream data
QMap<int, QString> audioInfo;
audioInfo.insert(1, QStringLiteral("stream1"));
KdenliveTests::setAudioTargets(timeline, audioInfo);
// Create AV clip 1
int cid1;
int cid2;
int cid3;
int cid4;
int cid5;
int audio1;
int audio2;
int audio5;
REQUIRE(timeline->requestClipInsertion(binId, tid2, 100, cid1));
REQUIRE(timeline->requestItemResize(cid1, 10, true, true));
audio1 = timeline->getClipSplitPartner(cid1);
// Create AV clip 2
REQUIRE(timeline->requestClipInsertion(binId, tid2, 110, cid2));
REQUIRE(timeline->requestItemResize(cid2, 10, true, true));
REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
audio2 = timeline->getClipSplitPartner(cid2);
// Create color clip 1
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 500, cid3));
REQUIRE(timeline->requestItemResize(cid3, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 520, cid4));
REQUIRE(timeline->requestItemResize(cid4, 20, true, true));
int mixDuration = pCore->getDurationFromString(KdenliveSettings::mix_duration());
auto state0 = [&]() {
REQUIRE(timeline->getClipsCount() == 6);
REQUIRE(timeline->getClipPlaytime(cid1) == 10);
REQUIRE(timeline->getClipPosition(cid1) == 100);
REQUIRE(timeline->getClipPlaytime(cid2) == 10);
REQUIRE(timeline->getClipPosition(cid2) == 110);
REQUIRE(timeline->getClipPosition(cid3) == 500);
REQUIRE(timeline->getClipPlaytime(cid3) == 20);
REQUIRE(timeline->getClipPosition(cid4) == 520);
REQUIRE(timeline->getClipPlaytime(cid4) == 20);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid1)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
};
auto state0b = [&]() {
REQUIRE(timeline->getClipsCount() == 8);
REQUIRE(timeline->getClipPlaytime(cid1) == 10);
REQUIRE(timeline->getClipPosition(cid1) == 100);
REQUIRE(timeline->getClipPlaytime(cid2) == 10);
REQUIRE(timeline->getClipPosition(cid2) == 110);
REQUIRE(timeline->getClipPlaytime(cid5) == 10);
REQUIRE(timeline->getClipPosition(cid5) == 120);
REQUIRE(timeline->getClipPosition(cid3) == 500);
REQUIRE(timeline->getClipPlaytime(cid3) == 20);
REQUIRE(timeline->getClipPosition(cid4) == 520);
REQUIRE(timeline->getClipPlaytime(cid4) == 20);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid1)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
};
auto state1 = [&]() {
REQUIRE(timeline->getClipsCount() == 6);
REQUIRE(timeline->getClipPlaytime(cid1) > 10);
REQUIRE(timeline->getClipPosition(cid1) == 100);
REQUIRE(timeline->getClipPlaytime(cid2) > 10);
REQUIRE(timeline->getClipPosition(cid2) < 110);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
};
auto state1b = [&]() {
REQUIRE(timeline->getClipsCount() == 8);
REQUIRE(timeline->getClipPlaytime(cid1) > 10);
REQUIRE(timeline->getClipPosition(cid1) == 100);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(audio1) == 0);
REQUIRE(timeline->getClipPlaytime(cid2) > 10);
REQUIRE(timeline->getClipPosition(cid2) < 110);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(audio2) == 1);
REQUIRE(timeline->getClipPlaytime(cid5) == 10);
REQUIRE(timeline->getClipPosition(cid5) == 120);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(audio5) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
};
auto state3 = [&, mixDuration]() {
REQUIRE(timeline->getClipsCount() == 6);
REQUIRE(timeline->getClipPlaytime(cid1) > 30);
REQUIRE(timeline->getClipPosition(cid1) == 100);
REQUIRE(timeline->getClipPlaytime(cid2) > 30);
REQUIRE(timeline->getClipPosition(cid2) < 130);
REQUIRE(timeline->getMixDuration(cid2) == mixDuration);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
};
auto state2 = [&]() {
REQUIRE(timeline->getClipsCount() == 6);
REQUIRE(timeline->getClipPlaytime(cid3) == 32);
REQUIRE(timeline->getClipPosition(cid3) == 500);
REQUIRE(timeline->getClipPlaytime(cid4) == 33);
REQUIRE(timeline->getClipPosition(cid4) == 507);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid1)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
};
SECTION("Create and delete mix on color clips")
{
// Cid3 at 500, length 20
// Cid4 at 520, length 20
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
undoStack->undo();
state0();
undoStack->redo();
state2();
undoStack->undo();
state0();
}
SECTION("Add mix and resize last clip in playlist")
{
// Cid3 at 500, length 20
// Cid4 at 520, length 20
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
// Resize clip 4
REQUIRE(timeline->requestItemResize(cid4, 60, true, true));
REQUIRE(timeline->getClipPlaytime(cid4) == 60);
undoStack->undo();
REQUIRE(timeline->getClipPlaytime(cid4) == 33);
undoStack->redo();
REQUIRE(timeline->getClipPlaytime(cid4) == 60);
undoStack->undo();
undoStack->undo();
state0();
undoStack->redo();
state2();
undoStack->undo();
state0();
}
SECTION("Create mix on color clips and move main (right side) clip")
{
// CID 3 length=20, pos=500, CID4 length=20, pos=520
// Default mix duration = 25 frames (12 before / 13 after)
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
// Move right clip to the left, should fail
REQUIRE(timeline->requestClipMove(cid4, tid2, 506) == false);
// Move clip inside mix zone, should delete the mix
REQUIRE(timeline->requestClipMove(cid4, tid2, 509));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
state2();
// Move clip outside mix zone, should delete the mix and move it back to playlist 0
REQUIRE(timeline->requestClipMove(cid4, tid2, 600));
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
undoStack->undo();
state2();
// Move clip to another track, should delete mix
REQUIRE(timeline->requestClipMove(cid4, tid4, 600));
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
undoStack->undo();
state2();
undoStack->undo();
state0();
}
SECTION("Create mix on color clip and move left side clip")
{
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
// Move left clip to the right, should silently fail
REQUIRE(timeline->requestClipMove(cid3, tid2, 502, true, true, false) == false);
REQUIRE(timeline->getClipPosition(cid3) == 500);
// Move clip inside mix zone, should delete the mix
REQUIRE(timeline->requestClipMove(cid3, tid2, 499));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
state2();
// Move clip outside mix zone, should delete the mix
REQUIRE(timeline->requestClipMove(cid3, tid2, 450));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
state2();
// Move clip to another track, should delete mix
REQUIRE(timeline->requestClipMove(cid3, tid4, 600));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
undoStack->undo();
state2();
undoStack->undo();
state0();
}
SECTION("Create mix on color clips and move some to another track")
{
state0();
// insert third color clip
cid5 = -1;
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->getClipPosition(cid5) == 540);
audio5 = timeline->getClipSplitPartner(cid5);
// CID 3 length=20, pos=500, CID4 length=20, pos=520, CID5 length=20, pos=540
// Default mix duration = 25 frames (12 before / 13 after)
REQUIRE(timeline->mixClip(cid3));
REQUIRE(timeline->mixClip(cid4));
REQUIRE(timeline->getClipPosition(cid5) < 540);
undoStack->undo();
REQUIRE(timeline->getClipPosition(cid5) == 540);
undoStack->redo();
REQUIRE(timeline->getClipPosition(cid5) < 540);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Move middle clip to another track, should delete the mixes
REQUIRE(timeline->requestClipMove(cid4, tid4, 500));
REQUIRE(timeline->getClipPosition(cid5) == 540);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
// Undo track move
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Undo mixes
undoStack->undo();
undoStack->undo();
// undo 3rd clip resize & insert
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Create mix on color clips and group move")
{
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
// Move clip inside mix zone, should resize the mix
auto g1 = std::unordered_set<int>({cid3, cid4});
REQUIRE(timeline->requestClipsGroup(g1));
// Move clip to another track, should delete mix
REQUIRE(timeline->requestClipMove(cid4, tid4, 600));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 1);
undoStack->undo();
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 0);
state2();
// Move on same track
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->requestClipMove(cid4, tid3, 800));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
undoStack->undo();
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
state2();
// Undo group
undoStack->undo();
// Undo mix
undoStack->undo();
state0();
}
SECTION("Create and delete mix on AV clips")
{
state0();
// Clips are cid1 at 100, cid2 at 110
REQUIRE(timeline->requestItemResize(cid2, 30, true, true) == 30);
REQUIRE(timeline->requestItemResize(cid2, 10, false, true) == 10);
REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
REQUIRE(timeline->mixClip(cid1));
state1();
undoStack->undo();
state0();
undoStack->redo();
state1();
undoStack->undo();
state0();
}
SECTION("Create mix and move AV clips")
{
// CID 1 length=10, pos=100, CID2 length=10, pos=110
// Default mix duration = 25 frames (12 before / 13 after)
// Resize CID2 so that it has some space to expand left
REQUIRE(timeline->requestItemResize(cid2, 30, true, true) == 30);
REQUIRE(timeline->requestItemResize(cid2, 10, false, true) == 10);
REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
// Resize clip, should resize the mix
state0();
REQUIRE(timeline->mixClip(cid2));
state1();
// Resize right clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid2, 15, false, true) == 15);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
undoStack->undo();
state1();
// Resize left clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid1, 18, true, true) == 18);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
undoStack->undo();
state1();
// Move clip outside mix zone, should delete the mix
REQUIRE(timeline->requestClipMove(cid2, tid2, 200));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
undoStack->undo();
state1();
// Undo mix
undoStack->undo();
state0();
}
SECTION("Create chained mixes on AV clips")
{
// CID 1 length=10, pos=100, CID2 length=10, pos=110
// Default mix duration = 25 frames (12 before / 13 after)
// Resize CID2 so that it has some space to expand left
REQUIRE(timeline->requestItemResize(cid2, 30, true, true) == 30);
REQUIRE(timeline->requestItemResize(cid2, 10, false, true) == 10);
REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
state0();
// Create a third AV clip and make some space
cid5 = -1;
REQUIRE(timeline->requestClipInsertion(binId, tid2, 120, cid5));
REQUIRE(timeline->requestItemResize(cid5, 30, true, true) == 30);
REQUIRE(timeline->requestItemResize(cid5, 10, false, true) == 10);
REQUIRE(timeline->requestClipMove(cid5, tid2, 120));
audio5 = timeline->getClipSplitPartner(cid5);
state0b();
// CID 1 length=10, pos=100, CID2 length=20, pos=130, CID5 length=20, pos=130
// Create mix between cid1 and cid2
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 0);
REQUIRE(timeline->mixClip(cid1));
state1b();
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid2) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixIsReversed(audio2) == false);
// Create mix between cid2 and cid5
REQUIRE(timeline->mixClip(cid2));
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid2) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixIsReversed(audio2) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixIsReversed(audio5) == true);
// Undo cid5 mix
undoStack->undo();
state1b();
// Undo cid2 mix
undoStack->undo();
// Undo cid5
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Create mix on color clip and test resize")
{
state0();
// CID 3 length=20, pos=500, CID4 length=20, pos=520
// Default mix duration = 25 frames (12 before / 13 after)
REQUIRE(timeline->mixClip(cid3));
state2();
// Resize left clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid3, 24, true, true) == 24);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->undo();
state2();
// Resize left clip outside mix zone, should delete the mix
REQUIRE(timeline->requestItemResize(cid3, 4, true, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
state2();
// Resize right clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid4, 16, false, true) == 16);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->undo();
state2();
// Resize right clip outside mix zone, should delete the mix
REQUIRE(timeline->requestItemResize(cid4, 4, false, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
state2();
// Resize right clip before left clip, should limit the resize to left clip position
REQUIRE(timeline->requestItemResize(cid4, 50, false, true) == 40);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->undo();
state2();
// Resize left clip past right clip, should limit the resize to left clip position
REQUIRE(timeline->requestItemResize(cid3, 100, true, true) == 40);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->undo();
state2();
// Before mix: CID 3 length=20, pos=500, CID4 length=20, pos=520
// Default mix duration = 25 frames (12 before / 13 after)
// Resize left clip before right clip start, then right clip outside left clip, should delete the mix
REQUIRE(timeline->requestItemResize(cid3, 20, true, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->requestItemResize(cid4, 20, false, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
undoStack->undo();
state2();
// Resize right clip after left clip end, then left clip outside right clip, should delete the mix
REQUIRE(timeline->requestItemResize(cid4, 20, false, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->requestItemResize(cid3, 20, true, true) == 20);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
undoStack->undo();
undoStack->undo();
state2();
undoStack->undo();
state0();
}
SECTION("Create mix on AV clips and resize")
{
state0();
// CID 1 length=10, pos=100, CID2 length=10, pos=110
REQUIRE(timeline->getClipPlaytime(cid1) == 10);
REQUIRE(timeline->getClipPlaytime(cid2) == 10);
// Resize clip in to have some space for mix
REQUIRE(timeline->requestItemResize(cid2, 90, true, true) == 90);
REQUIRE(timeline->requestItemResize(cid2, 30, false, true) == 30);
REQUIRE(timeline->requestClipMove(cid2, tid2, 130));
REQUIRE(timeline->requestItemResize(cid1, 30, true, true) == 30);
REQUIRE(timeline->mixClip(cid1));
state3();
// CID 1 length=30, pos=100, CID2 length=30, pos=130
// Default mix duration = 25 frames (12 before / 13 after)
// Resize left clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid1, 35, true, true) == 35);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 1);
undoStack->undo();
state3();
// Resize left clip outside mix zone, should delete the mix
REQUIRE(timeline->requestItemResize(cid1, 10, true, true) == 30);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 0);
undoStack->undo();
state3();
// Resize right clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid2, 25, false, true) == 25);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 1);
undoStack->undo();
state3();
// Resize right clip outside mix zone, should delete the mix
REQUIRE(timeline->requestItemResize(cid2, 4, false, true) == 30);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 0);
undoStack->undo();
state3();
// Resize right clip before left clip, should limit to left clip position
REQUIRE(timeline->requestItemResize(cid2, 80, false, true) == 60);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 1);
undoStack->undo();
state3();
// Resize left clip after right clip, should limit to right clip duration
REQUIRE(timeline->requestItemResize(cid1, 80, true, true) == 60);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid3)->mixCount() == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid1) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid2) == 1);
undoStack->undo();
state3();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test chained mixes on color clips")
{
// Add 2 more color clips
cid5 = -1;
int cid6;
int cid7;
state0();
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 560, cid6));
REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 600, cid7));
REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
audio5 = timeline->getClipSplitPartner(cid5);
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=40
// Cid7 pos=600, duration=20
// Mix 3 and 4
REQUIRE(timeline->mixClip(cid3));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
// Mix 6 and 7
REQUIRE(timeline->mixClip(cid6));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Mix 5 and 6
REQUIRE(timeline->mixClip(cid5));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 3);
// Undo mix 5 and 6
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Undo mix 6 and 7
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
// Undo mix 3 and 4
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test chained mixes and clip resize")
{
// Add 3 more color clips
cid5 = -1;
int cid6;
int cid7;
state0();
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 560, cid6));
REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 600, cid7));
REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=40
// Cid7 pos=600, duration=20
auto mix0 = [&]() {
REQUIRE(timeline->getClipsCount() == 9);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
};
auto mix1 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
};
// Mix 4 and 5
REQUIRE(timeline->mixClip(cid4));
mix0();
// Mix 6 and 7
REQUIRE(timeline->mixClip(cid6));
mix1();
// Test resize, should fail
int clipSize = timeline->getClipPlaytime(cid5);
REQUIRE(timeline->requestItemResize(cid5, 38, true, true) == clipSize);
clipSize = timeline->getClipPlaytime(cid6);
REQUIRE(timeline->requestItemResize(cid6, 60, false, true) == clipSize);
// Undo second mix
undoStack->undo();
// Undo first mix
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test grouped mixes and clip resize")
{
// Add 3 more color clips
cid5 = -1;
int cid6;
int cid7;
state0();
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 560, cid6));
REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid4, 520, cid7));
REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=40
// Cid7 pos=520, duration=20 on tid4
auto mix1 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
};
// Mix cid3 & cid4
REQUIRE(timeline->mixClip(cid3));
REQUIRE(timeline->getClipPlaytime(cid4) == 33);
// Group cid4 and cid7
auto g1 = std::unordered_set<int>({cid4, cid7});
REQUIRE(timeline->requestClipsGroup(g1));
// Try to resize the grouped cid7, should not be allowed
REQUIRE(timeline->requestItemResize(cid7, 23, true, true) == -1);
// Mix cid5 & cid6
REQUIRE(timeline->mixClip(cid6));
mix1();
// Try to resize the grouped cid7, should not be allowed
REQUIRE(timeline->requestItemResize(cid7, 23, true, true) == -1);
// Undo second mix
undoStack->undo();
// Undo group
undoStack->undo();
// Undo first mix
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test chained mixes and check mix direction")
{
// Add 3 more color clips
cid5 = -1;
int cid6;
int cid7;
state0();
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 560, cid6));
REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 600, cid7));
REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=40
// Cid7 pos=600, duration=20
auto mix0 = [&]() {
REQUIRE(timeline->getClipsCount() == 9);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
};
auto mix1 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == true);
};
auto mix2 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 3);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid7) == false);
};
auto mix3 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 4);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid4) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid7) == true);
};
// Mix 4 and 5
REQUIRE(timeline->mixClip(cid4));
mix0();
// Mix 5 and 6
REQUIRE(timeline->mixClip(cid5));
mix1();
// Mix 6 and 7
REQUIRE(timeline->mixClip(cid6));
mix2();
// Mix 3 and 4, this will revert all subsequent mixes
REQUIRE(timeline->mixClip(cid3));
mix3();
// Undo mix 3 and 4
undoStack->undo();
mix2();
// Now switch mixes to Slide type
timeline->switchComposition(cid7, QStringLiteral("slide"));
timeline->switchComposition(cid6, QStringLiteral("slide"));
timeline->switchComposition(cid5, QStringLiteral("slide"));
mix2();
// Mix 3 and 4, this will revert all subsequent mixes
REQUIRE(timeline->mixClip(cid3));
mix3();
// Undo mix 3 and 4
undoStack->undo();
mix2();
// Now switch mixes to Wipe type
timeline->switchComposition(cid7, QStringLiteral("wipe"));
timeline->switchComposition(cid6, QStringLiteral("wipe"));
timeline->switchComposition(cid5, QStringLiteral("wipe"));
mix2();
// Mix 3 and 4, this will revert all subsequent mixes
REQUIRE(timeline->mixClip(cid3));
mix3();
// Undo mix 3 and 4
undoStack->undo();
mix2();
// Undo Wipe mix switch on cid5
undoStack->undo();
// Undo mix switch on cid6
undoStack->undo();
// Undo mix switch on cid7
undoStack->undo();
mix2();
// Undo Slide mix switch on cid5
undoStack->undo();
// Undo mix switch on cid6
undoStack->undo();
// Undo mix switch on cid7
undoStack->undo();
mix2();
// Undo mix 6 and 7
undoStack->undo();
mix1();
// Undo mix 5 and 6
undoStack->undo();
mix0();
// Undo mix 4 and 5
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test mixes track move and direction")
{
// Add 3 more av clips
cid5 = -1;
int cid6;
int cid7;
state0();
REQUIRE(timeline->requestClipInsertion(binId, tid2, 540, cid5));
REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
REQUIRE(timeline->requestClipInsertion(binId, tid2, 560, cid6));
REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
REQUIRE(timeline->requestClipInsertion(binId, tid2, 600, cid7));
REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
audio5 = timeline->getClipSplitPartner(cid5);
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=20
// Cid5 pos=540, duration=20
// Cid6 pos=560, duration=40
// Cid7 pos=600, duration=20
auto mix0 = [&]() {
REQUIRE(timeline->getClipsCount() == 12);
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
};
auto mix1 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == true);
};
auto mix2 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 3);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid7) == false);
};
auto mix3 = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 4);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid4) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid5) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid6) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixIsReversed(cid7) == true);
};
auto mix3b = [&]() {
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid7) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixCount() == 4);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixIsReversed(cid4) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixIsReversed(cid5) == true);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixIsReversed(cid6) == false);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid4)->mixIsReversed(cid7) == true);
};
// Mix 4 and 5
REQUIRE(timeline->mixClip(cid4));
mix0();
// Mix 5 and 6
REQUIRE(timeline->mixClip(cid5));
mix1();
// Mix 6 and 7
REQUIRE(timeline->mixClip(cid6));
mix2();
// Mix 3 and 4, this will revert all subsequent mixes
REQUIRE(timeline->mixClip(cid3));
mix3();
// Move everything to another track
auto g1 = std::unordered_set<int>({cid3, cid4, cid5, cid6, cid7});
REQUIRE(timeline->requestClipsGroup(g1));
REQUIRE(timeline->requestClipMove(cid3, tid4, 600));
// Now clips 3, 4, 5, 6 and 7 will be on top video track. Check mixes have the correct direction
mix3b();
// Undo track move
undoStack->undo();
mix3();
// Redo track move
undoStack->redo();
mix3b();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
SECTION("Test chained mixes and cuts")
{
// Add 2 more color clips
cid5 = -1;
int cid6;
state0();
REQUIRE(timeline->requestItemResize(cid4, 80, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 600, cid5));
REQUIRE(timeline->requestItemResize(cid5, 80, true, true));
REQUIRE(timeline->requestClipInsertion(binId2, tid2, 680, cid6));
REQUIRE(timeline->requestItemResize(cid6, 80, true, true));
audio5 = timeline->getClipSplitPartner(cid5);
// Cid3 pos=500, duration=20
// Cid4 pos=520, duration=80
// Cid5 pos=600, duration=80
// Cid6 pos=680, duration=80
// Mix 3 and 4
REQUIRE(timeline->mixClip(cid3));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
// Mix 4 and 5
REQUIRE(timeline->mixClip(cid4));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Mix 5 and 6
REQUIRE(timeline->mixClip(cid5));
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 1);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 3);
// Now try to cut mixes and check they are in the correct subplaylist
// Cut a clip with mix start only
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid3, 505));
// Get newly created cut clip
int clone = timeline->getClipByPosition(tid2, 506, 0);
// Ensure each clip is on the correct playlist
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(clone) == 0);
// Undo cid3 cut
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
undoStack->redo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 1);
undoStack->undo();
// Cut a clip with mix at start and end
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid4, 540));
// Get newly created cut clip
clone = timeline->getClipByPosition(tid2, 540, 1);
// Ensure each clip is on the correct playlist
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(clone) == 1);
// Undo cid3 cut
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->redo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(clone) == 1);
undoStack->undo();
// Cut a clip with mix at end
REQUIRE(TimelineFunctions::requestClipCut(timeline, cid6, 710));
// Get newly created cut clip
clone = timeline->getClipByPosition(tid2, 710, 0);
// Ensure each clip is on the correct playlist
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(clone) == 0);
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
undoStack->redo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(clone) == 0);
undoStack->undo();
// Undo mix 5 and 6
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 2);
// Undo mix 4 and 5
undoStack->undo();
REQUIRE(timeline->getClipSubPlaylistIndex(cid3) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid4) == 1);
REQUIRE(timeline->getClipSubPlaylistIndex(cid5) == 0);
REQUIRE(timeline->getClipSubPlaylistIndex(cid6) == 0);
REQUIRE(KdenliveTests::getTrackById_const(timeline, tid2)->mixCount() == 1);
// Undo mix 3 and 4
undoStack->undo();
// Undo insert/resize ops
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
undoStack->undo();
state0();
}
timeline.reset();
pCore->projectManager()->closeCurrentDocument(false, false);
}