Sonic Pi playlist program

Previously  I have detailed here a jukebox program which enables you to select files from a directory to be played in Sonic Pi, making use of the Sonic Pi CLI gem module written by Nick Johnstone. This works well, but although it contains an option to play a series of linked files together, it does not enable this to happen without first modifying the files.

I decided to write a playlist script which could be run and would enable Sonic Pi to play all the SP files in a specified folder one after the other, with a 2 second break between each one. Once again the program relies on the Sonic Pi CLI and this needs to be installed, which is a simple process. You also need to have Sonic Pi running.

The script for the program is shown below

#!/usr/bin/ruby

#ruby script to play a playlist of sonic pi files contained in a specified directory by Robin Newman, July 2015
#sample usage: ./pl.rb /home/pi/spfiles    (where spfiles contains the sonic pi files to be played)
#A 2 second gap is placed between each file playing and the next
#requires the Command Line Interface gem sonic_pi downloadable from https://github.com/Widdershin/sonic-pi-cli

#check for arg
if ARGV.length == 0 then
  puts 'usage: ./pl.rb absolute/path/to/directory/of/sonicpifiles'
  exit 1
else
  spfiles = ARGV[0]
end

#PATHNAMES WHICH ARE USED
path="/tmp/jukebox" #path for temporary files folder
clipath="/usr/local/bin" #absolute path to sonic_cli command line interface

#setup temp file directory
system 'mkdir '+path
#set up init.txt file containing initialisation commands for SP
#makes sure that any changes made in one sp file are cancelled before the next one plays
f=open(path+'/init.txt','w')
f.puts "use_debug false"
f.puts "set_volume! 1"
f.close
#get list of filenames and number of files to be played
fnames=[]
Dir.foreach(spfiles) do |filename|
  next if File.directory?(spfiles+"/"+filename) #ignore non file entries
  fnames.concat [filename]
end
fnames=fnames.sort_by{|word| word.downcase}.reverse #sort in reverse order alpahbetically case insensitive

numfiles= fnames.length

#send commands to cli for each file, topping and tailing with sync and cue commands
for x in 0..(numfiles-1) do
    #set up sync command ahead of next file
    f=open(path+'/sync.txt','w')
    f.puts "\nsync :link"+(numfiles-x-1).to_s
    f.puts "sleep 2" #add sleep gaps between files
    f.close
    #set up cue command after next file
    f=open(path+'/cue.txt','w')
    f.puts "\ncue :link"+(numfiles-x).to_s
    f.close
    #check if last file
    if x < (numfiles -1) then
      #if not last file send sync, init, file data and cue commands
      system "cat "+path+"/sync.txt "+path+"/init.txt "+spfiles+"/"+fnames[x]+" "+path+"/cue.txt| "+clipath+"/sonic_pi "# >> "+path+"/out.txt" #
    else
      #now do last file, omitting the sync command so that this plays straight away
      system "cat "+path+"/init.txt "+spfiles+"/"+fnames[x]+" "+path+"/cue.txt| "+clipath+"/sonic_pi "# >> "+path+"/out.txt" #
    end
    puts "Now loading "+fnames[x]+" play number "+(numfiles-x).to_s
  end
  puts "\nNB files loaded in reverse to playorder"
  #tidy up by deleting temporary files
  system 'rm -fR '+path

Basically the program extracts the location of the sonic pi files folder from the argument supplied when it is called, and it makes a list of all the files in that folder in reverse alphabetical order.
It then goes into a loop calling the sonic_pi cli and sending it the code for each file in turn. The trick is that it sends a sync command BEFORE each file (except for the last one (which is the first name alphabetically). AFTER each file code it sends a cue command which links to the sync command of the previous file. By this mechanism, the last file sent (the first one alphabetically) plays, and then trigger the next file, and so on until all the files have been played.
Two further additions are made. After each sync command a series of commands are inserted to reset the standard volume and to disable debug. This is in case any of the files alter these values whilst they are playing. Secondly a sleep 2 is inserted to separate each file from the previous one.

As presented the file is for use on a Raspberry Pi. It can be amended slightly to work on a Mac (and no doubt a PC) as well. Differences may be:
The location of the ruby interpreter in the first line of the file. You can miss this line out and call ruby explicitly if it is easier: e g ruby pl.rb /path/to/sonicpi/files
Secondly the path to the sonic_cli command line interpreter. On my mac this was
/Users/rbn/.rvm/gems/ruby-2.1.2/bin/sonic_pi giving a clipath of
/Users/rbn/.rvm/gems/ruby-2.1.2/bin as opposed to /usr/local/bin on the Pi.

This leads on to installing the cli. Start a terminal window on the Pi and type

cd ~
git clone https://github.com/Widdershin/sonic-pi-cli.git

gem install sonic-pi-cli

The script can be downloaded by typing

wget https://gist.githubusercontent.com/rbnpi/8ae698b50e540b50ad21/raw/211e5356f67d5fe4e4a20b46358abf0b7b7dfc83/pl.rb

To use the script, assemble some sonic pi files in a folder in the Pi home directory, eg spfiles

Startup Sonic Pi

In the terminal window make sure the script is executable by typing

chmod 755 pl.rb

start the playlist running from the terminal window by typing

./pl.rb /home/pi/spfiles

You should see a list of the files on the screen as they are processed and then Sonic Pi will start playing them.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s