Autonomous loops attempt

This was an attempt to create something which doesn’t have to be ‘music’, but at least ‘interesting’ to listen to for a few minutes. Randomising whilst avoiding total cacophony is hard :slight_smile:


use_random_seed 17

notes = [:a, :b, :c, :d, :e, :f, :g]
scales = [:minor, :major, :m6, :diminished]

chords = [(chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose)]
pat = (ring chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose)

x = 0
panner1 = (ring -1, -0.8, -0.6, -0.4, -0.2, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 0.8, 0.6, 0.4, 0.2, 0, 0, 0, -0.2, -0.4, -0.6, -0.8, -1, -1)
rater1 = (ring 2.75, 2.7, 2.65, 2.6, 2.55, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 2.9, 2.85, 2.8)
rater2 = (ring 0.5, 0.45, 0.4, 0.35)
releaser1 = [0.1, 0.125, 0.15, 0.15, 0.15, 0.15, 0.175, 0.2]
attacker1 = (ring 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02)
amper1 = (ring 0.5, 0.55, 0.6, 0.65)
sleep 0.8

in_thread(name: :beeper) do
  live_loop :beeper1 do
    if one_in 5 then
      synthMem = "tri"
      use_synth :tri
      i = 1.2
      min = 0.015
    else
      if one_in 5 then
        synthMem = "dull_bell"
        use_synth :dull_bell
        i = 0.8
        min = 0.01
      else
        synthMem = "beep"
        use_synth :beep
        i = 1.8
        min = 0.02
      end
    end
    sync :startbeeper
    puts "startbeeper1: ", synthMem
    32.times do
      play pat.look, amp: i, attack: attacker1.tick, release: releaser1.choose
      i -= min
      i = 0 if i < 0
      sleep 0.25
    end
    sleep 1
    if one_in 2 then
      16.times do
        play pat.look, amp: i, attack: attacker1.tick * 2, release: releaser1.choose * 2
        i -= min
        i = 0 if i < 0
        sleep 0.2
        if one_in 2 then
          play pat.look, amp: i, attack: attacker1.tick * 2, release: releaser1.choose * 2
        end
        sleep 0.3
      end
    else
      sleep 16 * 0.5
    end
    sleep 1
    32.times do
      play pat.look, amp: i, attack: attacker1.tick, release: releaser1.choose
      i -= min
      i = 0 if i < 0
      sleep 0.25
    end
    puts "new chords, new pat"
    chords = [(chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose), (chord notes.choose, scales.choose)]
    pat = (ring chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose, chords.choose)
  end
end

in_thread(name: :bass) do
  sync :startbass1
  puts "started bass1"
  live_loop :bass1 do
    sample :bd_boom, amp: 2, rate: 1.75
    sleep 4
    if one_in 64 then
      puts"stopped bass1"
      sync :restartbass1
      puts"restarted bass1"
    end
  end
  
  sync :startbass2
  puts "startbass2"
  live_loop :bass2 do
    sample :bd_klub, amp: 3, rate: 0.8
    sleep 0.5
    if one_in 128 then
      puts"stopped bass2"
      cue :bass2alt
      sync :restartbass2
      puts"restarted bass2"
    end
  end
  
  live_loop :bass2alt do
    sync :bass2alt
    puts "started bass2alt"
    8.times do
      sample :bd_klub, amp: 2.8, rate: 0.6
      sleep 0.25
    end
  end
  
  sync :startbass3
  puts "startbass3"
  live_loop :bass3 do
    sample :bd_pure, amp: 3.5, rate: rater1.look(:rate) - 1.8
    sleep 0.125
    if one_in 64 then
      puts"stopped bass3"
      cue :ambi2
      sync :restartbass3
      puts"restarted bass3"
    end
  end
end

in_thread(name: :slowAmbi) do
  live_loop :slowAmbi do
    use_synth :hollow
    sync :slowAmbi
    puts "slowAmbi"
    2.times do
      play pat.tick, amp: 3, attack: 0.05, release: 7
      sleep 8
    end
  end
  live_loop :ambi2 do
    use_synth :dark_ambience
    sync :ambi2
    puts "ambi2"
    2.times do
      sleep 2
      play pat.look, amp: 2.5, attack: 3, release: 7
      sleep 12
    end
  end
end

