Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Getting a few things together, in Sonic Pi. Pulse width and ring modulation driven by breath. Lip pressure (sent through MIDI as pitch bend) modulates the ring modulation mix. Incoming notes for the melody (with TB-303 type synth), counter motion for the counter melody (in FM synth).
use_real_time # Preventing latency
use_tuning :just, :c # Just Intonation
delta=counter=naute=idx=0 # Initialize a few things
previous=60 # First note for the counter melody
gamme=(scale 50, :hex_dorian, num_octaves: 5) # Setting a “ring” of values in which to find incoming notes
counter_gamme=(scale 38, :hex_dorian, num_octaves: 2) # Same for the countermelody, an octave below
with_fx :compressor, threshold: 0.2 do # Preventing clipping
with_fx :reverb, room: 0.8 do # Everything on the same reverb
with_fx :ring_mod, mix_slide: 0.02 do |ringy| # Everything on lip-controlled Ring Mod
with_fx :rlpf, res: 0.7, cutoff_slide: 0.02 do |lipf| # Everything on breath-controlled low-pass filter
tibi = synth :tb303, note: 0, wave: 1, pulse_width_slide: 0.02, res: 0.7, release: 1000, amp: 0 # TB-303-inspired pulse
counter_melody = synth :fm, divider: 4, note: 0, release: 1000, amp: 0 # FM synthesis
live_loop :notes do
note_on, velocity = sync "/midi/USB_Midi_Cable/4/1/note_on" # Incoming notes from Yamaha WX-11 wind controller
if velocity > 0 # Only use actual note-ons
delta=note_on - previous # Are we going up or down? By how much?
if gamme.index(note_on) # If you find the note in the scale…
idx=gamme.index(note_on) # Set the position in the scale
control tibi, note_slide: 0 # No portamento
control tibi, note_slide: 0.25 # Otherwise, add portamento
if delta > 0 # We’re going up, so go up the scale
idx=idx-1 # Otherwise, go down the scale
naute=gamme[idx] # Find the note in the scale
control tibi, note: naute, amp: velocity / 150.0 # Incoming note
if delta < 0 # If we’re going down
counter=counter_gamme.tick # Increment the counter if we’re going down
counter=counter_gamme.reverse.tick # Decrement it otherwise
control counter_melody, note: counter-12, amp: velocity / 160.0 # The counter note goes in reverse motion, an octave lower
previous=naute # Set the current note for the next time around
control ringy, freq: naute-20, amp: velocity / 160.0 # Assign a lower frequency to ring mod
live_loop :windy do # Use the incoming breath control, MIDI CC#2, to modulate the low-pass filter
control_change, breath = sync "/midi/USB_Midi_Cable/4/1/control_change"
if control_change==2
control lipf, cutoff: breath # Breath control opens/closes the low-pass filter
if breath==0
control ringy, amp: 0
control tibi, pulse_width: 0.5-(breath/256.0) # Also modulate the pulse width: lower is closer to square wave
live_loop :bendy do
bend_change = sync "/midi/USB_Midi_Cable/4/1/pitch_bend" # The WX-11 sends lip pressure as pitch bend
bent=(bend_change[0]-8192)/ 8192.0 # Convert pitch bend to -1.0 to 1.0
control ringy, mix: (bent.abs) # Use the absolute value to modulate the ring mod mix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment