Commit d8c9742a authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Time remap: seek clip and project monitor for better adjustment, mark remaped...

Time remap: seek clip and project monitor for better adjustment, mark remaped timeline clips with a red square
parent 94e27faf
Pipeline #69310 passed with stage
in 9 minutes and 13 seconds
......@@ -306,7 +306,7 @@ void RemapView::mouseMoveEvent(QMouseEvent *event)
if (pos != m_position) {
qDebug()<<"=== CURSOR MOVE MODE!!!";
slotSetPosition(pos);
emit seekToPos(pos);
emit seekToPos(pos, getKeyframePosition());
}
}
return;
......@@ -372,6 +372,11 @@ void RemapView::mouseMoveEvent(QMouseEvent *event)
}
}
int RemapView::position() const
{
return m_position;
}
int RemapView::getClosestKeyframe(int pos, bool bottomKeyframe) const
{
int deltaMin = -1;
......@@ -468,7 +473,7 @@ void RemapView::mousePressEvent(QMouseEvent *event)
m_moveKeyframeMode = TopMove;
if (KdenliveSettings::keyframeseek()) {
slotSetPosition(m_currentKeyframeOriginal.first);
emit seekToPos(m_currentKeyframeOriginal.first);
emit seekToPos(m_currentKeyframeOriginal.first, getKeyframePosition());
} else {
update();
}
......@@ -514,7 +519,7 @@ void RemapView::mousePressEvent(QMouseEvent *event)
m_moveKeyframeMode = BottomMove;
if (KdenliveSettings::keyframeseek()) {
slotSetPosition(m_currentKeyframeOriginal.first);
emit seekToPos(m_currentKeyframeOriginal.first);
emit seekToPos(m_currentKeyframeOriginal.first, getKeyframePosition());
} else {
update();
}
......@@ -531,7 +536,7 @@ void RemapView::mousePressEvent(QMouseEvent *event)
if (pos != m_position) {
m_moveKeyframeMode = CursorMove;
slotSetPosition(pos);
emit seekToPos(pos);
emit seekToPos(pos, getKeyframePosition());
update();
}
}
......@@ -587,7 +592,7 @@ void RemapView::goNext()
if (i.key() > m_position) {
m_currentKeyframe = {i.key(),i.value()};
slotSetPosition(i.key());
emit seekToPos(i.key());
emit seekToPos(i.key(), getKeyframePosition());
std::pair<double,double> speeds = getSpeed(m_currentKeyframe);
emit selectedKf(m_currentKeyframe, speeds);
break;
......@@ -609,7 +614,7 @@ void RemapView::goPrev()
}
m_currentKeyframe = {it.key(), it.value()};
slotSetPosition(m_currentKeyframe.first);
emit seekToPos(m_currentKeyframe.first);
emit seekToPos(m_currentKeyframe.first, getKeyframePosition());
std::pair<double,double> speeds = getSpeed(m_currentKeyframe);
emit selectedKf(m_currentKeyframe, speeds);
previousFound = true;
......@@ -619,7 +624,7 @@ void RemapView::goPrev()
// We are after the last keyframe
m_currentKeyframe = {m_keyframes.lastKey(), m_keyframes.value(m_keyframes.lastKey())};
slotSetPosition(m_currentKeyframe.first);
emit seekToPos(m_currentKeyframe.first);
emit seekToPos(m_currentKeyframe.first, getKeyframePosition());
std::pair<double,double> speeds = getSpeed(m_currentKeyframe);
emit selectedKf(m_currentKeyframe, speeds);
}
......@@ -719,6 +724,41 @@ std::pair<double,double> RemapView::getSpeed(std::pair<int,int>kf)
return speeds;
}
int RemapView::getKeyframePosition() const
{
QMapIterator<int, int> i(m_keyframes);
std::pair<int, int> newKeyframe = {-1,-1};
std::pair<int, int> previous = {-1,-1};
newKeyframe.first = m_position;
while (i.hasNext()) {
i.next();
if (i.key() > m_position) {
if (i.key() == m_keyframes.firstKey()) {
// This is the first keyframe
double ratio = (double)m_position / i.key();
return i.value() * ratio;
break;
} else if (previous.first > -1) {
std::pair<int,int> current = {i.key(), i.value()};
double ratio = (double)(m_position - previous.first) / (current.first - previous.first);
return previous.second + (qAbs(current.second - previous.second) * ratio);
break;
}
}
previous = {i.key(), i.value()};
}
if (newKeyframe.second == -1) {
// We are after the last keyframe
if (m_keyframes.isEmpty()) {
return m_position;
} else {
double ratio = (double)(m_position - m_keyframes.lastKey()) / (m_duration - m_keyframes.lastKey());
return m_keyframes.value(m_keyframes.lastKey()) + (qAbs(m_duration - m_keyframes.value(m_keyframes.lastKey())) * ratio);
}
}
return m_position;
}
void RemapView::addKeyframe()
{
// insert or remove keyframe at interpolated position
......@@ -989,6 +1029,7 @@ void TimeRemap::selectedClip(int cid, int splitId)
}
QObject::disconnect( m_seekConnection1 );
QObject::disconnect( m_seekConnection2 );
QObject::disconnect( m_seekConnection3 );
m_cid = cid;
m_splitId = splitId;
if (cid == -1) {
......@@ -999,9 +1040,11 @@ void TimeRemap::selectedClip(int cid, int splitId)
m_remapLink.reset();
bool keyframesLoaded = false;
std::shared_ptr<TimelineItemModel> model = pCore->window()->getCurrentTimeline()->controller()->getModel();
const QString binId = pCore->getTimelineClipBinId(cid);
int min = pCore->getItemIn({ObjectType::TimelineClip,cid});
m_lastLength = pCore->getItemDuration({ObjectType::TimelineClip,cid});
int max = min + m_lastLength;
pCore->selectBinClip(binId, true, min, {min,max});
m_startPos = pCore->getItemPosition({ObjectType::TimelineClip,cid});
m_in->setRange(min, max);
m_out->setRange(min, max);
......@@ -1042,11 +1085,15 @@ void TimeRemap::selectedClip(int cid, int splitId)
}
}
}
m_seekConnection1 = connect(m_view, &RemapView::seekToPos, [this](int pos) {
pCore->getMonitor(Kdenlive::ProjectMonitor)->requestSeek(pos + m_startPos);
m_seekConnection3 = connect(pCore->getMonitor(Kdenlive::ClipMonitor), &Monitor::seekPosition, [this](int pos) {
m_view->slotSetPosition(pos);
});
m_seekConnection1 = connect(m_view, &RemapView::seekToPos, [this](int pos, int pos2) {
pCore->getMonitor(Kdenlive::ProjectMonitor)->requestSeek(pos2 + m_startPos);
pCore->getMonitor(Kdenlive::ClipMonitor)->requestSeek(pos);
});
m_seekConnection2 = connect(pCore->getMonitor(Kdenlive::ProjectMonitor), &Monitor::seekPosition, [this](int pos) {
m_view->slotSetPosition(pos - m_startPos);
m_view->slotSetPosition(GenTime(m_remapLink->anim_get_double("map", pos)).frames(pCore->getCurrentFps()) - m_startPos);
});
}
......@@ -1054,6 +1101,7 @@ void TimeRemap::setClip(std::shared_ptr<ProjectClip> clip, int in, int out)
{
QObject::disconnect( m_seekConnection1 );
QObject::disconnect( m_seekConnection2 );
QObject::disconnect( m_seekConnection3 );
m_cid = -1;
if (!clip->statusReady() || clip->clipType() != ClipType::Playlist) {
qDebug()<<"===== CLIP NOT READY; TYPE; "<<clip->clipType();
......@@ -1129,7 +1177,6 @@ void TimeRemap::setClip(std::shared_ptr<ProjectClip> clip, int in, int out)
qDebug()<<"=== UNHANDLED TRACK TYPE";
break;
}
break;
}
}
}
......
......@@ -50,6 +50,8 @@ public:
void setDuration(std::shared_ptr<Mlt::Producer> service, int duration);
void loadKeyframes(const QString &mapData);
const QString getKeyframesData() const;
int position() const;
int getKeyframePosition() const;
int remapDuration() const;
QTimer timer;
......@@ -110,7 +112,7 @@ private:
std::pair<double,double> getSpeed(std::pair<int,int>kf);
signals:
void seekToPos(int);
void seekToPos(int, int);
void selectedKf(std::pair<int,int>, std::pair<double,double>);
/** When the cursor position changes inform parent if we are on a keyframe or not. */
void atKeyframe(bool);
......@@ -148,6 +150,7 @@ private:
int m_splitId;
QMetaObject::Connection m_seekConnection1;
QMetaObject::Connection m_seekConnection2;
QMetaObject::Connection m_seekConnection3;
};
......
......@@ -52,6 +52,7 @@ ClipModel::ClipModel(const std::shared_ptr<TimelineModel> &parent, std::shared_p
, m_subPlaylistIndex(0)
, m_mixDuration(0)
, m_mixCutPos(0)
, m_hasTimeRemap(isChain())
{
m_producer->set("kdenlive:id", binClipId.toUtf8().constData());
m_producer->set("_kdenlive_cid", m_id);
......@@ -492,6 +493,13 @@ void ClipModel::refreshProducerFromBin(int trackId, PlaylistState::ClipState sta
std::shared_ptr<Mlt::Producer> binProducer = binClip->getTimelineProducer(trackId, m_id, state, stream, m_speed, secondPlaylist, timeremap);
m_producer = std::move(binProducer);
m_producer->set_in_and_out(in, out);
if (m_hasTimeRemap != isChain()) {
m_hasTimeRemap = !m_hasTimeRemap;
if (auto ptr = m_parent.lock()) {
QModelIndex ix = ptr->makeClipIndexFromID(m_id);
emit ptr->dataChanged(ix, ix, {TimelineModel::TimeRemapRole});
}
}
if (hasPitch) {
// Check if pitch shift is enabled
m_producer->parent().set("warp_pitch", 1);
......
......@@ -270,6 +270,8 @@ protected:
int m_mixDuration;
/** @brief Position of the original cut, relative to mix right side */
int m_mixCutPos;
/** @brief True if the clip has a timeremap effect */
bool m_hasTimeRemap;
};
#endif
......@@ -233,6 +233,7 @@ QHash<int, QByteArray> TimelineItemModel::roleNames() const
roles[FadeOutRole] = "fadeOut";
roles[FileHashRole] = "hash";
roles[SpeedRole] = "speed";
roles[TimeRemapRole] = "timeremap";
roles[HeightRole] = "trackHeight";
roles[TrackTagRole] = "trackTag";
roles[ItemIdRole] = "item";
......@@ -363,6 +364,8 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
return clip->selected;
case TagRole:
return clip->clipTag();
case TimeRemapRole:
return clip->isChain();
default:
break;
}
......
......@@ -160,6 +160,7 @@ public:
SpeedRole, /// clip only
ReloadThumbRole, /// clip only
PositionOffsetRole, /// clip only
TimeRemapRole, /// clip only
ItemATrack, /// composition only
ItemIdRole,
ThumbsFormatRole, /// track only
......
......@@ -41,6 +41,7 @@ Rectangle {
property int clipDuration: 0
property int maxDuration: 0
property bool isAudio: false
property bool timeremap: false
property int audioChannels
property int audioStream: -1
property bool multiStream: false
......@@ -895,6 +896,32 @@ Rectangle {
styleColor: 'black'
}
}
Rectangle{
//proxy
id:remapRect
color: '#cc0033'
width: labelRect.height
height: labelRect.height
x: labelRect.x
anchors.top: labelRect.top
anchors.left: labelRect.right
visible: clipRoot.timeremap
Text {
// Proxy P
id: remapLabel
text: "R"
font.pointSize: root.fontUnit +1
visible: remapRect.visible
anchors {
top: remapRect.top
left: remapRect.left
leftMargin: (labelRect.height-proxyLabel.width)/2
topMargin: (labelRect.height-proxyLabel.height)/2
}
color: 'white'
styleColor: 'white'
}
}
}
KeyframeView {
......
......@@ -231,6 +231,12 @@ Item{
value: model.binId
when: loader.status == Loader.Ready && clipItem
}
Binding {
target: loader.item
property: "timeremap"
value: model.timeremap
when: loader.status == Loader.Ready && clipItem
}
sourceComponent: {
if (clipItem) {
return clipDelegate
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment