Get bpm (beats per minute) of a song

I am currently playing around with arduino and LED stripes.

There is a cool demo in the FastLED library wich generates a pulsing rainbow to a defined bpm.

I think it would be great if I openhab could get the bpm of a current playing song and sends the bpm value to the arduino.

So maybe someone likes this idea and could develope a binding or action to use the artist and titel of a song (supposed you already got these information in openhab) that returns the bpm.

A quick search brought up this api.
http://developer.echonest.com/raw_tutorials/faqs/faq_04.html

Anyway, I just wanted to post this idea and carry on with my other project. :slight_smile:

1 Like

Since you are not talking about actually listening to the audio and calculating the BPM, all you are really talking about is a lookup in a database. You should be able to implement this in a rule easily.

When the current playing song changes an Item (somehow) changes in OH. This triggers a rule and OH makes a call to that API using the http request actions, parses the BPM out of the result, and sends it to your Arduino. There is no need for a binding to do this.

You are right.
I haven’t thought about that.

I will look into it, when I have time… :slight_smile:

Or anybody else can pickup the idea and post his code. :wink:

I case anybody (or me) will investigate further into this topic, here is (another) service that might be worth looking at.

I am getting closer… :slight_smile:

import java.net.URLEncoder

rule "Test"
    when
        Item Test changed
    then
        logInfo("Test", "Test")

        var String url = "https://api.getsongbpm.com/search/?api_key="
        var String api_key = "********************************"
        var String artist = "lorde"
        var String song = "green light"


        var String json = sendHttpGetRequest(url + api_key + "&type=both&lookup=artist:" + URLEncoder::encode(artist, 'UTF-8') + "+song:" + URLEncoder::encode(song, 'UTF-8'))
        var String value = transform("JSONPATH", "$.search[0].tempo", json)

        logDebug<------>("Test", "json: " + json)
        logInfo("Test", "Tempo: " + value)
end

I am just posting this intermediate result, because it might take a while before I will finish this topic. :slight_smile:
But it should be relatively easy to get the artist and song titel from existing items and do something with the tempo we get.

Here is my final rule:

song_tempo.rules

import java.net.URLEncoder

rule "Song_Tempo"
    when
        Item HTPC_title changed
    then
        logInfo("Song Tempo", "artist or title changed")

            // wait until all items got updated
            Thread::sleep(250)
        if ( HTPC_mediatype.state == "song" ) {

            var String url     = "https://api.getsongbpm.com/search/?api_key="
            var String api_key = "fadc328ea3a34455a98c70c36f0ed85e"
            var String artist  = URLEncoder::encode(HTPC_artist.state.toString.split(",").get(0), 'UTF-8')
            var String song    = URLEncoder::encode(HTPC_title.state.toString, 'UTF-8')

            logInfo("Song Tempo", "artist: " + artist + " (" + HTPC_artist.state + ")")
            logInfo("Song Tempo", "song: "   + song   + " (" + HTPC_title.state  + ")")

            var String json = sendHttpGetRequest(url + api_key + "&type=both&lookup=artist:" + artist + "+song:" + song)
            var String value = transform("JSONPATH", "$.search[0].tempo", json)

            logInfo("Song Tempo", "request: " + url + api_key + "&type=both&lookup=artist:" + artist + "+song:" + song)
            logInfo("Song Tempo", "json: " + json)
            logInfo("Song Tempo", "Tempo: " + value)

            if ( value != null ) {
                sLED_tempo.sendCommand(value)
            } else {
                logInfo("Song Tempo", "No valid value returned.")
            }

        }
end

and a video. :sunglasses:

1 Like