Play_pattern_timed adding sustain...?

I introduce my brother to SonicPi (“Of course you can learn to code, check this thing out…”), and now we’re replicating “Where Is My Mind” in SP. He’s unrolled the first bit:

play :fb5
sleep 0.5
play :gs5
sleep 0.5

play :fb5
sleep 0.5
play :gs5
sleep 0.5

play :fb5
sleep 0.5
play :gs5
sleep 0.5

play :fb5
sleep 0.5
play :gs5
sleep 0.5

As per the docs, this should be equivalent to:

4.times do
  play_pattern_timed [:fb5, :gs5], 0.5
end

However, it sounds different, and when I check the logs, I see this when using play_pattern:

synth :blade, {note: 76.0, sustain: 0.5}

and this when just using play:

synth :blade, {note: 76.0}

So it seems like play_pattern_timed is also adding a sustain to match the timing…? How would I prevent that from happening?

Thanks!

Yep! Here’s the code:

  def play_pattern_timed(notes, times, *args)
    if is_list_like?(times)
      t = times.ring
      notes.each_with_index do |note, idx|
        kwargs = if args.last.is_a?(Hash) then args.last else {} end
        duration = t[idx]
        kwargs[:duration] = duration
        play(note, *[kwargs])
        sleep(duration)
      end
    else
      play_pattern_timed(notes, [times], *args)
    end
  end

You can see:

kwargs[:duration] = duration

is where that’s added. It also looks like it overrides, so I could not, for example:

play_pattern_timed [:fb5, :gs5], 0.5, duration: 2

The duration would be ignored, and the internal play call would receive a duration of 0.5… right?

So to change than - and If I’m reading everything correctly - then using this line instead:

kwargs[:duration] ||= duration

would keep existing behavior the same, but allow you to set any particular duration, including default duration (-1, right?).

So that:

play_pattern_timed [:fb5, :gs5], 0.5, duration: 2

would play the notes overlapping, while

play_pattern_timed [:fb5, :gs5], 2, duration: -1

would play the notes with a gap between them.

Hi,

as always many roads lead to Rome; here is one of the alternative ways to do that:

live_loop :play_with_release do
  # nrd -> n(otes), r(eleases), d(urations)
  # -> (ring n1, r1, d1, n2, r2, d2 ...)
  nrd = (ring :c, 1, 2, :e, 2, 2, :g, 3, 2, :c5, 4, 2)
  play nrd.tick, release: nrd.tick
  sleep nrd.tick
end
1 Like

you can use susrtain: and release: arguments with play_pattren _timed to do this eg

use_synth :blade

4.times do
  play_pattern_timed [:fb5, :gs5], 0.5,sustain: 0,release: 0.2 #alter sustain and release values as you wish, applies to all notes
end

Yes, good hint…

Last but not least, here are some examples of different ways I collected:

This trick is my bread and butter when working with the SC synths. Controlled random values in place of the ordered list are the key to my style. :slight_smile:

1 Like