Tune to start with sonic pi : au clair de la lune

As @Eli claims i don’t post m u s i c, i propose this tune for beginners with a well-known tune Au clair de la lune in French, how you call it into your own country ?
I introduce an idea for futur : the use of json format to save parameters.
We can do with array yes we can.

# NLB - 25-03-2020
# Au clair de la lune -
# understand how to code a little tune
# use of json format for the hype (or not)
# use robert

require "json"

# json may be useful or not :-)
# See in the futur
# the idea : save into it parameters modified by knob of a midi device.


my_instruments = '
{
 "piano":
  {
  "piano_01": {"a":0.01,"d":0.1,"s":0.8, "r":0.25, "cutoff":80},
  "piano_02": {"a":0.01,"d":1,"s":0.1, "r":0.25, "cutoff":60}
  },
 "tb303":
  {
  "tb303_01": {"a":0.3,"d":0.8,"s":0.4, "r":0.5, "cutoff":120},
  "tb303_02": {"a":0.1,"d":0.5,"s":0.25, "r":0.5, "cutoff":60},
  "tb303_03": {"a":0.1,"d":0.3,"s":1, "r":1, "cutoff":80}
  },
"pretty_bell":
  {
  "pretty_bell_01": {"a":0.1,"d":0.8,"s":0.4, "r":0.5, "cutoff":40},
  "pretty_bell_02": {"a":0,"d":0.4,"s":0.5, "r":1, "cutoff":80}
  }
}'


define :robert do | famille, num |
  
  parsed = JSON.parse(my_instruments) # returns a hash
  flavour = famille +"_"+num
  foo = parsed[famille][flavour]
  use_synth famille
  use_synth_defaults attack: foo["a"],
    decay: foo["d"],
    sustain: foo["s"],
    release: foo["r"],
    cutoff: foo["cutoff"]
end

# set the tempo 190 beat per minute
use_bpm 120


# puzzle your whole tune into many pieces that will repeat themselves during the tune

# the notes "riff"
riff_A = [:c, :c, :c, :d, :e, :d]

# the length "l" for each note
l_A = [1, 1, 1, 1, 2, 2]

# do the same model for all the pieces
riff_B = [:c, :e, :d, :d,:c]
l_B = [1, 1, 1, 1, 4]

riff_C = [:d, :d, :d, :d,:a3, :a3, :d, :c, :b3, :a3, :g3]
l_C = [1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 4 ]


# define the structure of the whole tune

define :structure do
  
  2.times do
    play_pattern_timed riff_A, l_A
    play_pattern_timed riff_B, l_B
  end
  
  play_pattern_timed riff_C, l_C
  play_pattern_timed riff_A, l_A
  play_pattern_timed riff_B, l_B
end

live_loop :metronome do
  sleep 1
end


live_loop :first_voice, sync: :metronome do
  
  robert "piano", '02'
  with_fx :reverb, room: 0.5 do
    with_fx :level, amp: 1.2 do
      structure
    end
  end
end

# canon effect
# you can change the tb303 favour to 02 and run again,
# at the end of the structure, the change will be set
live_loop :second_voice, sync: :metronome, delay: 4 do
  robert "tb303", '02'
  with_fx :level, amp: 0.5 do
    use_octave -1
    structure
  end
end

live_loop :drum, sync: :metronome do
  with_fx :reverb, room: 0.5 do
    sample :drum_tom_lo_soft, amp: 1, pan: -0.5
    sample :drum_bass_hard, amp: 0.5, pan: 0.5
    sleep [2, 0.5, 1.5, 3, 1].tick
  end
  
end

live_loop :hh, sync: :metronome do
  tick
  sample :drum_cymbal_pedal, rate: 2, attack: 0, sustain: 0.2, amp: 0.4
  if look==16
    sample :drum_cymbal_soft, attack: 0, sustain: 1, amp: 0.4
    tick_set 1
  end
  sleep 1
  
end

Voilà voilà

2 Likes

Hey now… just a weee second there! @nlb :slight_smile:

I did not say you dont post music! I said it’s nice to see you posting
music AGAIN… as well as all the technical posts and help you do.

Eli…

1 Like

Some interesting coding ideas in your au clair de la lune piece.

I find this pretty interesting, because I was just in the process of trying to figure out how to persist a series of notes from the work Pavane (by Faure), and do so in a way that is both readable and concise, will keeping note duration, amp, and without needing to provide ADSR for every single note.

I found a tone.js tool that will convert a MIDI file to JSON (https://tonejs.github.io/Midi/) which was nice because I had also found a site that made a MIDI file available for Pavane for a clarinet duo: (https://www.8notes.com/scores/11159.asp?ftype=midi).

Now, reading your code I see some Lang words that I don’t see in the Lang reference, which causes me to realize something that I had not realized yet. It seems that Sonic Pi isn’t just built with Ruby, but is in fact an extension of the Ruby language? So… we can just write Ruby code in the Sonic Pi application? …I don’t really know Ruby code yet but think I can learn it!

It is true that Sonic Pi is written in Ruby, and many Ruby language command do work within the context of a Sonic Pi program. However such commands should be used carefully and with the proviso that although they may work now they are not guaranteed to continue to work in the future. Having said that, there are some commands that have been used quite a bit. However there are other areas which although they may work are perhaps best avoided. For example using the ruby def command instead of the Sonic Pi define command. Using def doesn’t bring any significant advantages, and can lead to confusion when it is normally replaced with slightly different syntax with the define command.
Personally I have found some string handling commands within Ruby very effective to use in Sonic Pi code, albeit that some can be a bit inscrutable to follow if you don’t know them. The other thing is Sam’s phlosopy that there shouldn’t be anything in the Sonic Pi language that a 9 or 10 year lod couldn’t understand and be comfortable with.

Thanks Robin. Not trying to be pedantic, but there is a difference (to me) between “being written in” and “being an extension of” – I knew Sonic Pi was written in Ruby, but I didn’t realize until today that it was also an extension of Ruby… and I didn’t realize that until seeing some language elements in this post that I don’t see in the Sonic Pi Lang guide.

Maybe I don’t know enough about Ruby and perhaps everything written in Ruby is also an extension of Ruby?

I see it this way… to use an example. The Basic interpreter is written in C and Assembly, that doesn’t make it an extension of those languages – it just means those languages were used to build the interpreter – somebody could have used Pascal instead to build the interpreter… and it would have changed nothing about the Basic language itself. Does this distinction make sense?

So when you say we should be careful about using a Ruby lang element in Sonic Pi because it might not be supported in the future – I’m curious about that? Does this mean that Sonic Pi might stop being an extension of Ruby at some point?

hi everybody,

IMHO it would be great to have the fully ruby instructions available into spi ; a child can use the spi language and then go to more sophisticated concepts.
What i have understood is that sonic pi contains only a space of functions of ruby ? Am i wrong ?

the loading of a external json file works right now into sonic pi.

require "json"
require 'net/http'


# call to an external api
url = "https://quote-garden.herokuapp.com/quotes/search/love"
uri = URI(url)
puts response = Net::HTTP.get(uri)
# to get enough time to get the api answer
sleep 4
foo = JSON.parse(response)
puts foo

# to puts the values
foo["results"].each do | quote|
  puts quote["quoteText"] + " by " + quote["quoteAuthor"]
end


# if you want to get the index
foo["results"].each_with_index do |quote, idx|
  puts idx.to_s + " -- " + quote["quoteText"] + " by " + quote["quoteAuthor"]
end


# to get some indice quote
puts foo["results"][25]["quoteText"]
puts foo["results"][25]["quoteAuthor"]


# get json string from a local file
s = File.read("/home/nlb/audio/audio-code/spi/instruments.json")
# parse and convert JSON to Ruby
obj = JSON.parse(s)
puts obj

Sam may or may not have further comments on this, but some ideas have been thrown around about rewriting the DSL in another language, so yes, that is a possibility. If it does happen though, as far as I know it would be a long way off yet.