Locking fcurves

I’ve been trying to create a sound visualisation with the help of the Blender Cookie tutorial by Patrick Boelens and at the moment my script works fine. However, if I select all of my objects to animate and scale them using individual origins parallel to their local z-axes, and I try running my script I get an error at

bpy.context.active_object.animation_data.action.fcurves[0].lock = True

which says AttributeError: ‘NoneType’ object has no attribute ‘action’. Here is my full script:


def insert(item):
    i = 0
    sorting = True
    while ((sorting) and (i < len(items) - 1)):
        if (item.location.y <= items[i].location.y):
            sorting = False
            items.append(items[len(items) - 1])
            j = len(items) - 2
            while (j >= i):
                items[j+1] = items[j]
                j-=1
            items[i] = item
        i+=1
    if (i >= len(items) - 1):
        items.append(item)

import bpy
bpy.ops.object.select_all(action='DESELECT')
items = []
for object in bpy.data.groups['Things'].objects:
    object.select = True
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    bpy.ops.anim.keyframe_insert_menu(type='Scaling')
    bpy.context.active_object.animation_data.action.fcurves[0].lock = True
    bpy.context.active_object.animation_data.action.fcurves[1].lock = True
    insert(object)
    object.select = False
    
bpy.ops.object.select_all(action='DESELECT')
bpy.context.area.type = 'GRAPH_EDITOR'
step = 16000 / len(items)
i = 0
for object in items:
    object.select = True
    bpy.ops.graph.sound_bake(filepath="/home/Music File.mp3", low=i * step, high=(i + 1) * step)
    object.select = False
    i+=1

Why does this error only just happen after scaling and how can I fix it?
Thanks.

Objects have no animation_data by default, it will be None. Either check if there is, or animation_data_create() it if appropriate.

.action may also be None, so you should test for that case too.

Accessing F-Curves via indices can be problematic:
.fcurves[0]

It’s better if you iterate over F-Curves and check their data_path and array_index attributes to find the ones you are actually after.

Thanks for the information; animation_data_create() fixed the action attribute error I think, but I now get ‘NoneType’ object has no attribute ‘fcurves’ and I don’t know how to iterate over the F-curves like you suggested (especially as there is a problem when using action.fcurves.data_path or action.fcurves[0].data_path). Please could you elaborate some more, perhaps with code examples. Thanks.

You’re not supposed to create animation data if you don’t need it…

As I said, neither is .action guaranteed to be something. If there’s animation_data but no action, it will be None.


for ob in bpy.context.selected_objects:
    if ob.animation_data is not None:
        action = ob.animation_data.action
        if action is not None:
            for fcu in action.fcurves:
                if (fcu.data_path == 'scale' # check for simple scaling anims
                    and fcu.array_index == 2): # but only for z-axis

                    fcu.lock = True

This definitely helped (although I don’t understand why), and I eventually got my script to work with a good success rate with the addition of

animation_data.action.fcurves.new(data_path=“scale”, index=2)

Thanks very much!

All that does is to add a new empty F-Curve for the z-“scale” property animations, animation_data and and an action are automatically created if not present.