Page 1 of 1

Setting markers to the beat via script?

PostPosted: Wed Jan 13, 2021 10:20 pm
by brokenfeet
Hi guys!
I would like to cut a video to a beat of a song.
Normally I play the song and set markers on the beats manually. (Transient detection doesn't work...its not a dance song :D )
This method normally works pretty fine but also you will get some "jitter" of a few frames just because i'm not a drummer with a perfect sense for rhythm.

Anyway...I know the tempo/bpm of the song. So my idea is:
Find a DEFINITE start of a measure (the kickdrum...) and set one marker. From that marker on, I want to set a series of markers, all 57 frames apart: because that's one measure at 105 bpm (the song) at 25 fps.

Assuming that the song does not have any tempo changes, this should generate a marker on each "One" of the song.
I guess this can be done with a LUA/python script pretty easily...but I haven't done that yet at all. (I know some programming though....)

Can anyone give me some starting tipps?

Thanks
Volker

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 4:54 am
by Igor Riđanović
Here is a script that will do it. I haven't tested it though.
Code: Select all
resolve = bmd.scriptapp('Resolve')
project = resolve.GetCurrentProject()
timeline = project.GetCurrentTimeline()

# Frame rate. You can also get the actual rate from GetSetting()
fps = 23.976

# BPM
bpm = 60

# Set offset for the starting marker
offset = 0

markerSpacing = 60*fps/bpm

# Place 100 timeline markers. You can also calculate the marker count
# from the timeline length and the markerSpacing
for i in range(0 + offset, 100, round(markerSpacing)):
    timeline.AddMarker(i, 'blue', 'My beats', 'My note', 1)

These two tutorials are kind of old, but the fundamentals haven't changed a lot. I have a few other tutorials on scripting there.


Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 8:54 am
by Peter Cave
If you don't want to use scripting you can make a 57 frame clip of a generator and copy/paste a block of 10 to 20 of them on a timeline for as long as you want. Then you can edit on video track 2 or step to each clip boundary and add a marker, using the down arrow and M key until you have the duration required. It's quite quick and faster than learning the scripting method. If you do this on a regular basis then scripting is worth spending the time to learn.

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 9:17 am
by brokenfeet
Hi everyone!
Thanks so far!

Apparently I'm already struggling with getting Python to work or the environment variables.

So for example, if I run this command in the console of Davinci:

Py2> R = bmd.scriptapp('Resolve')
Py2> R
Py2> print R
Resolve (0x00007FF686A31CE0) [App: 'Resolve' on 127.0.0.1, UUID: 5eb9fc13-9fb3-4f31-868c-f39a577358fb]


There seems to be some pointer(?) to the Resolve interface(?).

But with the next command I get this:
p = resolve.GetCurrentProject()
Traceback (most recent call last):
File "<nofile>", line 1, in <module>
TypeError: 'NoneType' object is not callable


What am I missing here?

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 9:20 am
by brokenfeet
Ah...also:
I know how to run the scripts via "Workspace-->Scripts"...but shouldn't it be possible to call the script from the console directly? How do I do that?

(Sorry for the noobie question...I'm used to Matlab, in which you also have an interpreter and a command line...but it seems a bit easier and intuitive).

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 7:24 pm
by iddos-l
brokenfeet wrote:Hi everyone!
Thanks so far!

Apparently I'm already struggling with getting Python to work or the environment variables.

So for example, if I run this command in the console of Davinci:

Py2> R = bmd.scriptapp('Resolve')
Py2> R
Py2> print R
Resolve (0x00007FF686A31CE0) [App: 'Resolve' on 127.0.0.1, UUID: 5eb9fc13-9fb3-4f31-868c-f39a577358fb]


There seems to be some pointer(?) to the Resolve interface(?).

But with the next command I get this:
p = resolve.GetCurrentProject()
Traceback (most recent call last):
File "<nofile>", line 1, in <module>
TypeError: 'NoneType' object is not callable


What am I missing here?

In your example R is the resolve object so you should write:

p = R.ProjectManager().GetCurrentProject()
And so on...



Sent from my iPhone using Tapatalk

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 7:28 pm
by iddos-l
brokenfeet wrote:Ah...also:
I know how to run the scripts via "Workspace-->Scripts"...but shouldn't it be possible to call the script from the console directly? How do I do that?

(Sorry for the noobie question...I'm used to Matlab, in which you also have an interpreter and a command line...but it seems a bit easier and intuitive).

I think this only works with studio.
In general you need to call python to execute the script. Depending on which python version you have or set in the env variables.
Something like:

Code: Select all
python3 your_script_path.py



Sent from my iPhone using Tapatalk

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 8:57 pm
by brokenfeet
Hi guys!

Thanks for your support so far! I somehow managed to get Python 2 to work..

I actually made some progress...not perfectly the way I wanted it to be, but it might get the job done. I'll post the whole script on here later, if someone is interested.
I was wondering...on the one hand there seem to be some powerful scripting possibilites, on the other hand, something simple as "GetCurrentClip()" does not exist.

I was struggling with stuff like this:
Does not work: FirstClip.AddMarker(i, "red", "Marker1", "Marker1 at frame 1", 1)
Does work: FirstClip.AddMarker(i, "Red", "Marker1", "Marker1 at frame 1", 1)

But I can't find a documentation of those attributes/arguments anywhere :-(

Also in the Fusion script guide I couldn't find this...

Thanks!
Volker

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 9:25 pm
by John Holt
Hello

This is now built into Version 17 with a little caveat, they have forgotten to finish it in the beta versions. I am hoping it will be included in the upcoming final release.

It is on the Fairlight tab and called transient detector.

Hope that helps

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 10:28 pm
by Igor Riđanović
brokenfeet wrote:...on the other hand, something simple as "GetCurrentClip()" does not exist.

I was struggling with stuff like this:
Does not work: FirstClip.AddMarker(i, "red", "Marker1", "Marker1 at frame 1", 1)
Does work: FirstClip.AddMarker(i, "Red", "Marker1", "Marker1 at frame 1", 1)

But I can't find a documentation of those attributes/arguments anywhere :-(

Also in the Fusion script guide I couldn't find this...


The concept of "current clip" doesn't really exist in a Resolve bin. By this do you mean the clip that's loaded in the source viewer? Or do you mean the clip or clips that are selected in the bin? Still the API does not provide access to either.

The documentation for valid marker color attributes does not exist. But you can get creative. One way to get it is by placing timeline markers of all colors, getting them via the API and examining the color name strings.

The Fusion scripting guide is included with Fusion 9. It's possible it's included with the newer standalone Fusion versions too.

Re: Setting markers to the beat via script?

PostPosted: Thu Jan 14, 2021 11:39 pm
by brokenfeet
Hi everyone!

Thanks for your interest in this...
So..I've progressed a little bit more (and I now figured why I had trouble setting the markers to that first song in the first place...that song had a few breaks with measure changes in it....)

Anyway.
So my current script (will post it later, when beautified) does this:

- You set ONE marker on the first proper downbeat that you can find in your audio track
- run the script
- script will set a red marker according to the given bpm on each downbeat till the end of the audio clip.

bpm are still hard coded in the script but hoping to change that with a little GUI/User- dialog.
Also, I probably should add a dialogue to pick the audio track and so on. And the audio clip must be the first one within its track.

So, if the song is a typical pop or dance song, one can expect a very precise, steady rhythm and the script works pretty well.
I'll keep you updated soon!

Thx

Re: Setting markers to the beat via script?

PostPosted: Sat Jan 16, 2021 1:26 am
by brokenfeet
Hi everyone!

After spending WAY too much time on this I got this script now.
How it works:
1) Set the first few (reference) markers manually as precise as possible on the downbeats (at least two)
2) The markers must be "in a row" ---> don't skip a bar
3) run the script
4) it will estimate the BPM and set markers accordingly
5) check the console for some info

