Blender V5.0
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#include "DNA_sound_types.h"
16
17#include "BLI_bounds.hh"
18#include "BLI_listbase.h"
19#include "BLI_map.hh"
20#include "BLI_math_geom.h"
21#include "BLI_math_vector.h"
23#include "BLI_span.hh"
24#include "BLI_vector.hh"
25
26#include "BKE_sound.h"
27
28#include "SEQ_iterator.hh"
29#include "SEQ_retiming.hh"
30#include "SEQ_sequencer.hh"
31#include "SEQ_time.hh"
32#include "SEQ_transform.hh"
33
34#include "sequencer.hh"
35#include "strip_time.hh"
36
37namespace blender::seq {
38
44
45bool retiming_is_last_key(const Strip *strip, const SeqRetimingKey *key)
46{
47 return retiming_key_index_get(strip, key) == strip->retiming_keys_num - 1;
48}
49
51{
52 return strip->retiming_keys + strip->retiming_keys_num - 1;
53}
54
55int retiming_key_index_get(const Strip *strip, const SeqRetimingKey *key)
56{
57 return key - strip->retiming_keys;
58}
59
60static int content_frame_index_get(const Scene *scene,
61 const Strip *strip,
62 const int timeline_frame)
63{
64 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
65 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
66 return (timeline_frame - time_start_frame_get(strip) - sound_offset) *
68}
69
71 const Strip *strip,
72 const int timeline_frame)
73{
74 for (auto &key : retiming_keys_get(strip)) {
75 const int key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, &key);
76 if (key_timeline_frame == timeline_frame) {
77 return &key;
78 }
79 }
80
81 return nullptr;
82}
83
84SeqRetimingKey *retiming_find_segment_start_key(const Strip *strip, float frame_index)
85{
86 SeqRetimingKey *start_key = nullptr;
87 for (auto &key : retiming_keys_get(strip)) {
88 if (retiming_is_last_key(strip, &key)) {
89 break;
90 }
91 if (key.strip_frame_index > frame_index) {
92 break;
93 }
94
95 start_key = &key;
96 }
97
98 return start_key;
99}
100
101int retiming_keys_count(const Strip *strip)
102{
103 return strip->retiming_keys_num;
104}
105
107{
108 if (!retiming_is_allowed(strip)) {
109 return;
110 }
111
112 if (retiming_is_active(strip)) {
113 return;
114 }
115
117 SeqRetimingKey *key = strip->retiming_keys + 1;
118 key->strip_frame_index = strip->len;
119 key->retiming_factor = 1.0f;
120 strip->retiming_keys_num = 2;
121}
122
124{
125 if (strip->retiming_keys != nullptr) {
126 MEM_freeN(strip->retiming_keys);
127 strip->retiming_keys = nullptr;
128 strip->retiming_keys_num = 0;
129 }
130 strip->flag &= ~SEQ_SHOW_RETIMING;
131}
132
133static void retiming_key_overlap(Scene *scene, Strip *strip)
134{
135 ListBase *seqbase = active_seqbase_get(editing_get(scene));
138 dependant.add(strip);
139 iterator_set_expand(scene, seqbase, dependant, query_strip_effect_chain);
140 strips.add_multiple(dependant);
141 dependant.remove(strip);
142 transform_handle_overlap(scene, seqbase, strips, dependant, true);
143}
144
145void retiming_reset(Scene *scene, Strip *strip)
146{
147 if (!retiming_is_allowed(strip)) {
148 return;
149 }
150
151 retiming_data_clear(strip);
152
156
157 retiming_key_overlap(scene, strip);
158}
159
160bool retiming_is_active(const Strip *strip)
161{
162 return strip->retiming_keys_num > 1;
163}
164
166{
167 return strip->flag & SEQ_SHOW_RETIMING;
168}
169
170bool retiming_is_allowed(const Strip *strip)
171{
172 if (strip->len < 2) {
173 return false;
174 }
175
176 return ELEM(strip->type,
184}
185
187{
188 const SeqRetimingKey *end_key = start_key + 1;
189 return end_key->strip_frame_index - start_key->strip_frame_index;
190}
191
193{
194 const SeqRetimingKey *end_key = start_key + 1;
195 const double segment_length = strip_retiming_segment_length_get(start_key);
196 const double segment_fac_diff = end_key->retiming_factor - start_key->retiming_factor;
197 return segment_fac_diff / segment_length;
198}
199
201 double r_v1[2],
202 double r_v2[2])
203{
204 const SeqRetimingKey *end_key = start_key + 1;
205 r_v1[0] = start_key->strip_frame_index;
206 r_v1[1] = start_key->retiming_factor;
207 r_v2[0] = end_key->strip_frame_index;
208 r_v2[1] = end_key->retiming_factor;
209}
210
212 double r_center[2],
213 double *radius)
214{
215 blender::double2 s1_1, s1_2, s2_1, s2_2, p1_2;
216
217 /* Get 2 segments. */
218 strip_retiming_segment_as_line_segment(start_key - 1, s1_1, s1_2);
219 strip_retiming_segment_as_line_segment(start_key + 1, s2_1, s2_2);
220 /* Backup first segment end point - needed to calculate arc radius. */
221 copy_v2_v2_db(p1_2, s1_2);
222 /* Convert segments to vectors. */
224 sub_v2_v2v2_db(v1, s1_1, s1_2);
225 sub_v2_v2v2_db(v2, s2_1, s2_2);
226 /* Rotate segments by 90 degrees around seg. 1 end and seg. 2 start point. */
227 std::swap(v1[0], v1[1]);
228 std::swap(v2[0], v2[1]);
229 v1[0] *= -1;
230 v2[0] *= -1;
231 copy_v2_v2_db(s1_1, s1_2);
232 s1_2 += v1;
233 copy_v2_v2_db(s2_2, s2_1);
234 s2_2 += v2;
235 /* Get center and radius of arc segment between 2 linear segments. */
236 double lambda, mu;
237 isect_seg_seg_v2_lambda_mu_db(s1_1, s1_2, s2_1, s2_2, &lambda, &mu);
238 r_center[0] = s1_1[0] + lambda * (s1_2[0] - s1_1[0]);
239 r_center[1] = s1_1[1] + lambda * (s1_2[1] - s1_1[1]);
240 *radius = len_v2v2_db(p1_2, r_center);
241}
242
244{
245 return (key->flag & SEQ_SPEED_TRANSITION_IN) != 0 || (key->flag & SEQ_SPEED_TRANSITION_OUT) != 0;
246}
247
249{
250 return (key->flag & SEQ_SPEED_TRANSITION_IN) != 0;
251}
252
254{
255 if (key->flag & SEQ_SPEED_TRANSITION_OUT) {
256 return key - 1;
257 }
258 if (key->flag & SEQ_SPEED_TRANSITION_IN) {
259 return key;
260 }
261 return nullptr;
262}
263
265{
266 return (key->flag & SEQ_FREEZE_FRAME_IN) != 0 || (key->flag & SEQ_FREEZE_FRAME_OUT) != 0;
267}
268
269/* Check colinearity of 2 segments allowing for some imprecision.
270 * `isect_seg_seg_v2_lambda_mu_db()` return value does not work well in this case. */
271
272static bool strip_retiming_transition_is_linear(const Strip *strip, const SeqRetimingKey *key)
273{
274 const float prev_speed = retiming_key_speed_get(strip, key);
275 const float next_speed = retiming_key_speed_get(strip, key + 2);
276
277 return abs(prev_speed - next_speed) < 0.01f;
278}
279
281 const float frame_index)
282{
283 double c[2], r;
285 const int side = c[1] > key->retiming_factor ? -1 : 1;
286 const float y = c[1] + side * sqrt(pow(r, 2) - pow((frame_index - c[0]), 2));
287 return y;
288}
289
290float strip_retiming_evaluate(const Strip *strip, const float frame_index)
291{
292 const SeqRetimingKey *start_key = retiming_find_segment_start_key(strip, frame_index);
293
294 const int start_key_index = start_key - strip->retiming_keys;
295 BLI_assert(start_key_index < strip->retiming_keys_num);
296
297 const float segment_frame_index = frame_index - start_key->strip_frame_index;
298
299 if (!retiming_key_is_transition_start(start_key)) {
300 const float segment_step = strip_retiming_segment_step_get(start_key);
301 return std::min(1.0f, start_key->retiming_factor + float(segment_step * segment_frame_index));
302 }
303
304 if (strip_retiming_transition_is_linear(strip, start_key)) {
305 const float segment_step = strip_retiming_segment_step_get(start_key - 1);
306 return std::min(1.0f, start_key->retiming_factor + float(segment_step * segment_frame_index));
307 }
308
309 /* Sanity check for transition type. */
310 BLI_assert(start_key_index > 0);
311 BLI_assert(start_key_index < strip->retiming_keys_num - 1);
312 UNUSED_VARS_NDEBUG(start_key_index);
313
314 return std::min(1.0f, strip_retiming_evaluate_arc_segment(start_key, frame_index));
315}
316
317static SeqRetimingKey *strip_retiming_add_key(Strip *strip, float frame_index)
318{
319 if (!retiming_is_allowed(strip)) {
320 return nullptr;
321 }
322 /* Clamp timeline frame to strip content range. */
323 if (frame_index <= 0) {
324 return &strip->retiming_keys[0];
325 }
326 if (frame_index >= retiming_last_key_get(strip)->strip_frame_index) {
327 return retiming_last_key_get(strip); /* This is expected for strips with no offsets. */
328 }
329
330 SeqRetimingKey *start_key = retiming_find_segment_start_key(strip, frame_index);
331
332 if (start_key->strip_frame_index == frame_index) {
333 return start_key; /* Retiming key already exists. */
334 }
335
336 if ((start_key->flag & SEQ_SPEED_TRANSITION_IN) != 0 ||
337 (start_key->flag & SEQ_FREEZE_FRAME_IN) != 0)
338 {
339 return nullptr;
340 }
341
342 float value = strip_retiming_evaluate(strip, frame_index);
343
344 SeqRetimingKey *keys = strip->retiming_keys;
345 const int keys_count = retiming_keys_count(strip);
346 const int new_key_index = start_key - keys + 1;
347 BLI_assert(new_key_index >= 0);
348 BLI_assert(new_key_index < keys_count);
349
350 SeqRetimingKey *new_keys = MEM_calloc_arrayN<SeqRetimingKey>(keys_count + 1, __func__);
351 if (new_key_index > 0) {
352 memcpy(new_keys, keys, new_key_index * sizeof(SeqRetimingKey));
353 }
354 if (new_key_index < keys_count) {
355 memcpy(new_keys + new_key_index + 1,
356 keys + new_key_index,
357 (keys_count - new_key_index) * sizeof(SeqRetimingKey));
358 }
359 MEM_freeN(keys);
360 strip->retiming_keys = new_keys;
361 strip->retiming_keys_num++;
362
363 SeqRetimingKey *added_key = (new_keys + new_key_index);
364 added_key->strip_frame_index = frame_index;
365 added_key->retiming_factor = value;
366
367 return added_key;
368}
369
370SeqRetimingKey *retiming_add_key(const Scene *scene, Strip *strip, const int timeline_frame)
371{
372 return strip_retiming_add_key(strip, content_frame_index_get(scene, strip, timeline_frame));
373}
374
376 const Strip *strip,
377 SeqRetimingKey *key,
378 const int timeline_frame)
379{
381 SeqRetimingKey *key_end = key_start + 1;
382 const float start_frame_index = key_start->strip_frame_index;
383 const float midpoint = key_start->original_strip_frame_index;
384 const float new_frame_index = content_frame_index_get(scene, strip, timeline_frame);
385 float new_midpoint_offset = new_frame_index - midpoint;
386 const float prev_segment_step = strip_retiming_segment_step_get(key_start - 1);
387 const float next_segment_step = strip_retiming_segment_step_get(key_end);
388
389 /* Prevent keys crossing eachother. */
390 SeqRetimingKey *prev_segment_end = key_start - 1, *next_segment_start = key_end + 1;
391 const float offset_max_left = midpoint - prev_segment_end->strip_frame_index - 1;
392 const float offset_max_right = next_segment_start->strip_frame_index - midpoint - 1;
393 new_midpoint_offset = fabs(new_midpoint_offset);
394 new_midpoint_offset = min_fff(new_midpoint_offset, offset_max_left, offset_max_right);
395 new_midpoint_offset = max_ff(new_midpoint_offset, 1);
396
397 key_start->strip_frame_index = midpoint - new_midpoint_offset;
398 key_end->strip_frame_index = midpoint + new_midpoint_offset;
399
400 const float offset = key_start->strip_frame_index - start_frame_index;
401 key_start->retiming_factor += offset * prev_segment_step;
402 key_end->retiming_factor -= offset * next_segment_step;
403}
404
406{
407 if ((key->flag & SEQ_FREEZE_FRAME_IN) != 0) {
408 SeqRetimingKey *next_key = key + 1;
410 next_key->flag &= ~SEQ_FREEZE_FRAME_OUT;
411 }
412 if ((key->flag & SEQ_FREEZE_FRAME_OUT) != 0) {
413 SeqRetimingKey *previous_key = key - 1;
415 previous_key->flag &= ~SEQ_FREEZE_FRAME_IN;
416 }
417}
418
420{
421 /* Transitions need special treatment, so separate these from `keys_to_remove`. */
423
424 /* Cleanup freeze frames and extract transition keys. */
425 for (SeqRetimingKey *key : keys_to_remove) {
428 }
429 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
430 transitions.append_non_duplicates(key);
431 transitions.append_non_duplicates(key + 1);
432 }
433 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
434 transitions.append_non_duplicates(key);
435 transitions.append_non_duplicates(key - 1);
436 }
437 }
438
439 /* Sanitize keys to be removed. */
440 keys_to_remove.remove_if([&](const SeqRetimingKey *key) {
441 return key->strip_frame_index == 0 || retiming_is_last_key(strip, key) ||
443 });
444
445 const size_t keys_count = retiming_keys_count(strip);
446 size_t new_keys_count = keys_count - keys_to_remove.size() - transitions.size() / 2;
447 SeqRetimingKey *new_keys = MEM_calloc_arrayN<SeqRetimingKey>(new_keys_count, __func__);
448 int keys_copied = 0;
449
450 /* Copy keys to new array. */
451 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
452 /* Create key that was used to make transition in new array. */
453 if (transitions.contains(&key) && retiming_key_is_transition_start(&key)) {
454 SeqRetimingKey *new_key = new_keys + keys_copied;
457 keys_copied++;
458 continue;
459 }
460 if (keys_to_remove.contains(&key) || transitions.contains(&key)) {
461 continue;
462 }
463 memcpy(new_keys + keys_copied, &key, sizeof(SeqRetimingKey));
464 keys_copied++;
465 }
466
467 MEM_freeN(strip->retiming_keys);
468 strip->retiming_keys = new_keys;
469 strip->retiming_keys_num = new_keys_count;
470}
471
473{
474 if (key->strip_frame_index == 0 || retiming_is_last_key(strip, key)) {
475 return; /* First and last key can not be removed. */
476 }
477
480 }
481
482 size_t keys_count = retiming_keys_count(strip);
483 SeqRetimingKey *keys = MEM_calloc_arrayN<SeqRetimingKey>(keys_count - 1, __func__);
484
485 const int key_index = key - strip->retiming_keys;
486 memcpy(keys, strip->retiming_keys, (key_index) * sizeof(SeqRetimingKey));
487 memcpy(keys + key_index,
488 strip->retiming_keys + key_index + 1,
489 (keys_count - key_index - 1) * sizeof(SeqRetimingKey));
490 MEM_freeN(strip->retiming_keys);
491 strip->retiming_keys = keys;
492 strip->retiming_keys_num--;
493}
494
495/* This function removes transition segment and creates retiming key where it originally was. */
497{
498 SeqRetimingKey *transition_start = key;
499 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
500 transition_start = key - 1;
501 }
502
503 const float orig_frame_index = transition_start->original_strip_frame_index;
504 const float orig_retiming_factor = transition_start->original_retiming_factor;
505
506 /* Remove both keys defining transition. */
507 int key_index = retiming_key_index_get(strip, transition_start);
508 strip_retiming_remove_key_ex(strip, transition_start);
509 strip_retiming_remove_key_ex(strip, strip->retiming_keys + key_index);
510
511 /* Create original linear key. */
512 SeqRetimingKey *orig_key = strip_retiming_add_key(strip, orig_frame_index);
513 orig_key->retiming_factor = orig_retiming_factor;
514 return orig_key;
515}
516
518{
519
522 return;
523 }
524
526}
527
529 const Strip *strip,
530 SeqRetimingKey *key)
531{
532 Bounds<float> max_tml_frame_offset = {MINAFRAMEF, MAXFRAMEF};
533
534 if (key->strip_frame_index != 0) {
535 SeqRetimingKey *prev_key = key - 1;
536 max_tml_frame_offset.min = retiming_key_timeline_frame_get(scene, strip, prev_key) -
537 retiming_key_timeline_frame_get(scene, strip, key);
538 }
539 if (!retiming_is_last_key(strip, key)) {
540 SeqRetimingKey *next_key = key + 1;
541 max_tml_frame_offset.max = retiming_key_timeline_frame_get(scene, strip, next_key) -
542 retiming_key_timeline_frame_get(scene, strip, key);
543 }
544 return max_tml_frame_offset;
545}
546
547/* Create pair of retiming keys separated by offset. */
548static std::pair<SeqRetimingKey *, SeqRetimingKey *> freeze_key_pair_create(const Scene *scene,
549 Strip *strip,
550 SeqRetimingKey *key,
551 const int offset)
552{
553
554 Bounds<float> max_offset = strip_retiming_clamp_bounds_get(scene, strip, key);
555 const float tml_frame_offset = math::clamp(float(offset), max_offset.min, max_offset.max);
556 const int orig_timeline_frame = retiming_key_timeline_frame_get(scene, strip, key);
557
558 /* Offset last key first, then add a freeze start key before it, because it is not possible to
559 * add keys after last one. */
560 if (retiming_is_last_key(strip, key)) {
561 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
562 const float frame_index_offset = tml_frame_offset *
563 time_media_playback_rate_factor_get(strip, scene_fps);
564 key->strip_frame_index += frame_index_offset;
565 SeqRetimingKey *freeze_start = retiming_add_key(scene, strip, orig_timeline_frame);
566
567 if (freeze_start == nullptr) {
568 key->strip_frame_index -= frame_index_offset;
569 return {nullptr, nullptr};
570 }
571 return {freeze_start, freeze_start + 1};
572 }
573
574 SeqRetimingKey *freeze_end = retiming_add_key(
575 scene, strip, orig_timeline_frame + tml_frame_offset);
576
577 if (freeze_end == nullptr) {
578 return {nullptr, nullptr};
579 }
580
581 return {freeze_end - 1, freeze_end};
582}
583
584/* This function tags previous key as freeze frame key. This is only a convenient way to prevent
585 * creating speed transitions. When freeze frame is deleted, this flag should be cleared. */
587 Strip *strip,
588 SeqRetimingKey *key,
589 const int offset)
590{
592 return nullptr;
593 }
594
595 const float orig_retiming_factor = key->retiming_factor;
596 std::pair<SeqRetimingKey *, SeqRetimingKey *> freeze_keys = freeze_key_pair_create(
597 scene, strip, key, offset);
598
599 if (freeze_keys.first == nullptr) {
600 return nullptr;
601 }
602
603 freeze_keys.first->flag |= SEQ_FREEZE_FRAME_IN;
604 freeze_keys.second->flag |= SEQ_FREEZE_FRAME_OUT;
605 freeze_keys.first->retiming_factor = orig_retiming_factor;
606 freeze_keys.second->retiming_factor = orig_retiming_factor;
607 return freeze_keys.second;
608}
609
611 Strip *strip,
612 SeqRetimingKey *key,
613 float offset)
614{
615 BLI_assert(!retiming_is_last_key(strip, key));
616 BLI_assert(key->strip_frame_index != 0);
617
618 SeqRetimingKey *prev_key = key - 1;
619 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0 ||
620 (prev_key->flag & SEQ_SPEED_TRANSITION_IN) != 0)
621 {
622 return nullptr;
623 }
624
625 if ((key->flag & SEQ_FREEZE_FRAME_IN) != 0 || (prev_key->flag & SEQ_FREEZE_FRAME_IN) != 0) {
626 return nullptr;
627 }
628
629 Bounds<float> max_offset = strip_retiming_clamp_bounds_get(scene, strip, key);
630 float clamped_offset = math::clamp(offset, max_offset.min, max_offset.max);
631
632 const int orig_key_index = retiming_key_index_get(strip, key);
633 const float orig_frame_index = key->strip_frame_index;
634 const float orig_retiming_factor = key->retiming_factor;
635
636 SeqRetimingKey *transition_out = strip_retiming_add_key(strip,
637 orig_frame_index + clamped_offset);
638 transition_out->flag |= SEQ_SPEED_TRANSITION_OUT;
639
640 SeqRetimingKey *transition_in = strip_retiming_add_key(strip, orig_frame_index - clamped_offset);
641 transition_in->flag |= SEQ_SPEED_TRANSITION_IN;
642 transition_in->original_strip_frame_index = orig_frame_index;
643 transition_in->original_retiming_factor = orig_retiming_factor;
644
645 strip_retiming_remove_key_ex(strip, strip->retiming_keys + orig_key_index + 1);
646 return strip->retiming_keys + orig_key_index + 1;
647}
648
650 const Strip *strip,
651 SeqRetimingKey *start_key,
652 float offset)
653{
654 SeqRetimingKey *end_key = start_key + 1;
655 SeqRetimingKey *prev_key = start_key - 1;
656 SeqRetimingKey *next_key = start_key + 2;
657 const float prev_max_offset = prev_key->strip_frame_index - start_key->strip_frame_index;
658 const float next_max_offset = next_key->strip_frame_index - end_key->strip_frame_index;
659 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
660 const float min_step = time_media_playback_rate_factor_get(strip, scene_fps);
661
662 return std::clamp(offset, prev_max_offset + min_step, next_max_offset - min_step);
663}
664
666 Strip *strip,
667 SeqRetimingKey *key,
668 const float offset)
669{
670 float clamped_offset = strip_retiming_clamp_transition_offset(scene, strip, key, offset);
671 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
672 const float duration = (key->original_strip_frame_index - key->strip_frame_index) /
673 time_media_playback_rate_factor_get(strip, scene_fps);
674 const bool was_selected = retiming_selection_contains(editing_get(scene), key);
675
676 SeqRetimingKey *original_key = strip_retiming_remove_transition(strip, key);
677 original_key->strip_frame_index += clamped_offset;
678
679 SeqRetimingKey *transition_out = retiming_add_transition(scene, strip, original_key, duration);
680
681 if (was_selected) {
682 retiming_selection_append(transition_out);
683 retiming_selection_append(transition_out - 1);
684 }
685}
686
688 Strip *strip,
689 SeqRetimingKey *key,
690 const int timeline_frame)
691{
692 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
693 return timeline_frame;
694 }
695
696 int prev_key_timeline_frame = -MAXFRAME;
697 int next_key_timeline_frame = MAXFRAME;
698
699 if (key->strip_frame_index > 0) {
700 SeqRetimingKey *prev_key = key - 1;
701 prev_key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, prev_key);
702 }
703
704 if (!retiming_is_last_key(strip, key)) {
705 SeqRetimingKey *next_key = key + 1;
706 next_key_timeline_frame = retiming_key_timeline_frame_get(scene, strip, next_key);
707 }
708
709 return std::clamp(timeline_frame, prev_key_timeline_frame + 1, next_key_timeline_frame - 1);
710}
711
712/* Remove and re-create transition. This way transition won't change length.
713 * Alternative solution is to find where in arc segment the `y` value is closest to key
714 * retiming factor, then trim transition to that point. This would change transition length. */
715
716static void strip_retiming_fix_transition(const Scene *scene, Strip *strip, SeqRetimingKey *key)
717{
718 const int keys_num = strip->retiming_keys_num;
719 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
720 const float transition_duration = (key->original_strip_frame_index - key->strip_frame_index) /
721 time_media_playback_rate_factor_get(strip, scene_fps);
722 SeqRetimingKey *orig_key = strip_retiming_remove_transition(strip, key);
723 retiming_add_transition(scene, strip, orig_key, transition_duration);
724 BLI_assert(keys_num == strip->retiming_keys_num);
725 UNUSED_VARS_NDEBUG(keys_num);
726}
727
728static void strip_retiming_fix_transitions(const Scene *scene, Strip *strip, SeqRetimingKey *key)
729{
730 /* Store value, since handles array will be reallocated. */
731 const int key_index = retiming_key_index_get(strip, key);
732
733 if (key_index > 1) {
734 SeqRetimingKey *prev_key = key - 2;
735 if (retiming_key_is_transition_start(prev_key)) {
736 strip_retiming_fix_transition(scene, strip, prev_key);
737 }
738 }
739
740 if (!retiming_is_last_key(strip, &retiming_keys_get(strip)[key_index])) {
741 SeqRetimingKey *next_key = &retiming_keys_get(strip)[key_index + 1];
742 if (retiming_key_is_transition_start(next_key)) {
743 strip_retiming_fix_transition(scene, strip, next_key);
744 }
745 }
746}
747
748static void strip_retiming_key_offset(const Scene *scene,
749 Strip *strip,
750 SeqRetimingKey *key,
751 const float offset)
752{
753 if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
754 strip_retiming_transition_offset(scene, strip, key, offset);
755 }
756 else {
757 key->strip_frame_index += offset;
758 strip_retiming_fix_transitions(scene, strip, key);
759 }
760}
761
763 const Strip *strip,
764 const SeqRetimingKey *key)
765{
766 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
767 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
768 return round_fl_to_int(time_start_frame_get(strip) + sound_offset +
769 key->strip_frame_index /
770 time_media_playback_rate_factor_get(strip, scene_fps));
771}
772
774 const Scene *scene, Strip *strip, SeqRetimingKey *key, int timeline_frame, bool keep_retiming)
775{
776 if ((key->flag & SEQ_SPEED_TRANSITION_OUT) != 0) {
777 return;
778 }
779
780 const int orig_timeline_frame = retiming_key_timeline_frame_get(scene, strip, key);
781 const int clamped_timeline_frame = strip_retiming_clamp_timeline_frame(
782 scene, strip, key, timeline_frame);
783 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
784 const float offset = (clamped_timeline_frame - orig_timeline_frame) *
785 time_media_playback_rate_factor_get(strip, scene_fps);
786
787 const int key_count = retiming_keys_get(strip).size();
788 const int key_index = retiming_key_index_get(strip, key);
789
790 if (orig_timeline_frame == time_right_handle_frame_get(scene, strip) && keep_retiming) {
791 for (int i = key_index; i < key_count; i++) {
792 SeqRetimingKey *key_iter = &retiming_keys_get(strip)[i];
793 strip_retiming_key_offset(scene, strip, key_iter, offset);
794 }
795 }
796 else if (orig_timeline_frame == time_left_handle_frame_get(scene, strip) ||
797 key->strip_frame_index == 0)
798 {
799 strip->start += clamped_timeline_frame - orig_timeline_frame;
800 for (int i = key_index + 1; i < key_count; i++) {
801 SeqRetimingKey *key_iter = &retiming_keys_get(strip)[i];
802 strip_retiming_key_offset(scene, strip, key_iter, -offset);
803 }
804 }
805 else {
806 strip_retiming_key_offset(scene, strip, key, offset);
807 }
808
812}
813
814float retiming_key_speed_get(const Strip *strip, const SeqRetimingKey *key)
815{
816 if (key->strip_frame_index == 0) {
817 return 1.0f;
818 }
819
820 BLI_assert(retiming_key_index_get(strip, key) > 0);
821 const SeqRetimingKey *key_prev = key - 1;
822 const int frame_index_max = strip->len;
823 const float frame_index_start = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
824 const float frame_index_end = round_fl_to_int(key->retiming_factor * frame_index_max);
825 const float segment_content_frame_count = frame_index_end - frame_index_start;
826 const float segment_length = key->strip_frame_index - key_prev->strip_frame_index;
827 const float speed = segment_content_frame_count / segment_length;
828 return speed;
829}
830
832 const Scene *scene, Strip *strip, SeqRetimingKey *key, const float speed, bool keep_retiming)
833{
834 if (key->strip_frame_index == 0) {
835 return;
836 }
837
838 const SeqRetimingKey *key_prev = key - 1;
839
840 const int frame_index_max = strip->len;
841 const float frame_index_prev = round_fl_to_int(key_prev->retiming_factor * frame_index_max);
842 const float frame_index = round_fl_to_int(key->retiming_factor * frame_index_max);
843
844 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
845 const float segment_timeline_duration = (frame_index - frame_index_prev) /
846 time_media_playback_rate_factor_get(strip, scene_fps);
847 const float new_timeline_duration = segment_timeline_duration / speed;
848
849 const float new_timeline_frame = std::round(
850 retiming_key_timeline_frame_get(scene, strip, key_prev) + new_timeline_duration);
851
852 retiming_key_timeline_frame_set(scene, strip, key, new_timeline_frame, keep_retiming);
853}
854
858};
859
867
869 public:
870 int start, end;
871 float speed;
873
875 RetimingRange(const Strip *strip, int start_frame, int end_frame, float speed, eRangeType type)
876 : start(start_frame), end(end_frame), speed(speed), type(type)
877 {
878 if (type == TRANSITION) {
879 this->speed = 1.0f;
881 }
882 }
883
884 RetimingRange(int start_frame, int end_frame, float speed, eRangeType type)
885 : start(start_frame), end(end_frame), speed(speed), type(type)
886 {
887 }
888
890 {
892 for (int i = 0; i < speed_table.size(); i++) {
893 new_range.speed_table.append(speed_table[i]);
894 }
895 return new_range;
896 }
897
898 /* Create new range representing overlap of 2 ranges.
899 * Returns overlapping range. */
901 {
902 RetimingRange new_range = RetimingRange(0, 0, 0, LINEAR);
903
904 /* Offsets to merge speed tables. */
905 int range_offset = 0, rhs_range_offset = 0;
906 if (intersect_type(rhs_range) == FULL) {
907 new_range.start = start;
908 new_range.end = end;
909 rhs_range_offset = start - rhs_range.start;
910 }
911 else if (intersect_type(rhs_range) == PARTIAL_START) {
912 new_range.start = start;
913 new_range.end = rhs_range.end;
914 rhs_range_offset = start - rhs_range.start;
915 }
916 else if (intersect_type(rhs_range) == PARTIAL_END) {
917 new_range.start = rhs_range.start;
918 new_range.end = end;
919 range_offset = rhs_range.start - start;
920 }
921 else if (intersect_type(rhs_range) == INSIDE) {
922 new_range.start = rhs_range.start;
923 new_range.end = rhs_range.end;
924 range_offset = rhs_range.start - start;
925 }
926
927 if (type != TRANSITION && rhs_range.type != TRANSITION) {
928 new_range.speed = speed * rhs_range.speed;
929 return new_range;
930 }
931
932 /* One of ranges is transition type, so speed tables has to be copied. */
933 new_range.type = TRANSITION;
934 new_range.speed = 1.0f;
935 const int new_range_len = new_range.end - new_range.start;
936
937 if (type == TRANSITION && rhs_range.type == TRANSITION) {
938 for (int i = 0; i < new_range_len; i++) {
939 const float range_speed = speed_table[i + range_offset];
940 const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
941 new_range.speed_table.append(range_speed * rhs_range_speed);
942 }
943 }
944 else if (type == TRANSITION) {
945 for (int i = 0; i < new_range_len; i++) {
946 const float range_speed = speed_table[i + range_offset];
947 new_range.speed_table.append(range_speed * rhs_range.speed);
948 }
949 }
950 else if (rhs_range.type == TRANSITION) {
951 for (int i = 0; i < new_range_len; i++) {
952 const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
953 new_range.speed_table.append(speed * rhs_range_speed);
954 }
955 }
956
957 return new_range;
958 }
959
961 {
962 for (int timeline_frame = start; timeline_frame <= end; timeline_frame++) {
963 /* We need number actual number of frames here. */
964 const double normal_step = 1 / double(strip->len - 1);
965
966 const int frame_index = timeline_frame - time_start_frame_get(strip);
967 /* Who needs calculus, when you can have slow code? */
968 const double val_prev = strip_retiming_evaluate(strip, frame_index - 1);
969 const double val = strip_retiming_evaluate(strip, frame_index);
970 const double speed_at_frame = (val - val_prev) / normal_step;
971 speed_table.append(speed_at_frame);
972 }
973 }
974
976 {
977 if (other.start <= start && other.end >= end) {
978 return FULL;
979 }
980 if (other.start > start && other.start < end && other.end > start && other.end < end) {
981 return INSIDE;
982 }
983 if (other.start > start && other.start < end) {
984 return PARTIAL_END;
985 }
986 if (other.end > start && other.end < end) {
987 return PARTIAL_START;
988 }
989 return NONE;
990 }
991};
992
994 public:
997 {
998 for (const SeqRetimingKey &key : retiming_keys_get(strip)) {
999 if (key.strip_frame_index == 0) {
1000 continue;
1001 }
1002 const SeqRetimingKey *key_prev = &key - 1;
1003 float speed = retiming_key_speed_get(strip, &key);
1004 int frame_start = time_start_frame_get(strip) + key_prev->strip_frame_index;
1005 int frame_end = time_start_frame_get(strip) + key.strip_frame_index;
1006
1008 RetimingRange range = RetimingRange(strip, frame_start, frame_end, speed, type);
1009 ranges.append(range);
1010 }
1011 }
1012
1014 {
1015 if (ranges.is_empty()) {
1016 for (const RetimingRange &rhs_range : rhs.ranges) {
1018 rhs_range.start, rhs_range.end, rhs_range.speed, rhs_range.type);
1019 ranges.append(range);
1020 }
1021 return *this;
1022 }
1023
1024 for (int i = 0; i < ranges.size(); i++) {
1025 RetimingRange &range = ranges[i];
1026 for (const RetimingRange &rhs_range : rhs.ranges) {
1027 if (range.intersect_type(rhs_range) == NONE) {
1028 continue;
1029 }
1030 if (range.intersect_type(rhs_range) == FULL) {
1031 RetimingRange isect = range * rhs_range;
1032 ranges.remove(i);
1033 ranges.insert(i, isect);
1034 }
1035 if (range.intersect_type(rhs_range) == PARTIAL_START) {
1036 ranges.insert(i, range * rhs_range);
1037 ranges.insert(i, range * rhs_range);
1038 range.start = rhs_range.end + 1;
1039 }
1040 else if (range.intersect_type(rhs_range) == PARTIAL_END) {
1041 ranges.insert(i, range * rhs_range);
1042 range.end = rhs_range.start;
1043 }
1044 else if (range.intersect_type(rhs_range) == INSIDE) {
1045 RetimingRange left_range = range.duplicate();
1046 left_range.end = rhs_range.start;
1047 range.start = rhs_range.end + 1;
1048
1049 ranges.insert(i, left_range);
1050 ranges.insert(i, range * rhs_range);
1051 }
1052 }
1053 }
1054 return *this;
1055 }
1056};
1057
1059{
1060 RetimingRangeData strip_retiming_data = RetimingRangeData(strip);
1061
1062 const Strip *meta_parent = lookup_meta_by_strip(scene->ed, strip);
1063 if (meta_parent == nullptr) {
1064 return strip_retiming_data;
1065 }
1066
1067 RetimingRangeData meta_retiming_data = RetimingRangeData(meta_parent);
1068 strip_retiming_data *= meta_retiming_data;
1069 return strip_retiming_data;
1070}
1071
1072void retiming_sound_animation_data_set(const Scene *scene, const Strip *strip)
1073{
1074
1075 RetimingRangeData retiming_data = strip_retiming_range_data_get(scene, strip);
1076
1077 /* No need to apply the time-stretch effect if all the retiming range speeds are 1, as the
1078 * effect itself is still expensive while the audio is playing and want to avoid having to use it
1079 * whenever we can. */
1080 bool correct_pitch = (strip->flag & SEQ_AUDIO_PITCH_CORRECTION) && strip->sound != nullptr &&
1081 std::any_of(retiming_data.ranges.begin(),
1082 retiming_data.ranges.end(),
1083 [](const RetimingRange &range) {
1084 return range.type != TRANSITION && range.speed != 1.0;
1085 });
1086#if !defined(WITH_RUBBERBAND)
1087 correct_pitch = false;
1088#endif
1089
1090 void *sound_handle = strip->sound ? strip->sound->playback_handle : nullptr;
1091 const float scene_fps = float(scene->r.frs_sec) / float(scene->r.frs_sec_base);
1092 if (correct_pitch) {
1094 sound_handle, strip->scene_sound, scene_fps);
1096 strip->scene_sound, 0, strip->start + strip->len, 1.0f);
1097 }
1098
1099 /* Content cut off by `anim_startofs` is as if it does not exist for sequencer. But Audaspace
1100 * seeking relies on having animation buffer initialized for whole sequence. */
1101 if (strip->anim_startofs > 0) {
1102 const int strip_start = time_start_frame_get(strip);
1104 strip->scene_sound, strip_start - strip->anim_startofs, strip_start, 1.0f);
1105 }
1106
1107 const int sound_offset = time_get_rounded_sound_offset(strip, scene_fps);
1108
1109 for (int i = 0; i < retiming_data.ranges.size(); i++) {
1110 const RetimingRange &range = retiming_data.ranges[i];
1111 if (range.type == TRANSITION) {
1112 const int range_length = range.end - range.start;
1113 for (int i = 0; i <= range_length; i++) {
1114 const int frame = range.start + i;
1115 if (correct_pitch) {
1117 sound_handle, frame - strip->start, 1.0 / range.speed_table[i], true);
1118 }
1119 else {
1121 strip->scene_sound, frame + sound_offset, range.speed_table[i], true);
1122 }
1123 }
1124 }
1125 else {
1126 if (correct_pitch) {
1127 const float speed = range.speed == 0.0f ? 1.0f : 1.0f / range.speed;
1129 sound_handle, range.start - strip->start, range.end - strip->start, speed);
1130 }
1131 else {
1133 strip->scene_sound, range.start + sound_offset, range.end + sound_offset, range.speed);
1134 }
1135 }
1136 }
1137
1138 if (correct_pitch) {
1139 BKE_sound_update_sequence_handle(strip->scene_sound, sound_handle);
1140 }
1141}
1142
1144{
1145 bool was_empty = true;
1146
1147 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1148 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
1149 was_empty &= (key.flag & SEQ_KEY_SELECTED) == 0;
1150 key.flag &= ~SEQ_KEY_SELECTED;
1151 }
1152 }
1153 return !was_empty;
1154}
1155
1157
1158 SeqRetimingKey *key)
1159{
1160 key->flag |= SEQ_KEY_SELECTED;
1161}
1162
1167
1169{
1171 dst->flag |= (src->flag & SEQ_KEY_SELECTED);
1172}
1173
1175{
1177 if (!ed) {
1178 return selection;
1179 }
1180 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1181 for (SeqRetimingKey &key : retiming_keys_get(strip)) {
1182 if ((key.flag & SEQ_KEY_SELECTED) != 0) {
1183 selection.add(&key, strip);
1184 }
1185 }
1186 }
1187 return selection;
1188}
1189
1191{
1192 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1193 for (const SeqRetimingKey &key_iter : retiming_keys_get(strip)) {
1194 if ((key_iter.flag & SEQ_KEY_SELECTED) != 0 && &key_iter == key) {
1195 return true;
1196 }
1197 }
1198 }
1199 return false;
1200}
1201
1203{
1205 SeqRetimingKey *key_end = key_start + 1;
1206 bool has_start = false, has_end = false;
1207
1209
1210 for (auto item : selection.items()) {
1211 if (item.key == key_start) {
1212 has_start = true;
1213 }
1214 if (item.key == key_end) {
1215 has_end = true;
1216 }
1217 if (has_start && has_end) {
1218 return true;
1219 }
1220 }
1221 return false;
1222}
1223
1224} // namespace blender::seq
void BKE_sound_set_scene_sound_time_stretch_constant_range(void *handle, int frame_start, int frame_end, float time_stretch)
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle, int frame_start, int frame_end, float pitch)
void * BKE_sound_ensure_time_stretch_effect(void *sound_handle, void *sequence_handle, float fps)
void BKE_sound_set_scene_sound_time_stretch_at_frame(void *handle, int frame, float time_stretch, char animated)
void BKE_sound_update_sequence_handle(void *handle, void *sound_handle)
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 MAXFRAMEF
#define MINAFRAMEF
#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_AUDIO_PITCH_CORRECTION
@ 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)
nullptr float
#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)
T clamp(const T &a, const T &min, const T &max)
int retiming_key_index_get(const Strip *strip, const SeqRetimingKey *key)
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_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:286
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:254
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
static Bounds< float > strip_retiming_clamp_bounds_get(const Scene *scene, const Strip *strip, SeqRetimingKey *key)
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)
void retiming_key_timeline_frame_set(const Scene *scene, Strip *strip, SeqRetimingKey *key, int timeline_frame, bool keep_retiming)
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:433
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 std::pair< SeqRetimingKey *, SeqRetimingKey * > freeze_key_pair_create(const Scene *scene, Strip *strip, SeqRetimingKey *key, const int offset)
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 bSound * sound
struct SeqRetimingKey * retiming_keys
void * playback_handle
i
Definition text_draw.cc:230
ParamHandle ** handles