Audacity labels to Timeline Markers script.

[EDIT] The scripts are now Add-ons. :smiley:

Hello,

As you might know Audacity has the ability to do some very nice audio analyzing like beat finding etcetera and displays this data as Labels. These Labels can be exported to a simple .txt file. To make use of this within Blender I wrote a little Add-on which converts these Labels into Timeline Markers (not the actual Label names but just the start times for each Label).
[EDIT] Iā€™ve also included an Add-on which does the reverse and saves Blenderā€™s Timeline Markers to an Audacity Labels (.txt) file.

Iā€™m not a programmer so forgive me if my code is being very sloppy, but it seems to work fine for me so I just wanted to share it, maybe itā€™s useful for someone out there as wellā€¦ :cool:

(btw. I forgot if Audacity comes standard packed with those awesome analyzing tools, if not I think to remember I got those extra plugins with Sonicvisualiser, either way the Label system is a standard feature of Audacity)

The Add-ons are in the AudacityLabelsAddons.zip attachment. An example labels.txt file generated by Audacity is also available in the attachments.
Current version: 0.3

gREEtZ,
tumtidum

Attachments

AudacityLabelsAddons.zip (3.2 KB)LabelsExample.zip (914 Bytes)

1 Like

Hey cool idea, thanks! I donā€™t mind sloppy code, mine is sloppy too :slight_smile:

Hey thats really interesting. Thankyou.

I was wondering if there is a way to reverse the process and send markers to Audacity? For example I might like to indicate where edits or animation beats occur in Blender and use them as ques in Audacity.



<b>import</b> bpy
 
scene <b>=</b> bpy<b>.</b>context<b>.</b>scene
 
fps <b>=</b> scene<b>.</b>render<b>.</b>fps
fps_base <b>=</b> scene<b>.</b>render<b>.</b>fps_base
 
<b>def</b> <b>frame_to_time</b>(frame_number):
    raw_time <b>=</b> (frame_number <b>-</b> 1) <b>/</b> fps
    <b>return</b> round(raw_time, 3)
 
<i># key frames, try this with location </i>
<i># keyframes on a cube</i>
<b>print</b>('---') 
<b>for</b> key <b>in</b> bpy<b>.</b>data<b>.</b>actions[0]<b>.</b>fcurves: 
    <b>for</b> marker <b>in</b> key<b>.</b>keyframe_points:
        frame <b>=</b> marker<b>.</b>co<b>.</b>x
        frame_time <b>=</b> frame_to_time(frame)
        <b>print</b>(frame, frame_time)        
    <b>break</b>
 
<i># time line markers</i>
<b>for</b> k, v <b>in</b> scene<b>.</b>timeline_markers<b>.</b>items():
    frame <b>=</b> v<b>.</b>frame
    frame_time <b>=</b> frame_to_time(frame)
    <b>print</b>(frame, frame_time)    

This will output frame number of the Marker/Keyframe and the time_stamp associated with it in milliseconds.

A little update to V 0.2 alpha (you can get it from the attachment in the first post).
Some analyzing plugins apparently write commas instead of points in the labels.txt files which caused the script to fail, that should be fixed now. Also the the scene doesnā€™t have to be called ā€œSceneā€ anymore.

@3pointEdit
Yes, that should be possible. Iā€™ll have a look into that as well, but no promises since Iā€™m just learning bits of python on the go. :rolleyes:

You doing better than me. I never understood the vse pyrhon. All the tutorials are for creating 3d stuff.

@zeffii
hEyA, thanks mate! I had been working on my own version, before I had a look at your post, and almost got it working, but your code is much cleaner anyway and it actually works!
Iā€™ve made minor adjustments to your code so itā€™ll save the output in a manner Audacity understands. Since I wanted to just focus on Markers and Labels I also took out the Keyframing part, hope you wonā€™t mind. :stuck_out_tongue:

Iā€™ve added the Markers2Labels.py to the attachment in the first post.
Thanks again, great job! :wink:

not at all, if you learnt something - thatā€™s great.

Do either of you think itā€™s possible to send cut media from vse to audacity. That is trimmed tops and tails then placed at the correct time? Not sure of audacity does some sort of omfi import.

@tumtidum

A little bit more pythonic still, using with open as log, and adjusting for fps_base (if custom fps)


<b>import</b> bpy
 
scene <b>=</b> bpy<b>.</b>context<b>.</b>scene
fps <b>=</b> scene<b>.</b>render<b>.</b>fps
fps_base <b>=</b> scene<b>.</b>render<b>.</b>fps_base
 
<b>if</b> <b>not</b> fps_base <b>==</b> 1.0:
    fps <b>=</b> fps <b>/</b> fps_base
 
<b>with</b> open('/PathToWhereYouWantToSave/B-labels.txt', 'w') <b>as</b> log:
 
    <b>print</b>('---')
    <b>def</b> <b>frame_to_time</b>(frame_number):
        raw_time <b>=</b> (frame_number <b>-</b> 1) <b>/</b> fps
        <b>return</b> round(raw_time, 3)
     
    <b>for</b> k, v <b>in</b> scene<b>.</b>timeline_markers<b>.</b>items():
        frame_time <b>=</b> frame_to_time(v<b>.</b>frame)
        <b>print</b>(frame_time, v<b>.</b>frame, file <b>=</b> log)