It works pretty well if you set the reference markers precisely... Problem is, the error of the "bpm estimation" adds up. So check the end of your audio clip....markers might be shifted there.
Currently works for the first audio clip on audio track #1.
I guess, the higher the framerate of the project, the better the result.
What do you think? I'm not really happy with it, probably going to "tap" a lot of my markers in the future anyway. It would be cool to combine this with the transient detection.

Here's the code (the init (importing....) of the script might be weird. I had no real idea what i was doing there....)
Code: Select all
from python_get_resolve import GetResolve
import DaVinciResolveScript
import sys
import math

resolve = GetResolve()
pm      = resolve.GetProjectManager()
project = pm.GetCurrentProject()
tl      = project.GetCurrentTimeline()
time    = tl.GetCurrentTimecode()
fps     = project.GetSetting("timelineFrameRate")

print (" ")
print ("=========================================================================")
print   ("Project '" + project.GetName() +"':")
print   ("  Framerate " + project.GetSetting("timelineFrameRate"))
print ("=========================================================================")
print (" ")

clips       = tl.GetItemListInTrack("Audio", 1)   
FirstClip   = clips[0]
Duration    = FirstClip.GetDuration()
FirstClip.DeleteMarkersByColor("Red")
Markers     = FirstClip.GetMarkers() 

