I'm making an audio visualizer which I want to render from the command line. Unfortunately the bpy.ops.graph.sound_bake() function seems only to work from the GUI.

I've found various tutorials, but they all use the gui to create the animation. They always require this fix

bpy.context.area.type = 'GRAPH_EDITOR'

to set the correct context for bpy.ops.graph.sound_bake() to work. This works for scripts run from the gui, but when a script is started from he command line bpy.context.area is undefined.

For materials I already found that instead of bpy.ops.material.new() I should use mat = bpy.data.materials.new("") to avoid problems with the context. I have not been able how to work out how to do something similar with sounds.

It seems in scripting, using bpy.ops.* can easily give problems with the context, as these function might check the mouse position for some reason, etc. and there would/should be alternative functions. I have no clue on how to find those alternatives. So far I found them by chance, but I have not been able to find an alternative for bpy.ops.graph.sound_bake()

How can I bake an mp3 to an fcurve and apply that curve to an object, in a script?


For Sound Drivers Addon I do a lot of sound baking, so I thought I'd check out how it would perform running in background mode (this has led to another q re running modal timer operators in bg mode). Anyhow using context override the following bakes in bg mode using command

blender -b ./Desktop/baketest.blend --python-text bake.py

using the following as a text block named bake.py.

import bpy
#from sound_drivers.utils import get_context_area
def get_context_area(context, context_dict, area_type='GRAPH_EDITOR',
    context : the current context
    context_dict : a context dictionary. Will update area, screen, scene, 
                   area, region
    area_type: the type of area to search for
    context_screen: Boolean. If true only search in the context screen.
    if not context_screen:  # default
        screens = bpy.data.screens
        screens = [context.screen]
    for screen in screens:
        for area_index, area in screen.areas.items():
            if area.type == area_type:
                for region in area.regions:
                    if region.type == 'WINDOW':
                        context_dict["area"] = area
                        context_dict["screen"] = screen
                        context_dict["scene"] = context.scene
                        context_dict["window"] = context.window
                        context_dict["region"] = region
                        return area
    return None

c = bpy.context.copy()
get_context_area(bpy.context, c)
obj = bpy.data.objects["Cube"]
obj["y"] = 0.0
obj.keyframe_insert('["y"]', frame=1)

speaker = bpy.data.speakers["Speaker"]
bpy.ops.graph.sound_bake(c, filepath=speaker.sound.filepath)

Note for convenience sake I grabbed the filepath from a speaker's sound. This successfully baked the sound file onto the "y" custom property of the Cube in bg mode.

Use something like How to pass command line arguments to a Blender Python script? to extend functionality,.

NB: Example of creating a simple sound visualiser using sound_drivers.

  • $\begingroup$ You sir are my hero for the day. May good things come your way. $\endgroup$
    – doakey3
    Jun 17 '18 at 20:15
  • $\begingroup$ There is trouble with selecting only channel ["y"] in the graph editor. So at the start it somehow have to deselect all channels, groups, objects > then select only obj["y"] and then bpy.ops.graph.sound_bake. But with the blender background deselecting is somehow tricky, I don't know how to do that properly trough bpy.data.. because data.actions[].groups[].select ... is not setable trough text editor. $\endgroup$
    – MRL
    Oct 12 at 15:14

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.