Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A polyphonic gated synth for Sonic Pi3 with midi keyboard input. Runs on Raspberry Pi3 or more powerful computer with Sonic Pi 3. Accompanying article and video
#polyphonic midi input program with sustained notes
#experimental program by Robin Newman, November 2017
#pitchbend can be applied to notes at any time while they are sounding
use_debug false
set :synth,:tb303 #initial value
set :pb,0 #pitchbend initial value
kill_list=[] #list to contain notes to be killed
on_notes=[] #list of notes currently playing
ns=[] #array to store note playing references
nv=[0]*128 #array to store state of note for a particlar pitch 1=on, 0=off
128.times do |i|
ns[i]=("n"+i.to_s).to_sym #set up array of symbols :n0 ...:n127
end
#puts ns #for testing
define :sv do |sym| #extract numeric value associated with symbol eg :n64 => 64
return sym.to_s[1..-1].to_i
end
#puts sv(ns[64]) #for testing
live_loop :choose_synth do
b= sync "/midi/*/*/*/control_change" #use wild cards to works with any controller
if b[0]==10 #adjust control number to suit your controller
sc=(b[1].to_f/127*3 ).to_i
set :synth,[:tri,:saw,:tb303,:fm][sc] #can change synth list if you wish
puts "Synth #{get(:synth)} selected"
end
end
live_loop :pb do #get current pitchbend value adjusted in range -12 to +12 (octave)
b = sync "/midi/*/*/*/pitch_bend" #change to match your controller
set :pb,(b[0]-8192).to_f/8192*12
end
with_fx :reverb,room: 0.8,mix: 0.6 do #add some reverb
live_loop :midi_note_on do #this loop starts 100 second notes for specified pitches and stores reference
use_real_time
note, on = sync "/midi/*/*/*/note_on" #change to match your controller
if on >0
if nv[note]==0 #check if new start for the note
puts "setting note #{note} on"
vn=on.to_f/127
nv[note]=1 #mark note as started for this pitch
use_synth get(:synth)
x = play note+get(:pb),attack: 0.01, sustain: 100,amp: vn #start playing note
set ns[note],x #store reference to note in ns array
on_notes.push [note,vn] #add note to list of notes playing
end
else
if nv[note]==1 #check if this pitch is on
nv[note]=0 #set this pitch off
kill_list.push note #add note to list of notes to kill
end
end
end
live_loop :processnote,auto_cue: false,delay: 0.4 do # this applies pitchbend if any to note as it plays
#delayed start helps reduce timing errors
use_real_time
if on_notes.length > 0 #check if any notes on
k=on_notes.pop #get next note from "on" list
puts "processing note #{k[0]}"
in_thread do #start a thread to apply pitchbend to the note every 0.05 seconds
v=get(ns[k[0]]) #retrieve control value for the note
while nv[k[0]]==1 #while the note is still merked as on
control v,note: k[0]+get(:pb),note_slide: 0.05,amp: k[1]
sleep 0.05
end
#belt and braces kill here as well as in notekill liveloop: catches any that miss
control v,amp: 0,amp_slide: 0.02 #fade note out in 0.02 seconds
sleep 0.02
puts "backup kill note #{k[0]}"
kill v #kill the note referred to in ns array
end
end
sleep 0.08 #so that the loop sleeps if no notes on
end
live_loop :notekill,auto_cue: false,delay: 0.3 do # this loop kills released notes
#delayed start helps reduce timing errors
use_real_time
while kill_list.length > 0 #check if there are notes to be killed
k=kill_list.pop #get next note to kill
puts "killing note #{k}"
v=get(ns[k]) #retrieve reference to the note
control v,amp: 0,amp_slide: 0.02 #fade note out in 0.02 seconds
sleep 0.02
kill v #kill the note referred to in ns array
end
sleep 0.08 #so that the loop sleeps if no notes to be killed
end
end #reverb
@mrclasse

This comment has been minimized.

Show comment Hide comment
@mrclasse

mrclasse Apr 25, 2018

Hi ! I tested it and the kill process doesn't seem to work. When I press a key & release it the note stays sustained. My version is 3.1.0.

Hi ! I tested it and the kill process doesn't seem to work. When I press a key & release it the note stays sustained. My version is 3.1.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment