Sonic-pi-cli for Sonic Pi3.2dev

One piece of code which I have used quite a bit with Sonic Pi is Nick Johnstone’s excellent sonic-pi-cli command line tool, which enables you to send commands to Sonic Pi as if they were coming from the GUI. Thus you can emulate the stop-all-jobs command or run code remotely from a terminal (on the local host).

However, recent changes to the port allocations in Sonic Pi 3.2dev break the present version (and similar tools). Over the last couple of days I have been working on a solution to this, initially adding a -p parameter to allow the port to be specified, but this was kludgy and needed the user to determine the port, which is now dynamically allocated. Then I realised that the Listen port for the server is actually posted to the server-output.log and so I hit on the idea of reading the log file and extracting the port value and then incorporating the correct value in the sonic-pi-cli tool. To start with I used a ruby system command and ‘grep’ to extract the required data, but then I realised that this would have problems for Windows users, so instead I used Ruby file handling commands to open the file and read the port value. I also added an override so that it would work with earlier values of Sonic Pi which did not include the Listen port data, but for all of which the server port was the known static value 4557.

I have posted the code on a fork of the sonic-pi-cli code here if you want to try it out, and I have tested it on Raspberry Pi, Mac and Windows. I haven’t tested a Linux box directly, but it should perform as does the Raspberry Pi, if someone would like to check it out.
You can build the gem by downloading the sonic-pi-cli folder, then from within the folder using gem build sonic-pi-cli-gemspec
followed by gem install sonic-pi-cli-0.1.3.gem
After a bit more testing I will do a PR back to Nick’s original version.

The code is also useful directly within Sonic Pi to set up a programmatic stop-all-jobs command as if you had pushed the stop button, as shown below:

#This program lets you find the current server Listen port,
#where the Sonic Pi server listens to command from the GUI front end
#It also demonstrates how to setup a Stop All command
#and how to send code to run on Sonic Pi
#developed by Robin Newman, August 2019

#WARNING this uses undocumented features in Sonic Pi which MAY CHANGE
#and it is not guaranteed to work with future versions of Sonic Pi
#The program was developed because of upcoming changes introduced in SP3.2dev

define :pvalue do #get current listen port for Sonic Pi from log file
  value= 4557 #pre new logfile format port was always 4557
  File.open(ENV['HOME']+'/.sonic-pi/log/server-output.log','r') do |f1|
    while l = f1.gets
      if l.include?"Listen port:"
        value = l.split(" ").last.to_i
        break
      end
    end
    f1.close
  end
  return value
end
puts "Server Listen port is: #{pvalue}"

define :stop_all do #this command simulates pusshing the stop button
  osc_send "localhost",pvalue, "/stop-all-jobs"
end

define :command do |s| #this command lets you send code to be executed
  #the guid-rbn can be any value you like eg foo, but IS necessary
  osc_send "localhost",pvalue, "/run-code","guid-rbn",s
end

#send some sonic Pi commands to be played
command 'use_debug false;live_loop :pl do; play rrand_i(48,84),release: 0.2; sleep 0.2; end'
sleep 5
#now stop anything playing on Sonic Pi
stop_all
1 Like

Hi Robin, do you still use sonic pi cli? I am trying to get it to work on v4 BETA 7 and it will not connect to a port.

Hi Omzehn
The present sonic-pi-cli is broken for SP v4, which is not surprising because a lot has changed in Sp under the hood, and the cli makes use of unpublished data which has every right to be changed. I have however done some experimentation with Sp v4 beta and do have a working version of the cli which accommodates the changes. I am not publishing it yet, as things may still change before version 4 is released, but at that stage I will either publish it as a separate gem, (at present it is called sonic-pi-cli4 and the calling code is sonic_pi4 rather than sonic_pi. It may be possible to produce an integrated version that can accommodate earlier versions, but this would make it more complex and probably slower.
The basic operation is the same as before, and what it does is to simulate sending messages to the SP server as if they come from the GUI. This requires two pieces of information. The port to which the OSC call should be sent and the guid. In the existing version only the port required to be determined, as the guid could be anything you liked. However, you now have to use an internally generated Token which is randomly generated each time SP is run. Fortunately, as for the current version the information is currently available in the new spider.log file. Here is a copy of the start of a typical log.

Sonic Pi Spider Server booting...
The time is 2022-06-13 16:22:28 +0100
Warning, you have an older init.rb file in /Users/rbn/.sonic-pi/init.rb which is now being ignored as your newer config/init.rb file is being used instead. Consider deleting your old init.rb (perhaps copying anything useful across first).
Using primary protocol: udp
Detecting port numbers...
Ports: {:server_port=>37234, :gui_port=>37235, :scsynth_port=>37236, :scsynth_send_port=>37236, :osc_cues_port=>4560, :tau_port=>37237, :listen_to_tau_port=>37241}
Token: 2009719731
Opening UDP Server to listen to GUI on port: 37234

What the new gem does it to extract the server_port and the Token values from this file and then use them to produce a send_osc command of the form:
send_osc "127.0.0.1", server_port, "/run_code",Token,"play 72" for example.
You would actually type in a terminal: sonic_pi4 "play 72"

Initial tests show that it works well.