1

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?

Ray Mairlot
  • 29,192
  • 11
  • 103
  • 125
Roland
  • 33
  • 4

2 Answers2

2

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_screen=False):
    '''
    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
    else:
        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)
bpy.ops.wm.save_mainfile()

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.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • You sir are my hero for the day. May good things come your way. – doakey3 Jun 17 '18 at 20:15
  • 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. – MRL Oct 12 '21 at 15:14
0

batFINGER's answer is great, but I was getting an incorrect context error until I selected the object I was trying to bake the sound curve onto.

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

speaker = bpy.data.speakers["Speaker"] obj.select_set(True) # This was important bpy.ops.graph.sound_bake(c, filepath=speaker.sound.filepath)

struny
  • 1
  • 1