Thursday, May 5, 2011

BPM detection using Banshee.Bpm

Banshee has a built-in extension to detect Beats Per Minute (BPM) in Banshee.Bpm. Unfortunately it is not possible to use this extension directly for our purpose, because the visibility of GetDetector () is set to internal. A quick and dirty solution to this is to copy the BpmDetectJob.cs file (which can be found in /banshee/src/Extensions/Banshee.Bpm/Banshee.Bpm/ after checking out the source from the git repository) to our project and change the visibility to public, since everything else we need is accessible from the Banshee API.

To see if the detection works, we use the following pieces of code.

We declare the private member IBpmDetector detector in our extension class and use the following code to initialize it in the constructor and set the FileFinished handler:

detector = BpmDetectJob.GetDetector ();
if (detector != null) {
    detector.FileFinished += OnFileFinished;
}

with

private void OnFileFinished (object o, BpmEventArgs args)
{
    Hyena.ThreadAssist.ProxyToMain (delegate {
        Hyena.Log.DebugFormat ("Foo1 - Detected BPM of {0} for {1}", args.Bpm, args.Uri);
    });
}

This simply outputs the BPM to the log. Now all we have to do is use the detector on a track, which can be done using the following method.

private void DetectBPMs(TrackInfo track) 
{
    if (track != null) {
        detector.ProcessFile (track.Uri);
    }
}

Now if we call DetectBPMs(TrackInfo track) with the first song in our library (i.e. ServiceManager.SourceManager.MusicLibrary.TrackModel[0]) as parameter, we get an output like "Foo1 - Detected BPM of 65 for file:///home/thomas/Musik/Black%20Holes%20and%20Revelations/Muse%20-%2001%20-%20Take%20a%20Bow.mp3".

Caution:
The class ThreadAssist was recently moved from Banshee.Base to Hyena!