@zeffii
Although coding doesnā€™t come naturally to me (something which takes me hours to do, you probably write in minutes), I did have learnt something about it! :yes:
When I have the time and am able to wrap my head around it, Iā€™ll try to make these scripts as an import/export add-on with proper file selections, and also include the more pythonic manner as you as used above.
For now Iā€™m just glad itā€™s actually usable.

@3pointEdit
Think that should be possible as well, but Iā€™m afraid Iā€™ll be well over my head trying to make something like that. :spin:

just a heads up, frame_to_time is a builtin function (only recently noticed it, but it might be there for years) from


bpy.utils.time_from_frame()  
bpy.utils.frame_from_time()

Update to version 0.3

Iā€™ve made both import and export scripts available as addons! For ease of use Iā€™ve also implemented proper file selections. When activated theyā€™ll be accessible from the Info, File, Import/Export menu.
You can download the addons at the first post. If you donā€™t know how to install addons the .zip file also contains a README.txt which should explain all of that.

@zeffii
Ah pretty useful indeed, although I only used it with the import part since I couldnā€™t quite figure out how to use it for the export part.

That is really cool for sending my mixdown to Audacity for sound post. I wonder if I can automate Blender to place markers at VSE strip start and end frames? They would become cutpoints (unless a sounmd overlaps of course)

@3pointEdit
Yes, thatā€™s possible. I gave it a little go and came up with this:


## This should place Timeline Markers at the start & end of each
## selected strip in the Video Sequence Editor. gREEtZ, tumtidum.

import bpy

scene = bpy.context.scene
default_frame = scene.frame_current
default_area = bpy.context.area.type
bpy.context.area.type = ('TIMELINE')
seq = bpy.context.selected_sequences
a = (len(seq))
b = 0

if a &gt; 0:
    print('---')
    while b &lt; a:
        scene.frame_current = (seq[b].frame_final_start)
        bpy.ops.marker.add()
        scene.frame_current = (seq[b].frame_final_end)
        bpy.ops.marker.add()
        b=b+1
    bpy.ops.marker.select_all(action='TOGGLE')
else:
    print('No strips selected...')

scene.frame_current = default_frame
bpy.context.area.type = default_area

Not sure how buggy it is, but again also this seems to work quite fineā€¦ itā€™s almost like Iā€™m actually starting to understand a thing or two about pythonā€¦ :eek:

Omg. Youā€™re smarter than me! Thanks. Would you mind commenting the lines of the script so I could understand the process better. Especially the definitions at the start?

NP, hope it makes senseā€¦ :wink:


## This should place Timeline Markers at the start & end of each
## selected strip in the Video Sequence Editor. gREEtZ, tumtidum.

import bpy

scene = bpy.context.scene

## Getting the current frame and assign it to "default_frame" so it can be set
## back at the end of the script. Not really needed, but just neat.
default_frame = scene.frame_current

## Getting the current area type (which in this case is Text Editor) and assign
## it to "default_area" so it can be set back at the end of the script.
default_area = bpy.context.area.type

## Set area type to Timeline which seems to be required in order to be able to place Markers.
bpy.context.area.type = ('TIMELINE')

## Assigning "seq" to the list of selected strips.
seq = bpy.context.selected_sequences

## Getting the length of "seq", thus amount of selected strips.
a = (len(seq))

## Will be used to iterate through selected strips, starting at the first strip.
b = 0

## Check if any strips are selected.
if a &gt; 0:
    ## If so..
    print('---')

    ## Keep repeating the following code untill amount of selected strips is met.
    while b &lt; a:
        ## Set current frame to start of strip b
        scene.frame_current = (seq[b].frame_final_start)
        ## Place marker
        bpy.ops.marker.add()
        ## Set current frame to end of strip b
        scene.frame_current = (seq[b].frame_final_end)
        ## Place marker
        bpy.ops.marker.add()
        ## Current strip will become next strip (unless it's already the last one)
        b=b+1
    
    ## For deselecting last (all) Marker, not really needed but just neat.
    bpy.ops.marker.select_all(action='TOGGLE')

## If no strips where selected in the first place...
else:
    print('No strips selected...')

## Setting back the frame to where it was before the script was executed.
scene.frame_current = default_frame

## Setting back the area type to where it was before the script was executed.
bpy.context.area.type = default_area

Thank you so much!

Youā€™re welcome!

Ah, man this is great! I was just looking for a way to extract BWF markers embedded in WAV files. My Tascam DR40 can embed those(and I believe most of the Zoom recorders can do this too), but I havenā€™t found any software which actually can extract those. But a coder has actually coded the function to do it in python for Audacity, but they havenā€™t added it yet to the releases(if they ever will). Would it be possible to add it to Blender?

Hereā€™s the code: http://wiki.audacityteam.org/wiki/Importing_Timestamp_Information

And hereā€™s a bwf/wav test file with embedded Time Stamps: http://we.tl/AnbqF54ciC