Skip to content

Instantly share code, notes, and snippets.

@antonhornquist
Created May 20, 2017 13:55
Show Gist options
  • Save antonhornquist/ce549a61caf076466f9ffa5e76435b64 to your computer and use it in GitHub Desktop.
Save antonhornquist/ce549a61caf076466f9ffa5e76435b64 to your computer and use it in GitHub Desktop.
require 'tempfile'
# pure data patching dsl for ruby hack
file = Tempfile.new
begin
my_patch = patch # 1. create patch
my_patch + 'declare -stdpath creb' # 2. add object
mod = my_patch + 'loadbang' >> 'list 200 10000' >> 'line~' >> 'osc~ 2' >> '*~ 800' >> '+~ 1000' # 3. connect
sine = mod >> 'osc~ 429' >> '*~ 0.5'
saw = mod >> 'blosc~ saw' >> '*~ 0.7'
vol = my_patch + 'vol~ 80'
sine >> vol
saw >> vol
writesf = my_patch + 'writesf~ 2'
trim = my_patch + 'list trim'
my_patch + 'list append open out.wav' >> trim
my_patch + 'list append start' >> trim
connect(my_patch, trim, 0, writesf, 0)
dac = my_patch + 'dac~'
connect(my_patch, vol, 0, dac, 0)
connect(my_patch, vol, 0, dac, 1)
connect(my_patch, vol, 0, writesf, 0)
connect(my_patch, vol, 0, writesf, 1)
=begin
p = patch
$p = p
object(p, 'declare', '-stdpath', 'creb')
test = 'osc~ 429' >> '*~ 0.8' >> 'dac~'
puts test
object(p, 'declare', '-stdpath', 'creb')
mod = object(p, 'osc~', 2)
mul = object(p, '*~', 400)
add = object(p, '+~', 1000)
# mod = patch('osc~ 2' >> '*~ 400' >> '+~ 1000')
osc = object(p, 'blosc~', 'saw')
connect(p, mod, 0, mul, 0)
connect(p, mul, 0, add, 0)
connect(p, add, 0, osc, 0)
vol = object(p, 'vol~', 80)
connect(p, osc, 0, vol, 0)
dac = object(p, 'dac~')
connect(p, vol, 0, dac, 0)
connect(p, vol, 0, dac, 1)
=end
file.write(patch_to_s(ze_patch))
file.close
# pid = run_pd(file, ["-nogui", "-send \"pd dsp 1;\""])
pid = run_pd(file, ["-send \"pd dsp 1;\""])
gets
ensure
if pid
puts "close pd..."
Process.kill("KILL", pid)
end
file.unlink if file
end
BEGIN {
module CoreExtensions
module String
module Patching
def to_object(patch)
strs = self.split
name = strs.first
args = strs.drop(1)
# [name, args]
object(patch, name, *args)
end
end
end
module Hash
module Patching
def +(something)
patch = self
something.to_object(patch)
end
def >>(something)
patch = self[:patch]
if something.respond_to? :keys
# assume Hash
connect(patch, self, 0, something, 0)
something
else
# assume String
obj = something.to_object(patch)
connect(patch, self, 0, obj, 0)
obj
end
end
end
end
end
String.include CoreExtensions::String::Patching # monkey patching, beware
Hash.include CoreExtensions::Hash::Patching # monkey patching, beware
def patch(name=nil)
{ :name => name, :declarations => [], :objects => [], :connections => [] }
end
def object(patch, name, *args)
object = { :patch => patch, :name => name, :args => args }
patch[:objects] << object
if name.to_sym == :declare
(args.size/2).times do |i|
flag, value = *args[(i*2)..(i*2+1)]
patch[:declarations] << { :flag => flag, :value => value }
end
end
object
end
def connect(patch, from, outlet_no, to, inlet_no)
connection = { :from => from, :outlet => outlet_no, :to => to, :inlet => inlet_no }
patch[:connections] << connection
connection
end
def object_name_args_to_s(object)
"#{object[:name]}#{object[:args].empty? ? "" : " " + object[:args].join(" ")}"
end
def declaration_to_s(declaration)
"#X declare #{declaration[:flag]} #{declaration[:value]};"
end
def object_to_s(object, index)
"#X obj 10 #{10+index*30} #{object_name_args_to_s(object)};"
end
def connection_to_s(patch, connection)
objects = patch[:objects]
from = objects.find_index(connection[:from])
to = objects.find_index(connection[:to])
"#X connect #{from} #{connection[:outlet]} #{to} #{connection[:inlet]};"
end
def patch_to_s(patch)
declarations = patch[:declarations]
objects = patch[:objects]
connections = patch[:connections]
arr = ["#N canvas 50 50 450 300 10;"] + declarations.map do |declaration|
declaration_to_s(declaration)
end + objects.each_with_index.map do |object, i|
object_to_s(object, i)
end + connections.map do |connection|
connection_to_s(patch, connection)
end
arr.join("\n")
end
def run_pd(file, opts=[], fork=true)
pd_path = case RUBY_PLATFORM
when /darwin/ then "/Applications/Pd-0.47-1-64bit.app/Contents/Resources/bin/pd" # assumes pd installed on this path
when /mingw32/ then "pd.exe" # assumes pd.exe is in PATH
end
cmd = pd_path
cmd = cmd + " #{opts.join(" ")}" unless opts.empty?
cmd = cmd + " \"#{file.path}\"" if file
puts "cmd: #{cmd}"
if fork
pid = case RUBY_PLATFORM
when /darwin/ then fork { exec(cmd) }
when /mingw32/ then Process.spawn(cmd)
end
pid
else
exec(cmd)
end
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment