How do I access the name of an OSC message once it has been received?

Hello,

I have been playing around with the p5.touchGui library which has some options for sending OSC messages.

I am playing around with an example that has a grid of 16 buttons.
Each time you click a button, it send an OSC message with the name of the button - /button0, /button5, /button8 etc

However, the information sent with this message is just a 1 for the button being pressed and a 0 for when the button is released.

Since there are so many diffferent possible OSC messages, I was able to make so nice short code to receive any of the buttons in one line of code:

live_loop :foo do
  use_real_time
  a = sync "/osc*/*"
   
end

However, I am now stuck for a way to determine which button was pressed since the information being sent is just 0s and 1s, no matter which button sent it.

Is there a way to get the name of the OSC message in addition to the info that is sent? Can I store it in a variable?

Ideally, I’m looking to do something like this:

live_loop :foo do
  use_real_time
  a = sync "/osc*/*"
   
  if osc_name == "/button0" # Im aware there isn't a function like this, but it is the gist of what I want 
    if a == 1
      sample :ambi_choir
      end
    end
  end 
end

Thanks in advance

This is what you need: a routine that uses an undocumented call in Sonic Pi which enables you to extract the actual osc message used to trigger the previous sync
I have used it over several years, together with a similar one for midi messages. (The latter had to be updated when midi messages were restructured in Sonic Pi see this post

use_osc "localhost",4560
use_debug false
use_osc_logging false

define:parse_sync_address do |address| #gets info on wild cards used in sync address
  v= get_event(address).to_s.split(",")[6]
  if v != nil
    #return a list of address elements with wild cards substituted by actual values
    return v[3..-2].split("/")
  else
    return ["error"]
  end
end

live_loop :findpushed do
  
  v = sync "/osc*/push*" #respond to button osc and save data in v[0]
  res = parse_sync_address("/osc*/push*") #use parse routing to extract actual osc message
  puts res #shows the output of parse_sync address
  puts "button ",res[1],"was triggered"
  puts "this has index",res[1][4..-1].to_i
  puts "data value sent was",v[0]
end


live_loop :test do #this loop generates osc calls from 30 virtual push buttons
  n = rrand_i(1,30)
  message = "/push"+n.to_s
  osc message,[0,1].choose #chooses random data 0 or 1 to send from push buton
  sleep 1
end

In this example I send messages from virtual push buttons named push1 to push30 with data 0 or 1 and use a single live_loop to extract the data and work out which button was activated and what data it sent.
I have used this technique very extensively especially with touchOSC interfaces.

Here is a second example selecting different samples and notes to play using six buttons

use_osc "localhost",4560
use_debug false
use_osc_logging false

define:parse_sync_address do |address| #gets info on wild cards used in sync address
  v= get_event(address).to_s.split(",")[6]
  if v != nil
    #return a list of address elements with wild cards substituted by actual values
    return v[3..-2].split("/")
  else
    return ["error"]
  end
end

live_loop :findpushed do
  
  v = sync "/osc*/button*" #respond to button osc and save data in v[0]
  if v[0]==1 #button active =>1 ignore button released data 0
    res = parse_sync_address("/osc*/button*") #use parse routing to extract actual osc message
    puts res #shows the output of parse_sync address
    puts "button ",res[1],"was triggered"
    bn=res[1][6..-1].to_i
    puts "this has index",bn
    puts "data value sent was",v[0]
    case bn
    when 1
      sample :bd_haus
    when 2
      sample :loop_amen
    when 3
      synth :tb303,note: :c3,cutoff: 80,release: 2
    when 4
      sample :guit_harmonics
    when 5
      sample :ambi_glass_rub
    when 6
      sample :drum_roll
    end
    
    
  end
end



live_loop :test do #this loop generates osc calls from 30 virtual push buttons
  n = rrand_i(1,6)
  message = "/button"+n.to_s
  osc message,1 #chooses random data 0 or 1 to send from push buton
  sleep 0.2
  osc message,0
  sleep rrand(2,5)
end
1 Like

Thank you @robin.newman, that is exactly what I was looking for! I had a feeling you’d be the one to know :wink:

If you don’t mind, I have a couple of questions about the code so I can better understand what is going on:

v= get_event(address).to_s.split(",")[6]

What is the significance of the [6] in this line? I tried changing the number (4, 8, etc) and it would no longer provide the event address.

Similarly, what is the significance of the specific range of [6…-1] in this line:

 bn=res[1][6..-1].to_i

I understand that this is extracting the button number and converting it into an integer. I also think I know that the … operator establishes a range between two numbers. It seems that this line extracts a certain number of characters from the original string. It just isn’t quite clear to me how you arrive at 6 and -1. Is it that the 6 is for the characters you don’t want “button” and the -1 indicates to extract the remaining character?

Thanks again!

This is all about buy string handling.
I take the result of the call to getevent and convert it to a string .to_s

I’ve added some puts statements to the parse routine which shows the result of each string manipulation
remeber strings count from character 0 at the beginning or -1 from the end. So the bits in square brackets extract what you want.
Depending on other bits in the address eg buttons/1/3 you may want acess number greater than 1 in the returned res result.

define:parse_sync_address do |address| #gets info on wild cards used in sync address
  puts 1,get_event(address).to_s
  puts 2,get_event(address).to_s.split(",")
  puts 3,get_event(address).to_s.split(",")[6]
  v= get_event(address).to_s.split(",")[6]
  if v != nil
    #return a list of address elements with wild cards substituted by actual values
    puts 4,v[3..-2]
    puts 5,v[3..-2].split("/")
    return v[3..-2].split("/")
  else
    return ["error"]
  end
end

the [6…-1] extracts everiting from character to the end
ie button7 => 7 from character 0,1,2,3,4,5,6 onwards
b u t t o n 7
0 1 2 3 4 5 6

2 Likes