I re-created a track from Brian Eno's music for airports!

I got into sonic pi because I want to make soundscapes and ambient music, mainly because I am becoming obsessed with Brian Eno’s work. I stumbled upon this article by Reverb Machine breaking down two tracks from Music for airports.

The album is mainly made from loops with different lengths that slowly get out of sync. And because the article provides with some choir and piano samples I could very easily recreate the Eno sound with a bunch of live loops.

I left sonic pi running in the background until it sounded like a good intro and pressed record for a few minutes, here’s the final product.


Here’s the code!

##| Music for airports
##| 2.5


sampchoir = "C:/Users/Alex/Music/samples/Music for Airports Loops/Choir"
samppiano = "C:/Users/Alex/Music/samples/Music for Airports Loops/Piano"


live_loop :piano1 do
  sample samppiano, 0
  sleep sample_duration samppiano, 0
end

live_loop :piano2 do
  sample samppiano, 1
  sleep sample_duration samppiano, 1
end

live_loop :piano3 do
  sample samppiano, 2
  sleep sample_duration samppiano, 2
end

live_loop :piano4 do
  sample samppiano, 3
  sleep sample_duration samppiano, 3
end

live_loop :piano5 do
  sample samppiano, 4
  sleep sample_duration samppiano, 4
end

live_loop :piano6 do
  sample samppiano, 5
  sleep sample_duration samppiano, 5
end

live_loop :piano7 do
  sample samppiano, 6
  sleep sample_duration samppiano, 6
end

live_loop :piano8 do
  sample samppiano, 7
  sleep sample_duration samppiano, 7
end


live_loop :chorus1 do
  sample sampchoir, 0
  sleep sample_duration sampchoir, 0
end

live_loop :chorus2 do
  sample sampchoir, 1
  sleep sample_duration sampchoir, 1
end

live_loop :chorus3 do
  sample sampchoir, 2
  sleep sample_duration sampchoir, 2
end

live_loop :chorus4 do
  sample sampchoir, 3
  sleep sample_duration sampchoir, 3
end

live_loop :chorus5 do
  sample sampchoir, 4
  sleep sample_duration sampchoir, 4
end

live_loop :chorus6 do
  sample sampchoir, 5
  sleep sample_duration sampchoir, 5
end

live_loop :chorus7 do
  sample sampchoir, 6
  sleep sample_duration sampchoir, 6
end

I know the code is real simple, but I find it super nice how simple code creates great results. And I think sonic pi is great for those type of projects.


Update!

I just learned about defining my own functions, so I quickly created my own looper just to save up on some space and make the code be more compact. Here’s the new shortened version:

##| Music for airports
##| 2.5


sampchoir = "C:/Users/Alex/Music/samples/Music for Airports Loops/Choir"
samppiano = "C:/Users/Alex/Music/samples/Music for Airports Loops/Piano"


define :enoloop do |n, samp|
  in_thread do
    loop do
      sample samp, (n - 1)
      sleep sample_duration samp, (n - 1)
    end
  end
end


enoloop 1, samppiano
enoloop 2, samppiano
enoloop 3, samppiano
enoloop 4, samppiano
enoloop 5, samppiano
enoloop 6, samppiano
enoloop 7, samppiano
enoloop 8, samppiano

enoloop 1, sampchoir
enoloop 2, sampchoir
enoloop 3, sampchoir
enoloop 4, sampchoir
enoloop 5, sampchoir
enoloop 6, sampchoir
enoloop 7, sampchoir

I guess it could be even more compact because it still has tons of repetition, if I figure a way to do that ill post it here :slight_smile:

5 Likes

I added a couple of small editions… simply to add to the soundscape,
which was a little sparse for my own taste.

The ocean is a variant of Sam’s original ocean, from the examples.

Keep them or not, as you see fit.

Eli…

live_loop :chime1 do
  sample :elec_chime, amp: rand(0.01..0.05)
  sleep sample_duration :elec_chime
  sleep rand(2.5..4.5)
end

live_loop :chime2 do
  sample :drum_cymbal_soft, amp: rand(0.1..0.3)
  sleep sample_duration :drum_cymbal_soft
  sleep rand(2.5..4.5)
end

with_fx :reverb, mix: 0.5 do
  live_loop :oceans do
    s = synth [:bnoise, :cnoise, :gnoise].choose, amp: rand(0.05..0.075), attack: rrand(0, 4),
      sustain: rrand(0, 2), release: rrand(1, 3), cutoff_slide: rrand(0, 5), cutoff: rrand(60, 100),
      pan: rrand(-1, 1), pan_slide: rrand(1, 5)# ,  amp: rrand(0.150, 0.3)
    control s, pan: rrand(-1, 1), cutoff: rrand(60, 70)
    sleep rrand(1, 3)
  end
end
1 Like

Thanks! sounds super cool together!

Hey man can you give me a hand? hehe I’m trying to make the code sorter, here’s what I’d come up with so far:

sampchoir = "C:/Users/Alex/Music/samples/Music for Airports Loops/Choir"
samppiano = "C:/Users/Alex/Music/samples/Music for Airports Loops/Piano"

define :enoloop do |n, samp|
  in_thread do
    loop do
      sample samp, (n - 1)
      sleep sample_duration samp, (n - 1)
    end
  end
end

enoloop 1, samppiano
enoloop 2, samppiano
enoloop 3, samppiano
enoloop 4, samppiano
enoloop 5, samppiano
enoloop 6, samppiano
enoloop 7, samppiano
enoloop 8, samppiano

enoloop 1, sampchoir
enoloop 2, sampchoir
enoloop 3, sampchoir
enoloop 4, sampchoir
enoloop 5, sampchoir
enoloop 6, sampchoir
enoloop 7, sampchoir

So I defined my own looper called enoloop to avoid 15 live loops, but the code still looks super repetitive, with repeating the same function with the only difference being the argument 1 or 2 or 3 (and so on). So because of all the repetition I guess the code could be further shortened. My idea is to create a second function that takes the amount of loops as an argument and runs enoloop that amount of times. My plan is to crate this general looper function and just call it twice.

So I came up with this:

define :enoloop do |n, samp|
  in_thread do
    loop do
      sample samp, (n - 1)
      sleep sample_duration samp, (n - 1)
    end
  end
end

define :glooper do |instances, samplefolder|
  internalcount = 1
  while internalcount < instances
    enoloop internalcount, samplefolder
    internalcount + 1
  end
end

but when I call glooper (that stands for general looper) sonic pi freezes and my computer slows down to a hault and I have to reboot my system. Am I accidentally creating a million instances of enoloop? or is my logic all wrong? What other ways could I accomplish a more compact code?

Thanks in advanced bud :blush:

hi,

Could you post your whole script ? A repo on github ?
thanks

Cant you just do this

sampchoir = "~/Downloads/Music for Airports Loops/Choir" #change to suit where your samples are
samppiano = "~/Downloads/Music for Airports Loops/Piano"

define :enoloop do |n, samp|
  n.times do |i| #i goes from 0 to n-1
    in_thread do
      loop do
        sample samp, i
        sleep sample_duration samp, i
      end
    end
  end
end


enoloop 8, samppiano
enoloop 7, sampchoir
1 Like

Hey Alex :slight_smile:

Indeed! If you look at your :glooper function:

define :glooper do |instances, samplefolder|
  internalcount = 1
  while internalcount < instances
    enoloop internalcount, samplefolder
    internalcount + 1
  end
end

…Notice that on the last line of the while loop, you are not actually assigning the result of that expression back to the internalcount variable. Its value is always < instances when the loop repeats, so it never exits. New threads ahoy!

Having said that, for compact solutions, the above idea from @robin.newman is good. (Technically speaking you could even go one step further and replace the in_thread and loop with dynamically named live_loops - but that’s probably a needless optimisation :laughing:)

1 Like

That’s why I suggested to get the whole script :smiling_face:

Right now it’s a big mess because I keep commenting out previous versions, but here you go!

Yep this is the issue .

Are the samples for the piano and choir available somewhere?

You could also say

internalcount += 1

I find this more concise and elegant.