Building an Audio Visualizer in Python

In this Blender 2.5 video tutorial, we will be taking a look at how to use sound to drive an object’s scale.

We will be building a ‘field’ of cubes, each of which will pulse along to certain frequencies of a song.

What is covered in this tutorial:
– Baking sound to F-curves.
– Programatically creating an N-by-M matrix (field/ grid)
– Setting a keyframe and baking F-curves from Python
– Finding out which frequencies to use using Audacity

Note: In recent SVN versions the API has been updated. If you’re using one of these later versions please be sure to replace “bpy.ops.object.scale_apply()” with “bpy.ops.object.transform_apply(scale=True)

Leave Comment

Discussion

344 Responses to “Building an Audio Visualizer in Python”
  1. Posts: 1
    Adi says:

    would it be possible to create a grid of little squares, each of them changing its color corresponding to the volume of its own audio file?

    the reason i ask is the following:
    i am an audio engineer and i would like to visualize room mode patterns (which consist of sound pressure differences in a room because of interfering sound waves). To record the audio files, i would divide the room into a grid and record a sweep (a sine tone that sweeps from 20Hz to 20kHz) on each of those measuring positions. e.g. if i would divide the room in a 10×12 grid, i would end up with 120 audio files.

    then i would need a similar script but the differences would be:
    – the bars should not move, they should rather be flat surfaces
    (or think: bars with a height of zero)
    – instead they should change color (where green would be an amplitude of zero, red would be an amplitude of 1)
    – the surfaces can ignore the frequency given
    – each surface would have its own file
    – the grid would have to be editable, to match the rooms that i want to measure

    Now i really don’t know how difficult and/or time-consuming such a script would be, but i imagine that it is less tricky than the one mentioned here..
    So if i’m right, could someone please help me in programming this?

    i would be very thankful
    looking forward to your answers.

  2. Posts: 2
    anders malik says:

    Hey thanks so much for the tut, here is what i came up with, mixed it up with some smoke effects

      • Posts: 4
        Lance Wagner says:

        I know you posted this awhile ago, but I’m trying to into python, and I would like to see what others have learned from these tutorials. This tutorial mixed with smoke particles sounds cool. I clicked on your link, but it says the video is private. Is there any way I can see the video?

  3. Posts: 1
    Marco says:

    hi

    I just want to try this for bender but it dont works like i want^^.
    It´s a Phython script fail.

    import bpy

    rows = 5
    columns = 5

    r = 0
    c = 0

    for i in range (0, rows*columns):
    if c == columns:
    r += 1
    c = 0

    bpy.ops.mesh.primitive_cube_add(location = (r, c, 0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location
    bpy.context.scene.cursor_location.z -= 1
    bpy.ops.object.origin_set(type = ‘ORIGIN_CURSOR’)
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 5
    bpy.ops.object.scale_apply()

    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

    bpy.context.area.type = ‘GRAPH_EDITOR’

    step = 20000 / (rows*columns)
    bpy.ops.graph.sound_bake(filepath=”C:\Users\Marco\Hardstyle\First Try1.MP3″, low=i*step, high=i*step + step)

    bpy.context.active_object.animation_data.action.fcurves [2]. lock = true

    c += 1

  4. Posts: 2
    Balázs Varga says:

    The biggest cube is too big for me. Can somebody tell me how to lessen its scaling values?

    • Posts: 2
      Balázs Varga says:

      Got it :)

  5. Posts: 7
    scherzo says:

    After baking to the sound, I find I can’t move my keyframes around. It’s not a huge problem, but is this normal, or is it a bug? Anyway, my visualizer works great. Thanks for another epic tutorial!

    • Posts: 491
      Metalix says:

      I believe this is how it is supposed to be, though I haven’t looked through this tutorial but have done similar things and locked off my animation.
      -Alex

  6. Posts: 1
    Prashanth says:

    Thank you for this Amazing tutorial – Good work! :-)

  7. Posts: 2
    Alex says:

    What did I do wrong?

    import bpy

    rows = 5
    columns = 5

    r = 0
    c = 0

    for i in range(0, rows*columns):
    if c == columns:
    r += 1
    c = 0

    bpy.ops.mesh.primitive_cube_add(location = (r, c, 0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location
    bpy.context.scene.cursor_location.z -= 1
    bpy.ops.object.origin_set(type=”ORIGIN_CURSOR”)
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 5
    bpy.ops.object.transform_apply(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

    bpy.context.area.type = ‘GRAPH_EDITOR’

    step = 20000/ (rows*columns) bpy.ops.graph.sound_bake(filepath=”C:/Documents and Settings/Metrowerks.SLAB20/My_Documents/DownloadsUp All Night (audio) by Blink 182 – Interscope”, low=i*step, high=i*step + step)

    bpy.context.active_object.animation_data.action.fcurves[2].lock = true

    c += 1

    • Posts: 2
      Alex says:

      more or less, I can’t figure out line 32, which is the steps. I’m guessing it’s the way I’m entering it, but I’m just not figuring how to do it.

  8. Posts: 1
    kenfitz says:

    it keeps on saying “IndentationError: unexpected indent”
    where’s the problem?

    import bpy

    rows=122
    colunms=122

    r=0
    c=0

    for i in range(0, rows*columns),
    if c == columns,
    r += 1
    c = 0

    bpy.ops.mesh.primitive_cube_add(location = (r, c, 0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location
    bpy.context.scene.cursor_location z -= 1
    bpy.ops.object.origin_set(type=’ORIGIN_CURSOR’)
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 4
    bpy.ops.object.scale_apply()

    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

    bpy.context.area.type = ‘GRAPH_EDITOR’

    step = 15000/ (rows*columns)
    bpy.ops.graph.sound_bake(filepath=”/home/kenfitz/Music/electro/deadmau5 – There might be coffee.mp3″, low=i*step, high=i*step + step)

    bpy.context.active_object.animation_data.action.fcurves(2).lock = True

    c += 1

  9. Posts: 4

    Ok, here is my turn to ask for help, this is my script:

    import bpy

    rows = 5
    columns = 5

    r = 0
    c = 0

    for i in range(0, rows*columns):
    if c == columns:
    r += 1
    c = 0

    bpy.ops.mesh.primitive_cube_add(location = (r,c,0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location
    bpy.context.scene.cursor_location.z -= 1
    bpy.ops.object.origin_set(type= ‘ORIGIN_CURSOR’)
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 5
    bpy.ops.object.transform_apply(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

    bpy.context.area.type=’GRAPH_EDITOR’

    step = 20000/ (rows*columns)
    bpy.ops.graph.sound_bake(filepath=’C:\Users\User\Documents\gerra\3638148_Trilogy_Pome_Research_Lab_Rework.mp3′, low=i*step, high=i*step + step)
    bpy.context.active_object.animation_data.action.fcurves[2].lock = true

    c += 1

    and here is the weird error I get as output, while pressing alt-p:

    on line 33 (which is “bpy.ops.graph.sound_bake(filepath=’C:\Users\User\Documents\gerra\3638148_Trilogy_Pome_Research_Lab_Rework.mp3′, low=i*step, high=i*step + step) “)

    SyntaxError:
    (Unicode error)’unicodeescape’ codec can’t decode bytes on position 2-4: truncated \UXXXXXXXX escape
    location:: -1

    Anyone wishing to help me please?

    • Posts: 4

      ok, done, the problem was the string:

      bpy.ops.graph.sound_bake(filepath=’C:\Users\User\Documents\gerra\3638148_Trilogy_Pome_Research_Lab_Rework.mp3′, low=i*step, high=i*step + step)

      to

      “bpy.ops.graph.sound_bake(filepath=r’C:\Users\User\Documents\gerra\3638148_Trilogy_Pome_Research_Lab_Rework.mp3′, low=i*step, high=i*step + step)

  10. Posts: 2

    The only problem with this tutorial is that it splits the spectrum with a fixed step: 15000/ (rows*columns). That’s not how we humans hear, and music is made. He should split it somehow along a logarithmic scale. This is the reason why at the beginning of the row there’s plenty action, but towards to the end there’s hardly any change. If it was using logarithmic scale, the beginning would be expanded to almost the complete series, making it muck more awesome. I don’t really know how to create a logarithmic scale, but if you do, you should try that instead of just using a fixed step.

    Anything other than that, this is a really awesome tutorial.

    • Posts: 2

      The easiest way to create a logarithmic scale is to use powers of a number. I’ll be using powers of 2. Start off with a step of 10, and multiply with two each time, getting a series of: 10, 20, 40, 80, 160, 360, 720, 1440, 2880, 5760, 11520, 23040.
      The lowest frequency the human ear perceives is 20Hz, but we don’t need to throw out our first number, just add 10, to each getting the series: 20, 30, 50, 90, 170, 270, 730, 1450, 2890, 5770, 11530, 23050
      As he used ~1500 as step size, in our series he showed 8 values with a single one, even tho these contain beautiful information. At the end of this series there’s like 5 steps packet to a single one, because those are only similar, boring stuff.

      You can play more with such scales taking in account for example that C is 440Hz, and is in many keys used in songs. Thus most songs contain note information between 440Hz and 880Hz (that’s exactly an octave). So if you were to show the temporal scale, one note exactly to a single bar, it should become visible how someone plays the piano for example.

      • Posts: 4

        I’ll take a look to it this week, maybe try one of your suggestions, still didn’t finish the work for Pome, my friend, I’ll get in touch with news.

  11. Posts: 2
    Oscar Paz says:

    hi, i cant make it work.

    my script looks like this

    import bpy

    columns = 5
    row = 5

    r = 0
    c = 0

    def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = -1
    for i in range(max(X, Y)**2):
    if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
    bpy.ops.mesh.primitive_cube_add (location= (x,y,0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location
    bpy.context.scene.cursor_location.z -= 1
    bpy.ops.object.origin_set(type = ‘ORIGIN_CURSOR’)
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 5
    bpy.ops.object.scale_apply()

    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

    bpy.context.area.type = ‘GRAPH_EDITOR’

    step = 20000 / (rows*columns)
    bpy.ops.graph.sound_bake(filepath="M:\Proyectos\Datashow\telmex\audios finales\Performance3Talento_Final.mp3", low=i*step, high=i*step + step)

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

    if x == y or (x 0 and x == 1-y):
    dx, dy = -dy, dx
    x, y = x+dx, y+dy

    spiral (row, columns)

    i got this an invalid character identifier Line 25 please help

  12. Posts: 1
    Reed Novak says:

    Has anyone figured out the code? It seems to be a common error among us.

  13. Posts: 1

    Thanks for the tutorial. I did this quite some time ago and just signed up for Blender Cookie and thought I would post the video that I created from this tutorial.
    http://vimeo.com/29214534
    Let me know what you think of it. Again, thanks for the intro to Python

  14. Posts: 1
    kristenm says:

    I am new to Blender, Can someone please let me know where I went wrong? Everytime I try to Run scrypt it says Python script fail, look in console for now…
    Thankyou.

    import bpy

    rows = 5
    columns = 5

    r = 0
    c = 0

    def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = -1
    for i in range(max(X, Y)**2):
    if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
    bpy.ops.mesh.primitive_cube_add(location = (x, y, 0))
    bpy.context.scene.cursor_location = bpy.context.active_object.location = bpy.context.active_object.location
    bpy.context.scene.cursor_location.z -= 1
    bpy.ops.origin_set(type='ORIGIN_CURSOR')
    ####
    bpy.context.active_object.scale.x = 0.5
    bpy.context.active_object.scale.y = 0.5
    bpy.context.active_object.scale.z = 5
    bpy.ops.object.transform_apply(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

    bpy.context.area.type = 'GRAPH_EDITOR'

    step = 20000/ (rows*columns)
    bpy.ops.graph.sound_bake(filepath ="C:\Users\Morales\Desktop\Birds in The Stratosphere.wav", low=i* step, high=i* step + step

    bpy.context.active_object.animation_data.action.fcurves[2].lock = True
    if x == y or (x 0 and x == 1-y):
    dx, dy = -dy, dx
    x, y = x+dx, y+dy

    spiral(rows, columns)

    • Posts: 584
      richard w says:

      If you have any coding problems, then please either use pasteall.org or use underscores to represent the indentation. It makes it very hard to find the problem if I can’t see the code how you see it.

    • Posts: 584
      richard w says:

      A note about copying the code from pasteall.org: if you highlight everything and paste, then you’ll likely have an extra tab/4 spaces on the left of each line. Copy using pasteall’s ‘copy to clipboard’ button to avoid this issue.

  15. Posts: 1
    k0rantu2 says:

    what should i do if its saying:”Python script fail, look in the console for now…”

    • Posts: 584
      richard w says:

      Either run Blender via a terminal/command line interface or you might get some information if you pull the information bar down a little: http://www.pasteall.org/pic/74938

      The information window may not provide all of the information about what went wrong, so for debugging, running Blender via a terminal is advised. (You can occasionally get the annoying situation where even the terminal only tells you to look in the terminal for more information and then you’re stuck.)

      If you don’t understand the output of the terminal, then try the code I uploaded to the link above. I’ve made an updated version of the script that runs on 2.7x. There are differences in the API that mean the code provided in the tutorial won’t work any more in later versions of Blender and it may just be that causing the problem.

Leave a Comment

You must be logged in to post a comment.