Musique avec Sonic Pi

« Sonic Pi » est un environnement de programmation basé sur le langage Ruby. Il a été créé comme un outil d’apprentissage à la fois de la musique et de la programmation. On doit son développement à Sam Aaron dans le cadre d’une collaboration entre l’Université de Cambridge (Computer Laboratory) et la « Raspberry Pi Foundation » .


http://sonic-pi.net/

L’environnement sert à programmer et exécuter des musiques, mais il peut être également servir d’instrument, puisque le code peut être modifié pendant l’exécution.

Pour tester Sonic Pi , je propose  une mise en œuvre des propriétés de musique aléatoire de Sonic Pi sur une grille classique.
L’ « instrument » sonic pi est basé sur un nombre d’  exécutants numériques : les threads qui jouent les rôles de musiciens.


Le code est composé de 5 threads. Le premier d’entre eux synchronise les autres.
La grille est rejouée à l’infini. Le thread principal incrémente un compteur à chaque exécution complète de la grille .
Les voix (mélodie et tempo) sont exécutées de manière aléatoire (plus ou moins …).

# Claude Guéganno - 2019
use_debug false

# grille
L = (ring chord(:C3, :major), chord(:G3, :major),  chord(:A3, :minor), 
          chord(:E3, :major), chord(:F3, :major),chord(:C3, :major), 
          chord(:F3, :major), chord(:G3, :major))
G =  (ring scale(:C3, :major), scale(:G3, :major),  scale(:A3, :minor), 
           scale(:E3, :major), scale(:F3, :major),scale(:C3, :major), 
           scale(:F3, :major), scale(:G3, :major))
N = 8 # nombre d'accords dans la grille

S = (ring "zawa", "prophet", "supersaw", "tb303", "pretty_bell")

i = 0 # accord courant ( de 0 à N-1 )
ni = 0 # nombre de boucles complètes effectuées
syntheCourant = choose(S)

# tempo
tempo  = 1.0

define :arpege do |accord, n, synth|
  use_synth synth
  n.times do
    12.times do
      play choose(accord), release: 0.3, cutoff: rrand(60, 120), amp: 0.5
      sleep tempo/8
    end
  end
end


define :melodie do |accord, n|
  n.times do
    T = [tempo/2, 3*tempo/4, tempo/4]
    T = shuffle T
    j = 0
    3.times do
      play choose(accord), release: 0.7, cutoff: rrand(60, 90), amp: 2, pitch: 12
      sleep T[j]
      j = j+1
    end
  end
end


define :melodie_2 do |accord, n|
  use_synth syntheCourant
  n.times do
    T2 = [3*tempo/4, tempo/2, tempo/4]
    T2 = shuffle T2
    j2 = 0
    3.times do
      play choose(accord), release: 0.5, cutoff: rrand(60, 100), amp: 2, pitch: 12
      sleep T2[j2]
      j2 = j2+1
    end
  end
end


define :melodie_gamme do |gamme, n|
  use_synth syntheCourant
  d = tempo/8
  sleep 4*d
  n.times do
    play_pattern_timed gamme, d, release: 1.0 , pitch: 12
  end
end


in_thread(name:  :boucle) do
  rapide = 0
  loop do
    with_fx :reverb do
      arpege L[i], 1, S[i]
      i = i+1
      if i%N == 0 then
        ni = ni + 1
        if ni%3 == 0 || rapide==1 then
          syntheCourant = choose(S)
          tempo = 0.5
          rapide = 1 - rapide
        elsif ni%7 == 0 then
          tempo = 2.0
        else
          tempo = 1.0
        end
      end
      cue :tick
    end
  end
end



in_thread(name:  :air) do
  use_synth :dsaw
  loop do
    with_fx :reverb do
      sync :tick
      melodie L[i], 1
    end
  end
end



in_thread(name:  :air_2) do
  use_synth :pretty_bell
  loop do
    with_fx :reverb do
      sync :tick
      if (ni+1)%6 == 0
        melodie_gamme G[i], 1
      elsif ni > 2
        melodie_2 L[i], 1
      end
    end
  end
end



in_thread(name:  :basse) do
  use_synth :hoover
  T2 = [3*tempo/4, tempo/2, tempo/4]
  loop do
    with_fx :reverb do
      sync :tick
      if ni > 4 then
        shuffle T2
        j2 = 0
        3.times do
          play L[i][0], pitch: 12, amp: 0.5
          sleep T2[j2]
          j2 = j2+1
        end
      elsif ni > 1 then
        play L[i][0], pitch: 12, amp: 0.5
      end
    end
  end
end



in_thread(name:  :mer) do
  loop do
    sync :tick
    if ni%N > 4 and ni%N < 6 then 
        with_fx :reverb, mix: 0.5 do 
          s = synth [:bnoise, :cnoise, :gnoise].choose, amp: rrand(0.5, 1.5), attack: rrand(0, 4), sustain: rrand(0, 2), release: rrand(1, 5), cutoff_slide: rrand(0, 5), cutoff: rrand(60, 100), pan: rrand(-1, 1), pan_slide: rrand(1, 5), amp: rrand(0.5, 1) 
          control s, pan: rrand(-1, 1), cutoff: rrand(60, 110)
          sleep rrand(2, 4) 
        end 
    end 
  end 
end 

in_thread(name: :percu) do
  loop do 
    with_fx :echo, phase: 0.125, mix: 0.4 do 
       sync :tick 
       if ni>3 then
          sample :bd_tek
          sample  :drum_cymbal_soft, sustain: 0, release: tempo/3
       end
      sleep tempo/2
    end
  end
end