Blender V4.5
strip_retiming.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_scene_types.h"
14#include "DNA_sequence_types.h"
15
16#include "BLI_listbase.h"
17#include "BLI_map.hh"
18#include "BLI_math_geom.h"
19#include "BLI_math_vector.h"
21#include "BLI_span.hh"
22#include "BLI_vector.hh"
23
24#include "BKE_sound.h"
25
26#include "SEQ_iterator.hh"
27#include "SEQ_retiming.hh"
28#include "SEQ_sequencer.hh"
29#include "SEQ_time.hh"
30#include "SEQ_transform.hh"
31
32#include "sequencer.hh"
33#include "strip_time.hh"
34
35namespace blender::seq {
36
42
43bool retiming_is_last_key(const Strip *strip, const SeqRetimingKey *key)
44{
45 return retiming_key_index_get(strip, key) == strip->retiming_keys_num - 1;
46}
47
49{
50 return strip->retiming_keys + strip->retiming_keys_num - 1;
51}
52
53int retiming_key_index_get(const Strip *strip, const SeqRetimingKey *key)
54{
55 return key - strip->retiming_keys;
56}
57
58static int content_frame_index_get(const Scene *scene,
59 const Strip *strip,
60 const int timeline_frame)
61{
62 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
63 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
64 return (timeline_frame - time_start_frame_get(strip) - sound_offset) *
66}
67
69 const Strip *strip,
70 const int timeline_frame)
71{
72 for (auto &key : retiming_keys_get(strip)) {
73 const int key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, &key);
74 if (key_timeline_frame == timeline_frame) {
75 return &key;
76 }
77 }
78
79 return nullptr;
80}
81
82SeqRetimingKey *retiming_find_segment_start_key(const Strip *strip, float frame_index)
83{
84 SeqRetimingKey *start_key = nullptr;
85 for (auto &key : retiming_keys_get(strip)) {
86 if (retiming_is_last_key(strip, &key)) {
87 break;
88 }
89 if (key.strip_frame_index > frame_index) {
90 break;
91 }
92
93 start_key = &key;
94 }
95
96 return start_key;
97}
98
99int retiming_keys_count(const Strip *strip)
100{
101 return strip->retiming_keys_num;
102}
103
105{
106 if (!retiming_is_allowed(strip)) {
107 return;
108 }
109
110 if (retiming_is_active(strip)) {
111 return;
112 }
113
115 SeqRetimingKey *key = strip->retiming_keys + 1;
116 key->strip_frame_index = strip->len - 1;
117 key->retiming_factor = 1.0f;
118 strip->retiming_keys_num = 2;
119}
120
122{
123 if (strip->retiming_keys != nullptr) {
124 MEM_freeN(strip->retiming_keys);
125 strip->retiming_keys = nullptr;
126 strip->retiming_keys_num = 0;
127 }
128 strip->flag &= ~SEQ_SHOW_RETIMING;
129}
130
131static void retiming_key_overlap(Scene *scene, Strip *strip)
132{
133 ListBase *seqbase = active_seqbase_get(editing_get(scene));
136 dependant.add(strip);
137 iterator_set_expand(scene, seqbase, dependant, query_strip_effect_chain);
138 strips.add_multiple(dependant);
139 dependant.remove(strip);
140 transform_handle_overlap(scene, seqbase, strips, dependant, true);
141}
142
143void retiming_reset(Scene *scene, Strip *strip)
144{
145 if (!retiming_is_allowed(strip)) {
146 return;
147 }
148
149 retiming_data_clear(strip);
150
154
155 retiming_key_overlap(scene, strip);
156}
157
158bool retiming_is_active(const Strip *strip)
159{
160 return strip->retiming_keys_num > 1;
161}
162
164{
165 return strip->flag & SEQ_SHOW_RETIMING;
166}
167
168bool retiming_is_allowed(const Strip *strip)
169{
170 if (strip->len < 2) {
171 return false;
172 }
173
174 return ELEM(strip->type,
182}
183
185{
186 const SeqRetimingKey *end_key = start_key + 1;
187 return end_key->strip_frame_index - start_key->strip_frame_index;
188}
189
191{
192 const SeqRetimingKey *end_key = start_key + 1;
193 const double segment_length = strip_retiming_segment_length_get(start_key);
194 const double segment_fac_diff = end_key->retiming_factor - start_key->retiming_factor;
195 return segment_fac_diff / segment_length;
196}
197
199 double r_v1[2],
200 double r_v2[2])
201{
202 const SeqRetimingKey *end_key = start_key + 1;
203 r_v1[0] = start_key->strip_frame_index;
204 r_v1[1] = start_key->retiming_factor;
205 r_v2[0] = end_key->strip_frame_index;
206 r_v2[1] = end_key->retiming_factor;
207}
208
210 double r_center[2],
211 double *radius)
212{
213 blender::double2 s1_1, s1_2, s2_1, s2_2, p1_2;
214
215 /* Get 2 segments. */
216 strip_retiming_segment_as_line_segment(start_key - 1, s1_1, s1_2);
217 strip_retiming_segment_as_line_segment(start_key + 1, s2_1, s2_2);
218 /* Backup first segment end point - needed to calculate arc radius. */
219 copy_v2_v2_db(p1_2, s1_2);
220 /* Convert segments to vectors. */
222 sub_v2_v2v2_db(v1, s1_1, s1_2);
223 sub_v2_v2v2_db(v2, s2_1, s2_2);
224 /* Rotate segments by 90 degrees around seg. 1 end and seg. 2 start point. */
225 std::swap(v1[0], v1[1]);
226 std::swap(v2[0], v2[1]);
227 v1[0] *= -1;
228 v2[0] *= -1;
229 copy_v2_v2_db(s1_1, s1_2);
230 s1_2 += v1;
231 copy_v2_v2_db(s2_2, s2_1);
232 s2_2 += v2;
233 /* Get center and radius of arc segment between 2 linear segments. */
234 double lambda, mu;
235 isect_seg_seg_v2_lambda_mu_db(s1_1, s1_2, s2_1, s2_2, &lambda, &mu);
236 r_center[0] = s1_1[0] + lambda * (s1_2[0] - s1_1[0]);
237 r_center[1] = s1_1[1] + lambda * (s1_2[1] - s1_1[1]);
238 *radius = len_v2v2_db(p1_2, r_center);
239}
240
242{
243 return (key->flag & SEQ_SPEED_TRANSITION_IN) != 0 || (key->flag & SEQ_SPEED_TRANSITION_OUT) != 0;
244}
245
247{
248 return (key->flag & SEQ_SPEED_TRANSITION_IN) != 0;
249}
250
252{
253 if (key->flag & SEQ_SPEED_TRANSITION_OUT) {
254 return key - 1;
255 }
256 if (key->flag & SEQ_SPEED_TRANSITION_IN) {
257 return key;
258 }
259 return nullptr;
260}
261
263{
264 return (key->flag & SEQ_FREEZE_FRAME_IN) != 0 || (key->flag & SEQ_FREEZE_FRAME_OUT) != 0;
265}
266
267/* Check colinearity of 2 segments allowing for some imprecision.
268 * `isect_seg_seg_v2_lambda_mu_db()` return value does not work well in this case. */
269
270static bool strip_retiming_transition_is_linear(const Strip *strip, const SeqRetimingKey *key)
271{
272 const float prev_speed = retiming_key_speed_get(strip, key - 1);
273 const float next_speed = retiming_key_speed_get(strip, key + 2);
274
275 return abs(prev_speed - next_speed) < 0.01f;
276}
277
279 const float frame_index)
280{
281 double c[2], r;
283 const int side = c[1] > key->retiming_factor ? -1 : 1;
284 const float y = c[1] + side * sqrt(pow(r, 2) - pow((frame_index - c[0]), 2));
285 return y;
286}
287
288float strip_retiming_evaluate(const Strip *strip, const float frame_index)
289{
290 const SeqRetimingKey *start_key = retiming_find_segment_start_key(strip, frame_index);
291
292 const int start_key_index = start_key - strip->retiming_keys;
293 BLI_assert(start_key_index < strip->retiming_keys_num);
294
295 const float segment_frame_index = frame_index - start_key->strip_frame_index;
296
297 if (!retiming_key_is_transition_start(start_key)) {
298 const float segment_step = strip_retiming_segment_step_get(start_key);
299 return std::min(1.0f, start_key->retiming_factor + float(segment_step * segment_frame_index));
300 }
301
302 if (strip_retiming_transition_is_linear(strip, start_key)) {
303 const float segment_step = strip_retiming_segment_step_get(start_key - 1);
304 return std::min(1.0f, start_key->retiming_factor + float(segment_step * segment_frame_index));
305 }
306
307 /* Sanity check for transition type. */
308 BLI_assert(start_key_index > 0);
309 BLI_assert(start_key_index < strip->retiming_keys_num - 1);
310 UNUSED_VARS_NDEBUG(start_key_index);
311
312 return std::min(1.0f, strip_retiming_evaluate_arc_segment(start_key, frame_index));
313}
314
315static SeqRetimingKey *strip_retiming_add_key(Strip *strip, float frame_index)
316{
317 if (!retiming_is_allowed(strip)) {
318 return nullptr;
319 }
320 /* Clamp timeline frame to strip content range. */
321 if (frame_index <= 0) {
322 return &strip->retiming_keys[0];
323 }
324 if (frame_index >= retiming_last_key_get(strip)->strip_frame_index) {
325 return retiming_last_key_get(strip); /* This is expected for strips with no offsets. */
326 }
327
328 SeqRetimingKey *start_key = retiming_find_segment_start_key(strip, frame_index);
329
330 if (start_key->strip_frame_index == frame_index) {
331 return start_key; /* Retiming key already exists. */
332 }
333
334 if ((start_key->flag & SEQ_SPEED_TRANSITION_IN) != 0 ||
335 (start_key->flag & SEQ_FREEZE_FRAME_IN) != 0)
336 {
337 return nullptr;
338 }
339
340 float value = strip_retiming_evaluate(strip, frame_index);
341
342 SeqRetimingKey *keys = strip->retiming_keys;
343 const int keys_count = retiming_keys_count(strip);
344 const int new_key_index = start_key - keys + 1;
345 BLI_assert(new_key_index >= 0);
346 BLI_assert(new_key_index < keys_count);
347
348 SeqRetimingKey *new_keys = MEM_calloc_arrayN<SeqRetimingKey>(keys_count + 1, __func__);
349 if (new_key_index > 0) {
350 memcpy(new_keys, keys, new_key_index * sizeof(SeqRetimingKey));
351 }
352 if (new_key_index < keys_count) {
353 memcpy(new_keys + new_key_index + 1,
354 keys + new_key_index,
355 (keys_count - new_key_index) * sizeof(SeqRetimingKey));
356 }
357 MEM_freeN(keys);
358 strip->retiming_keys = new_keys;
359 strip->retiming_keys_num++;
360
361 SeqRetimingKey *added_key = (new_keys + new_key_index);
362 added_key->strip_frame_index = frame_index;
363 added_key->retiming_factor = value;
364
365 return added_key;
366}
367
368SeqRetimingKey *retiming_add_key(const Scene *scene, Strip *strip, const int timeline_frame)
369{
370 return strip_retiming_add_key(strip, content_frame_index_get(scene, strip, timeline_frame));
371}
372
374 const Strip *strip,
375 SeqRetimingKey *key,
376 const int timeline_frame)
377{
379 SeqRetimingKey *key_end = key_start + 1;
380 const float start_frame_index = key_start->strip_frame_index;
381 const float midpoint = key_start->original_strip_frame_index;
382 const float new_frame_index = content_frame_index_get(scene, strip, timeline_frame);
383 float new_midpoint_offset = new_frame_index - midpoint;
384 const float prev_segment_step = strip_retiming_segment_step_get(key_start - 1);
385 const float next_segment_step = strip_retiming_segment_step_get(key_end);
386
387 /* Prevent keys crossing eachother. */
388 SeqRetimingKey *prev_segment_end = key_start - 1, *next_segment_start = key_end + 1;
389 const float offset_max_left = midpoint - prev_segment_end->strip_frame_index - 1;
390 const float offset_max_right = next_segment_start->strip_frame_index - midpoint - 1;
391 new_midpoint_offset = fabs(new_midpoint_offset);
392 new_midpoint_offset = min_fff(new_midpoint_offset, offset_max_left, offset_max_right);
393 new_midpoint_offset = max_ff(new_midpoint_offset, 1);
394
395 key_start->strip_frame_index = midpoint - new_midpoint_offset;
396 key_end->strip_frame_index = midpoint + new_midpoint_offset;
397
398 const float offset = key_start->strip_frame_index - start_frame_index;
399 key_start->retiming_factor += offset * prev_segment_step;
400 key_end->retiming_factor -= offset * next_segment_step;
401}
402
404{
405 if ((key->flag & SEQ_FREEZE_FRAME_IN) != 0) {
406 SeqRetimingKey *next_key = key + 1;
408 next_key->flag &= ~SEQ_FREEZE_FRAME_OUT;
409 }
410 if ((key->flag & SEQ_FREEZE_FRAME_OUT) != 0) {
411 SeqRetimingKey *previous_key = key - 1;
413 previous_key->flag &= ~SEQ_FREEZE_FRAME_IN;
414 }
415}
416
418{
419 /* Transitions need special treatment, so separate these from `keys_to_remove`. */
421
422 /* Cleanup freeze frames and extract transition keys. */
423 for (SeqRetimingKey *key : keys_to_remove) {
426 }
427 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
428 transitions.append_non_duplicates(key);
429 transitions.append_non_duplicates(key + 1);
430 }
431 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
432 transitions.append_non_duplicates(key);
433 transitions.append_non_duplicates(key - 1);
434 }
435 }
436
437 /* Sanitize keys to be removed. */
438 keys_to_remove.remove_if([&](const SeqRetimingKey *key) {
439 return key->strip_frame_index == 0 || retiming_is_last_key(strip, key) ||
441 });
442
443 const size_t keys_count = retiming_keys_count(strip);
444 size_t new_keys_count = keys_count - keys_to_remove.size() - transitions.size() / 2;
445 SeqRetimingKey *new_keys = MEM_calloc_arrayN<SeqRetimingKey>(new_keys_count, __func__);
446 int keys_copied = 0;
447
448 /* Copy keys to new array. */
449 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
450 /* Create key that was used to make transition in new array. */
451 if (transitions.contains(&key) && retiming_key_is_transition_start(&key)) {
452 SeqRetimingKey *new_key = new_keys + keys_copied;
455 keys_copied++;
456 continue;
457 }
458 if (keys_to_remove.contains(&key) || transitions.contains(&key)) {
459 continue;
460 }
461 memcpy(new_keys + keys_copied, &key, sizeof(SeqRetimingKey));
462 keys_copied++;
463 }
464
465 MEM_freeN(strip->retiming_keys);
466 strip->retiming_keys = new_keys;
467 strip->retiming_keys_num = new_keys_count;
468}
469
471{
472 if (key->strip_frame_index == 0 || retiming_is_last_key(strip, key)) {
473 return; /* First and last key can not be removed. */
474 }
475
478 }
479
480 size_t keys_count = retiming_keys_count(strip);
481 SeqRetimingKey *keys = MEM_calloc_arrayN<SeqRetimingKey>(keys_count - 1, __func__);
482
483 const int key_index = key - strip->retiming_keys;
484 memcpy(keys, strip->retiming_keys, (key_index) * sizeof(SeqRetimingKey));
485 memcpy(keys + key_index,
486 strip->retiming_keys + key_index + 1,
487 (keys_count - key_index - 1) * sizeof(SeqRetimingKey));
488 MEM_freeN(strip->retiming_keys);
489 strip->retiming_keys = keys;
490 strip->retiming_keys_num--;
491}
492
493/* This function removes transition segment and creates retiming key where it originally was. */
495{
496 SeqRetimingKey *transition_start = key;
497 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
498 transition_start = key - 1;
499 }
500
501 const float orig_frame_index = transition_start->original_strip_frame_index;
502 const float orig_retiming_factor = transition_start->original_retiming_factor;
503
504 /* Remove both keys defining transition. */
505 int key_index = retiming_key_index_get(strip, transition_start);
506 strip_retiming_remove_key_ex(strip, transition_start);
507 strip_retiming_remove_key_ex(strip, strip->retiming_keys + key_index);
508
509 /* Create original linear key. */
510 SeqRetimingKey *orig_key = strip_retiming_add_key(strip, orig_frame_index);
511 orig_key->retiming_factor = orig_retiming_factor;
512 return orig_key;
513}
514
516{
517
520 return;
521 }
522
524}
525
527 const Strip *strip,
528 SeqRetimingKey *key,
529 int offset)
530{
531 SeqRetimingKey *prev_key = key - 1;
532 SeqRetimingKey *next_key = key + 1;
533 const int prev_dist = retiming_key_timeline_frame_get(scene, strip, prev_key) -
534 retiming_key_timeline_frame_get(scene, strip, key);
535 const int next_dist = retiming_key_timeline_frame_get(scene, strip, next_key) -
536 retiming_key_timeline_frame_get(scene, strip, key);
537 return std::clamp(offset, prev_dist + 1, next_dist - 1);
538}
539
541 Strip *strip,
542 SeqRetimingKey *key,
543 const int offset)
544{
545 /* First offset old key, then add new key to original place with same fac
546 * This is not great way to do things, but it's done in order to be able to freeze last key. */
548 return nullptr;
549 }
550
551 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
552 const int clamped_offset = strip_retiming_clamp_create_offset(
553 scene, strip, key, offset * time_media_playback_rate_factor_get(strip, scene_fps));
554
555 const int orig_timeline_frame = retiming_key_timeline_frame_get(scene, strip, key);
556 const float orig_retiming_factor = key->retiming_factor;
557 key->strip_frame_index += clamped_offset;
559
560 SeqRetimingKey *new_key = retiming_add_key(scene, strip, orig_timeline_frame);
561
562 if (new_key == nullptr) {
563 key->strip_frame_index -= clamped_offset;
565 return nullptr;
566 }
567
568 new_key->retiming_factor = orig_retiming_factor;
569 new_key->flag |= SEQ_FREEZE_FRAME_IN;
570
571 /* Tag previous key as freeze frame key. This is only a convenient way to prevent creating
572 * speed transitions. When freeze frame is deleted, this flag should be cleared. */
573 return new_key + 1;
574}
575
577 Strip *strip,
578 SeqRetimingKey *key,
579 float offset)
580{
581 BLI_assert(!retiming_is_last_key(strip, key));
582 BLI_assert(key->strip_frame_index != 0);
583
584 SeqRetimingKey *prev_key = key - 1;
585 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0 ||
586 (prev_key->flag & SEQ_SPEED_TRANSITION_IN) != 0)
587 {
588 return nullptr;
589 }
590
591 if ((key->flag & SEQ_FREEZE_FRAME_IN) != 0 || (prev_key->flag & SEQ_FREEZE_FRAME_IN) != 0) {
592 return nullptr;
593 }
594
595 float clamped_offset = strip_retiming_clamp_create_offset(scene, strip, key, offset);
596
597 const int orig_key_index = retiming_key_index_get(strip, key);
598 const float orig_frame_index = key->strip_frame_index;
599 const float orig_retiming_factor = key->retiming_factor;
600
601 SeqRetimingKey *transition_out = strip_retiming_add_key(strip,
602 orig_frame_index + clamped_offset);
603 transition_out->flag |= SEQ_SPEED_TRANSITION_OUT;
604
605 SeqRetimingKey *transition_in = strip_retiming_add_key(strip, orig_frame_index - clamped_offset);
606 transition_in->flag |= SEQ_SPEED_TRANSITION_IN;
607 transition_in->original_strip_frame_index = orig_frame_index;
608 transition_in->original_retiming_factor = orig_retiming_factor;
609
610 strip_retiming_remove_key_ex(strip, strip->retiming_keys + orig_key_index + 1);
611 return strip->retiming_keys + orig_key_index + 1;
612}
613
615 const Strip *strip,
616 SeqRetimingKey *start_key,
617 float offset)
618{
619 SeqRetimingKey *end_key = start_key + 1;
620 SeqRetimingKey *prev_key = start_key - 1;
621 SeqRetimingKey *next_key = start_key + 2;
622 const float prev_max_offset = prev_key->strip_frame_index - start_key->strip_frame_index;
623 const float next_max_offset = next_key->strip_frame_index - end_key->strip_frame_index;
624 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
625 const float min_step = time_media_playback_rate_factor_get(strip, scene_fps);
626
627 return std::clamp(offset, prev_max_offset + min_step, next_max_offset - min_step);
628}
629
631 Strip *strip,
632 SeqRetimingKey *key,
633 const float offset)
634{
635 float clamped_offset = strip_retiming_clamp_transition_offset(scene, strip, key, offset);
636 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
637 const float duration = (key->original_strip_frame_index - key->strip_frame_index) /
638 time_media_playback_rate_factor_get(strip, scene_fps);
639 const bool was_selected = retiming_selection_contains(editing_get(scene), key);
640
641 SeqRetimingKey *original_key = strip_retiming_remove_transition(strip, key);
642 original_key->strip_frame_index += clamped_offset;
643
644 SeqRetimingKey *transition_out = retiming_add_transition(scene, strip, original_key, duration);
645
646 if (was_selected) {
647 retiming_selection_append(transition_out);
648 retiming_selection_append(transition_out - 1);
649 }
650}
651
653 Strip *strip,
654 SeqRetimingKey *key,
655 const int timeline_frame)
656{
657 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
658 return timeline_frame;
659 }
660
661 int prev_key_timeline_frame = -MAXFRAME;
662 int next_key_timeline_frame = MAXFRAME;
663
664 if (key->strip_frame_index > 0) {
665 SeqRetimingKey *prev_key = key - 1;
666 prev_key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, prev_key);
667 }
668
669 if (!retiming_is_last_key(strip, key)) {
670 SeqRetimingKey *next_key = key + 1;
671 next_key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, next_key);
672 }
673
674 return std::clamp(timeline_frame, prev_key_timeline_frame + 1, next_key_timeline_frame - 1);
675}
676
677/* Remove and re-create transition. This way transition won't change length.
678 * Alternative solution is to find where in arc segment the `y` value is closest to key
679 * retiming factor, then trim transition to that point. This would change transition length. */
680
681static void strip_retiming_fix_transition(const Scene *scene, Strip *strip, SeqRetimingKey *key)
682{
683 const int keys_num = strip->retiming_keys_num;
684 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
685 const float transition_duration = (key->original_strip_frame_index - key->strip_frame_index) /
686 time_media_playback_rate_factor_get(strip, scene_fps);
687 SeqRetimingKey *orig_key = strip_retiming_remove_transition(strip, key);
688 retiming_add_transition(scene, strip, orig_key, transition_duration);
689 BLI_assert(keys_num == strip->retiming_keys_num);
690 UNUSED_VARS_NDEBUG(keys_num);
691}
692
693static void strip_retiming_fix_transitions(const Scene *scene, Strip *strip, SeqRetimingKey *key)
694{
695 /* Store value, since handles array will be reallocated. */
696 const int key_index = retiming_key_index_get(strip, key);
697
698 if (key_index > 1) {
699 SeqRetimingKey *prev_key = key - 2;
700 if (retiming_key_is_transition_start(prev_key)) {
701 strip_retiming_fix_transition(scene, strip, prev_key);
702 }
703 }
704
705 if (!retiming_is_last_key(strip, key)) {
706 SeqRetimingKey *next_key = &retiming_keys_get(strip)[key_index + 1];
707 if (retiming_key_is_transition_start(next_key)) {
708 strip_retiming_fix_transition(scene, strip, next_key);
709 }
710 }
711}
712
713static void strip_retiming_key_offset(const Scene *scene,
714 Strip *strip,
715 SeqRetimingKey *key,
716 const float offset)
717{
718 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
719 strip_retiming_transition_offset(scene, strip, key, offset);
720 }
721 else {
722 key->strip_frame_index += offset;
723 strip_retiming_fix_transitions(scene, strip, key);
724 }
725}
726
728 const Strip *strip,
729 const SeqRetimingKey *key)
730{
731 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
732 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
733 return round_fl_to_int(time_start_frame_get(strip) + sound_offset +
734 key->strip_frame_index /
735 time_media_playback_rate_factor_get(strip, scene_fps));
736}
737
739 Strip *strip,
740 SeqRetimingKey *key,
741 const int timeline_frame)
742{
743 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
744 return;
745 }
746
747 const int orig_timeline_frame = retiming_key_timeline_frame_get(scene, strip, key);
748 const int clamped_timeline_frame = strip_retiming_clamp_timeline_frame(
749 scene, strip, key, timeline_frame);
750 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
751 const float offset = (clamped_timeline_frame - orig_timeline_frame) *
752 time_media_playback_rate_factor_get(strip, scene_fps);
753
754 const int key_count = retiming_keys_get(strip).size();
755 const int key_index = retiming_key_index_get(strip, key);
756
757 if (orig_timeline_frame == time_right_handle_frame_get(scene, strip)) {
758 for (int i = key_index; i < key_count; i++) {
759 SeqRetimingKey *key_iter = &retiming_keys_get(strip)[i];
760 strip_retiming_key_offset(scene, strip, key_iter, offset);
761 }
762 }
763 else if (orig_timeline_frame == time_left_handle_frame_get(scene, strip) ||
764 key->strip_frame_index == 0)
765 {
766 strip->start += clamped_timeline_frame - orig_timeline_frame;
767 for (int i = key_index + 1; i < key_count; i++) {
768 SeqRetimingKey *key_iter = &retiming_keys_get(strip)[i];
769 strip_retiming_key_offset(scene, strip, key_iter, -offset);
770 }
771 }
772 else {
773 strip_retiming_key_offset(scene, strip, key, offset);
774 }
775
779}
780
781float retiming_key_speed_get(const Strip *strip, const SeqRetimingKey *key)
782{
783 if (key->strip_frame_index == 0) {
784 return 1.0f;
785 }
786
787 const SeqRetimingKey *key_prev = key - 1;
788 const int frame_index_max = strip->len - 1;
789 const float frame_index_start = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
790 const float frame_index_end = round_fl_to_int(key->retiming_factor * frame_index_max);
791 const float segment_content_frame_count = frame_index_end - frame_index_start;
792 const float segment_length = key->strip_frame_index - key_prev->strip_frame_index;
793 const float speed = segment_content_frame_count / segment_length;
794 return speed;
795}
796
798 const Scene *scene, Strip *strip, SeqRetimingKey *key, const float speed, bool keep_retiming)
799{
800 if (key->strip_frame_index == 0) {
801 return;
802 }
803
804 const SeqRetimingKey *key_prev = key - 1;
805
806 const int frame_index_max = strip->len - 1;
807 const float frame_index_prev = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
808 const float frame_index = round_fl_to_int(key->retiming_factor * frame_index_max);
809
810 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
811 const float segment_timeline_duration = (frame_index - frame_index_prev) /
812 time_media_playback_rate_factor_get(strip, scene_fps);
813 const float new_timeline_duration = segment_timeline_duration / speed;
814
815 const float orig_timeline_frame = retiming_key_timeline_frame_get(scene, strip, key);
816 const float new_timeline_frame = std::round(
817 retiming_key_timeline_frame_get(scene, strip, key_prev) + new_timeline_duration);
818
819 retiming_key_timeline_frame_set(scene, strip, key, new_timeline_frame);
820
821 if (keep_retiming) {
822 const int key_index = retiming_key_index_get(strip, key);
823 const int offset = new_timeline_frame - orig_timeline_frame;
824 for (int i = key_index + 1; i < retiming_keys_count(strip); i++) {
825 SeqRetimingKey *key_iter = &retiming_keys_get(strip)[i];
826 strip_retiming_key_offset(scene, strip, key_iter, offset);
827 }
828 }
829}
830
834};
835
843
845 public:
846 int start, end;
847 float speed;
849
851 RetimingRange(const Strip *strip, int start_frame, int end_frame, float speed, eRangeType type)
852 : start(start_frame), end(end_frame), speed(speed), type(type)
853 {
854 if (type == TRANSITION) {
855 this->speed = 1.0f;
857 }
858 }
859
860 RetimingRange(int start_frame, int end_frame, float speed, eRangeType type)
861 : start(start_frame), end(end_frame), speed(speed), type(type)
862 {
863 }
864
866 {
868 for (int i = 0; i < speed_table.size(); i++) {
869 new_range.speed_table.append(speed_table[i]);
870 }
871 return new_range;
872 }
873
874 /* Create new range representing overlap of 2 ranges.
875 * Returns overlapping range. */
877 {
878 RetimingRange new_range = RetimingRange(0, 0, 0, LINEAR);
879
880 /* Offsets to merge speed tables. */
881 int range_offset = 0, rhs_range_offset = 0;
882 if (intersect_type(rhs_range) == FULL) {
883 new_range.start = start;
884 new_range.end = end;
885 rhs_range_offset = start - rhs_range.start;
886 }
887 else if (intersect_type(rhs_range) == PARTIAL_START) {
888 new_range.start = start;
889 new_range.end = rhs_range.end;
890 rhs_range_offset = start - rhs_range.start;
891 }
892 else if (intersect_type(rhs_range) == PARTIAL_END) {
893 new_range.start = rhs_range.start;
894 new_range.end = end;
895 range_offset = rhs_range.start - start;
896 }
897 else if (intersect_type(rhs_range) == INSIDE) {
898 new_range.start = rhs_range.start;
899 new_range.end = rhs_range.end;
900 range_offset = rhs_range.start - start;
901 }
902
903 if (type != TRANSITION && rhs_range.type != TRANSITION) {
904 new_range.speed = speed * rhs_range.speed;
905 return new_range;
906 }
907
908 /* One of ranges is transition type, so speed tables has to be copied. */
909 new_range.type = TRANSITION;
910 new_range.speed = 1.0f;
911 const int new_range_len = new_range.end - new_range.start;
912
913 if (type == TRANSITION && rhs_range.type == TRANSITION) {
914 for (int i = 0; i < new_range_len; i++) {
915 const float range_speed = speed_table[i + range_offset];
916 const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
917 new_range.speed_table.append(range_speed * rhs_range_speed);
918 }
919 }
920 else if (type == TRANSITION) {
921 for (int i = 0; i < new_range_len; i++) {
922 const float range_speed = speed_table[i + range_offset];
923 new_range.speed_table.append(range_speed * rhs_range.speed);
924 }
925 }
926 else if (rhs_range.type == TRANSITION) {
927 for (int i = 0; i < new_range_len; i++) {
928 const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
929 new_range.speed_table.append(speed * rhs_range_speed);
930 }
931 }
932
933 return new_range;
934 }
935
937 {
938 for (int timeline_frame = start; timeline_frame <= end; timeline_frame++) {
939 /* We need number actual number of frames here. */
940 const double normal_step = 1 / double(strip->len - 1);
941
942 const int frame_index = timeline_frame - time_start_frame_get(strip);
943 /* Who needs calculus, when you can have slow code? */
944 const double val_prev = strip_retiming_evaluate(strip, frame_index - 1);
945 const double val = strip_retiming_evaluate(strip, frame_index);
946 const double speed_at_frame = (val - val_prev) / normal_step;
947 speed_table.append(speed_at_frame);
948 }
949 }
950
952 {
953 if (other.start <= start && other.end >= end) {
954 return FULL;
955 }
956 if (other.start > start && other.start < end && other.end > start && other.end < end) {
957 return INSIDE;
958 }
959 if (other.start > start && other.start < end) {
960 return PARTIAL_END;
961 }
962 if (other.end > start && other.end < end) {
963 return PARTIAL_START;
964 }
965 return NONE;
966 }
967};
968
970 public:
973 {
974 for (const SeqRetimingKey &key : retiming_keys_get(strip)) {
975 if (key.strip_frame_index == 0) {
976 continue;
977 }
978 const SeqRetimingKey *key_prev = &key - 1;
979 float speed = retiming_key_speed_get(strip, &key);
980 int frame_start = time_start_frame_get(strip) + key_prev->strip_frame_index;
981 int frame_end = time_start_frame_get(strip) + key.strip_frame_index;
982
984 RetimingRange range = RetimingRange(strip, frame_start, frame_end, speed, type);
985 ranges.append(range);
986 }
987 }
988
990 {
991 if (ranges.is_empty()) {
992 for (const RetimingRange &rhs_range : rhs.ranges) {
994 rhs_range.start, rhs_range.end, rhs_range.speed, rhs_range.type);
995 ranges.append(range);
996 }
997 return *this;
998 }
999
1000 for (int i = 0; i < ranges.size(); i++) {
1001 RetimingRange &range = ranges[i];
1002 for (const RetimingRange &rhs_range : rhs.ranges) {
1003 if (range.intersect_type(rhs_range) == NONE) {
1004 continue;
1005 }
1006 if (range.intersect_type(rhs_range) == FULL) {
1007 RetimingRange isect = range * rhs_range;
1008 ranges.remove(i);
1009 ranges.insert(i, isect);
1010 }
1011 if (range.intersect_type(rhs_range) == PARTIAL_START) {
1012 ranges.insert(i, range * rhs_range);
1013 ranges.insert(i, range * rhs_range);
1014 range.start = rhs_range.end + 1;
1015 }
1016 else if (range.intersect_type(rhs_range) == PARTIAL_END) {
1017 ranges.insert(i, range * rhs_range);
1018 range.end = rhs_range.start;
1019 }
1020 else if (range.intersect_type(rhs_range) == INSIDE) {
1021 RetimingRange left_range = range.duplicate();
1022 left_range.end = rhs_range.start;
1023 range.start = rhs_range.end + 1;
1024
1025 ranges.insert(i, left_range);
1026 ranges.insert(i, range * rhs_range);
1027 }
1028 }
1029 }
1030 return *this;
1031 }
1032};
1033
1035{
1036 RetimingRangeData strip_retiming_data = RetimingRangeData(strip);
1037
1038 const Strip *meta_parent = lookup_meta_by_strip(scene->ed, strip);
1039 if (meta_parent == nullptr) {
1040 return strip_retiming_data;
1041 }
1042
1043 RetimingRangeData meta_retiming_data = RetimingRangeData(meta_parent);
1044 strip_retiming_data *= meta_retiming_data;
1045 return strip_retiming_data;
1046}
1047
1048void retiming_sound_animation_data_set(const Scene *scene, const Strip *strip)
1049{
1050 /* Content cut off by `anim_startofs` is as if it does not exist for sequencer. But Audaspace
1051 * seeking relies on having animation buffer initialized for whole sequence. */
1052 if (strip->anim_startofs > 0) {
1053 const int strip_start = time_start_frame_get(strip);
1055 strip->scene_sound, strip_start - strip->anim_startofs, strip_start, 1.0f);
1056 }
1057
1058 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
1059 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
1060
1061 RetimingRangeData retiming_data = strip_retiming_range_data_get(scene, strip);
1062 for (int i = 0; i < retiming_data.ranges.size(); i++) {
1063 RetimingRange range = retiming_data.ranges[i];
1064 if (range.type == TRANSITION) {
1065
1066 const int range_length = range.end - range.start;
1067 for (int i = 0; i <= range_length; i++) {
1068 const int frame = range.start + i;
1070 strip->scene_sound, frame + sound_offset, range.speed_table[i], true);
1071 }
1072 }
1073 else {
1075 strip->scene_sound, range.start + sound_offset, range.end + sound_offset, range.speed);
1076 }
1077 }
1078}
1079
1081{
1082 bool was_empty = true;
1083
1084 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1085 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
1086 was_empty &= (key.flag & SEQ_KEY_SELECTED) == 0;
1087 key.flag &= ~SEQ_KEY_SELECTED;
1088 }
1089 }
1090 return !was_empty;
1091}
1092
1094
1095 SeqRetimingKey *key)
1096{
1097 key->flag |= SEQ_KEY_SELECTED;
1098}
1099
1104
1106{
1108 dst->flag |= (src->flag & SEQ_KEY_SELECTED);
1109}
1110
1112{
1114 if (!ed) {
1115 return selection;
1116 }
1117 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1118 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
1119 if ((key.flag & SEQ_KEY_SELECTED) != 0) {
1120 selection.add(&key, strip);
1121 }
1122 }
1123 }
1124 return selection;
1125}
1126
1128{
1129 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1130 for (const SeqRetimingKey &key_iter : retiming_keys_get(strip)) {
1131 if ((key_iter.flag & SEQ_KEY_SELECTED) != 0 && &key_iter == key) {
1132 return true;
1133 }
1134 }
1135 }
1136 return false;
1137}
1138
1140{
1142 SeqRetimingKey *key_end = key_start + 1;
1143 bool has_start = false, has_end = false;
1144
1146
1147 for (auto item : selection.items()) {
1148 if (item.key == key_start) {
1149 has_start = true;
1150 }
1151 if (item.key == key_end) {
1152 has_end = true;
1153 }
1154 if (has_start && has_end) {
1155 return true;
1156 }
1157 }
1158 return false;
1159}
1160
1161} // namespace blender::seq
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle, int frame_start, int frame_end, float pitch)
void BKE_sound_set_scene_sound_pitch_at_frame(void *handle, int frame, float pitch, char animated)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE float min_fff(float a, float b, float c)
int isect_seg_seg_v2_lambda_mu_db(const double v1[2], const double v2[2], const double v3[2], const double v4[2], double *r_lambda, double *r_mu)
MINLINE void copy_v2_v2_db(double r[2], const double a[2])
MINLINE double len_v2v2_db(const double v1[2], const double v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2v2_db(double r[2], const double a[2], const double b[2])
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define MAXFRAME
@ SEQ_KEY_SELECTED
@ SEQ_SPEED_TRANSITION_OUT
@ SEQ_FREEZE_FRAME_OUT
@ SEQ_SPEED_TRANSITION_IN
@ SEQ_FREEZE_FRAME_IN
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_META
@ STRIP_TYPE_MASK
@ SEQ_SHOW_RETIMING
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
void append(const T &value)
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
ItemIterator items() const &
Definition BLI_map.hh:902
bool remove(const Key &key)
bool add(const Key &key)
void add_multiple(Span< Key > keys)
int64_t size() const
int64_t remove_if(Predicate &&predicate)
bool contains(const T &value) const
void append_non_duplicates(const T &value)
RetimingRangeData & operator*=(const RetimingRangeData &rhs)
RetimingRangeData(const Strip *strip)
blender::Vector< RetimingRange > ranges
RetimingRange(int start_frame, int end_frame, float speed, eRangeType type)
eIntersectType intersect_type(const RetimingRange &other) const
RetimingRange(const Strip *strip, int start_frame, int end_frame, float speed, eRangeType type)
RetimingRange operator*(const RetimingRange &rhs_range)
blender::Vector< float > speed_table
void claculate_speed_table_from_seq(const Strip *strip)
#define pow
#define abs
#define sqrt
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 fabs(const float2 a)
int retiming_key_index_get(const Strip *strip, const SeqRetimingKey *key)
static float strip_retiming_clamp_create_offset(const Scene *scene, const Strip *strip, SeqRetimingKey *key, int offset)
Strip * lookup_meta_by_strip(Editing *ed, const Strip *key)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
static bool strip_retiming_transition_is_linear(const Strip *strip, const SeqRetimingKey *key)
SeqRetimingKey * retiming_add_transition(const Scene *scene, Strip *strip, SeqRetimingKey *key, float offset)
void retiming_key_speed_set(const Scene *scene, Strip *strip, SeqRetimingKey *key, const float speed, bool keep_retiming)
static SeqRetimingKey * strip_retiming_add_key(Strip *strip, float frame_index)
bool retiming_key_is_transition_start(const SeqRetimingKey *key)
bool retiming_selection_has_whole_transition(const Editing *ed, SeqRetimingKey *key)
static double strip_retiming_segment_length_get(const SeqRetimingKey *start_key)
void retiming_key_timeline_frame_set(const Scene *scene, Strip *strip, SeqRetimingKey *key, const int timeline_frame)
void retiming_reset(Scene *scene, Strip *strip)
bool retiming_selection_contains(const Editing *ed, const SeqRetimingKey *key)
int retiming_keys_count(const Strip *strip)
blender::Map< SeqRetimingKey *, Strip * > retiming_selection_get(const Editing *ed)
float time_media_playback_rate_factor_get(const Strip *strip, const float scene_fps)
Definition strip_time.cc:41
SeqRetimingKey * retiming_add_freeze_frame(const Scene *scene, Strip *strip, SeqRetimingKey *key, const int offset)
int retiming_key_timeline_frame_get(const Scene *scene, const Strip *strip, const SeqRetimingKey *key)
static void strip_retiming_key_offset(const Scene *scene, Strip *strip, SeqRetimingKey *key, const float offset)
static void strip_retiming_line_segments_tangent_circle(const SeqRetimingKey *start_key, double r_center[2], double *radius)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
blender::Span< Strip * > SEQ_lookup_effects_by_strip(Editing *ed, const Strip *key)
void retiming_remove_multiple_keys(Strip *strip, blender::Vector< SeqRetimingKey * > &keys_to_remove)
MutableSpan< SeqRetimingKey > retiming_keys_get(const Strip *strip)
SeqRetimingKey * retiming_transition_start_get(SeqRetimingKey *key)
void retiming_data_ensure(Strip *strip)
void retiming_remove_key(Strip *strip, SeqRetimingKey *key)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
static SeqRetimingKey * strip_retiming_remove_transition(Strip *strip, SeqRetimingKey *key)
SeqRetimingKey * retiming_find_segment_start_key(const Strip *strip, float frame_index)
int time_get_rounded_sound_offset(const Strip *strip, const float frames_per_second)
void retiming_selection_remove(SeqRetimingKey *key)
void retiming_data_clear(Strip *strip)
float time_start_frame_get(const Strip *strip)
void query_strip_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:231
void strip_time_update_effects_strip_range(const Scene *scene, const blender::Span< Strip * > effects)
SeqRetimingKey * retiming_key_get_by_timeline_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
bool retiming_is_active(const Strip *strip)
bool retiming_key_is_transition_type(const SeqRetimingKey *key)
void time_update_meta_strip_range(const Scene *scene, Strip *strip_meta)
bool retiming_key_is_freeze_frame(const SeqRetimingKey *key)
static void strip_retiming_remove_key_ex(Strip *strip, SeqRetimingKey *key)
bool retiming_data_is_editable(const Strip *strip)
void iterator_set_expand(const Scene *scene, ListBase *seqbase, VectorSet< Strip * > &strips, void strip_query_func(const Scene *scene, Strip *strip_reference, ListBase *seqbase, VectorSet< Strip * > &strips))
Definition iterator.cc:82
void retiming_selection_copy(SeqRetimingKey *dst, const SeqRetimingKey *src)
static void strip_retiming_transition_offset(const Scene *scene, Strip *strip, SeqRetimingKey *key, const float offset)
static void retiming_key_overlap(Scene *scene, Strip *strip)
void retiming_sound_animation_data_set(const Scene *scene, const Strip *strip)
bool retiming_selection_clear(const Editing *ed)
float retiming_key_speed_get(const Strip *strip, const SeqRetimingKey *key)
static float strip_retiming_evaluate_arc_segment(const SeqRetimingKey *key, const float frame_index)
static float strip_retiming_clamp_transition_offset(const Scene *scene, const Strip *strip, SeqRetimingKey *start_key, float offset)
bool retiming_is_allowed(const Strip *strip)
static void strip_retiming_segment_as_line_segment(const SeqRetimingKey *start_key, double r_v1[2], double r_v2[2])
void retiming_transition_key_frame_set(const Scene *scene, const Strip *strip, SeqRetimingKey *key, const int timeline_frame)
static float strip_retiming_segment_step_get(const SeqRetimingKey *start_key)
void transform_handle_overlap(Scene *scene, ListBase *seqbasep, blender::Span< Strip * > transformed_strips, bool use_sync_markers)
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:420
static int strip_retiming_clamp_timeline_frame(const Scene *scene, Strip *strip, SeqRetimingKey *key, const int timeline_frame)
static void strip_retiming_fix_transition(const Scene *scene, Strip *strip, SeqRetimingKey *key)
SeqRetimingKey * retiming_last_key_get(const Strip *strip)
void retiming_selection_append(SeqRetimingKey *key)
SeqRetimingKey * retiming_add_key(const Scene *scene, Strip *strip, const int timeline_frame)
bool retiming_is_last_key(const Strip *strip, const SeqRetimingKey *key)
static void strip_retiming_fix_transitions(const Scene *scene, Strip *strip, SeqRetimingKey *key)
float strip_retiming_evaluate(const Strip *strip, const float frame_index)
static RetimingRangeData strip_retiming_range_data_get(const Scene *scene, const Strip *strip)
static void strip_retiming_cleanup_freeze_frame(SeqRetimingKey *key)
static int content_frame_index_get(const Scene *scene, const Strip *strip, const int timeline_frame)
VecBase< double, 2 > double2
struct Editing * ed
struct RenderData r
double original_strip_frame_index
void * scene_sound
int retiming_keys_num
struct SeqRetimingKey * retiming_keys
i
Definition text_draw.cc:230
ParamHandle ** handles