How to check if a value exists in an array

Hello Legends,
I’m building off Robin Newman’s awesome Dual Ultrasonic Theramin

I’m using a single sensor and have divided the osc data stream into various ranges (3 - 30, 31-40, 41-55)
using if statements eg, (if b>2 and b>31) but it tends to throw timing exceptions.

Is there a more efficient way to check if the received distance reading is within a defined range (range 3, 30) similar to ruby’s ‘include?’ method?

Any and all replies appreciated!

footnote: sonic pi was my introduction to code and programming - thank you Sam Aaron!

Hey @jonathongriggs :slight_smile: Welcome to the community!
How about you post some of your code below, and we can check it for any potential issues :+1:


see if this makes sense, the received osc value bb if checked against the two statements determines if it plays 60. When I give it only 1 condition it runs fine but with extra step of 2 conditions, i think, is causing it to get behind time. So Ive been looking for alternative ways to check if a number is within a range, looking to ruby for clues… I thought about using an array to define the ranges and check if a value exists within the array.

live_loop :how do
b=sync “/osc:*/play_this/”
if bb > 40 and bb <60
play 60
sleep 0.05

@robin.newman will likely have some more comments, but I am not sure it is just the conditional statements that are the issue. There are a couple of recommended practices when receiving a stream of OSC commands, one of them usually being to place use_real_time at the top of the OSC receiving loop to remove Sonic Pi’s scheduling delay for that loop, as we want the OSC to arrive as quickly as possible. We’d also typically separate the OSC loop from the actual playing of the synth/sample, and communicate between them using the Time-State system, (a kind of global memory store). If you haven’t yet, it’d probably be worth reading through the documentation for get and set - (see Tutorial chapters 10 and 10.1 for those).

1 Like

This really helps, I’ve been mostly groping in the dark for ways to do things. Separating the osc loop from the synth/sample loop is a great idea and I’ll try that immediately, will report back…

Hi Jon… welcome to the madness.

I’m sorry you’ve felt left alone in the dark…

This forum exists purely to help people and
to bring us all together… and it’s also fun to
bounce idea’s off each other.

So please… come here as often as you like,
contribute if you can… or just lurk… it’s all good. :slight_smile:




Haha thanks Eli, well not entirely in the dark, these forums are gold for ideas :slight_smile:

Sorry you’ve been having problems. I meant to add something yesterday but life was rather busy then.
As has been stated I’d start with adding the use_real_time inside the osc receiving loop.
There are various ways to deal with ranges of input. You can use the ruby include? method (although ruby per-se is not formally supported I find it works OK.) Similarly the ruby case structure is something I’ve also used in such situations. Ive also used multiple if…elsif… statements.
The ultrasonic sensors are not particularly responsive. You will find things are much better if you invest in a ToF (Time of Flight) sensor

All good! I’m just exploring all the options I don’t yet know about, it’s been quite the adventure.
I found that running the ultrasonic sensor from the raspi as well as the tons of sonic pi sounds and samples I was using caused constant sensor script crashes, most common error “no echo received”. I troubleshooted various forms and methods for triggering the sensor but it wasn’t as snappy as it needed to be for the sculpture. So I used arduino and ethernet rig to send osc to raspi - which is bulletproof, but still not great past 30cm.

ToF looks ideal! Had no idea that existed :slight_smile: Looks like a solid setup! Enjoyed your vid :slight_smile: I’ll be using that for the next piece!

I included use_real_time in each of the time sensitive loops, and dedicated a loop to posting the latest osc value to Time State as Ethen suggested :slight_smile: which immediately gave results​:+1:

Ah! else if ! I’m going to try that :slight_smile: Here’s a vid that sort of shows what it is. It’s not the final sounds but it gives the idea :slight_smile:


That sounds interesting! The video is of your project?

1 Like

It is! Still refining the actual sounds, the key has been in hearing the sound in quick response to the touching. Connecting the hand to what you hear. The biggest issue currently is getting the sensor to see every little object that passes in front. The sensor is mounted inside the left “elbow”, looking across the internal space behind the bits that hang down. When the bits are touched, the idea is that the person’s hand or the wool strip will be pushed back in some way which will cause it to trip the sensor and give a distance reading. It’s not a perfect system, it is not without its limitations but it’s how this one has come together :slight_smile: The next one will use a Time of Flight sensor i think for sure, seems fast, accurate and more responsive.

I do have some code that I would love advice on. It is lifted from @robin.newman’s theremin, replacing the synth with noise and modulating the cutoff with the osc readings to create a wind effect. The problem is it won’t always notice when there is no input and will not fade out. It is also using the long sustained note which is then controlled conditionally and is activated only when the data value is within a set range 20-50cm.
My question is how to let the wind sound timeout when there is no activity and return to silence. I’ve tried a few different approaches but I’d love to know your thoughts?

with_fx :ixi_techno,phase: 30,phase_offset: 1, cutoff_max: 20, mix: 0.8 do |p|
set :p, p
use_synth :pnoise
k=play 60, sustain: 50000,amp: 0.1,amp_slide: 0.2, cutoff: 30, release: 3
set :k, k
live_loop :remin do
sync “/live_loop/remin” ## loop that checks :oscset if the value is 20-50, if so, this loop syncs
r1=get(:oscset) ## osc value posted in time state
r3=90-r1 ## inverting the range for the cutoff
if ??? (this loop syncs when value is in range so how do I stop it when it is not?
control get(:k), amp: 0.7, amp_slide: 0.3, cutoff: r3+30, cutoff_slide: 2
control get(:p),cutoff_max: r1+40, cutoff_max_slide: 2,mix: 0.7
else ??? (
control get(:k), amp: 0.1, amp_slide: 0.3
control get(:p),cutoff_max: 40, cutoff_max_slide: 2
sleep 0.3

You mention that there may not always be values arriving from the sensor (do I understand that correctly?) - can your setup be modified to always send a value, such as a default value when the sensor is not detecting anything?


Maybe have a look at Control the stop of a live_loop with a condition
search for kill.
Tip : to format your code on this forum use backtips :slight_smile: