Sonic Pi + Ruby Stuff - Helper Methods and Code Samples

Perhaps like many, I’d never ever heard of Ruby until I found (and fell in love with) SonicPi.

I thought I’d make a topic to collect and share some stuff I’ve munged, in case they’re any use, or there’s better (or preferred : ) approaches, and to welcome similar submissions…
Credits to everyone that’s inspired and helped with similar stuff they’ve shared here, on gh, youtube, reddit… especially @robin.newman !! and shout out to GPT for her assistance :robot:


sequence in subset

Hot off the press, newest first; WIP - further dev planned, this is v1 (first to work*)

  • limited testing with examples cited (there may be bugs in them there code)
def subset_exists?(a, b)
  a_arr = a.is_a?(String) ? a.split(',').map(&:strip) : a
  b_arr = b.is_a?(String) ? b.split(',').map(&:strip) : b
  
  a_index = 0
  b_arr.each do |elem|
    if elem == a_arr[a_index]
      a_index += 1
      return true if a_index == a_arr.size
    else
      a_index = 0 if elem == a_arr[0]  # Reset if the current element matches the first element of a
    end
  end
  
  false
end

# Examples
a1 = [true, true, true]
b1 = [true, false, true, true, false]
puts "a in b: #{subset_exists?(a1, b1)}"  # Output: a in b: false

a2 = [false, true, true]
b2 = [true, false, true, true, false]
puts "a in b: #{subset_exists?(a2, b2)}"  # Output: a in b: true

a3 = "1, 3, 5"
b3 = "1, 2, 3, 5"
puts "a in b: #{subset_exists?(a3, b3)}"  # Output: a in b: false

knit-spread

ring-math (WIP v1.2)

Spreads are great, and so are knits, and combined you can reduce a lot of keystrokes…

(This one was made last night, just methodised now, and discovered $global_var : )

#$spreads = (spread 1,4)

define :spreadbeats do |beats = [], spr = (spread 1, 4), n: 4 | #$spreads can be used for global var
  #  [4,7,3,9,6,7,5,9]
  beats.each_slice(2) {|_| spr += (knit (spread _[0],_[1]),n).flatten }
  spr
end


puts spreadbeats
puts spreadbeats [2,3,4,5], n: 1

pad ‘multiple n’

This one was made with GPT (assume this is the correct version)

def pad_to_next_multiple_of_8(pattern)
  remainder = pattern.length % 8
  if remainder != 0
    padding_length = 8 - remainder
    pattern += '-' * padding_length
  end
  pattern
end

which I optimised (and maybe obfuscated a little : )

define :pad do |pattern, length = 8|
  pattern += '-' * (length - (pattern.length % length))
  pattern
end

usage:

pat1 = pad "x-x", 16
puts pat1

speeches!

some good stuff for playing with :autotuner et al?

I was just about to try to convert (to wav, with ffmpeg, as I didn’t see mp3 mentioned in supported file types… but then just used an mp3 with the sample function, and it worked!)

The art of speaking too soon… appears the .mp3 sample plays with sample unless sample is in autotuner loop, does autotuner require a wav sample be loaded? tried adding a sleep in the autotuner loop, as per the example, but still no sound when sample played in :autotuner

This takes a while to get them, but appears to be working (folder created and being populated as i type)

Source: Greatest Speeches of the 20th Century : Public Domain : Free Download, Borrow, and Streaming : Internet Archive
:robot::+1:t2:


# URL of the webpage containing MP3 links
url = 'https://archive.org/details/Greatest_Speeches_of_the_20th_Century'

# Directory to save downloaded MP3 files
download_dir = File.join(Dir.home, 'Music', 'Speeches')

# Create the directory if it doesn't exist
FileUtils.mkdir_p(download_dir) unless Dir.exist?(download_dir)

# Hash to store speeches information
speeches = {}

# Retrieve HTML content of the webpage
html_content = URI.open(url).read

# Extract MP3 links from HTML content
mp3_links = html_content.scan(/https?:\/\/[^'"]+\.mp3/)

# Download each MP3 file and add to the speeches hash
mp3_links.each do |mp3_url|
  # Extract filename from URL
  filename = mp3_url.split('/').last.downcase
  
  # Define local filepath to save the downloaded MP3 file
  filepath = File.join(download_dir, filename)
  
  # Download the MP3 file if it doesn't exist locally
  unless File.exist?(filepath)
    puts "Downloading #{filename}..."
    URI.open(mp3_url) do |mp3|
      File.open(filepath, 'wb') { |file| file.write(mp3.read) }
    end
  end
  
  # Add the speech to the speeches hash
  speeches[filename.gsub('.mp3', '').to_sym] = filepath
end

# Test accessing a speech from the hash
puts "Sample file path for :addressfromfrance is #{speeches[:addressfromfrance]}"

… (continued on from speeches) example with amen_loop

use_sched_ahead_time 3
# URL of the webpage containing MP3 links
url = 'https://archive.org/details/Greatest_Speeches_of_the_20th_Century'

# Directory to save downloaded MP3 files
download_dir = File.join(Dir.home, 'Music', 'Speeches')

# Create the directory if it doesn't exist
FileUtils.mkdir_p(download_dir) unless Dir.exist?(download_dir)

# Hash to store speeches information
speeches = {}

# Retrieve HTML content of the webpage
html_content = URI.open(url).read

# Extract MP3 links from HTML content
mp3_links = html_content.scan(/https?:\/\/[^'"]+\.mp3/)

# Download each MP3 file and add to the speeches hash
mp3_links.each do |mp3_url|
  # Extract filename from URL
  filename = mp3_url.split('/').last.downcase
  
  # Define local filepath to save the downloaded MP3 file
  filepath = File.join(download_dir, filename)
  
  # Download the MP3 file if it doesn't exist locally
  unless File.exist?(filepath)
    puts "Downloading #{filename}..."
    URI.open(mp3_url) do |mp3|
      File.open(filepath, 'wb') { |file| file.write(mp3.read) }
    end
  end
  
  # Add the speech to the speeches hash
  speeches[filename.gsub('.mp3', '').to_sym] = filepath
end

# Test accessing a speech from the hash
#puts "Sample file path for :addressfromfrance is #{speeches[:addressfromfrance]}"
#puts "Speech Samples:"
#speeches.each_key {|k| puts k}

=begin
=end
puts 'ready'
wait 3

uncomment do
  live_loop :amen, delay: 3 do
    sam = :loop_amen_full
    sam = (sample_names :loop).choose if one_in 9
    use_sample_bpm sam
    sample sam
    wait 1
    cue :speech if one_in (rand_i 4)
    # stop
    # wait
    # sync
  end
end

#test sample_bpm logic
live_loop :vox, delay: 3, sync: :speech do #
  s = (speeches.values).choose
  use_sample_bpm s
  sample s, amp: 1.5
  wait 1 # I forgot to add!
  sync :speech
end


##| with_fx :autotuner,note: :c do
##| end