Skip to content

Instantly share code, notes, and snippets.

@rbnpi
Last active March 5, 2021 22:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbnpi/37a05ffade22357a4c1e07dc03ec19f6 to your computer and use it in GitHub Desktop.
Save rbnpi/37a05ffade22357a4c1e07dc03ec19f6 to your computer and use it in GitHub Desktop.
Laser ToF sensor theremin (updated Aug 2020)for Sonic Pi Full article at https://rbnrpi.wordpress.com/new-sonic-pi-theremin-using-time-of-flight-laser-sensor/ and video at https://youtu.be/MPgnz9gjeEc (osctheremin.py script now updated)
#!/usr/bin/env python3
#script to read vl53l1x sensor and send reading via OSC to Sonic Pi
#written by Robin Newman August 2018 updated August 2020 for version 0.0.5 of library
#with thanks to Pimoroni's Phil Howard @Gadgetoid for the graph.py example
#on which I based some of this script.
import time
import sys
import signal
from pythonosc import osc_message_builder
from pythonosc import udp_client
import argparse
import VL53L1X
MAX_DISTANCE_MM = 800 # Set upper range
"""
Open and start the VL53L1X ranging sensor
"""
tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29)
tof.open() # Initialise the i2c bus and configure the sensor
tof.set_timing(66000,70) #This line is added from the original version to set refresh timings
tof.start_ranging(2) # Start ranging, 1 = Short Range, 2 = Medium Range, 3 = Long Range (LINE UPDATED)
sys.stdout.write("\n")
running = True
def exit_handler(signal, frame):
global running
running = False
tof.stop_ranging() # Stop ranging
sys.stdout.write("\n")
sys.exit(0)
signal.signal(signal.SIGINT, exit_handler)
def control(spip):
sender=udp_client.SimpleUDPClient(spip,4560) #port updated to 4560
while running:
distance_in_mm = tof.get_distance() # Grab the range in mm
distance_in_mm = min(MAX_DISTANCE_MM, distance_in_mm) # Cap at our MAX_DISTANCE
sender.send_message('/range',distance_in_mm)
sys.stdout.write("\r") # Return the cursor to the beginning of the current line
sys.stdout.write ("range %3d " % (distance_in_mm))
sys.stdout.flush() # Flush the output buffer, since we're overdrawing the last line
#time.sleep(0.01)
if __name__=="__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--sp",
default = "127.0.0.1", help="The ip of the Sonic Pi computer")
args = parser.parse_args()
spip=args.sp
print("Sonic Pi on ip",spip)
control(spip)
#Sonic Pi theremin using time of flight sensor VL531X
#Discrete note version (c: major {changeable})
#by Robin Newman, August 2018 updated August 2020
with_fx :reverb,room: 0.8,mix: 0.7 do
use_synth :tri
#start long note at zero volume: will be controlled later by k
k = play octs(0,2),sustain: 10000,amp: 0
set :k,k #store k in time-state reference :k
live_loop :theremin do
use_real_time
b = sync "/osc*/range" #get osc message from sensor script. Syntax updated
v= (b[0]/12.0).to_i #scale reading and convert result to integer
puts v #print on screen
# puts scale(:g3,:major,num_octaves: 5).length #for debugging puts total no notes
if v < 36
#change the scale if you wish. (may need to change note range too)
nv=scale(:g3,:major,num_octaves: 5)[v] #get note pitch from c scale
#control the note and set the pitch and volume
control get(:k),note: nv,amp: 1,amp_slide: 0.04
else
#if v is too high then set volume to zero
control get(:k),amp: 0,amp_slide: 0.04
end
end
end #fx reverb
#Sonic Pi theremin using time of flight sensor
#smooth continuous note pitch version
#by Robin Newman, August 2018 updated August 2020
#works on Mac or Pi3
with_fx :reverb,room: 0.8,mix: 0.7 do
use_synth :dpulse
#start long note at zero vol. It will be controlled by k later
k = play 0,sustain: 10000,amp: 0
set :k,k #store k pointer in time-state as :k
live_loop :theremin do
use_real_time
b = sync "/osc*/range" #syntax updated
v= (b[0].to_f/10) #scale and convert range data to a float
puts v #put value on screen
if v<=48.2
#control the note retrieving :k pointer and adjusting pitch and amp
control get(:k),note: v+47.9,amp: 0.7,amp_slide: 0.04,note_slide: 0.04
else
#if range too high set vol to 0
control get(:k),amp: 0,amp_slide: 0.04
end
end
end #fx reverb
#Sonic Pi theremin using time of flight sensor
#tb303 frenzy version!
#by Robin Newman, August 2018 updated August 2020
#experiment changing octs(v+25.8,2) to octs(v+47.9,1) line22
#may want to increase sample default amp to 3 on a Mac
#and decrease tb303 vol from 1.4 to 0.5 on a Mac
use_sample_defaults amp: 2 #for percussion samples
with_fx :reverb,room: 0.8,mix: 0.7 do #can try gverb as well
use_synth :tb303
#start long continous note at zero volume: controlled later on by k
k = play 0,sustain: 10000,amp: 0
set :k,k #save k pointer in time state as :k
live_loop :theremin do #start thermin loop
use_real_time
b = sync "/osc*/range" #wait for input from python script
v= (b[0]/8.0)#scale the received data as a float
puts v #print value on screen
if v<=48.2 #set limit for high note
cue :drums #send cue to :dr live loop ty sync percussion
control get(:k),note: octs(v+25.8,2).tick,amp: 1.4,amp_slide: 0.04,note_slide: 0.04,cutoff: 1.5*v+57,pan: 0.8*(-1)**look
else #if outside range then set note volume to zero
control get(:k),amp: 0,amp_slide: 0.04
end
end
live_loop :dr do
use_real_time
sync :drums #only run when theremin playing a note
tick
#use three samples with spread to give some funky rhythm
sample :bd_haus if spread(2,5).look
sample :elec_twip if !spread(5,8).look
sample :drum_cymbal_closed if spread(5,8).look
sleep 0.2 #wait then go back for next cue
end
end #fx reverb
@pseddon
Copy link

pseddon commented Dec 6, 2018

I enjoyed your dual sensor version so now am trying your Time of Flight version using a Win10 laptop.
I am correctly getting varying Range data in a cmd window on the laptop but Sonic Pi does not pick up the cues and reports in the Cues window:
/live_loop/theremin []
/set/k #SonicPI::SynthNode @id=13, @name=sonic-pi-dpulse @State=pending>
/set/k #SonicPI::SynthNode @id=19, @name=sonic-pi-dpulse @State=pending>

I notice that you used Sleep(2) in the original dual sensor .py script, but not the ToF script.

Do you have any suggestions as to why Sonic Pi is not getting cues (I have enabled midi subsystems and ticked Enable OSC server and received remote Osc messages, but the log says:
=> Pausing SuperCollider Audio Server).
regards Peter

@rbnpi
Copy link
Author

rbnpi commented Aug 30, 2020

Just updated the software for latest sonic pi 3.2.2 and latest ToF library 0.0.5

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