Student asked me why "no implicit conversion of nil to integer"

Hallo friends
my young student and I are exploring a few different and simple ways of programming drum patterns, including arrays of numbers or of symbols. When we came to this example:

k1 = [9,0,0,0,7,0,0,5] # how loud is each sound, div by 10.0
s1 = [0,0,6,0,0,0,4,0]
h1 = [0,8,0,5,0,7,0,4]
h2 = [5,0,4,0,3,0,2,0]

live_loop :drums98 do
  #stop
  sample :bd_zum, amp: k1.tick * 0.1
  sample :sn_zome, amp: s1.look * 0.1
  sample :hat_bdu, amp: h1.look * 0.1
  sample :hat_gnu, amp: h2.look * 0.1
  
  sleep 0.25
end

He asked if we could use a loop counter to tick through the arrays, and use k1[i] * 0.1 (as we had in a previous working example), instead of .tick. Using live_loop :drums98 do | i | the answer is no we can’t.

The previous working example was this one:

drm = [1,0,2,0,1,0,2,1]
cym = [0,1,0,2,0,1,0,2]
live_loop :drums1 do
  stop
  8.times do |i| #loop counter
    sample :drum_bass_hard if drm[i] == 1
    sample :sn_dolf if drm[i] == 2
    sample :hat_bdu if cym[i] == 1
    sample :hat_gnu if cym[i] == 2
    sleep 0.25
  end
end

I realise this example polls the array and then applies a conditional, and the example above that is polling the array for the actual value itself. Again, revealing my n00bosity - where is the nil coming from, and why can’t we index through the array values in the first example. I tried k[1].to_i without success.

Many thanks for your continued support

Brendan

Yet this works fine. It reveals my basic lack of understanding of how the loop counter works - if it’s at the head of the loop it behaves differenter (yes, it’s a word :D) to when it’s assigned to a nested loop:

k1 = [9,0,0,0,7,0,0,5]
s1 = [0,0,6,0,0,0,4,0]
h1 = [0,8,0,5,0,7,0,4]
h2 = [5,0,4,0,3,0,2,0]

live_loop :drums28 do
  #stop
  8.times do |i|
    sample :bd_zum, amp: k1[i] * 0.1
    sample :sn_zome, amp: s1[i] * 0.1
    sample :hat_bdu, amp: h1[i] * 0.1
    sample :hat_gnu, amp: h2[i] * 0.1
    
    sleep 0.25
  end
end

Hey ho

I am slowly coming to the realisation (the correct one, I believe) that any time I post a question here it is not about Sonic Pi specifically, it is more about programming in general, particularly using Ruby. If I spend 2hrs a day coding, about 25 - 50 % of that time is learning about Ruby. And having great fun too. Sonic Pi doesn’t present me with any barriers or problems - they stem from my ‘lack’ of programming skills (although I did teach Supercollider for a few years at uni).

So I have decided to begin learning Ruby formally (and the experts here can say if that is a good or bad idea), either online or locally . Wish me luck :wink:

I’m not sure what the issue is, but I suspect it might be to do with indexing outside of the array. When you use the array[x] notation (as opposed to array.tick), it will return a nil value when the index is out of range, instead of looping back to the start.
You can prevent this by converting the arrays to rings, then indexing will always loop back to the start, e.g.: k1 = [9,0,0,0,7,0,0,5].ring or k1 = ring(9,0,0,0,7,0,0,5).

1 Like

The reason this works with the 8.times loop is that i only exists within that loop and is set to zero every time the live_loop repeats, so you don’t go out of bounds.

Making k1, s1, etc rings instead of lists would avoid that problem.

1 Like

Thanks both for the confirmation