Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarifying usage of OSC \run-code in latest versions (4+) #3330

Closed
mhl787156 opened this issue Sep 30, 2023 · 4 comments
Closed

Clarifying usage of OSC \run-code in latest versions (4+) #3330

mhl787156 opened this issue Sep 30, 2023 · 4 comments

Comments

@mhl787156
Copy link

mhl787156 commented Sep 30, 2023

Hi,

I've been trying to use the \run-code osc message from a companion python program to control sonic-pi, and have not been succesful.

I think this thread on the forums and this other thread are the latest on the topic. If I am to understand correctly, you need to parse the server_port and the token from spider.log in order to use the \run_code message specifically, due to security reasons (understandable). There is one example of a Python program in the latter thread, but I couldn't reproduce it, making me think that things might have moved on since last year.

So if I do this inside the sonic-pi gui, it works great (with the relevant server_port and token) and I get a sound:

use_osc "127.0.0.1", 32373
osc "/run-code",1605599894, "play 72"

Perhaps weirdly, if I use 4560 and the token instead of 32373 this does not make a sound.

Now if open a cli and try to use pythonosc with the same \run-code osc as above (token included), and also using 127.0.0.1, I have had very limited success.

  1. If I use server_port, nothing goes through to sonic-pi and it does not come up in the cue list
  2. If I use 4560 (default OSC port), sonic-pi registers an OSC message but doesn't play the note

So I have several questions:

  1. Is this expected behaviour? Or have there been internal developments since that forum post? Could you clarify when \run-code OSC is allowed to run?
  2. If expected why does using the server_port inside sonic-pi work (or ruby as the forum says there exists a ruby sonic-pi-cli which hasn't been touched for ages), but its not possible from python?
  3. I tried for a while to get it to work with wsl2 using the wsl2 ip address (172.18.XXX.XXX) but this did not work either, does \run-code only work localhost?
  4. Would you be able to link to the place in the sonic-pi codebase where these validation checks are done?

Many Thanks!

Sonic-Pi Version: 4.4.0
Platform: Windows/WSL
Settings: Both Allow incoming OSC and Allow OSC from other computers is checked


Edit, I just spotted this thread in which changes are discussed, but it is still not very clear to me how I might connect and interact. Some of the comments in the daemon.rb file seem to suggest that \run-code should really only be run from the GUI and are independent and separate from external osc messages coming in on 4560. That the raises the question of how should my python program pretend to be the GUI...

@SunderB
Copy link
Contributor

SunderB commented Sep 30, 2023

Hey @mhl787156,
I've poked around with this stuff before, so hopefully I can answer some of your questions.

Is this expected behaviour?

In case 1, no (I think). If you send the message in the correct format to the right port and with the right token, it should work.
In case 2, yes. All messages sent to 4560 are treated by the server as cue triggers.

If expected why does using the server_port inside sonic-pi work (or ruby as the forum says there exists a ruby sonic-pi-cli which hasn't been touched for ages), but its not possible from python?

If the port and token are right, it should just work (given that the server is running). Could you share your python code on how you are trying to do this?

Does \run-code only work localhost?

Don't know for sure but probably. I believe Sonic Pi is designed to have the GUI and server to run on the same PC.

Would you be able to link to the place in the sonic-pi codebase where these validation checks are done?

if incoming_token == token
code = args[1].force_encoding("utf-8")
sp.__spider_eval code
else
STDOUT.puts "Invalid token: #{incoming_token} - ignoring /run-code API call"
STDOUT.flush
end

If you want to see how a GUI can be emulated, it might be worth checking out some of the plugins that have been made for code editors for reference:

I hope this helps :)

@mhl787156
Copy link
Author

Hey thanks for the help, that was all really useful! And I think I've gotten down almost to the bottom of why my things was working.

Essentially the token also needed to be an integer! I was sending it through as a string, so it was getting rejected.

So to start I've gotten the following to work well, and I can confirm that its working!

def get_token_and_ports():
    file=Path.home().joinpath( '.sonic-pi', 'log', 'spider.log' )
    token_and_ports={}
    for line in file:
        if line.startswith('Token:'):
            token_and_ports['token']=line.split()[1]
        elif line.startswith('Ports:'):
            token_and_ports['ports']=dict(item.split('=>') for item in line[8:-1].replace(' ','').split(','))
        if len(token_and_ports) == 2:
            return token_and_ports

if __name__ == "__main__":
    token_and_ports=get_token_and_ports()
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", default="127.0.0.1",
                        help="The ip of the OSC server")
    parser.add_argument('commands', metavar='command', type=str, nargs='+',
                        help='Command to send to sonic pi')
    args = parser.parse_args()
    token=int(token_and_ports['token'])
    port=int(token_and_ports['ports'][':server_port'])
    client = udp_client.SimpleUDPClient(args.ip, port)
    print(f'Using token {token} port {port} command {args.commands}')
    client.send_message('/run-code', [token, '\n'.join(args.commands)])

@rbnpi
Copy link
Contributor

rbnpi commented Oct 1, 2023

Good work. If you want to try a ruby version, I have an updated sonic-pi-cli named sonic-pi-cli4 which is specifically for version 4 and above of Sonic PI. It too gets data from the lg files, so although it works with current versions is not guaranteed to continue. You can use gem install sonic-pi-cli4 to get it. (On a Pi you need sudo)
Usage: sonic_pi4 'run_code "play 72;sleep 1;play 84"'
or
sonic_pi4 'run_file "filename-with-path"'
or
sonic_pi4 stop

@mhl787156
Copy link
Author

Thanks @rbnpi thats a cool cli! Main reason for us using Python is because it forms part of a larger program controlling lights and other bits and pieces.

I just updated python-sonic to support the sonic-pi v4+ and will request a PR: https://github.com/mhl787156/python-sonic

This is resolved so will now close the issue thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants