blender/release/scripts/startup/bl_operators/sequencer.py

373 lines
14 KiB
Python
Raw Normal View History

# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
2010-02-12 13:34:04 +00:00
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Operator
from bpy.props import IntProperty
2010-03-06 01:40:29 +00:00
2010-05-16 12:15:04 +00:00
class SequencerCrossfadeSounds(Operator):
"""Do cross-fading volume animation of two selected sound strips"""
bl_idname = "sequencer.crossfade_sounds"
bl_label = "Crossfade sounds"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
2012-02-29 12:11:06 +00:00
if context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip:
return context.scene.sequence_editor.active_strip.type == 'SOUND'
else:
2012-02-29 12:11:06 +00:00
return False
def execute(self, context):
seq1 = None
seq2 = None
for s in context.scene.sequence_editor.sequences:
Apply first pass of edits to rna values from rna_booleans.txt. These are not animated and are best not change names like this too late in the release. ActionGroup.selected -> select: boolean Action Group is selected BezierSplinePoint.hidden -> hide: boolean Visibility status BezierSplinePoint.selected_control_point -> select_control_point: boolean Control point selection status BezierSplinePoint.selected_handle1 -> select_left_handle: boolean Handle 1 selection status BezierSplinePoint.selected_handle2 -> select_right_handle: boolean Handle 2 selection status Bone.restrict_select -> hide_select: boolean Bone is able to be selected Bone.selected -> select: boolean CurveMapPoint.selected -> select: boolean Selection state of the curve point EditBone.restrict_select -> hide_select: boolean Bone is able to be selected EditBone.selected -> select: boolean EditBone.selected_head -> select_head: boolean EditBone.selected_tail -> select_tail: boolean EditBone.locked -> lock: boolean Bone is not able to be transformed when in Edit Mode EditBone.hidden -> hide: boolean Bone is not visible when in Edit Mode NEGATE * FCurve.disabled -> enabled: boolean F-Curve could not be evaluated in past, so should be skipped when evaluating FCurve.locked -> lock: boolean F-Curve's settings cannot be edited FCurve.muted -> mute: boolean F-Curve is not evaluated FCurve.selected -> select: boolean F-Curve is selected for editing NEGATE * FCurve.visible -> hide: boolean F-Curve and its keyframes are shown in the Graph Editor graphs FCurveSample.selected -> select: boolean Selection status GPencilFrame.selected -> select: boolean Frame is selected for editing in the DopeSheet GPencilLayer.locked -> lock: boolean Protect layer from further editing and/or frame changes GPencilLayer.selected -> select: boolean Layer is selected for editing in the DopeSheet Keyframe.selected -> select: boolean Control point selection status Keyframe.selected_handle1 -> select_left_handle: boolean Handle 1 selection status Keyframe.selected_handle2 -> select_right_handle: boolean Handle 2 selection status MeshEdge.selected -> select: boolean MeshEdge.hidden -> hide: boolean MeshFace.hidden -> hide: boolean MeshFace.selected -> select: boolean MeshVertex.hidden -> hide: boolean MeshVertex.selected -> select: boolean MotionPathVert.selected -> select: boolean Path point is selected for editing NlaStrip.selected -> select: boolean NLA Strip is selected NlaTrack.locked -> lock: boolean NLA Track is locked NlaTrack.muted -> mute: boolean NLA Track is not evaluated NlaTrack.selected -> select: boolean NLA Track is selected Object.restrict_render -> hide_render: boolean Restrict renderability Object.restrict_select -> hide_select: boolean Restrict selection in the viewport Object.restrict_view -> hide: boolean Restrict visibility in the viewport Object.selected -> select: boolean Object selection state ObjectBase.selected -> select: boolean Object base selection state PoseBone.selected -> select: boolean Sequence.right_handle_selected -> select_right_handle: boolean Sequence.selected -> select: boolean SplinePoint.selected -> select_control_point: boolean Selection status TimelineMarker.selected -> select: boolean Marker selection state Sequence.left_handle_selected -> select_left_handle: boolean ActionGroup.locked -> lock: boolean Action Group is locked Bone.hidden -> hide: boolean Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes) SplinePoint.hidden -> hide: boolean Visibility status FModifier.muted -> mute: boolean F-Curve Modifier will not be evaluated note: rebaned uv_select to select_uv
2010-07-15 16:56:04 +00:00
if s.select and s.type == 'SOUND':
if seq1 is None:
seq1 = s
elif seq2 is None:
seq2 = s
else:
seq2 = None
break
if seq2 is None:
self.report({'ERROR'}, "Select 2 sound strips")
return {'CANCELLED'}
2010-04-01 21:44:56 +00:00
if seq1.frame_final_start > seq2.frame_final_start:
s = seq1
seq1 = seq2
seq2 = s
2010-04-01 21:44:56 +00:00
if seq1.frame_final_end > seq2.frame_final_start:
tempcfra = context.scene.frame_current
context.scene.frame_current = seq2.frame_final_start
seq1.keyframe_insert("volume")
2010-04-01 21:44:56 +00:00
context.scene.frame_current = seq1.frame_final_end
seq1.volume = 0
seq1.keyframe_insert("volume")
seq2.keyframe_insert("volume")
2010-04-01 21:44:56 +00:00
context.scene.frame_current = seq2.frame_final_start
seq2.volume = 0
seq2.keyframe_insert("volume")
2010-04-01 21:44:56 +00:00
context.scene.frame_current = tempcfra
return {'FINISHED'}
else:
self.report({'ERROR'}, "The selected strips don't overlap")
return {'CANCELLED'}
class SequencerCutMulticam(Operator):
"""Cut multi-cam strip and select camera"""
bl_idname = "sequencer.cut_multicam"
bl_label = "Cut multicam"
bl_options = {'REGISTER', 'UNDO'}
camera: IntProperty(
2018-06-26 17:41:37 +00:00
name="Camera",
min=1, max=32,
soft_min=1, soft_max=32,
default=1,
)
@classmethod
def poll(cls, context):
if context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip:
return context.scene.sequence_editor.active_strip.type == 'MULTICAM'
else:
return False
def execute(self, context):
camera = self.camera
s = context.scene.sequence_editor.active_strip
if s.multicam_source == camera or camera >= s.channel:
return {'FINISHED'}
Apply first pass of edits to rna values from rna_booleans.txt. These are not animated and are best not change names like this too late in the release. ActionGroup.selected -> select: boolean Action Group is selected BezierSplinePoint.hidden -> hide: boolean Visibility status BezierSplinePoint.selected_control_point -> select_control_point: boolean Control point selection status BezierSplinePoint.selected_handle1 -> select_left_handle: boolean Handle 1 selection status BezierSplinePoint.selected_handle2 -> select_right_handle: boolean Handle 2 selection status Bone.restrict_select -> hide_select: boolean Bone is able to be selected Bone.selected -> select: boolean CurveMapPoint.selected -> select: boolean Selection state of the curve point EditBone.restrict_select -> hide_select: boolean Bone is able to be selected EditBone.selected -> select: boolean EditBone.selected_head -> select_head: boolean EditBone.selected_tail -> select_tail: boolean EditBone.locked -> lock: boolean Bone is not able to be transformed when in Edit Mode EditBone.hidden -> hide: boolean Bone is not visible when in Edit Mode NEGATE * FCurve.disabled -> enabled: boolean F-Curve could not be evaluated in past, so should be skipped when evaluating FCurve.locked -> lock: boolean F-Curve's settings cannot be edited FCurve.muted -> mute: boolean F-Curve is not evaluated FCurve.selected -> select: boolean F-Curve is selected for editing NEGATE * FCurve.visible -> hide: boolean F-Curve and its keyframes are shown in the Graph Editor graphs FCurveSample.selected -> select: boolean Selection status GPencilFrame.selected -> select: boolean Frame is selected for editing in the DopeSheet GPencilLayer.locked -> lock: boolean Protect layer from further editing and/or frame changes GPencilLayer.selected -> select: boolean Layer is selected for editing in the DopeSheet Keyframe.selected -> select: boolean Control point selection status Keyframe.selected_handle1 -> select_left_handle: boolean Handle 1 selection status Keyframe.selected_handle2 -> select_right_handle: boolean Handle 2 selection status MeshEdge.selected -> select: boolean MeshEdge.hidden -> hide: boolean MeshFace.hidden -> hide: boolean MeshFace.selected -> select: boolean MeshVertex.hidden -> hide: boolean MeshVertex.selected -> select: boolean MotionPathVert.selected -> select: boolean Path point is selected for editing NlaStrip.selected -> select: boolean NLA Strip is selected NlaTrack.locked -> lock: boolean NLA Track is locked NlaTrack.muted -> mute: boolean NLA Track is not evaluated NlaTrack.selected -> select: boolean NLA Track is selected Object.restrict_render -> hide_render: boolean Restrict renderability Object.restrict_select -> hide_select: boolean Restrict selection in the viewport Object.restrict_view -> hide: boolean Restrict visibility in the viewport Object.selected -> select: boolean Object selection state ObjectBase.selected -> select: boolean Object base selection state PoseBone.selected -> select: boolean Sequence.right_handle_selected -> select_right_handle: boolean Sequence.selected -> select: boolean SplinePoint.selected -> select_control_point: boolean Selection status TimelineMarker.selected -> select: boolean Marker selection state Sequence.left_handle_selected -> select_left_handle: boolean ActionGroup.locked -> lock: boolean Action Group is locked Bone.hidden -> hide: boolean Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes) SplinePoint.hidden -> hide: boolean Visibility status FModifier.muted -> mute: boolean F-Curve Modifier will not be evaluated note: rebaned uv_select to select_uv
2010-07-15 16:56:04 +00:00
if not s.select:
s.select = True
2010-05-16 12:15:04 +00:00
cfra = context.scene.frame_current
bpy.ops.sequencer.cut(frame=cfra, type='SOFT', side='RIGHT')
for s in context.scene.sequence_editor.sequences_all:
Apply first pass of edits to rna values from rna_booleans.txt. These are not animated and are best not change names like this too late in the release. ActionGroup.selected -> select: boolean Action Group is selected BezierSplinePoint.hidden -> hide: boolean Visibility status BezierSplinePoint.selected_control_point -> select_control_point: boolean Control point selection status BezierSplinePoint.selected_handle1 -> select_left_handle: boolean Handle 1 selection status BezierSplinePoint.selected_handle2 -> select_right_handle: boolean Handle 2 selection status Bone.restrict_select -> hide_select: boolean Bone is able to be selected Bone.selected -> select: boolean CurveMapPoint.selected -> select: boolean Selection state of the curve point EditBone.restrict_select -> hide_select: boolean Bone is able to be selected EditBone.selected -> select: boolean EditBone.selected_head -> select_head: boolean EditBone.selected_tail -> select_tail: boolean EditBone.locked -> lock: boolean Bone is not able to be transformed when in Edit Mode EditBone.hidden -> hide: boolean Bone is not visible when in Edit Mode NEGATE * FCurve.disabled -> enabled: boolean F-Curve could not be evaluated in past, so should be skipped when evaluating FCurve.locked -> lock: boolean F-Curve's settings cannot be edited FCurve.muted -> mute: boolean F-Curve is not evaluated FCurve.selected -> select: boolean F-Curve is selected for editing NEGATE * FCurve.visible -> hide: boolean F-Curve and its keyframes are shown in the Graph Editor graphs FCurveSample.selected -> select: boolean Selection status GPencilFrame.selected -> select: boolean Frame is selected for editing in the DopeSheet GPencilLayer.locked -> lock: boolean Protect layer from further editing and/or frame changes GPencilLayer.selected -> select: boolean Layer is selected for editing in the DopeSheet Keyframe.selected -> select: boolean Control point selection status Keyframe.selected_handle1 -> select_left_handle: boolean Handle 1 selection status Keyframe.selected_handle2 -> select_right_handle: boolean Handle 2 selection status MeshEdge.selected -> select: boolean MeshEdge.hidden -> hide: boolean MeshFace.hidden -> hide: boolean MeshFace.selected -> select: boolean MeshVertex.hidden -> hide: boolean MeshVertex.selected -> select: boolean MotionPathVert.selected -> select: boolean Path point is selected for editing NlaStrip.selected -> select: boolean NLA Strip is selected NlaTrack.locked -> lock: boolean NLA Track is locked NlaTrack.muted -> mute: boolean NLA Track is not evaluated NlaTrack.selected -> select: boolean NLA Track is selected Object.restrict_render -> hide_render: boolean Restrict renderability Object.restrict_select -> hide_select: boolean Restrict selection in the viewport Object.restrict_view -> hide: boolean Restrict visibility in the viewport Object.selected -> select: boolean Object selection state ObjectBase.selected -> select: boolean Object base selection state PoseBone.selected -> select: boolean Sequence.right_handle_selected -> select_right_handle: boolean Sequence.selected -> select: boolean SplinePoint.selected -> select_control_point: boolean Selection status TimelineMarker.selected -> select: boolean Marker selection state Sequence.left_handle_selected -> select_left_handle: boolean ActionGroup.locked -> lock: boolean Action Group is locked Bone.hidden -> hide: boolean Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes) SplinePoint.hidden -> hide: boolean Visibility status FModifier.muted -> mute: boolean F-Curve Modifier will not be evaluated note: rebaned uv_select to select_uv
2010-07-15 16:56:04 +00:00
if s.select and s.type == 'MULTICAM' and s.frame_final_start <= cfra and cfra < s.frame_final_end:
context.scene.sequence_editor.active_strip = s
2010-05-16 12:15:04 +00:00
context.scene.sequence_editor.active_strip.multicam_source = camera
return {'FINISHED'}
2010-05-16 12:15:04 +00:00
class SequencerDeinterlaceSelectedMovies(Operator):
"""Deinterlace all selected movie sources"""
bl_idname = "sequencer.deinterlace_selected_movies"
bl_label = "Deinterlace Movies"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return (context.scene and context.scene.sequence_editor)
def execute(self, context):
for s in context.scene.sequence_editor.sequences_all:
Apply first pass of edits to rna values from rna_booleans.txt. These are not animated and are best not change names like this too late in the release. ActionGroup.selected -> select: boolean Action Group is selected BezierSplinePoint.hidden -> hide: boolean Visibility status BezierSplinePoint.selected_control_point -> select_control_point: boolean Control point selection status BezierSplinePoint.selected_handle1 -> select_left_handle: boolean Handle 1 selection status BezierSplinePoint.selected_handle2 -> select_right_handle: boolean Handle 2 selection status Bone.restrict_select -> hide_select: boolean Bone is able to be selected Bone.selected -> select: boolean CurveMapPoint.selected -> select: boolean Selection state of the curve point EditBone.restrict_select -> hide_select: boolean Bone is able to be selected EditBone.selected -> select: boolean EditBone.selected_head -> select_head: boolean EditBone.selected_tail -> select_tail: boolean EditBone.locked -> lock: boolean Bone is not able to be transformed when in Edit Mode EditBone.hidden -> hide: boolean Bone is not visible when in Edit Mode NEGATE * FCurve.disabled -> enabled: boolean F-Curve could not be evaluated in past, so should be skipped when evaluating FCurve.locked -> lock: boolean F-Curve's settings cannot be edited FCurve.muted -> mute: boolean F-Curve is not evaluated FCurve.selected -> select: boolean F-Curve is selected for editing NEGATE * FCurve.visible -> hide: boolean F-Curve and its keyframes are shown in the Graph Editor graphs FCurveSample.selected -> select: boolean Selection status GPencilFrame.selected -> select: boolean Frame is selected for editing in the DopeSheet GPencilLayer.locked -> lock: boolean Protect layer from further editing and/or frame changes GPencilLayer.selected -> select: boolean Layer is selected for editing in the DopeSheet Keyframe.selected -> select: boolean Control point selection status Keyframe.selected_handle1 -> select_left_handle: boolean Handle 1 selection status Keyframe.selected_handle2 -> select_right_handle: boolean Handle 2 selection status MeshEdge.selected -> select: boolean MeshEdge.hidden -> hide: boolean MeshFace.hidden -> hide: boolean MeshFace.selected -> select: boolean MeshVertex.hidden -> hide: boolean MeshVertex.selected -> select: boolean MotionPathVert.selected -> select: boolean Path point is selected for editing NlaStrip.selected -> select: boolean NLA Strip is selected NlaTrack.locked -> lock: boolean NLA Track is locked NlaTrack.muted -> mute: boolean NLA Track is not evaluated NlaTrack.selected -> select: boolean NLA Track is selected Object.restrict_render -> hide_render: boolean Restrict renderability Object.restrict_select -> hide_select: boolean Restrict selection in the viewport Object.restrict_view -> hide: boolean Restrict visibility in the viewport Object.selected -> select: boolean Object selection state ObjectBase.selected -> select: boolean Object base selection state PoseBone.selected -> select: boolean Sequence.right_handle_selected -> select_right_handle: boolean Sequence.selected -> select: boolean SplinePoint.selected -> select_control_point: boolean Selection status TimelineMarker.selected -> select: boolean Marker selection state Sequence.left_handle_selected -> select_left_handle: boolean ActionGroup.locked -> lock: boolean Action Group is locked Bone.hidden -> hide: boolean Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes) SplinePoint.hidden -> hide: boolean Visibility status FModifier.muted -> mute: boolean F-Curve Modifier will not be evaluated note: rebaned uv_select to select_uv
2010-07-15 16:56:04 +00:00
if s.select and s.type == 'MOVIE':
s.use_deinterlace = True
2010-05-16 12:15:04 +00:00
return {'FINISHED'}
class SequencerFadesClear(Operator):
"""Removes fade animation from selected sequences"""
bl_idname = "sequencer.fades_clear"
bl_label = "Clear Fades"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
return context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip
def execute(self, context):
fcurves = context.scene.animation_data.action.fcurves
2019-09-22 23:31:08 +00:00
fcurve_map = {
curve.data_path: curve
for curve in fcurves
if curve.data_path.startswith("sequence_editor.sequences_all")
}
for sequence in context.selected_sequences:
animated_property = "volume" if hasattr(sequence, "volume") else "blend_alpha"
data_path = sequence.path_from_id() + "." + animated_property
curve = fcurve_map.get(data_path)
if curve:
fcurves.remove(curve)
setattr(sequence, animated_property, 1.0)
2019-09-22 23:35:27 +00:00
return {'FINISHED'}
class SequencerFadesAdd(Operator):
"""Adds or updates a fade animation for either visual or audio strips"""
bl_idname = "sequencer.fades_add"
bl_label = "Add Fades"
bl_options = {'REGISTER', 'UNDO'}
duration_seconds: bpy.props.FloatProperty(
name="Fade Duration",
description="Duration of the fade in seconds",
default=1.0,
min=0.01)
type: bpy.props.EnumProperty(
items=(
('IN_OUT', 'Fade In And Out', 'Fade selected strips in and out'),
('IN', 'Fade In', 'Fade in selected strips'),
('OUT', 'Fade Out', 'Fade out selected strips'),
('CURSOR_FROM', 'From Playhead', 'Fade from the time cursor to the end of overlapping sequences'),
('CURSOR_TO', 'To Playhead', 'Fade from the start of sequences under the time cursor to the current frame'),
),
name="Fade type",
description="Fade in, out, both in and out, to, or from the playhead. Default is both in and out",
default='IN_OUT')
@classmethod
def poll(cls, context):
# Can't use context.selected_sequences as it can have an impact on performances
return context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip
def execute(self, context):
from math import floor
# We must create a scene action first if there's none
scene = context.scene
if not scene.animation_data:
scene.animation_data_create()
if not scene.animation_data.action:
action = bpy.data.actions.new(scene.name + "Action")
scene.animation_data.action = action
sequences = context.selected_sequences
if self.type in {'CURSOR_TO', 'CURSOR_FROM'}:
sequences = [
s for s in sequences
if s.frame_final_start < context.scene.frame_current < s.frame_final_end
]
max_duration = min(sequences, key=lambda s: s.frame_final_duration).frame_final_duration
max_duration = floor(max_duration / 2.0) if self.type == 'IN_OUT' else max_duration
faded_sequences = []
for sequence in sequences:
duration = self.calculate_fade_duration(context, sequence)
duration = min(duration, max_duration)
if not self.is_long_enough(sequence, duration):
continue
animated_property = 'volume' if hasattr(sequence, 'volume') else 'blend_alpha'
fade_fcurve = self.fade_find_or_create_fcurve(context, sequence, animated_property)
fades = self.calculate_fades(sequence, fade_fcurve, animated_property, duration)
self.fade_animation_clear(fade_fcurve, fades)
self.fade_animation_create(fade_fcurve, fades)
faded_sequences.append(sequence)
sequence_string = "sequence" if len(faded_sequences) == 1 else "sequences"
2019-09-22 23:35:27 +00:00
self.report({'INFO'}, "Added fade animation to {} {}.".format(len(faded_sequences), sequence_string))
return {'FINISHED'}
def calculate_fade_duration(self, context, sequence):
frame_current = context.scene.frame_current
duration = 0.0
if self.type == 'CURSOR_TO':
duration = abs(frame_current - sequence.frame_final_start)
elif self.type == 'CURSOR_FROM':
duration = abs(sequence.frame_final_end - frame_current)
else:
duration = calculate_duration_frames(context, self.duration_seconds)
return max(1, duration)
def is_long_enough(self, sequence, duration=0.0):
minimum_duration = duration * 2 if self.type == 'IN_OUT' else duration
return sequence.frame_final_duration >= minimum_duration
def calculate_fades(self, sequence, fade_fcurve, animated_property, duration):
"""
Returns a list of Fade objects
"""
fades = []
if self.type in {'IN', 'IN_OUT', 'CURSOR_TO'}:
fade = Fade(sequence, fade_fcurve, 'IN', animated_property, duration)
fades.append(fade)
if self.type in {'OUT', 'IN_OUT', 'CURSOR_FROM'}:
fade = Fade(sequence, fade_fcurve, 'OUT', animated_property, duration)
fades.append(fade)
return fades
def fade_find_or_create_fcurve(self, context, sequence, animated_property):
"""
Iterates over all the fcurves until it finds an fcurve with a data path
that corresponds to the sequence.
Returns the matching FCurve or creates a new one if the function can't find a match.
"""
fade_fcurve = None
fcurves = context.scene.animation_data.action.fcurves
searched_data_path = sequence.path_from_id(animated_property)
for fcurve in fcurves:
if fcurve.data_path == searched_data_path:
fade_fcurve = fcurve
break
if not fade_fcurve:
fade_fcurve = fcurves.new(data_path=searched_data_path)
return fade_fcurve
def fade_animation_clear(self, fade_fcurve, fades):
"""
Removes existing keyframes in the fades' time range, in fast mode, without
updating the fcurve
"""
keyframe_points = fade_fcurve.keyframe_points
for fade in fades:
for keyframe in keyframe_points:
# The keyframe points list doesn't seem to always update as the
# operator re-runs Leading to trying to remove nonexistent keyframes
try:
if fade.start.x < keyframe.co[0] <= fade.end.x:
keyframe_points.remove(keyframe, fast=True)
except Exception:
pass
fade_fcurve.update()
def fade_animation_create(self, fade_fcurve, fades):
"""
Inserts keyframes in the fade_fcurve in fast mode using the Fade objects.
Updates the fcurve after having inserted all keyframes to finish the animation.
"""
keyframe_points = fade_fcurve.keyframe_points
for fade in fades:
for point in (fade.start, fade.end):
keyframe_points.insert(frame=point.x, value=point.y, options={'FAST'})
fade_fcurve.update()
# The graph editor and the audio waveforms only redraw upon "moving" a keyframe
keyframe_points[-1].co = keyframe_points[-1].co
class Fade:
# Data structure to represent fades.
__slots__ = (
"type",
"animated_property",
"duration",
"max_value",
"start",
"end",
)
def __init__(self, sequence, fade_fcurve, type, animated_property, duration):
from mathutils import Vector
self.type = type
self.animated_property = animated_property
self.duration = duration
self.max_value = self.calculate_max_value(sequence, fade_fcurve)
if type == 'IN':
self.start = Vector((sequence.frame_final_start, 0.0))
self.end = Vector((sequence.frame_final_start + self.duration, self.max_value))
elif type == 'OUT':
self.start = Vector((sequence.frame_final_end - self.duration, self.max_value))
self.end = Vector((sequence.frame_final_end, 0.0))
def calculate_max_value(self, sequence, fade_fcurve):
"""
Returns the maximum Y coordinate the fade animation should use for a given sequence
Uses either the sequence's value for the animated property, or the next keyframe after the fade
"""
max_value = 0.0
if not fade_fcurve.keyframe_points:
max_value = getattr(sequence, self.animated_property, 1.0)
else:
if self.type == 'IN':
fade_end = sequence.frame_final_start + self.duration
keyframes = (k for k in fade_fcurve.keyframe_points if k.co[0] >= fade_end)
if self.type == 'OUT':
fade_start = sequence.frame_final_end - self.duration
keyframes = (k for k in reversed(fade_fcurve.keyframe_points) if k.co[0] <= fade_start)
try:
max_value = next(keyframes).co[1]
except StopIteration:
pass
return max_value if max_value > 0.0 else 1.0
def __repr__(self):
return "Fade {}: {} to {}".format(self.type, self.start, self.end)
def calculate_duration_frames(context, duration_seconds):
return round(duration_seconds * context.scene.render.fps / context.scene.render.fps_base)
classes = (
SequencerCrossfadeSounds,
SequencerCutMulticam,
SequencerDeinterlaceSelectedMovies,
SequencerFadesClear,
SequencerFadesAdd,
)