# Help understanding ticks in sonification

I am trying to make my first sonification (expressing data through sound) with sonic pi, and I’m having a difficult time (I should note that I am also new to ruby, but not to coding).

What I am trying to do is create a sequence for each month, and (eventually) 4 synths for each quarter of the year. The beat will count what month we are in (1 beat for January, 12 for December) and the chords will play for the number of hirees for that month (I simplified it where every one hiree is 10). The chord sequence should repeat for 4 times, as it should play for each month in a quarter. I realize my [unfinished solution] is VERY naive, but I also haven’t figure out why the ticking isn’t working. I thought I could just make rings and tick through each of the arrays, but it isn’t working. For example, the beat section starts at 2, then jumps to 5 then 7. The chord ring didn’t work at all, and using variables (c instead of chords.tick as written below) also seems to give different results. I have spent far too many hours reading the sonic pi tutorial, this forum, and mehackit (great resource) without much luck. I would appreciate anyone’s advice on ways to improve this code!

``````hirees = [4, 6, 8, 6, 5, 4, 4, 5, 4, 5, 4, 6].ring
percentages = [7, 9, 12, 10, 9, 6, 6, 8, 7, 8, 7, 10].ring
chords = [chord(:c, :minor7), chord(:F, :minor7), (chord :Bb, "7")].ring
synths = [:piano, :pluck].ring
months = (range -0,13)

s = synths.tick
c = chords.tick
h = hirees.tick

puts months.look

use_bpm 200
puts hirees.look

define :month_beat do
puts months.look
months.tick.times do
sleep 0.75
end
end

month_beat

use_synth synths.tick
h.times do
play c,  amp: percentages[0]/2
sleep 1
end

##| use_synth :piano
##| hirees[0].times do
##|   play chord(:c, :minor7),  amp: percentages[0]/2
##|   sleep 1
##| end

month_beat

use_synth synths.tick

h.times do
play c, amp: percentages[1]/2
sleep 1
end
month_beat
``````

Hello @notintune!
This comment, and the others that follow it, might help:

I can’t believe I missed that! Thanks so much for your response. Then theoretically this method could work if I just put all into a loop? Since it is a pattern, I feel like it could be easily generated, but I’m going from very naive (where I wrote out 3 loops) → pretty naive (which didn’t work)

Perhaps, but the 3 loops should be fine the point that Sam refers to is that `tick` increments a counter unique to a live_loop or a thread, not unique per ring/list. (This includes if called outside of a live loop, (such as the very top-level, which is itself run in a hidden thread)).

So the idea is to use multiple named ticks if you need to separately increment things at different rates in a single loop or thread, or you could use a single `tick` to increment all rings if they can all advance at the same time, and use `look` where you need the value.

Hope that helps! Feel free to ask if you need further clarification

Thanks Ethan! This is very very helpful. It’s starting to make sense, but I don’t think I really grasp it. How do I increment all my arrays with one tick (and do all my arrays need to be rings?)? I really just want it to go through each value once (for a total of 12 loops), except the ones that have less than 12 values - these should just restart from the first index.

Do you have an example ; I m interested.

2 Likes

this is what I mean by using a single tick to increment multiple rings at once: I’ve edited
your example slightly @notintune to show how you could do this

``````hirees = [4, 6, 8, 6, 5, 4, 4, 5, 4, 5, 4, 6].ring
percentages = [7, 9, 12, 10, 9, 6, 6, 8, 7, 8, 7, 10].ring
chords = [chord(:c, :minor7), chord(:F, :minor7), (chord :Bb, "7")].ring
synths = [:piano, :pluck].ring
months = (range -0,13)

hirees.length.times do
tick

s = synths.look
c = chords.look
h = hirees.look

puts months.look

use_bpm 200
puts hirees.look

define :month_beat do
puts months.look
months.look.times do
sleep 2
end
end

month_beat

use_synth synths.look
h.times do
play c,  amp: percentages[0]/2
sleep 1
end

##| use_synth :piano
##| hirees[0].times do
##|   play chord(:c, :minor7),  amp: percentages[0]/2
##|   sleep 1
##| end

month_beat

use_synth synths.look

h.times do
play c, amp: percentages[1]/2
sleep 1
end
month_beat
end
``````

The key here is that I start by iterating over something in an ‘overall’ loop of sorts, (`hirees` in this case - you could just as easily make it a proper `live_loop` instead of just looping once over a single collection) and then at the top of the ‘loop’ I call `tick` every cycle around. Then, whenever I need to use this incremented counter value, I just use `.look` on whatever array or ring I’m cycling through. Since I’m only incrementing the counter once per iteration of the outer loop, everywhere I use `look` inside it will see the same counter value (and hence all the values used from these arrays or rings will advance at the same time).

Technically, yes, the ring functions only work on rings. However, if you just want to work with array syntax, Sonic Pi converts arrays to rings behind the scenes if you call a ring function on an array (such as `.tick`, `.look`, etc etc - see Tutorial chapter 8.5 for many more: Sonic Pi - Tutorial)

Let me know if that all makes sense! I’m happy to keep helping if needed

That’ll teach me to not double-check before writing
Yes, Sonic Pi converts arrays to rings if you call `.tick` or `.look` on them, but otherwise you need to use `[...].ring` yourself

Apologies

Hey @ethancrawford. I just want to thank you so much for your help & patience! I think it’s starting to make sense. The only thing I still don’t understand is why I can’t have `month_beat` play initially and then increment with the loop. I thought that this would be solved by putting it above the loop, like you suggested. Then I thought by making two live loops and making them sync would solve things, but this seemed to stray further from the solution.

``````
hirees = [4, 6, 8, 6, 5, 4, 4, 5, 4, 5, 4, 6].ring
percentages = [7, 9, 12, 10, 9, 6, 6, 8, 7, 8, 7, 10].ring
chords = [chord(:c, :minor7), chord(:F, :minor7), (chord :Bb, "7")].ring
synths = [:piano, :piano, :piano, :pluck, :pluck, :pluck].ring
months = (range 0,13)

months.length.times do
tick

s = synths.look
c = chords.look
h = hirees.look
p = percentages.look
m = months.look

use_bpm 250

live_loop :month_beat do
m.times do
sleep 2
end
end
live_loop :num_hirees do
sync :month_beat
use_synth synths.look
hirees.look.times do
play_pattern c, amp: p
end
end
end
``````

Is the idea that you want a beat sequence to play first, and once it has finished, one chord sequence, and this repeats with the next series of beat and chord sequences?
If that’s it, then here’s a version adapted from your latest example that does this: (using just one live_loop)

``````use_bpm 250
hirees = [4, 6, 8, 6, 5, 4, 4, 5, 4, 5, 4, 6].ring
percentages = [7, 9, 12, 10, 9, 6, 6, 8, 7, 8, 7, 10].ring
chords = [chord(:c, :minor7), chord(:F, :minor7), (chord :Bb, "7")].ring
synths = [:piano, :piano, :piano, :pluck, :pluck, :pluck].ring
months = (range 1,12, inclusive: true)

live_loop :num_hirees do
tick
months.look.times do
sleep 2
end
use_synth synths.look
hirees.look.times do
play_pattern chords.look, amp: percentages.look
end
end
``````

Do I understand your goal here?

1 Like

I’m off for now, but other folks are always welcome to chip in if I’m not back before them

YES!!! Ok that makes so much sense. Thanks for your help. I think I understand the tick, look and loops a lot more now. It doesn’t sound very melodic, but I just want to make sure people will be able to hear the data, especially when it is paired with a graph/animation.

My next challenge will be to play around the the `percentage` variable, as the `amp` isn’t very discernable, and to add custom synths.

Thanks again @ethancrawford. I hope I don’t have to bug you again too soon.

1 Like

So, one thing to note here is that Sonic Pi’s ‘standard’ amp level for synths is usually 0 - 1. Note that the docs for synths say this about `amp:`

Typically a value between 0 and 1. Higher amplitudes may be used, but won’t make the sound louder, they will just reduce the quality of all the sounds currently being played (due to compression.)

There is a built in signal limiter in the underlying audio-signal chain, there as a safety net to try to save people’s ears. Thus, after a certain point, the signal is limited to try to cap the levels. This may be why using these large numbers for `amp:` is not producing very distinctive results. The limiter can be turned off if you wish, by using the following command:

``````set_mixer_control!(limiter_bypass: 1)
``````

(But of course be aware of the implications if you do )

You’re welcome! and that’s no problem at all. I’m always happy to help where I can.
If you feel like sharing as the project progresses, by all means, go ahead! It’s always nice to see Sonic Pi projects develop

1 Like