Hello from Brooklyn

Hi, I’m Omar from Brooklyn, NY. I’m a web-oriented software engineer, computer science grad student and amateur musician. I used to play a lot of music in bands and do some home recording. I haven’t been too active musically lately, though, and would like to change that. I just recently heard about Sonic Pi at a hackathon, so I’m excited about using it to make some new music.

I started poking around with Sonic Pi this weekend for the first time, but loved every minute of it. I’ve watched a lot of tutorials for building four-to-the-floor-beat style music, however I’m leaning towards hip hop and trap beat production myself. If anyone has any good videos/resources on learning that style, please let me know.

3 Likes

Welcome Omar! Good to see you here. Queens representing!

I’ve posted a few youtube videos of some trap beats that I did in Sonic PI which feature the code that you can check out: https://www.youtube.com/channel/UC8dqNjZzWl_02cGpcuiNEWg?view_as=subscriber

Some are older and I have since refined my technique but they’re worth checking out. I’ve learned a lot from watch other people’s videos too. But I also come from a more hip hop aesthetic so I just had to figure out what works. Not a whole lot out there right now for producing that type of music in Sonic Pi. But I’m happy to help out if you have any questions.

Thanks, @mrbombmusic ! I might’ve stumbled upon one of your videos out of context over the weekend and it might’ve been like one of the only SonicPi + hiphop video I found on youtube. I really like how you do the time subdivision in this one:

Like doing 24th notes using the:

6.times do
    sample hats, h
    sleep dur / 24
end

It’s pretty great for like composing beats. I’m still getting used to doing this much fraction math in real time well enough for live-coding without weird out-of-sync hi-hats when my measures don’t totally add up, though.

Do you have any tips for that kinda stuff?

Take a look at the density function :slight_smile:

1 Like

Thanks @samaaron! That’s exactly what I needed. Much easier to work out evenly spaced rhythms using density.

1 Like

I agree that it takes some time to get used to the math part of adding fractions. One method I have started using more in place of what I did in that video is the knit function.

The knit is similar to a ring but it takes two arguments. The first argument is the value you want. In this case, the subdivision of rhythms. The second value is the number of times you want it to happen.

For example:

sleep (knit, 0.25, 4).tick

would be the same as this:

sleep (ring, 0.25, 0.25, 0.25, 0.25).tick

This can be more efficient when you start to add multiple subdivision for your hi hat.

I have also started using fractions more than floating point numbers for my sleep values. I find it is easier to visualize what the subdivision is. Just look at the denominator and you know how many subdivisions you get per beat. so 1/4 would be 4 hits per beat. I also use a variable for the numerator, even though it is just equal to 1. However, it needs to be 1.0, otherwise when dividing two integers, it will return an integer and anything less than 1 will be rounded down to 0 and you’ll get an error message.

Once you start putting this into a knit, just match the second argument with the denominator of your sleep value and that will be one beat. This makes a little easier to keep track of.

t = 1.0

live_loop :trapHats do
  sample :drum_cymbal_closed
  sleep (knit, t/4, 4, t/6, 6, t/8, 8, t/16, 16).tick
end

The density function also works well for this.
Here’s the same code as above with density

live_loop :trapHats do
  density (ring, 4, 6, 8, 16).tick do
    sample :drum_cymbal_closed
    sleep 1
  end
end

I like making a function with one argument for the density value just to make the code look a bit cleaner when I have a lot of loops going at once.

define :hats do |d|
  density d do
    sample :drum_cymbal_closed
    sleep 1
  end
end

live_loop :trapHats do
  hats (ring, 4, 6, 8, 16).tick
end

The one thing I prefer about the knits over density is that density doesn’t really allow you to do less than the full amount of subdivision. By this I mean, if I put 16 for my density value, I am going to get 16 hits of the hi hat before moving on to the next subdivision. But what if I only want 8 hits of that subdivision and then want to finish off the rest of it with a different subdivision, say, 4? I haven’t found a way to do that with density.

But with a knit, it would look like this:

t = 1.0

live_loop :trapHats do
  sample :drum_cymbal_closed
  sleep (knit, t/4, 4, t/6, 6, t/8, 8, t/16, 8, t/4, 2).tick
end

This method will get you back to your original issue of struggling with the math of adding fractions, but the more you do it, the easier it gets. Just keep in mind the number of beats you are working with, which should be 4, 8, 16 etc (although no one says it has to be that :wink:)

Hope that is helpful.

@mrbombmusic A lot of great ideas here, very helpful indeed.

I really like this knit function as a way to add variations on the hats. Will have to practice a bit more with making these knit arrays, though.

@mrbombmusic I’ve tried my hand at a simple beat using your system and I gotta say the knit function is actually pretty intuitive for expressing trap-ish patterns. That being said, I sometimes want to represent rest notes and I’m still trying to come up with a manageable way of doing it.

So far I’ve setup a system of “negative” notes to represent rests and used a helper function to sort them out:

M = 4.0  # Constant representing the base length of a measure

p1 = (knit, M/2, 2)
p2 = (knit, M/-4, 1, M/4, 1)
p3 = (knit, M/16, 4, M/24, 6, M/16, 4, M/24, 6, M/16, 4, M/64, 8)

define :hit do |n,s,a|
  if n >= 0
    sample s, rate: 1, amp: a + rrand(-0.5, 0.5)
  end
  sleep n.abs