in_thread(name: :fastTicker) do
  live_loop :fastTicker do
    x += 1
    if one_in 4 then
      puts "elec_triangle - blip"
      amp = 2.8
      32.times do
        sample :elec_triangle, amp: amp, rate: rater1.tick(:rate), pan: panner1.tick(:pan)
        amp -= 0.05
        amp = 2.8 if amp < 0
        if one_in 8 then
          sleep 0.1
          sample :elec_filt_snare, amp: amp / 4, rate: rater1.look(:rate) / 9, pan: panner1.tick
          sleep 0.15
        else
          sleep 0.25
        end
      end
    else
      if one_in 4 then
        puts "elec_soft_kick"
        64.times do
          sample :elec_soft_kick, amp: 2, rate: rater1.tick(:rate) - 1.8, pan: panner1.tick(:pan)
          sleep 0.25
        end
      else
        if one_in 4 then
          puts "elec_tick"
          64.times do
            sample :elec_tick, amp: 2, rate: rater1.tick(:rate) - 1.8, pan: panner1.tick(:pan)
            if one_in 4 then
              sleep 0.125
              sample :elec_tick, amp: 1.4, rate: rater1.look(:rate) - 1.2, pan: panner1.look(:pan)
              sleep 0.125
            else
              sleep 0.25
            end
          end
        else
          puts "cymbals"
          4.times do
            sample :drum_cymbal_hard, rate: rater2.tick
            sleep 0.2
            if one_in 2 then
              sample :drum_cymbal_pedal, rate: rater2.look - 0.25
            else
              sample :drum_cymbal_soft, rate: rater2.look - 0.25
            end
            sleep 0.6
            sample :ambi_choir, rate: rater2.look - 0.2, amp: amper1.tick
            sleep 3.2
          end
        end
      end
    end
    cue :slowAmbi
    puts "x", x
    
    cue :startbass1 if x == 1
    
    if x == 2 then
      cue :startbass2
      sample :misc_crow, rate: 0.23
    end
    if x == 3 then
      cue :startbass3
      sample :misc_crow, rate: 0.18
    end
    if one_in 2 then
      cue :startbeeper
      if one_in 2 then
        sample :misc_crow, rate: rrand(0.15, 0.25)
      end
    end
    if one_in 4 then
      puts "recue basses..."
      cue :restartbass1
      cue :restartbass2
      cue :restartbass3
    end
    if one_in 32 then
      puts "pat shuffled"
      pat.shuffle
    end
    if one_in 16 then
      puts "panner1 reversed"
      panner1.reverse
    end
    sleep 1
  end
end


5 Likes

Hmmmm… I think I’d find that far too distracting to just listen to… too many
squeaks and pops and… ‘stuff’… :slight_smile:

I’d want to know how it was done.

I also experimented with a series of tracks I called ‘Elevator Music’, because
quite literally you’d expect to hear them in an elevator.

Several of my Soundcloud tracks are also ambient loops meant to be played
for long periods, such as:

I just havent found a way to loop them on Soundcloud yet…

Eli…


chords = [(chord :C, :minor7), (chord :Ab, :major7), (chord :Eb, :major7), (chord :Bb, "7")].ring
c = chords[0]

violin_amp = 0.050
guitar_amp = 0.5
guitar_release = 10
piano_amp =0.25
drum_amp = 0.5


live_loop :piano_tune do
  use_synth :piano
  r = [0.25, 0.25, 0.5, 1].choose
  play c.choose, amp: piano_amp, release: 0.2, decay: 1.0125, sustain: 0.25
  sleep r
end

live_loop :keys do
  use_synth :piano
  play c, amp: 0.5
  sleep 1
end

live_loop :guitar do
  use_synth :pluck
  use_transpose -12
  3.times do
    play c[0], amp: guitar_amp, decay: 8, sustain: 10
    sleep 1
  end
  play c[2], amp: guitar_amp, decay: 8, sustain: 10
  sleep 0.5
  play c[1], amp: guitar_amp, decay: 8, sustain: 10
  sleep 0.5
  c = chords.tick
end

live_loop :drums do
  sync :guitar
  1. times do
    with_fx :reverb, room:0, damp: 0.7 do
      sample :drum_tom_mid_hard, rate: 1, pitch_dis: 0.001, amp: drum_amp
      sleep 0.75
      sample :drum_tom_lo_hard, rate: 1, pitch_dis: 0.001, amp:  drum_amp/2
      sleep 0.75
      sample :drum_tom_lo_soft, rate: 1, pitch_dis: 0.001, amp: drum_amp
      sleep 0.75
      if one_in(4) then
        sample :drum_bass_hard, rate: 1, pitch_dis: 0.001, amp: drum_amp
      end
      sleep 0.75
      sample :drum_cymbal_soft, rate: 1, pitch_dis: 0.001, amp: drum_amp/2
      if one_in(2) then
        sample :drum_heavy_kick, rate: 1, pitch_dis: 0.001, amp: drum_amp/2
        sample :drum_snare_hard, rate: 1, pitch_dis: 0.001, amp:  drum_amp
      end
      if one_in(3) then
        sample :drum_cymbal_open, rate: 1, pitch_dis: 0.001, amp: drum_amp/2
      end
    end
    sleep 0.75
  end
end

live_loop :slow_violin_strings do
  use_synth_defaults depth: 10, divisor: 0.1
  sync :piano_tune
  with_fx :flanger do
    use_synth :blade
    use_transpose 0
    play c, amp: violin_amp, attack: 2, sustain: 1.5, release: 1
    sleep 1.5
    play c[2], amp: violin_amp, attack: 2, sustain: 1.5, release: 1
    sleep 1.5
    play c[1], amp: violin_amp, attack: 2, sustain: 1.5, release: 1
    sleep 1.5
    if one_in(1)then
      sleep 1
      play c[4], amp: violin_amp, attack: 2, sustain: 1, release: 1
    end
    if one_in(5)then
      sleep 1.5
      play c[3], amp: violin_amp, attack: 2, sustain: 1, release: 1
    end
    if one_in(3)then
      sleep 1.5
      play c[6], amp: 0.25, attack: 2, sustain: 1, release: 1
    end
    c = chords.tick
    sleep 1
  end
end
2 Likes

Or perhaps this might be more up your street… it was a
’mashup’ of code posted on the old forums some time back
in early 2016…

Eli…

#Eli. 2016.

use_debug false

use_random_seed 66776

live_loop :beat do |idx|
  with_fx :hpf, cutoff: 10 do |f|
    this_sample = [:bd_808, :bd_zum, :bd_zome, :bd_klub, :bd_haus].choose
    if this_sample == :bd_klub then
      duration = 24
      cue :wibble
    end
    if this_sample == :bd_zome then
      duration = 16
      cue :lunar
    end
    if this_sample == :bd_zum then
      duration = 16
      cue :ambi
    end
    if this_sample == :bd_808 then
      duration = 8
      cue :long_wobble
    end
    if this_sample == :bd_haus then
      duration = 8
      cue :short_wobble
    end
    duration.times do
      sleep 0.25
      sample this_sample, rate: 1, amp: factor?(idx, 8) ? 6 : 4
      sleep 0.25
      sample :sn_dub, rate: 1, sustain: 0, release: (knit 0.05, 3, 0.5, 1)[idx]
      idx += 1
    end
  end
end

live_loop :tune1, auto_cue:false do |idx|
  sync :wibble
  use_random_seed 6667
  with_fx :echo, phase: 0.125, mix: 0.8  do
    this_note = [:e3, :a3, :c3].choose
    notes = scale(this_note, :minor_pentatonic, num_octaves: 2)
    16.times do |idx|
      sleep 0.25
      play notes.choose, pulse_width: 0.2, attack: 0, release: 0.1, pan: (range -1, 1, 0.125)[idx], amp: rrand(1, 2)
    end
  end
end

live_loop :tune2, auto_cue:false do |idx|
  sync :long_wobble
  use_random_seed 1234
  with_fx :wobble, phase: 0.125, mix: 0.8  do
    with_fx :echo do
      this_note = [:e3, :a3, :c3].choose
      notes = scale(this_note, :minor_pentatonic, num_octaves: 2)
      16.times do |idx|
        sleep 0.25
        play notes.choose, pulse_width: 0.2, attack: 0, release: 0.1, pan: (range -1, 1, 0.125)[idx], amp: rrand(1, 2)
      end
    end
  end
end

