Finding correct bpm of drum loops

I have been playing around with ways to use break beats and drum loops without having to use beat_stretch or variables for sleep values in order to have other sounds or sample line up correctly. I came up with a function that will take any loop and return the correct bpm. You just need to provide the number of beats in the loop.

Here is an example of it in use with the Amen break:

define :bpm do |samp, subDiv| # samp = loop you want to use, subDiv = number of beats in that loop
  t = sample_duration samp #variable to store duration of loop
  bps = t/subDiv # beats per second found by dividing loop duration by the number of beats in the loop
  beatsPerMin = 60/bps #converts beats per second to beats per minute
  return beatsPerMin # returns bpm of loop
end


use_bpm bpm :loop_amen, 4 #setting bpm to the correct bpm of the loop by using the function

live_loop :amen do
  sample :loop_amen #play sample
  sleep 4 #sleep for the same number of beats in the loop of the sample, most likely 2, 4 or 8
end

live_loop :bass, sync: :amen do
  play (octs, :d1, 3).choose, release: 0.5
  sleep 0.5 #Any accompanying synths or samples can use evenly divided sleep values and should align perfectly with loop
end

2 Likes

hi how would I use this with my own loops thanks :slight_smile:

Hi Soundwarrior, I’ve edited the original code a bit. Hopefully this is what you’re looking for.

define :getBpm do |samp, beats|   # samp = loop you want to use, subDiv = number of beats in that loop
  t = sample_duration samp        # variable to store duration of loop
  bps = t/beats                   # beats per second found by dividing loop duration by the number of beats in the loop
  beatsPerMin = 60/bps            # converts beats per second to beats per minute
  return beatsPerMin              # returns bpm of loop
end

sample = "C:/Users/l_bridge/OneDrive/Sonic Pi/Samples/Classic Breaks/Hot Pantz 162.wav"
beats = 16 # The 'Hot Pantz 162' break is 16 beats over 4 bars (and 162bpm). If you had a 1 bar loop beats would = 4.

puts getBpm(sample, beats)

# returns 162.00020663291662 for me

SInce writing this post, I have discovered that there is a command in Sonic Pi which does what this function set out to do.

It is called use_sample_bpm and takes an additional argument for how many beats you want there to be in the loop

use_sample_bpm :loop_amen, num_beats: 4

live_loop :looped do
  sample :loop_amen
  sleep 4
end

To use your own samples in this code, I would suggest assigning the sample path to a variable and then using that variable as the first argument in the command

yourSample =" C:/User/path/to/your/sample.wav"
use_sample_bpm yourSample, num_beats: 4

live_loop :looped do
  sample yourSample
  sleep 4
end
3 Likes

Note that this assumes that the sample duration matches the length of the bar. It doesn’t do any fancy beat detection analysis on the audio. If there’s any accidental silence at the beginning or end of the sample then this will not necessarily produce desirable results. However, most decent loop samples are appropriately trimmed so this shouldn’t be an issue in general.

2 Likes

Hi and thanks for having me, excuse the possibly silly question but, How do you get “use_sample_bpm” to play nice and speed up. It’s been a long time since I’ve done any coding.

    # doesn't work
    amen_sped_up = :loop_amen, rate: 1.1
    use_sample_bpm amen_sped_up, num_beats: 4

    live_loop :looped do
      sample :loop_amen, rate: 1.1
      sleep 4
    end
    # nor does
    use_sample_bpm :loop_amen, num_beats: 4

    live_loop :looped do
      sample :loop_amen, rate: 1.1
      sleep 4
    end
    # nor
    use_sample_bpm :loop_amen, rate: 1.1, num_beats: 4

    live_loop :looped do
      sample :loop_amen, rate: 1.1
      sleep 4
    end

Hello @Lukey_Moonshine :slight_smile:

There’s a couple of things going on here.
The first one doesn’t work due to the limitations of the structure of Sonic Pi code. For the line amen_sped_up = :loop_amen, rate: 1.1 - Sonic Pi attempts to interpret the line, but when it gets to the comma it doesn’t expect the rate: 1.1 to be the sort of thing that follows - it just sees some unexpected label it doesn’t know how to handle). It’s as if we were trying to assign two separate things to amen_sped_up at the same time, separated by a comma - that’s not going to work! :smile: (to actually do such a thing, we’d need to enclose the two items in square brackets so that we were assigning a single item which is really an array containing two elements. However, even if we were to do such a thing here, it doesn’t solve the problem still).

The middle one doesn’t work because use_sample_bpm :loop_amen, num_beats: 4 says ‘treat the length of the :loop_amen sample at the default rate (1) to last for 4 beats.’ However, we then ask the live_loop to play the :loop_amen sample at a slightly higher rate - so it will complete in less than 4 beats.

Regarding the last one however - in what way does that one not work? when I test it, the sample appears to play at slightly higher than normal rate, and the loop repeats exactly according to the beat.

Thanks for the reply and explanation. Interesting, the third is the one I tried first, when I run it it does the same as the second, completing in less than 4 beats so there is a pause between playing the sample and playing it again.
worked out a way of getting the result I desired, I’ll re-format the code tomorrow to make it more elegant but this seams to work,

use_sample_bpm :loop_amen, rate: 1.1, num_beats: 4
live_loop :looped do
sample :loop_amen, rate: 1.1
sleep 4/1.1
end

Quite odd. That one you share above loops before the sample has completed for me.
Which version of Sonic Pi are you using?