end

define :hat do |n|
  hit n, :elec_tick, 1.6
end

define :snare do |n|
  hit n, :sn_dolf, 4
end

define :kick do |n|
  hit n, :bd_tek, 2
end

live_loop :kicks do
  kick p1.tick
end

live_loop :snares do
  snare p2.tick
end

live_loop :hats do
    hat p3.tick
end

However, do you have any better systems for representing rest notes?

Although it works, I’m not crazy about the negative time as a logical way to represent this (since negative time to me feels more like “reverse”). However, negatives are pretty easy to work with code-wise.

Hi Bomb…

Maybe I’m missing something in this thread, but aren’t rests
annotated as :r ?

melody_1 = [:c4,:r,:ds4,:ds4,:g4,:c4,:r,:gs4,:r,:r,:gs3,:r,:g3,:r,:r,:r].ring

I thought things like play, play_timed etc took note of this, but if you were
writing your own, then something like?


if melody_1.look == ":r" then 
sleep 1
next
end

Eli…

@Eli thanks! Def. good to know, but those are all of the same duration and in the context of a ring of note symbols. I’m specifically referring to representing rests of arbitrary duration in numeric ring pattern. The context is not necessarily melodies, but a drum pattern for something like a kick drum.

One way is to use the matrix approach you were discussing in this thread

Another approach to that is to use the bools function which can be found in the Lang section of the help window. It basically operates the same way as using a ring of 1s and 0s but it automatically converts them to boolean values. Here’s a basic drum pattern using this method.

k = (bools, 1, 0, 0, 0, 1, 1, 0, 0)
s = (bools, 0, 0, 1, 0, 0, 0, 1, 0)
h = (bools, 1, 1, 1, 1, 1, 1, 1, 1)

t = 1.0

define :pattern do |b, s, r|
  if b.tick
    sample s
    sleep r
  else
    sleep r
  end
end

live_loop :kick do
  pattern k, :bd_tek, t/2
end

live_loop :snare do
  pattern s, :sn_dolf, t/2
end

live_loop :hat do
  pattern h, :elec_tick, t/4
end

This is ok for kick and snare patterns but would not be really effective for more complex patterns.

Another approach I’ve seen used for adding rests is to change the amp to zero to represent the rest. This can be used with more complex patterns by including a ring or knit for the amp value as well. Just be aware you will need to include .look instead of .tick for any other data structures you want to tick through in the same live loop.

Here’s an example of how that could be done with a trap hat pattern

t = 1.0

live_loop :hats do
  r = rrand(0.4, 0.8) #variable to store random amp for hits
  sample :drum_cymbal_closed, amp: (knit, r, 14, 0 ,2, r, 4).tick
  sleep (knit, t/4, 8, t/8, 8, t/4, 4).look 
end

This pattern is 4 beats = 2 beats of t/4, 1 beat of t/8 and the last beat is t/4
This is represented in the knit for the sleep value.

The rest happens on the 3rd beat for the last two hits of the t/8 subdivision
It would look like this = (1, 1, 1, 1, 1, 1, 0, 0)

The rests are executed from the knit in the amp values.
The numbers in the amp values are as follows:

r, 14 = r is the random values declared in the variable. The 14 is the number of hits before the rest happens. This comes from the 1st 8 in the sleep knit which is the 2 beats of t/4 added to 6 which is the number of t/8 hits before the 2 hits of rests using that subdivision.

0, 2 = This is the two t/8 worth of rest at amp: 0

r, 4 = The remaining beat of t/4 in the sleep knit at the random values set in the variable r.

To go back to the example you posted, here is a modified version using this technique to get the same results you had.

M = 4.0  # Constant representing the base length of a measure

p1 = M/2
p2 = M/4
p3 = (knit, M/16, 4, M/24, 6, M/16, 4, M/24, 6, M/16, 4, M/64, 8)

live_loop :kicks do
  sample :bd_tek, amp: rrand(2.5, 3.5)
  sleep p1
end

live_loop :snares do
  sample :sn_dolf, amp: (ring, 0, rrand(3.5, 4.5)).tick
  sleep p2
end

live_loop :hats do
  sample :elec_tick, amp: rrand(1.1, 2.1)
  sleep p3.tick
end

You’ll note that I’ve made some changes/omissions to the original code, some for cleaning up the code, some just to suit my own personal preferences ie I’m not a huge fan of defining a lot of functions to do basic commands.

But that main thing is the ring used for amp: in the snare loop to achieve the rest.

Hope this helps. Let me know if you have any further questions.

@Eli, I was not aware of the :r to represent rest. Thanks for sharing. But as nabisco pointed out, it is not so easy to change it’s duration within a more complex rhythmic pattern.

1 Like

@mrbombmusic A lot of good ideas here, thanks! The bools function works really well using the matrix approach for kicks and snares, perhaps it might be worth just mixing and matching with the knits (since that def feels like the way to go for hats and more intricate rhythms). I also recently found myself doing a lot of if p.tick == 1 stuff in a few places that becomes just if p.tick when p is a bools ring–much cleaner codewise. (It’s still fascinating to me that 0 is truthy in ruby :thinking: )

The amp: 0 to represent rests also feels consistent with a few of the tutorial videos I’ve been seeing online and code people have posted in these forums. That might actually be the most straightforward way to represent rests, perhaps.