live_loop :tune3, auto_cue:false do |idx|
  sync :short_wobble
  use_synth :mod_tri
  with_fx :wobble, phase: 0.5, mix: 0.8  do
    notes = [:e2, :c3]
    use_random_seed 67
    16.times do |idx|
      sleep 0.25
      play notes.choose, pulse_width: 0.2, attack: 0, release: 0.2, pan: (range -1, 1, 0.125)[idx], amp: rrand(1, 2)
    end
  end
end

live_loop :tish, auto_cue:false  do
  sync :lunar
  with_fx :echo do
    with_fx :ixi_techno do
      sample :ambi_lunar_land, amp: 5, rate: 1
    end
  end
  sleep sample_duration(:ambi_lunar_land)
end

live_loop :ambience, auto_cue:false do
  sync :ambi
  sample :ambi_glass_hum, amp: 3, rate: 0.5
  if one_in(2) then sample :ambi_glass_hum, amp: 3, rate: 0.5
  end
  if one_in(3) then sample :ambi_glass_rub, amp: 3, rate: 0.5
  end
  sleep 1
end
2 Likes

I was more aiming for a edm/idm or pearson sound kind of thing (didn’t really succeed at that!), rather than max richter or something more classical or elevator music :slight_smile: And main aim was unpredictability and loopability. To try to make things more random, I might have to consider inputting some randomness trough sensors in gpio on rpi. Make it a lighter piece on a lighter day and a darker piece at night :face_with_raised_eyebrow:

Yours sound very nice. Polished, clean and very listenable. I might give endlessly looping elevator music a try myself someday, when i’m in the mood for it.

This is the adapted code of a script that I have in python, in Sonic pi it is much simpler.

use_bpm 70
dur=[0.50,1]
live_loop :bajo do
  use_synth :tb303
  play (ring 37,37,33,33).tick, cutoff: 60
  sleep 1
end

live_loop :voz1 do
  use_synth :blade
  dur=[0.5,1].shuffle
  if dur [0]==0.50
    2.times do
      play [44,49,52].choose, release: dur[0]
      sleep dur[0]
    end
  else
    play [44,49,52].choose, release: dur[0]
    sleep dur[0]
  end
end


live_loop :voz2 do
  use_synth :chiplead
  if dur[1]==0.5
    2.times do
      play [61,64,66,68,71].choose, release: dur[1]
      sleep dur[1]
    end
  else
    play [61,64,66,68,71].choose, release: dur[1]
    sleep dur[1]
  end
end

The python version uses other syntetizers: the zynaddsubfx and the fluidsynth

1 Like

I’ve been looking at some code that Tonny posted over in this thread:

The cleaned up version (I knocked out a couple synths and changed some
release times, is all) is pretty cool…

Eli…

live_loop :melody do
  with_fx [:compressor, :echo, :reverb].choose, mix: rrand(0.3,0.6) do
    use_synth [:hollow, :dark_ambience, :blade].choose
    r = [ 1,2].choose
    play (chord :c, :minor).choose, attack: -0.25+r, release: r, amp: rrand(0.2, 0.8)
    sleep r+0.25
  end
end

live_loop :keys do
  use_synth :blade
  with_fx :ixi_techno, mix: rrand(0.2, 0.6) do
    play chord(:c, :minor), amp: rrand(0.2,0.6)
    sleep 0.5
  end
end

live_loop :bass do
  with_fx [:compressor, :echo, :reverb].choose, mix: rrand(0.4,0.7) do
    use_synth [:hollow].choose
    n = (chord :c2, :minor).tick
    7.times do
      play n, amp: rrand(0.8, 3.6)
      sleep [0.5, 1].choose
    end
    play n
    sleep 0.5
    play (chord :c2, :minor).tick, amp: rrand(0.8, 1.8)
    sleep 0.5
  end
end

Hi, @GooDump !

Here’s some tricks from Ruby land to help you do some of the thing you’re going a little easier:

chords = [(chord notes.choose, scales.choose), ..., (chord notes.choose, scales.choose)]
# can become
chords = 21.times.collect{(chord notes.choose, scales.choose)} 

Similarly,

pat = (ring chords.choose, ..., chords.choose)
# can become
pat = 32.times.collect{chords.choose}.ring

“Collect” means “For each element in the array, do something, and keep the result”, or in this case, “do this thing 21 times, and make an array out of that”. Does that make sense?

(The curly brackets are shortcut for do...end, if you only need one line in there)

Otherwise, I like this experimental sound. It’s neat!

1 Like

Thanks for the hint!