A basic framework for using TouchOSC with Sonic Pi

Hello Folks.

I spent easter getting TouchOSC to work with sonic pi and I thought I’d share my work. Hopefully this will help someone avoid a few of the problems I ran into.

Basic Setup
The first thing you need to do is go to settings -> Input/Output and allow Sonic Pi to receive external OSC messages. Then you need to grab the TouchOSC App from the App Store / Play Store. In TouchOSC you will need to set up the connection between it and your computer by entering the IP Address of the machine. You will also want to set the Outgoing Port field to 4559, since that’s the port Sonic Pi expects to get OSC messages from. Once you’ve done this, open Sonic Pi and TouchOSC, pick a layout on your app, and give one of the sliders a wiggle. If the connection works, you’ll see a ton of messages in the Cues section.

Making Layouts
Once you got this part working, you’ll probably want to make a less expansive layout at first. These are made with the TouchOSC Editor. My layout looks like this: 5 sliders for amplitude, 5 toggle buttons for on-off effects, and 6 sliders for messing with effects and parameters. You can download the layout file here and give it a try. OSC Layouts is a very personal thing, and I encourage you spend a bit of time making your own. It’s your instrument, after all!

Getting the code working
Accessing the OSC elements is quite simple. You refer to it as a web address like “/osc/1/Slider1”, and TouchOSC gives you a floating point number back. Usually one between 0 and 1. The question is how to save the data you get. This is where I ran into most of my trouble.

The general approach is to use set and get to store your OSC data in Time States and use those as a kind of global variable. With set, you can either get or sync the OSC data. sync makes the code wait until something changes, whereas get continuously poll the device for data. Using get will give you the most up-to-date data, but it takes up a ton of resources, and even on the biggest machines Sonic Pi will start cracking and popping within 10 minutes or so.

So what I did was to save a script for setting up the process of gathering data, and loading that in another buffer. This script has a loop for each layout item, which waits for changes in the layout items. I also ran into another problem, which is that since i wanted to fade my loops in and out, i needed them to run constantly. This also made Sonic Pi cry. So i also made a framework for having my five loops (one for each amplitude slider), and having them sleep when the amp is 0. This helped a ton, and now I can do fancy stuff with fading in and out and changing code snippets on the fly.

This first one is where I set up my communication with TouchOSC. It’s not very complicated, just awfully repetitive. It works perfectly with the layout I linked above. The second code piece is my “Boilerplate” where I put the actual music loops. I’m going to experiment with the idle time and see how responsive i can make it, while making sure it runs flawlessly.

Setup

use_osc "localhost",4559
#remote_ip="192.168.43.1" #hotspot
remote_ip="192.168.1.3" #at home

live_loop :bar1 do
  sig1 = sync "/osc/AmpFader/1"
  set :amp1,sig1[0]
end

live_loop :bar2 do
  sig2 = sync "/osc/AmpFader/2"
  set :amp2,sig2[0]
end

live_loop :bar3 do
  sig3 = sync "/osc/AmpFader/3"
  set :amp3,sig3[0]
end

live_loop :bar4 do
  sig4 = sync "/osc/AmpFader/4"
  set :amp4,sig4[0]
end

live_loop :bar5 do
  sig5 = sync "/osc/AmpFader/5"
  set :amp5,sig5[0]
end

live_loop :dial1 do
  sig6 = sync "/osc/FxRotary1"
  set :fx1,sig6[0]
end

live_loop :dial2 do
  sig7 = sync "/osc/FxRotary2"
  set :fx2,sig7[0]
end

live_loop :dial3 do
  sig8 = sync "/osc/FxRotary3"
  set :fx3,sig8[0]
end

live_loop :dial4 do
  sig9 = sync "/osc/FxRotary4"
  set :fx4,sig9[0]
end

live_loop :dial5 do
  sig10 = sync "/osc/FxRotary5"
  set :fx5,sig10[0]
end

live_loop :dial6 do
  sig11 = sync "/osc/FxRotary6"
  set :fx6,sig11[0]
end

live_loop :Toggle1 do
  sig12 = sync "/osc/FxToggle/1/1"
  set :toggle1,sig12[0]
end

live_loop :Toggle2 do
  sig13 = sync "/osc/FxToggle/1/2"
  set :toggle2,sig13[0]
end

live_loop :Toggle3 do
  sig14 = sync "/osc/FxToggle/1/3"
  set :toggle3,sig14[0]
end

live_loop :Toggle4 do
  sig15 = sync "/osc/FxToggle/1/4"
  set :toggle4,sig15[0]
end

live_loop :toggle5 do
  sig16 = sync "/osc/FxToggle/1/5"
  set :toggle5,sig16[0]
end

Boilerplate

live_loop :loop1 do
  if (get(:amp1) > 0) then
    
  else
    sleep 1
  end
end

live_loop :loop2 do
  if (get(:amp2) > 0) then
    
  else
    sleep 1
  end
end

live_loop :loop3 do
  if(get(:amp3) > 0) then
    
  else
    sleep 1
  end
end

live_loop :loop4
if (get(:amp4) > 0) then
  
else
  sleep 1
end
end

live_loop :loop5
  if (get(:amp5) > 0) then
    
  else
    sleep 1
  end
end

So there you have it. A basic setup for you to get started working with TouchOSC. Just having the amp sliders is priceless for fine-tuning your mix, fading seamlessly from one to another, and because Sonic Pi’s synthesizers have very different opinions on what amp: 1 means.

6 Likes

Just came over to read this after you mentioned it in reply to my question(s).

Great idea using a separate buffer to sync for OSC messages then updating them, I was wondering how to get around the whole… sync/get thing without blasting the processing out of the water on my poor little rPi.
In terms of applying this to my issue, I see that sonic pi can actually generate it’s own OSC messages, perhaps this will be of some use too.

Lots of ideas to test/play with thanks.

Hi @chris.krakou,

just a hint, you might want to consider: You can consolidate the listening live loops to one or two as here or here. This will probable reduce the load further. If you like have a look at the function parse_osc (which I borrowed slightly modified by Robin), that sorts out the incoming messages according to the osc path. If you have a clear naming convention it is easy to then use the path elements to identify your parameters within the listeniing live loop…

One more thing: If you provide a handler for your synth or sample where you e. g. want to set the amp you can not only set and get the amp globally (something like: set :amp2, sig2[0]) but control it in real time (example here). Not sure if you want that and how it fits into your framework but it is a neat option.

EDIT: Oh, just saw, that I am commenting on a 9 months old entry … :wink: Well, never mind, maybe it’ll be helpful anyway.

1 Like

Oh definitely. I haven’t looked at TouchOSC much since, I just might pick it up again to test out the stuff you wrote about. Anything that takes some of the load off the OSC code is much appreciated.

1 Like