Hello Folks

I’ve been using spread a lot to generate euclidean rhythms, and they work really well. One thing I can’t seem to figure out is how to shift them. For instance, `spread(2,16)` gives me a hit on 1 and 8, which sounds off when I try to add snares from one measure to the next. Is there an easy way to “pre-tick” it 4 times, so i get a hit on 5 and 13 instead?

aka. from
`(ring true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false)`
to
`(ring false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false)`

lovely question! You can skip or “rotate” a spread an arbitrary number of times using the `.rotate` modifier:

``````(spread 2,16).rotate(4)
``````

You can use positive or negative values for the rotate amount.

I hope that this helps

1 Like

Hi @samaaron,

according to my tests

``````v = 1
``````

will always return:

``````(ring true, false, false, false, true, false, false, false)
``````

no matter what value `v` has. At least in my SP 3.1.0

which is consitant with the documentation:

“… rotate to the next strong beat allowing for easy permutations of the original rhythmic grouping …”.

I would be glad if I am wrong because I was already looking for an easy way to shift beats irrespective of them being week or strong.

Hi @Martin,

yes, that would make sense. The option `rotate:` is different from the modifier `.rotate`. In other words, the option `rotate:` is specific to the `spread` function whereas the modifier `.rotate` works on any ring.

Note the difference:

``````(spread 2, 8, rotate: 4)
``````

Hope that this helps

1 Like

Ahh!! Great! Thanks for clearing up my misunderstanding and misreading.

1 Like

That’s exactly what i needed. Thanks @samaaron!

The .rotate function doesn’t appear anywhere in the built-in documentation. Finding the functions built into rings (beyond the tutorial) is generally a bit difficult, it would be nice if all the functions were listed in the ring entry.

I could write a bit about it if you want. Just give a hint as to where I should put it.

1 Like

Hi Chris,

I think .rotate is really a Ruby construct, and as such not documented in the SP help…

There are others, .mirror, .reverse, which come to mind, which were mentioned in another
much older post, somewhere.

Sam usually says they aren’t formally supported, even though they might work, and may not
work in future versions… which would be a shame, as they are damn useful.

Eli…

What he said.

I sat down and went through the ruby array operators to check which ones work and which ones don’t as of today (version 3.1.0), in case someone else comes across this thread.

``````###########
# WORKS
###########

# Transformations
puts (scale :a1, :minor) << 88
puts (scale :a1, :minor).unshift(33)
puts (scale :a1, :minor).push(33)
puts (scale :a1, :minor).pop
puts (scale :a1, :minor).shift
puts (scale :a1, :minor).delete_at(1)
puts (scale :a1, :minor).reverse

# Combining
puts (scale :c1,:major) + (scale :c2,:major)
puts (scale :c1,:major) + (scale :d1,:major).uniq
puts (scale :c1,:major) - (scale :d1,:major)

# Removing Duplicates
puts (scale :c1,:major).concat((scale :d1, :major))

# Moving
puts (scale :c1,:major).reverse
puts (scale :c1,:major).rotate
puts (scale :c1,:major).rotate(-2)

# Querying
puts (scale :c1,:major).include? 29
puts (scale :c1,:major).count 29
puts (scale :c1,:major).size

# Iterations
(scale :c1, :major).each {|i| puts i}
(scale :c1, :major).reverse_each {|i| puts i}
(scale :c1, :major).each_with_index do |note,index|
puts "#{note} at #{index} "
end

###########
# DOESN'T WORK
###########

# boolean operators
puts testring & (scale :d1,:minor)
puts testring | (scale :d1,:minor)

# Joining
puts (ring "hello","world").join``````
2 Likes

Hi everyone

going to revive this thread, as I am also interested in Euclid generated patterns.
I have the VPME.DE Circles and it has a mode where it also outputs the inverse. I had wondered how to do this with Sonic Pi and realised that it was a question of evaluating whether a ring item was true or false. I’m sure there are more refined ways to achieve this but, generally pleased with the result, especially the variable rotate. The inverse (false) would be good to deploy for alternating between open/closed hats.

``````live_loop :euclidPatt do
ticky = tick

if one_in(6)
rot = rrand_i(0,2)
else
rot = 0
end

#Positive
sample :perc_snap, release: 0.2, pan: -1, amp: 0.3 if (t[ticky] == true)
#Inverse of the Eucild pattern
sample :elec_flip, rate: 2, release: 0.2, pan: 1, amp: 0.4 if (t[ticky] == false)
sleep 0.25
end

``````

Cheers
Hussein

Hi @Hussein,

I might rewrite your code as the following:

``````live_loop :euclidPatt do
tick
if one_in(6)
rot = rrand_i(0,2)
else
rot = 0
end

#Positive
sample :perc_snap, release: 0.2, pan: -1, amp: 0.3, on: t.look
#Inverse of the Eucild pattern
sample :elec_flip, rate: 2, release: 0.2, pan: 1, amp: 0.4, on: !t.look
sleep 0.25
end
``````

Note, that I just call `tick` (there’s no need to assign the result as you can use `.look` to “look it up” later). I then use the `on:` opt instead of `if` as this lets you put the option anywhere in the options and not just at the end. It also supports counting `1` as true and `0` as false which can be useful in other situations. Finally I used the `!` modifier which returns the logical inversion of the value (`!true == false`).

I hope that this helps

Hi @samaaron cheers for the adaptation.

I sometimes run into issues using the !, i.e. not flipping when I expect it to.

In respect of `on:` is this preferred rather than using if? I’ve wondered about additional `opts` after the `if` statement, so this is good to know.

Much appreciated.

I’d love to see an example of this behaviour.

In respect of `on:` is this preferred rather than using if? I’ve wondered about additional `opts` after the `if` statement, so this is good to know.

I certainly prefer it (and designed it) for the reasons I stated above

yes, I’d love to make it happen consistently. I’m not saying it’s SPi, just getting odd results, that I need to better understand what might be causing them.

I was wondering about `on` because I picked up the `if(spread...` from the help docs. So if I read this right, `on` is good to use where the `ring` is in a variable result from running `spread`, rather than inline after `amp:` using an `if` statement. is that correct or gone down the wrong rabbit hole?

Cheers.

Essentially I’d use `on:` instead of a trailing `if` in all cases - unless I know specifically that I need an `if`.

The main semantic difference (which is rarely significant) is that the a false value after a trailing `if` causes none of the statement preceding the `if` to be executed. It’s as if that line wasn’t part of the code. However, with the `on:` opt, the line is executed, just that the synth or MIDI note isn’t triggered if the value is `false`, `nil` or `0` (note that `if` treats `0` as a truthy value).

So unless an explicit need for an `if`, always use `on`.
Thanks for that, I’ll move in this general direction.

1 Like

Also reviving this thread as I’m getting syntax errors from the code @chris.krakou (in version 3.3.1).

``````# Not working
# Transformations
##| puts (scale :a1, :minor) << 88
##| puts (scale :a1, :minor).unshift(33)
##| puts (scale :a1, :minor).push(33)
##| puts (scale :a1, :minor).pop
##| puts (scale :a1, :minor).shift
##| puts (scale :a1, :minor).delete_at(1)

# Removing Duplicates
##| puts (scale :c1,:major).concat((scale :d1, :major))

# Querying
##| puts (scale :c1,:major).include? 29
##| puts (scale :c1,:major).count 29

# Iterations
##| (scale :c1, :major).reverse_each {|i| puts i}
``````

No idea what’s changed since 3.1.0… and I’m “too lazy” to check now.

The change is that scales are now treated as rings. You need to convert to lists and remove extraneous bits at start. To be fair you are using Ruby constructs like << .push .pop and these are not guaranteed to work.

The solution looks like this:

``````# Not working
# Transformations
puts (scale :a1, :minor).to_a.flatten << 88

puts (scale :a1, :minor).to_a.flatten.unshift(33)
puts (scale :a1, :minor).to_a.flatten.push(33)
puts (scale :a1, :minor).to_a.flatten.pop
puts (scale :a1, :minor).to_a.flatten.shift
puts (scale :a1, :minor).to_a.flatten.delete_at(1)

# Removing Duplicates
puts (scale :c1,:major).to_a.flatten.concat((scale :d1, :major).to_a.flatten)

# Querying
puts (scale :c1,:major).to_a.flatten.include? 29
puts (scale :c1,:major).to_a.flatten.count 29

# Iterations
(scale :c1, :major).to_a.flatten.reverse_each {|i| puts i}
``````

The addition of .to_a.flatten appropriately sorts it out.

``````puts scale :a1,:minor)   => (ring <SonicPi::Scale :A :minor [33, 35, 36, 38, 40, 41, 43, 45])
puts scale( :a1, :minor).to_a  => #<SonicPi::Scale :A :minor [33, 35, 36, 38, 40, 41, 43, 45]>
puts scale:a1, :minor).to_a.flatten.  => [33, 35, 36, 38, 40, 41, 43, 45]
``````

EDIT you can add .ring at the end if you want a ring as the final result.
I’m not sure why the format of scale includes SonicPi::Scale, .flatten by itself removes this
@samaaron might like to comment

1 Like

Thanks!
Also helping me grasp a few more features of rings.