print ("Duration of Audio clip: " + str(Duration) + " frames")   


NrOfMarkers = len(Markers)

if (NrOfMarkers > 1):
    print ("Found " + str(NrOfMarkers) + " markers in audio clip")
else: 
    ("Not enough markers: " + str(NrOfMarkers))
    sys.exit()
       

MarkerList = list()

for Marker in Markers:
    MarkerList.append(int(Marker))

MarkerList.sort()   
print ("MArkers found at frames: " + str(MarkerList))           

MarkerSum = 0
for i in range(1,NrOfMarkers):
    MarkerDiff      = MarkerList[i] - MarkerList[i-1]
    MarkerSum       = MarkerSum +  MarkerDiff
    print (str(MarkerDiff) + " between markers [" + str(MarkerList[i-1]) + "] and [" + str(MarkerList[i]) + "]")
   
MarkerDurAvg    = float(MarkerSum)/float(NrOfMarkers-1)
print ("Avg frames between markers: " + str(round(MarkerDurAvg,3)))   
print ("=========================================================================")
 

DurationOfOneBar_Frames = MarkerDurAvg
DurationOfOneBar_Sec    = DurationOfOneBar_Frames/float(fps)
DurationOfOneBeat_Sec   = DurationOfOneBar_Sec/4
bpm                     = 60.0/DurationOfOneBeat_Sec
NrOfBars                = int((Duration-MarkerList[0])/DurationOfOneBar_Frames)

print ("Duration of one 4/4-bar: " + str(DurationOfOneBar_Sec) + " seconds")
print ("Duration of one 4/4-bar: " + str(DurationOfOneBar_Frames) + " FRAMES")
print ("Estimated BPM (4/4): " + str(round(bpm,1 )))
print ("Number of bars: " + str(NrOfBars))
print ("=========================================================================")

for i in range(1,NrOfBars):
    NextMarker  = int(float(i)*float(DurationOfOneBar_Frames)+ float(MarkerList[0]))
    LastMarker  = int(float(i-1)*float(DurationOfOneBar_Frames)+ float(MarkerList[0]))
    Dur         = NextMarker - LastMarker
    isSuccess   = FirstClip.AddMarker(NextMarker, "Red", "Beat" + str(i), "", 1)
               
    #if isSuccess:
     # print("Added marker after " + str(Dur) + " frames")
   
print ("=========================================================================")
print  ("DONE")
print ("=========================================================================")