2
$\begingroup$

In my script I get access to all selected strips using below code:

selection = [ seq for seq in context.scene.sequence_editor.sequences if seq.select and seq.type == 'SPEED' ]

Now, this gives me a list of speed effects from the selection. I want to modify (basically remove and insert new) the FCurve for the speed_factor property. However I can't see how can I access the FCurves for this specific property.

I see than I can access all scene FCurves through bpy.context.scene.animation_data.action.fcurves. However this seems to have at least two problems:

  • I don't know how to properly create data_path having only SpeedControlSequence instance (the only thing I can think of is some string concatenations, but it doesn't sound like right solution),
  • even if I had data_path value I am looking for I would have to scan through all FCurves for the whole scene to get to the one I want, which doesn't sound very efficient.

How can I access, modify and replace FCurves if I have specific instance of Sequence?

edit:

One solution seems to be:

seq = # code to get one sequence instance
f = None
for f in bpy.context.scene.animation_data.action.fcurves:
    if f.data_path == seq.path_from_id("speed_factor"):
        break
else:
    f = None

However it seems to be highly inefficient way of approaching that issue. Is there a better way to do it?

$\endgroup$
  • 2
    $\begingroup$ It's possible that you have come across the best answer. Do you mind moving your proposed solution from the question to a separate answer? That way people can vote on it alongside other answers. Also, it makes the question more concise. $\endgroup$ – Garrett Apr 5 '14 at 21:51
  • $\begingroup$ It is indeed the only way (checking the data_path), and you can only optimize it using a dict if you know you'll need to find several F-Curves in the same action (create a lookup dict once with the data_path as key and the F-Curve as value, then access different F-Curves via the key you are after. You may need to add the .array_index to the key for properties like loc/rot/scale). $\endgroup$ – CoDEmanX May 5 '14 at 23:58
2
$\begingroup$

I will wait few days before accepting my own answer. Maybe someone else will have a better idea.

Due to lack of other answers and request to do so I will give what I am currently using. I still feel like it is not the best approach, but it as well may be (I don't know Blender's API that well, just started learning).

I've created an operator that takes all selected speed effects and given the original frame rate of clips (I haven't found a way to get that automatically from movie sequences) creates linear interpolation curve for speed effect. It is is more useful than constant speed value as you can then go and edit curve not having to work out how it should look like to get original speed in your final edit (it also creates meta strip that actually is trimmed correctly so it appears in correct size in VSE, but that part is omitted as it is outside the scope of the question).

def execute(self, context):  
    # filter out non speed effects
    selection = [ seq for seq in context.scene.sequence_editor.sequences if seq.select and seq.type == 'SPEED' ]

    # get render frame rate and calculate how to scale input movie fps
    fc = context.scene.frame_current
    fps = bpy.context.scene.render.fps
    fcurves = bpy.context.scene.animation_data.action.fcurves
    factor = fps / self.original_framerate 

    # remove current fcurves for speed_factor if there are any
    # we create set for faster lookups (at least I'd home it would be faster than naïve approach
    paths_to_remove = set((s.path_from_id("speed_factor") for s in selection))
    for f in fcurves:
        if f.data_path in paths_to_remove:
            fcurves.remove(f)

    for s in selection:
        s.use_default_fade = False
        s.use_as_speed = False
        factor = fps / self.original_framerate 
        final_duration = s.input_1.frame_duration*factor
        final_duration = s.input_1.frame_duration*factor

        # create curve for this speed effect and add two keyframes
        curve = fcurves.new( s.path_from_id("speed_factor") )
        start_key = curve.keyframe_points.insert( s.frame_start, 0 )
        start_key.interpolation = 'LINEAR'
        end_point = curve.keyframe_points.insert( s.frame_start + final_duration, s.input_1.frame_duration )
        end_point.interpolation = 'LINEAR'
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.