Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

refactored module structure, removed Audio module

  • Loading branch information...
commit 54ff5c165484a8067a33f376eccf407f13ba810d 1 parent d13a17c
@maca authored
Showing with 7,421 additions and 64 deletions.
  1. +43 −43 Manifest.txt
  2. +15 −16 lib/scruby.rb
  3. BIN  lib/scruby/.DS_Store
  4. +153 −0 lib/scruby/buffer.rb
  5. +67 −0 lib/scruby/bus.rb
  6. +29 −0 lib/scruby/control_name.rb
  7. +93 −0 lib/scruby/env.rb
  8. +20 −0 lib/scruby/group.rb
  9. +106 −0 lib/scruby/node.rb
  10. +206 −0 lib/scruby/server.rb
  11. +58 −0 lib/scruby/synth.rb
  12. +109 −0 lib/scruby/synthdef.rb
  13. +38 −0 lib/scruby/ugens/env_gen.rb
  14. +62 −0 lib/scruby/ugens/in_out.rb
  15. +44 −0 lib/scruby/ugens/multi_out_ugens.rb
  16. +92 −0 lib/scruby/ugens/operation_indices.yaml
  17. +63 −0 lib/scruby/ugens/operation_ugens.rb
  18. +178 −0 lib/scruby/ugens/ugen.rb
  19. +3,389 −0 lib/scruby/ugens/ugen_defs.yaml
  20. +57 −0 lib/scruby/ugens/ugen_operations.rb
  21. +88 −0 lib/scruby/ugens/ugens.rb
  22. BIN  spec/.DS_Store
  23. +197 −0 spec/buffer_spec.rb
  24. +184 −0 spec/bus_spec.rb
  25. +119 −0 spec/core_ext/core_ext_spec.rb
  26. +140 −0 spec/core_ext/delegator_array_spec.rb
  27. +95 −0 spec/core_ext/typed_array_spec.rb
  28. +23 −0 spec/env_gen_spec.rb
  29. +5 −5 spec/env_spec.rb
  30. +71 −0 spec/group_spec.rb
  31. +121 −0 spec/in_out_spec.rb
  32. +88 −0 spec/integration_spec.rb
  33. +109 −0 spec/multiout_ugen_spec.rb
  34. +108 −0 spec/node_spec.rb
  35. +192 −0 spec/operation_ugens_spec.rb
  36. +12 −0 spec/server.rb
  37. +185 −0 spec/server_spec.rb
  38. +66 −0 spec/synth_spec.rb
  39. +262 −0 spec/synthdef_spec.rb
  40. +96 −0 spec/ugen_operations_spec.rb
  41. +366 −0 spec/ugen_spec.rb
  42. +72 −0 spec/ugens_spec.rb
View
86 Manifest.txt
@@ -49,21 +49,21 @@ doc/created.rid
doc/files/README_rdoc.html
doc/files/bin/live_session_rb.html
doc/files/lib/live/session_rb.html
-doc/files/lib/scruby/audio/control_name_rb.html
-doc/files/lib/scruby/audio/env_rb.html
-doc/files/lib/scruby/audio/node_rb.html
-doc/files/lib/scruby/audio/server_rb.html
-doc/files/lib/scruby/audio/synth_rb.html
-doc/files/lib/scruby/audio/synthdef_rb.html
-doc/files/lib/scruby/audio/ugens/env_gen_rb.html
-doc/files/lib/scruby/audio/ugens/in_out_rb.html
-doc/files/lib/scruby/audio/ugens/multi_out_ugens_rb.html
-doc/files/lib/scruby/audio/ugens/operation_indices_yaml.html
-doc/files/lib/scruby/audio/ugens/operation_ugens_rb.html
-doc/files/lib/scruby/audio/ugens/ugen_defs_yaml.html
-doc/files/lib/scruby/audio/ugens/ugen_operations_rb.html
-doc/files/lib/scruby/audio/ugens/ugen_rb.html
-doc/files/lib/scruby/audio/ugens/ugens_rb.html
+doc/files/lib/scruby/control_name_rb.html
+doc/files/lib/scruby/env_rb.html
+doc/files/lib/scruby/node_rb.html
+doc/files/lib/scruby/server_rb.html
+doc/files/lib/scruby/synth_rb.html
+doc/files/lib/scruby/synthdef_rb.html
+doc/files/lib/scruby/ugens/env_gen_rb.html
+doc/files/lib/scruby/ugens/in_out_rb.html
+doc/files/lib/scruby/ugens/multi_out_ugens_rb.html
+doc/files/lib/scruby/ugens/operation_indices_yaml.html
+doc/files/lib/scruby/ugens/operation_ugens_rb.html
+doc/files/lib/scruby/ugens/ugen_defs_yaml.html
+doc/files/lib/scruby/ugens/ugen_operations_rb.html
+doc/files/lib/scruby/ugens/ugen_rb.html
+doc/files/lib/scruby/ugens/ugens_rb.html
doc/files/lib/scruby/control/metro_rb.html
doc/files/lib/scruby/extensions_rb.html
doc/files/lib/scruby/typed_array_rb.html
@@ -84,39 +84,39 @@ extras/Ruby Live.tmbundle/Syntaxes/Ruby Live.tmLanguage
extras/Ruby Live.tmbundle/info.plist
lib/live/session.rb
lib/scruby.rb
-lib/scruby/audio/control_name.rb
-lib/scruby/audio/env.rb
-lib/scruby/audio/node.rb
-lib/scruby/audio/server.rb
-lib/scruby/audio/synth.rb
-lib/scruby/audio/synthdef.rb
-lib/scruby/audio/ugens/env_gen.rb
-lib/scruby/audio/ugens/in_out.rb
-lib/scruby/audio/ugens/multi_out_ugens.rb
-lib/scruby/audio/ugens/operation_indices.yaml
-lib/scruby/audio/ugens/operation_ugens.rb
-lib/scruby/audio/ugens/ugen.rb
-lib/scruby/audio/ugens/ugen_defs.yaml
-lib/scruby/audio/ugens/ugen_operations.rb
-lib/scruby/audio/ugens/ugens.rb
+lib/scruby/control_name.rb
+lib/scruby/env.rb
+lib/scruby/node.rb
+lib/scruby/server.rb
+lib/scruby/synth.rb
+lib/scruby/synthdef.rb
+lib/scruby/ugens/env_gen.rb
+lib/scruby/ugens/in_out.rb
+lib/scruby/ugens/multi_out_ugens.rb
+lib/scruby/ugens/operation_indices.yaml
+lib/scruby/ugens/operation_ugens.rb
+lib/scruby/ugens/ugen.rb
+lib/scruby/ugens/ugen_defs.yaml
+lib/scruby/ugens/ugen_operations.rb
+lib/scruby/ugens/ugens.rb
lib/scruby/extensions.rb
lib/scruby/typed_array.rb
script/console
script/destroy
script/generate
-spec/audio/env_gen_specs.rb
-spec/audio/in_out_spec.rb
-spec/audio/integration_spec.rb
-spec/audio/lib_spec.rb
-spec/audio/multiout_ugen_spec.rb
-spec/audio/node_spec.rb
-spec/audio/operation_ugens_spec.rb
-spec/audio/server_spec.rb
-spec/audio/synth_spec.rb
-spec/audio/synthdef_spec.rb
-spec/audio/ugen_operations_spec.rb
-spec/audio/ugen_spec.rb
-spec/audio/ugens_spec.rb
+spec/env_gen_specs.rb
+spec/in_out_spec.rb
+spec/integration_spec.rb
+spec/lib_spec.rb
+spec/multiout_ugen_spec.rb
+spec/node_spec.rb
+spec/operation_ugens_spec.rb
+spec/server_spec.rb
+spec/synth_spec.rb
+spec/synthdef_spec.rb
+spec/ugen_operations_spec.rb
+spec/ugen_spec.rb
+spec/ugens_spec.rb
spec/control/timer_spec.rb
spec/env_spec.rb
spec/extensions_spec.rb
View
31 lib/scruby.rb
@@ -39,29 +39,28 @@ module Scruby
require "scruby/core_ext/symbol"
require "scruby/core_ext/typed_array"
require "scruby/core_ext/delegator_array"
-require "scruby/audio/env"
-require "scruby/audio/control_name"
+require "scruby/env"
+require "scruby/control_name"
-require "scruby/audio/ugens/ugen"
-require "scruby/audio/ugens/ugen_operations"
-require "scruby/audio/ugens/multi_out_ugens"
-require "scruby/audio/ugens/in_out"
+require "scruby/ugens/ugen"
+require "scruby/ugens/ugen_operations"
+require "scruby/ugens/multi_out_ugens"
+require "scruby/ugens/in_out"
-require "scruby/audio/ugens/operation_ugens"
+require "scruby/ugens/operation_ugens"
-require "scruby/audio/ugens/ugens"
-require "scruby/audio/synthdef"
+require "scruby/ugens/ugens"
+require "scruby/synthdef"
-require "scruby/audio/server"
-require "scruby/audio/ugens/env_gen"
+require "scruby/server"
+require "scruby/ugens/env_gen"
-require "scruby/audio/node"
-require "scruby/audio/synth"
-require "scruby/audio/bus"
-require "scruby/audio/buffer"
+require "scruby/node"
+require "scruby/synth"
+require "scruby/bus"
+require "scruby/buffer"
include Scruby
-include Audio
include Ugens
View
BIN  lib/scruby/.DS_Store
Binary file not shown
View
153 lib/scruby/buffer.rb
@@ -0,0 +1,153 @@
+module Scruby
+ def expand_path path
+ path = "~/Scruby/#{ path }" unless path.match %r{^(?:/|~)}
+ File.expand_path path
+ end
+
+ class Buffer
+ # readNoUpdate
+ # loadCollection
+ # sendCollection
+ # streamCollection
+ # loadToFloatArray
+ # getToFloatArray
+ # set
+ # setn
+ # get
+ # getn
+ # fill
+ # normalize
+ # gen
+ # sine1
+ # ...
+ # copy
+ # copyData
+ # query
+ # updateInfo
+ # queryDone
+ # printOn
+ # play
+ # duration
+ # asBufWithValues
+
+ attr_reader :server
+ attr_accessor :path, :frames, :channels, :rate
+
+ def read path, file_start = 0, frames = -1, buff_start = 0, leave_open = false, &message
+ # @on_info = message
+ message ||= ["/b_query", buffnum]
+ @server.send "/b_read", buffnum, expand_path(path), file_start, frames, buff_start, leave_open, message.value(self)
+ self
+ end
+
+ def read_channel path, file_start = 0, frames = -1, buff_start = 0, leave_open = false, channels = [], &message
+ message ||= 0
+ @server.send *(["/b_ReadChannel", buffnum, expand_path(path), start, frames, buff_start, leave_open] + channels << message.value(self))
+ self
+ end
+
+ def close &message
+ message ||= 0
+ @server.send '/b_close', buffnum, message.value(self)
+ self
+ end
+
+ def zero &message
+ message ||= 0
+ @server.send '/b_zero', buffnum, message.value(self)
+ self
+ end
+
+ def cue_sound_file path, start = 0, &message
+ message ||= 0
+ @server.send "/b_read", buffnum, expand_path(path), start, @frames, 0, 1, message.value(self)
+ self
+ end
+
+ def write path = nil, format = 'aiff', sample_format = 'int24', frames = -1, start = 0, leave_open = false, &message
+ message ||= 0
+ path ||= "#{ DateTime.now }.#{ format }"
+ @server.send "/b_write", buffnum, expand_path(path), format, sample_format, frames, start, leave_open, message.value(self)
+ self
+ end
+
+ def initialize server, frames = -1, channels = 1
+ @server, @frames, @channels = server, frames, channels
+ end
+
+ def allocate &message
+ message ||= 0
+ @server.allocate :buffers, self
+ @server.send '/b_alloc', buffnum, frames, channels, message.value(self)
+ self
+ end
+
+ def buffnum
+ @server.buffers.index self
+ end
+ alias :as_ugen_input :buffnum
+ alias :index :buffnum
+ # alias :as_control_input :buffnum
+
+ def free &message
+ message ||= 0
+ @server.send "/b_free", buffnum, message.value(self)
+ @server.buffers.delete self
+ end
+
+ # :nodoc:
+ def allocate_and_read path, start, frames, &message
+ @server.allocate :buffers, self
+ message ||= ["/b_query", buffnum]
+ @server.send "/b_allocRead", buffnum, @path = expand_path(path), start, frames, message.value(self)
+ self
+ end
+
+ def allocate_read_channel path, start, frames, channels, &message
+ @server.allocate :buffers, self
+ message ||= ["/b_query", buffnum]
+ @server.send *(["/b_allocReadChannel", buffnum, expand_path(path), start, frames] + channels << message.value(self))
+ self
+ end
+
+ class << self
+ def allocate server, frames = -1, channels = 1, &message
+ new(server, frames, channels).allocate &message
+ end
+
+ def cue_sound_file server, path, start, channels = 2, buff_size = 32768, &message
+ allocate server, buff_size, channels do |buffer|
+ message ||= 0
+ ['/b_read', buffer.buffnum, expand_path(path), start, buff_size, 0, true, message.value(buffer)]
+ end
+ end
+
+ # Allocate a buffer and immediately read a soundfile into it.
+ def read server, path, start = 0, frames = -1, &message
+ buffer = new server, &message
+ buffer.allocate_and_read expand_path(path), start, frames
+ end
+
+ def read_channel server, path, start = 0, frames = -1, channels = [], &message
+ new(server, frames, channels).allocate_read_channel expand_path(path), start, frames, channels, &message
+ end
+
+ def alloc_consecutive buffers, server, frames = -1, channels = 1, &message
+ buffers = Array.new(buffers){ new server, frames, channels }
+ server.allocate :buffers, buffers
+ message ||= 0
+ buffers.each do |buff|
+ server.send '/b_alloc', buff.buffnum, frames, channels, message.value(buff)
+ end
+ end
+
+ named_arguments_for :allocate, :read, :cue_sound_file, :alloc_consecutive, :read_channel
+
+ # readNoUpdate
+ # loadCollection
+ # sendCollection
+ # loadDialog
+ end
+ end
+end
+
View
67 lib/scruby/bus.rb
@@ -0,0 +1,67 @@
+module Scruby
+
+ class Bus
+ attr_reader :server, :rate, :channels, :main_bus
+
+ def initialize server, rate, channels = 1, main_bus = self, hardware_out = false
+ @server, @rate, @channels, @main_bus, @hardware_out = server, rate, channels, main_bus, hardware_out
+ end
+
+ def index
+ @index ||= @server.__send__("#{ @rate }_buses").index(self)
+ end
+
+ def free
+ @index = nil
+ @server.__send__("#{ @rate }_buses").delete(self)
+ end
+
+ def to_map
+ raise SCError, 'Audio buses cannot be mapped' if rate == :audio
+ "c#{ index }"
+ end
+
+ def audio_out?
+ index < @server.instance_variable_get(:@opts)[:audio_outputs]
+ end
+
+ # Messaging
+ def set *args
+ args.flatten!
+ message_args = []
+ (index...channels).to_a.zip(args) do |chan, val|
+ message_args.push(chan).push(val) if chan and val
+ end
+ if args.size > channels
+ warn "You tried to set #{ args.size } values for bus #{ index } that only has #{ channels } channels, extra values are ignored."
+ end
+ @server.send '/c_set', *message_args
+ end
+
+ def fill value, channels = @channels
+ if channels > @channels
+ warn "You tried to set #{ channels } values for bus #{ index } that only has #{ @channels } channels, extra values are ignored."
+ end
+ @server.send '/c_fill', index, channels.min(@channels), value
+ end
+
+ class << self
+ private :new
+
+ def control server, channels = 1
+ buses = [new(server, :control, channels)]
+ buses.push new(server, :control, channels, buses.first) while buses.size < channels
+ server.allocate :control_buses, buses
+ buses.first
+ end
+
+ def audio server, channels = 1
+ buses = [new(server, :audio, channels)]
+ buses.push new(server, :audio, channels, buses.first) while buses.size < channels
+ server.allocate :audio_buses, buses
+ buses.first
+ end
+ end
+
+ end
+end
View
29 lib/scruby/control_name.rb
@@ -0,0 +1,29 @@
+module Scruby
+ class ControlName #:nodoc:
+ attr_accessor :name, :value, :rate, :index
+ RATES = { 'n_' => :noncontrol, 'i_' => :scalar, 'k_' => :control, 't_' => :trigger }
+
+ def initialize name, value, rate, index
+ @name, @value, @rate, @index = name.to_s, value.to_f, set_rate( name, rate ), index
+ end
+
+ def set_rate name, rate
+ RATES.has_value?( rate ) ? rate : rate_from_name( name )
+ end
+
+ def rate_from_name name
+ RATES[ name.to_s[0..1] ] || :control
+ end
+
+ def non_control?
+ @rate == :noncontrol
+ end
+
+ def == other
+ @name == other.name and
+ @value == other.value and
+ @rate == other.rate and
+ @index == other.index
+ end
+ end
+end
View
93 lib/scruby/env.rb
@@ -0,0 +1,93 @@
+module Scruby
+ class Env
+ attr_accessor :levels, :times, :curves, :release_node, :array
+ SHAPE_NAMES = {
+ :step => 0,
+ :lin => 1,
+ :linear => 1,
+ :exp => 2,
+ :exponential => 2,
+ :sin => 3,
+ :sine => 3,
+ :wel => 4,
+ :welch => 4,
+ :sqr => 6,
+ :squared => 6,
+ :cub => 7,
+ :cubed => 7
+ }
+
+ def initialize levels, times, curves = :lin, release_node = nil, loop_node = nil
+ #times should be one less than levels size
+ # raise( ArgumentError, 'levels and times must be array')
+ @levels, @times, @curves, @release_node, @loop_node = levels, times, curves.to_array, release_node, loop_node
+ raise ArgumentError, "levels and times should be array" unless levels.instance_of?(Array) and times.instance_of?(Array)
+ end
+
+ class << self
+ def triangle dur = 1, level = 1
+ dur = dur * 0.5
+ new [0, level, 0], [dur, dur]
+ end
+
+ def sine dur = 1, level = 1
+ dur = dur * 0.5
+ new [0, level, 0], [dur, dur], :sine
+ end
+
+ def perc attackTime = 0.01, releaseTime = 1, level = 1, curve = -4
+ new [0, level, 0], [attackTime, releaseTime], curve
+ end
+
+ def linen attackTime = 0.01, sustainTime = 1, releaseTime = 1, level = 1, curve = :lin
+ new [0, level, level, 0], [attackTime, sustainTime, releaseTime], curve
+ end
+
+ def cutoff releaseTime = 0.1, level = 1, curve = :lin
+ new [level, 0], [releaseTime], curve, 0
+ end
+
+ def dadsr delayTime = 0.1, attackTime = 0.01, decayTime = 0.3, sustainLevel = 0.5, releaseTime = 1, peakLevel = 1, curve = -4, bias = 0
+ new [0, 0, peakLevel, peakLevel * sustainLevel, 0].collect{ |e| e + bias }, [delayTime, attackTime, decayTime, releaseTime], curve, 3
+ end
+
+ def adsr attackTime = 0.01, decayTime = 0.3, sustainLevel = 0.5, releaseTime = 1, peakLevel = 1, curve = -4, bias = 0
+ new [0, peakLevel, peakLevel * sustainLevel, 0].collect{ |e| e + bias }, [attackTime, decayTime, releaseTime], curve, 2
+ end
+
+ def asr attackTime = 0.01, sustainLevel = 1, releaseTime = 1, curve = -4
+ new [0, sustainLevel, 0], [attackTime, releaseTime], curve, 1
+ end
+
+ named_arguments_for :triangle, :sine, :perc, :linen, :cutoff, :dadsr, :adsr, :asr
+ end
+
+ def to_array
+ contents = levels[0], times.size, release_node, loop_node
+ contents + levels[1..-1].wrap_and_zip( times, shape_numbers, curve_values ).flatten
+ end
+
+ def shape_numbers
+ curves.collect do |curve|
+ Ugens::Ugen.valid_input?( curve ) ? 5 : SHAPE_NAMES[curve]
+ end
+ end
+
+ def curve_values
+ curves.collect do |curve|
+ Ugens::Ugen.valid_input?( curve ) ? curve : 0
+ end
+ end
+
+ def release_node
+ @release_node ||= -99
+ end
+
+ def loop_node
+ @loop_node ||= -99
+ end
+
+ def collect_constants #:nodoc:
+ end
+ end
+end
View
20 lib/scruby/group.rb
@@ -0,0 +1,20 @@
+module Scruby
+ class Group < Node
+
+ def free_all
+ send '/g_freeAll', self.node_id
+ self
+ end
+
+ def deep_free
+ send '/g_deepFree', self.node_id
+ self
+ end
+
+ def dump_tree post = false
+ send '/g_dumpTree', self.node_id, post
+ self
+ end
+
+ end
+end
View
106 lib/scruby/node.rb
@@ -0,0 +1,106 @@
+module Scruby
+ class Node
+ @@base_id = 2000
+ attr_reader :servers, :group, :id
+ alias :node_id :id
+
+ ACTIONS = [:head, :tail, :before, :after, :replace]
+
+ def initialize *args
+ args.flatten!
+ args.compact!
+ @id = args.pop if args.last.is_a? Integer
+ @servers = args.empty? ? Server.all : TypedArray.new( Server, args )
+ @id ||= @@base_id += 1
+ end
+
+ def set args = {}
+ send '/n_set', self.id, *args.to_a.flatten
+ self
+ end
+
+ def free
+ send '/n_free', self.id
+ @group, @playing, @running = nil, false, false
+ self
+ end
+
+ def run run = true
+ send '/n_run', self.id, run
+ self
+ end
+
+ # Map controls in this Node to read from control or audio rate Buses. Controls are defined in a SynthDef as args or instances of
+ # Control or its subclasses. They are specified here using symbols, strings, or indices, and are listed in pairs with Bus objects.
+ # The number of sequential controls mapped corresponds to the Bus' number of channels. If this Node is a Group this will map all
+ # Nodes within the Group. Note that with mapMsg if you mix audio and control rate busses you will get an Array of two messages
+ # rather than a single message. Integer bus indices are assumed to refer to control buses. To map a control to an audio bus, you
+ # must use a Bus object.
+ def map args
+ control, audio, content = ['/n_mapn', self.id], ['/n_mapan', self.id], []
+ args = args.to_a.each do |param, bus|
+ raise ArgumentError, "`#{ control }` is not a Bus" unless bus.kind_of? Bus
+ array = audio if bus.rate == :audio
+ array = control if bus.rate == :control
+ array.push param, bus.index, bus.channels if array
+ end
+ content << control unless control.empty?
+ content << audio unless audio.empty?
+ send_bundle nil, *content
+ self
+ end
+
+ # mapn
+ def trace
+ send '/n_trace', self.id
+ self
+ end
+
+ def move_before node
+ @group = node.group
+ send '/n_before', self.id, node.id
+ self
+ end
+
+ def move_after node
+ @group = node.group
+ send '/n_after', self.id, node.id
+ self
+ end
+
+ # def move_to_head group
+ # @group = node.group
+ # @server.each{ |s| s.send '/n_after', self.id, node.id }
+ # end
+ #
+ # def move_to_tail group
+ # @group = node.group
+ # @server.each{ |s| s.send '/n_after', self.id, node.id }
+ # end
+
+ # def playing?
+ # @playing || false
+ # end
+ #
+ # def running?
+ # @running || false
+ # end
+
+ # Reset the node count
+ def self.reset!
+ @@base_id = 2000
+ end
+
+ # Sends a bundle to all registered +servers+ for this node
+ def send_bundle timestamp, *messages
+ bundle = Bundle.new( timestamp, *messages.map{ |message| Message.new *message } )
+ @servers.each{ |s| s.send bundle }
+ end
+
+ # Sends a message to all registered +servers+ for this node
+ def send command, *args
+ message = Message.new command, *args
+ @servers.each{ |s| s.send message }
+ end
+ end
+end
View
206 lib/scruby/server.rb
@@ -0,0 +1,206 @@
+require 'singleton'
+
+module Scruby
+ include OSC
+
+ class Message < OSC::Message
+ def initialize command, *args
+ args.peel!
+ args.collect! do |arg|
+ case arg
+ when Array
+ Blob.new self.class.new(*arg).encode
+ when true
+ 1
+ when false
+ 0
+ when Symbol
+ arg.to_s
+ else
+ arg
+ end
+ end
+ super command, type_tags(args), *args
+ end
+
+ def type_tags *args
+ args.peel!
+ args.collect{ |arg| OSC::Packet.tag arg }.join
+ end
+ end
+
+ class UDPSender < OSC::UDPServer #:nodoc:
+ include Singleton
+
+ alias :udp_send :send
+ def send command, host, port, *args
+ args = args.collect{ |arg| arg.kind_of?( Symbol ) ? arg.to_s : arg }
+ udp_send Message.new( command, *args ), 0, host, port
+ end
+
+ def send_message message, host, port
+ udp_send message, 0, host, port
+ end
+ end
+ $UDP_Sender = UDPSender.instance
+
+ class Server
+ attr_reader :host, :port, :path, :buffers, :control_buses, :audio_buses
+ DEFAULTS = { :buffers => 1024, :control_buses => 4096, :audio_buses => 128, :audio_outputs => 8, :audio_inputs => 8 }.freeze
+
+ # Initializes and registers a new Server instance and sets the host and port for it.
+ # The server is a Ruby representation of scsynth which can be a local binary or a remote
+ # server already running.
+ # Server class keeps an array with all the instantiated servers
+ # Options:
+ # +host+:
+ # defaults to 'localhost'
+ # +port+:
+ # TCP port defaults to 57111
+ # +control_buses+
+ # Number of buses for routing control data defaults to 4096, indices start at 0.
+ # +audio_buses+
+ # Number of audio Bus channels for hardware output and input and internal routing, defaults to 128
+ # +audio_outputs+
+ # Reserved +buses+ for hardware output, indices available are 0 to +audio_outputs+ - 1 defaults to 8.
+ # +audio_inputs+
+ # Reserved +buses+ for hardware input, +audio_outputs+ to (+audio_outputs+ + +audio_inputs+ - 1), defaults to 8.
+ # +buffers+
+ # Number of available sample buffers defaults to 1024
+ def initialize opts = {}
+ @host = opts.delete(:host) || 'localhost'
+ @port = opts.delete(:port) || 57111
+ @path = opts.delete(:path) || '/Applications/SuperCollider/scsynth'
+ @opts = DEFAULTS.dup.merge opts
+ @buffers = []
+ @control_buses = []
+ @audio_buses = []
+ Bus.audio self, @opts[:audio_outputs] # register hardware buses
+ Bus.audio self, @opts[:audio_inputs]
+ self.class.all << self
+ end
+
+ # Boots the local binary of the scsynth forking a process, it will rise a SCError if the scsynth
+ # binary is not found in /Applications/SuperCollider/scsynth (default Mac OS path) or given path.
+ # The default path can be overriden using Server.scsynt_path=('path')
+ def boot
+ raise SCError.new('Scsynth not found in the given path') unless File.exists? @path
+ if running?
+ warn "Server on port #{ @port } allready running"
+ return self
+ end
+
+ ready = false
+ @thread = Thread.new do
+ IO.popen "cd #{ File.dirname @path }; ./#{ File.basename @path } -u #{ @port }" do |pipe|
+ loop do
+ if response = pipe.gets
+ puts response
+ ready = true if response.match /ready/
+ end
+ end
+ end
+ end
+ sleep 0.01 until ready or !@thread.alive?
+ sleep 0.01 # just to be shure
+ send "/g_new", 1
+ self
+ end
+
+ def running?
+ @thread and @thread.alive? ? true : false
+ end
+
+ def stop
+ send "/g_freeAll", 0
+ send "/clearSched"
+ send "/g_new", 1
+ end
+
+ # Sends the /quit OSC signal to the scsynth
+ def quit
+ Server.all.delete self
+ send '/quit'
+ end
+
+ # Sends an OSC command or +Message+ to the scsyth server.
+ # E.g. +server.send('/dumpOSC', 1)+
+ def send message, *args
+ case message
+ when Bundle, Message
+ $UDP_Sender.send_message message, @host, @port
+ else
+ $UDP_Sender.send message, @host, @port, *args
+ end
+ self
+ end
+
+ def send_bundle timestamp = nil, *messages
+ send Bundle.new( timestamp, *messages.map{ |message| Message.new *message } )
+ end
+
+ # Encodes and sends a SynthDef to the scsynth server
+ def send_synth_def synth_def
+ send Bundle.new( nil, Message.new( '/d_recv', Blob.new(synth_def.encode), 0 ) )
+ end
+
+ # Allocates either buffer or bus indices, should be consecutive
+ def allocate kind, *elements
+ collection = instance_variable_get "@#{kind}"
+ elements.flatten!
+
+ max_size = @opts[kind]
+ if collection.compact.size + elements.size > max_size
+ raise SCError, "No more indices available -- free some #{ kind } before allocating more."
+ end
+
+ return collection.concat(elements) unless collection.index nil # just concat arrays if no nil item
+
+ indices = []
+ collection.each_with_index do |item, index| # find n number of consecutive nil indices
+ break if indices.size >= elements.size
+ if item.nil?
+ indices << index
+ else
+ indices.clear
+ end
+ end
+
+ case
+ when indices.size >= elements.size
+ collection[indices.first, elements.size] = elements
+ when collection.size + elements.size <= max_size
+ collection.concat elements
+ else
+ raise SCError, "No block of #{ elements.size } consecutive #{ kind } indices is available."
+ end
+ end
+
+ @@servers = []
+ class << self
+ # Returns an array with all the registered servers
+ def all
+ @@servers
+ end
+
+ # Clear the servers array
+ def clear
+ @@servers.clear
+ end
+
+ # Return a server corresponding to the specified index of the registered servers array
+ def [] index
+ @@servers[index]
+ end
+
+ # Set a server to the specified index of the registered servers array
+ def []= index
+ @@servers[index]
+ @@servers.uniq!
+ end
+ end
+ end
+
+ class SCError < StandardError
+ end
+end
View
58 lib/scruby/synth.rb
@@ -0,0 +1,58 @@
+module Scruby
+
+ class Synth < Node
+ attr_reader :name
+
+ def initialize name, servers
+ super servers
+ @name = name.to_s
+ end
+
+ protected
+
+
+ class << self
+ def new name, args = {}, target = nil, action = :head
+ servers, target_id = params_from_target target
+ synth = instantiate name, servers
+ synth.send '/s_new', synth.name, synth.id, Node::ACTIONS.index(action), target_id, *args.to_a.flatten
+ synth
+ end
+
+ def paused
+ end
+
+ def after
+ end
+
+ # before
+ # head
+ # tail
+ # replace
+
+ # def as_target obj
+ # case obj
+ # when Server then Group.new obj, 1
+ # when Node then obj
+ # when nil then Group.new
+ # end
+ # end
+
+
+ private
+ def params_from_target target
+ servers = target.servers if target.respond_to? :servers
+ target_id = target if target.is_a? Integer
+ target_id ||= target.respond_to?(:node_id) ? target.node_id : 1
+ [servers, target_id]
+ end
+
+ def instantiate *args
+ obj = allocate
+ obj.__send__ :initialize, *args
+ obj
+ end
+ end
+
+ end
+end
View
109 lib/scruby/synthdef.rb
@@ -0,0 +1,109 @@
+module Scruby
+ class SynthDef
+ attr_reader :name, :children, :constants, :control_names
+ # Creates a new SynthDef instance
+ # An "ugen graph" block should be passed:
+ #
+ # SynthDef.new('simple') do |rate|
+ # Out.ar( 0, SinOsc.ar(rate) )
+ # end
+ #
+ # Default values and rates for the block can be passed with the <tt>:values => []</tt> and <tt>:rates => []</tt> options:
+ # E.g.
+ # SynthDef.new( :am, :values => [1, 1000, 10, 1] ) do |gate, portadora, moduladora, amp|
+ # modulacion = SinOsc.kr( moduladora, 0, 0.5, 0.5 )
+ # sig = SinOsc.ar( portadora, 0, modulacion )
+ # env = EnvGen.kr( Env.asr(2,1,2), gate, :doneAction => 2 )
+ # Out.ar( 0, sig*env*amp )
+ # end
+ #
+ # is equivalent to the Sclang SynthDef
+ # SynthDef(\am, {|gate=1, portadora=1000, moduladora=10, amp=1|
+ # var modulacion, sig, env;
+ # modulacion = SinOsc.kr(moduladora, 0, 0.5, 0.5);
+ # sig = SinOsc.ar(portadora, 0, modulacion);
+ # env = EnvGen.kr(Env.asr(2,1,2), gate, doneAction:2);
+ # Out.ar(0, sig*env*amp);
+ # }).send(s)
+ #
+ def initialize name, options = {}, &block
+ @name, @children = name.to_s, []
+ raise( ArgumentError.new('An UGen graph (block) must be passed') ) unless block_given?
+
+ values = options.delete( :values ) || []
+ rates = options.delete( :rates ) || []
+
+ @control_names = collect_control_names block, values, rates
+ build_ugen_graph block, @control_names
+ @constants = collect_constants @children
+
+ @variants = [] #stub!!!
+ end
+
+ # Returns a string representing the encoded SynthDef in a way scsynth can interpret and generate.
+ # This method is called by a server instance when sending the synthdef via OSC.
+ #
+ # For complex synthdefs the encoded synthdef can vary a little bit from what SClang would generate
+ # but the results will be interpreted in the same way
+ def encode
+ controls = @control_names.reject { |cn| cn.non_control? }
+ encoded_controls = [controls.size].pack('n') + controls.collect{ |c| c.name.encode + [c.index].pack('n') }.join
+
+ init_stream + name.encode + constants.encode_floats + values.flatten.encode_floats + encoded_controls +
+ [children.size].pack('n') + children.collect{ |u| u.encode }.join('') +
+ [@variants.size].pack('n') #stub!!!
+ end
+
+ def init_stream file_version = 1, number_of_synths = 1 #:nodoc:
+ 'SCgf' + [file_version].pack('N') + [number_of_synths].pack('n')
+ end
+
+ def values #:nodoc:
+ @control_names.collect{ |control| control.value }
+ end
+
+ alias :send_msg :send
+ # Sends itself to the given servers. One or more servers or an array of servers can be passed.
+ # If no arguments are given the synthdef gets sent to all instantiated servers
+ # E.g.
+ # s = Server.new('localhost', 5114)
+ # s.boot
+ # r = Server.new('127.1.1.2', 5114)
+ #
+ # SynthDef.new('sdef'){ Out.ar(0, SinOsc.ar(220)) }.send(s)
+ # # this synthdef is only sent to s
+ #
+ # SynthDef.new('sdef2'){ Out.ar(1, SinOsc.ar(222)) }.send
+ # # this synthdef is sent to both s and r
+ #
+ def send *servers
+ servers.peel!
+ (servers.empty? ? Server.all : servers).each{ |s| s.send_synth_def( self ) }
+ self
+ end
+
+ private
+ def collect_control_names function, values, rates
+ names = function.arguments
+ names.zip( values, rates ).collect_with_index{ |array, index| ControlName.new *(array << index) }
+ end
+
+ def build_controls control_names
+ # control_names.select{ |c| c.rate == :noncontrol }.sort_by{ |c| c.control_name.index } +
+ [:scalar, :trigger, :control].collect do |rate|
+ same_rate_array = control_names.select{ |control| control.rate == rate }
+ Control.and_proxies_from( same_rate_array ) unless same_rate_array.empty?
+ end.flatten.compact.sort_by{ |proxy| proxy.control_name.index }
+ end
+
+ def build_ugen_graph function, control_names
+ Ugen.synthdef = self
+ function.call *build_controls(control_names)
+ Ugen.synthdef = nil
+ end
+
+ def collect_constants children
+ children.send( :collect_constants ).flatten.compact.uniq
+ end
+ end
+end
View
38 lib/scruby/ugens/env_gen.rb
@@ -0,0 +1,38 @@
+module Scruby
+ module Ugens
+ # Done Actions:
+ #
+ # * 0 do nothing when the UGen is finished
+ # * 1 pause the enclosing synth, but do not free it
+ # * 2 free the enclosing synth
+ # * 3 free both this synth and the preceding node
+ # * 4 free both this synth and the following node
+ # * 5 free this synth; if the preceding node is a group then do g_freeAll on it, else free it
+ # * 6 free this synth; if the following node is a group then do g_freeAll on it, else free it
+ # * 7 free this synth and all preceding nodes in this group
+ # * 8 free this synth and all following nodes in this group
+ # * 9 free this synth and pause the preceding node
+ # * 10 free this synth and pause the following node
+ # * 11 free this synth and if the preceding node is a group then do g_deepFree on it, else free it
+ # * 12 free this synth and if the following node is a group then do g_deepFree on it, else free it
+ # * 13 free this synth and all other nodes in this group (before and after)
+ # * 14 free the enclosing group and all nodes within it (including this synth)
+ class EnvGen < Ugen
+ class << self
+ # New EnvGen with :audio rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def ar envelope, gate = 1, levelScale = 1, levelBias = 0, timeScale = 1, doneAction = 0
+ new :audio, gate, levelScale, levelBias, timeScale, doneAction, *envelope.to_array
+ end
+ # New EnvGen with :control rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def kr envelope, gate = 1, levelScale = 1, levelBias = 0, timeScale = 1, doneAction = 0
+ new :control, gate, levelScale, levelBias, timeScale, doneAction, *envelope.to_array
+ end
+
+ named_arguments_for :ar, :kr
+ private
+ def new *args; super; end
+ end
+ end
+ end
+
+end
View
62 lib/scruby/ugens/in_out.rb
@@ -0,0 +1,62 @@
+module Scruby
+ module Ugens
+ class In < MultiOutUgen
+ #:nodoc:
+ def initialize rate, channels, bus
+ super rate, *(0...channels).map{ |i| OutputProxy.new rate, self, i }
+ @inputs = [bus]
+ end
+
+ class << self
+ # New In with :audio rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def ar bus, channels = 1
+ new :audio, channels, bus
+ end
+ # New In with :control rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def kr bus, channels = 1
+ new :control, channels, bus
+ end
+
+ def params #:nodoc:
+ {:audio => [[:bus, nil], [:channels, 1], [:mul, 1], [:add, 0]], :control => [[:bus, nil], [:channels, 1], [:mul, 1], [:add, 0]]}
+ end
+
+ private
+ def new *args; super; end
+ end
+ end
+
+ class Out < Ugen
+ # ar and kr should be use for instantiatio
+ def initialize *args
+ super
+ @channels = []
+ end
+
+ #:nodoc:
+ def output_specs; []; end
+
+ class << self
+ # New Out with :audio rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def ar bus, *inputs
+ inputs.peel!
+ new :audio, bus, *inputs; 0.0 #Out has no output
+ end
+
+ # New Out with :control rate, inputs should be valid Ugen inputs or Ugens, arguments can be passed as an options hash or in the given order
+ def kr bus, *inputs
+ inputs.peel!
+ new :control, bus, *inputs; 0.0 #Out has no output
+ end
+
+
+ def params #:nodoc:
+ {:audio => [[:bus,nil], [:inputs, []], [:mul, 1], [:add, 0]], :control => [[:bus,nil], [:inputs, []], [:mul, 1], [:add, 0]]}
+ end
+
+ private
+ def new *args; super; end
+ end
+ end
+ end
+end
View
44 lib/scruby/ugens/multi_out_ugens.rb
@@ -0,0 +1,44 @@
+module Scruby
+ module Ugens
+ class OutputProxy < Ugen #:nodoc:
+ attr_reader :source, :control_name, :output_index
+
+ def initialize rate, source, output_index, name = nil
+ super rate
+ @source, @control_name, @output_index = source, name, output_index
+ end
+
+ def index
+ @source.index
+ end
+
+ def add_to_synthdef; end
+ end
+
+ class MultiOutUgen < Ugen #:nodoc:
+ def initialize rate, *channels
+ super rate
+ @channels = channels
+ end
+
+ def self.new rate, *args
+ super.channels #returns the channels but gets instantiated
+ end
+
+ private
+ def output_specs
+ channels.collect{ |output| output.send :output_specs }.flatten
+ end
+ end
+
+ class Control < MultiOutUgen #:nodoc:
+ def initialize rate, *names
+ super rate, *names.collect_with_index{|n, i| OutputProxy.new rate, self, i, n }
+ end
+
+ def self.and_proxies_from names
+ new names.first.rate, *names
+ end
+ end
+ end
+end
View
92 lib/scruby/ugens/operation_indices.yaml
@@ -0,0 +1,92 @@
+
+binary:
+ !ruby/symbol +: 0
+ !ruby/symbol -: 1
+ !ruby/symbol *: 2
+ !ruby/symbol div: 3
+ !ruby/symbol /: 4
+ !ruby/symbol mod: 5
+ !ruby/symbol <=: 10
+ !ruby/symbol >=: 11
+ !ruby/symbol minimum: 12
+ !ruby/symbol maximum: 13 #can't be called max because there is an array method calle maximum
+ !ruby/symbol lcm: 17
+ !ruby/symbol gcd: 18
+ !ruby/symbol round: 19
+ !ruby/symbol roundUp: 20
+ !ruby/symbol trunc: 21
+ !ruby/symbol atan2: 22
+ !ruby/symbol hypot: 23
+ !ruby/symbol hypotApx: 24
+ !ruby/symbol pow: 25
+ !ruby/symbol leftShift: 26
+ !ruby/symbol rightShift: 27
+ !ruby/symbol unsignedRightShift: 28
+ !ruby/symbol ring1: 30
+ !ruby/symbol ring2: 31
+ !ruby/symbol ring3: 32
+ !ruby/symbol ring4: 33
+ !ruby/symbol difsqr: 34
+ !ruby/symbol sumsqr: 35
+ !ruby/symbol sqrsum: 36
+ !ruby/symbol sqrdif: 37
+ !ruby/symbol absdif: 38
+ !ruby/symbol thresh: 39
+ !ruby/symbol amclip: 40
+ !ruby/symbol scaleneg: 41
+ !ruby/symbol clip2: 42
+ !ruby/symbol excess: 43
+ !ruby/symbol fold2: 44
+ !ruby/symbol wrap2: 45
+ !ruby/symbol rrand: 47
+ !ruby/symbol exprand: 48
+
+unary:
+ !ruby/symbol neg: 0
+ !ruby/symbol bitNot: 4
+ !ruby/symbol abs: 5
+ !ruby/symbol asFloat: 6
+ !ruby/symbol ceil: 8
+ !ruby/symbol floor: 9
+ !ruby/symbol frac: 10
+ !ruby/symbol sign: 11
+ !ruby/symbol squared: 12
+ !ruby/symbol cubed: 13
+ !ruby/symbol sqrt: 14
+ !ruby/symbol exp: 15
+ !ruby/symbol reciprocal: 16
+ !ruby/symbol midicps: 17
+ !ruby/symbol cpsmidi: 18
+ !ruby/symbol midiratio: 19
+ !ruby/symbol ratiomidi: 20
+ !ruby/symbol dbamp: 21
+ !ruby/symbol ampdb: 22
+ !ruby/symbol octcps: 23
+ !ruby/symbol cpsoct: 24
+ !ruby/symbol log: 25
+ !ruby/symbol log2: 26
+ !ruby/symbol log10: 27
+ !ruby/symbol sin: 28
+ !ruby/symbol cos: 29
+ !ruby/symbol tam: 30
+ !ruby/symbol asin: 31
+ !ruby/symbol acos: 32
+ !ruby/symbol atan: 33
+ !ruby/symbol sinh: 34
+ !ruby/symbol cosh: 35
+ !ruby/symbol tanh: 36
+ !ruby/symbol rand: 37
+ !ruby/symbol rand2: 38
+ !ruby/symbol linrand: 39
+ !ruby/symbol bilinrand: 40
+ !ruby/symbol sum3rand: 41
+ !ruby/symbol distort: 42
+ !ruby/symbol softclip: 43
+ !ruby/symbol coin: 44
+ !ruby/symbol rectWindow: 48
+ !ruby/symbol hanWindow: 49
+ !ruby/symbol welWindow: 50
+ !ruby/symbol triWindow: 51
+ !ruby/symbol ramp: 52
+ !ruby/symbol scurve: 53
+
View
63 lib/scruby/ugens/operation_ugens.rb
@@ -0,0 +1,63 @@
+module Scruby
+ module Ugens
+
+ class BasicOpUgen < Ugen #:nodoc:
+ attr_accessor :operator
+
+ class << self
+ def new operator, *inputs
+ obj = super get_rate(inputs), inputs
+ set_operator_for obj, operator
+ obj
+ end
+
+ private
+ #:nodoc:
+ def set_operator_for input, operator
+ input.kind_of?(Array) ? input.each{ |element| set_operator_for element, operator } : input.operator = operator
+ end
+
+ #:nodoc:
+ def get_rate *inputs
+ max_index = inputs.flatten.collect{ |ugen| Ugen::RATES.index ugen.rate }.max
+ Ugen::RATES[max_index]
+ end
+ end
+ end
+
+ class UnaryOpUGen < BasicOpUgen
+ def self.new operator, input
+ super
+ end
+
+ def special_index
+ UgenOperations::UNARY[operator.to_sym]
+ end
+ end
+
+ class BinaryOpUGen < BasicOpUgen
+ def self.new operator, left, right
+ super
+ end
+
+ def special_index
+ UgenOperations::BINARY[operator.to_sym]
+ end
+ end
+
+ class MulAdd < Ugen
+ def self.new input, mul, add
+ no_mul = mul == 1.0
+ minus = mul == -1.0
+ return add if mul == 0
+ return input if no_mul and add == 0
+ return input.neg if minus and add == 0
+ return input * mul if add == 0
+ return add - input if minus
+ return input + add if no_mul
+ super input.rate, input, mul, add
+ end
+ end
+ end
+
+end
View
178 lib/scruby/ugens/ugen.rb
@@ -0,0 +1,178 @@
+module Scruby
+ module Ugens
+ # All ugens inherit from this "abstract" class
+ #
+ # == Creation
+ #
+ # Ugens are usually instantiated inside an "ugen graph" or the block passed when creating a SynthDef
+ # using either the ar, kr, ir or new methods wich will determine the rate.
+ # * ar: audio rate
+ # * kr: control rate
+ # * ir: scalar rate
+ # * new: demand rate
+ #
+ # Not all the ugens provide all the rates
+ #
+ # Two ugens inside an ugen graph:
+ # SynthDef.new('simple'){ Out.ar(0, SinOsc.ar) }
+ # # Out and SinOsc are both ugens
+ #
+ #
+ # == Passing arguments when creating
+ #
+ # Usually when instantiating an ugen the arguments can be passed in order:
+ # Pitch.kr(0, 220, 80, ...)
+ #
+ # Or using a hash where the keys are symbols corresponding to the argument name.
+ # Pitch.kr( :initFreq => 220, :execFreq => 300 )
+ #
+ # Or a combination of both ways:
+ # Pitch.kr(0, 220, :execFreq => 300)
+ #
+ # Arguments not passed in either way will resort to default
+ #
+ #
+ # == Defining ugens
+ #
+ # This named arguments functionality is provided for all the default Ugens but can be provided when defining a new Ugen by calling
+ # <tt>#named_arguments_for</tt> passing a symbol with the name of a defined method:
+ #
+ # class Umaguma < Ugen
+ # class << self
+ # def ar(karma = 200, pitch = 20, rate = 200)
+ # ...
+ # end
+ # named_arguments_for :ar
+ # end
+ #
+ # end
+ #
+ # For more info and limitations on named arguments check the gem: http://github.com/maca/arguments
+ #
+ # Otherwise usage is pretty the same as in SuperCollider
+ #
+ # TODO: Provide a way of getting the argument names and default values
+ class Ugen
+ attr_reader :inputs, :rate, :index, :special_index, :output_index, :channels
+
+ RATES = :scalar, :trigger, :demand, :control, :audio
+ E_RATES = :scalar, :control, :audio, :demand
+ VALID_INPUTS = Numeric, Array, Ugen, Env, ControlName
+ @@synthdef = nil
+
+
+ def initialize rate, *inputs
+ @rate, @inputs = rate, inputs.compact
+ @special_index ||= 0
+ @output_index ||= 0
+ @channels ||= [1]
+ @index = add_to_synthdef || 0
+ end
+
+ # Instantiate a new MulAdd passing self and the multiplication and addition arguments
+ def muladd mul, add
+ MulAdd.new self, mul, add
+ end
+
+ def encode
+ self.class.to_s.split('::').last.encode + [ E_RATES.index(rate) ].pack('w') +
+ [ inputs.size, channels.size, special_index, collect_input_specs ].flatten.pack('n*') +
+ output_specs.pack('w*')
+ end
+
+ private
+ def synthdef #:nodoc:
+ @synthdef ||= Ugen.synthdef
+ end
+
+ def add_to_synthdef #:nodoc:
+ (synthdef.children << self).size - 1 if synthdef
+ end
+
+ def collect_constants #:nodoc:
+ @inputs.send( :collect_constants )
+ end
+
+ def input_specs synthdef #:nodoc:
+ [index, output_index]
+ end
+
+ def collect_input_specs #:nodoc:
+ @inputs.collect{ |i| i.send :input_specs, synthdef }
+ end
+
+ def output_specs #:nodoc:
+ [E_RATES.index(rate)]
+ end
+
+ public
+ def == other
+ self.class == other.class and
+ self.rate == other.rate and
+ self.inputs == other.inputs and
+ self.channels == other.channels
+ end
+
+ class << self
+ #:nodoc:
+ def new rate, *inputs
+
+ if rate.kind_of? Array
+ rate = RATES.slice rate.collect { |rate| # get the highest rate, raise error if rate is not defined
+ rate = rate.to_sym
+ raise ArgumentError.new( "#{rate} not a defined rate") unless RATES.include? rate
+ RATES.index rate
+ }.max
+ else
+ raise ArgumentError.new( "#{rate} not a defined rate") unless RATES.include? rate.to_sym
+ end
+
+ size = 1 # Size of the largest multichannel input (Array)
+ inputs.peel! # First input if input is Array and size is 1
+ inputs.map! do |input|
+ input = input.as_ugen_input if input.respond_to?(:as_ugen_input) # Convert input to prefered form
+ raise ArgumentError.new( "#{ input.inspect } is not a valid ugen input") unless valid_input? input
+ size = input.size if input.size > size if input.kind_of? Array
+ input
+ end
+
+ return instantiate( rate, *inputs.flatten ) unless size > 1 #return an Ugen if no array was passed as an input
+
+ inputs.map! do |input|
+ Array === input ? input.wrap_to!(size) : input = Array.new(size, input)
+ input
+ end
+ output = inputs.transpose
+ output.map! do |new_inputs| new rate, *new_inputs end
+ output.to_da
+ end
+
+
+ def synthdef #:nodoc:
+ @@synthdef
+ end
+
+ def synthdef= synthdef #:nodoc:
+ @@synthdef = synthdef
+ end
+
+ def valid_input? obj
+ case obj
+ when *VALID_INPUTS then true
+ else false
+ end
+ end
+
+ def params
+ {}
+ end
+
+ def instantiate *args
+ obj = allocate
+ obj.__send__ :initialize, *args
+ obj
+ end
+ end
+ end
+ end
+end
View
3,389 lib/scruby/ugens/ugen_defs.yaml
@@ -0,0 +1,3389 @@
+---
+A2K:
+ :control:
+ - - :input
+ - 0
+APF:
+ :control:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :radius
+ - 0.8
+ :audio:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :radius
+ - 0.8
+AllpassC:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+AllpassL:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+AllpassN:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+AmpComp:
+ :scalar:
+ - - :freq
+ - 261.6256
+ - - :root
+ - 261.6256
+ - - :exp
+ - 0.3333
+ :control:
+ - - :freq
+ - 261.6256
+ - - :root
+ - 261.6256
+ - - :exp
+ - 0.3333
+ :audio:
+ - - :freq
+ - 261.6256
+ - - :root
+ - 261.6256
+ - - :exp
+ - 0.3333
+AmpCompA:
+ :scalar:
+ - - :freq
+ - 1000
+ - - :root
+ - 0
+ - - :minAmp
+ - 0.32
+ - - :rootAmp
+ - 1
+ :control:
+ - - :freq
+ - 1000
+ - - :root
+ - 0
+ - - :minAmp
+ - 0.32
+ - - :rootAmp
+ - 1
+ :audio:
+ - - :freq
+ - 1000
+ - - :root
+ - 0
+ - - :minAmp
+ - 0.32
+ - - :rootAmp
+ - 1
+Amplitude:
+ :control:
+ - - :input
+ - 0
+ - - :attackTime
+ - 0.01
+ - - :releaseTime
+ - 0.01
+ :audio:
+ - - :input
+ - 0
+ - - :attackTime
+ - 0.01
+ - - :releaseTime
+ - 0.01
+BPF:
+ :control:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :rq
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :rq
+ - 1
+BPZ2:
+ :control:
+ - - :input
+ - 0
+ :audio:
+ - - :input
+ - 0
+BRF:
+ :control:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :rq
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :freq
+ - 440
+ - - :rq
+ - 1
+BRZ2:
+ :control:
+ - - :input
+ - 0
+ :audio:
+ - - :input
+ - 0
+Balance2:
+ :control:
+ - - :left
+ -
+ - - :right
+ -
+ - - :pos
+ - 0
+ - - :level
+ - 1
+ :audio:
+ - - :left
+ -
+ - - :right
+ -
+ - - :pos
+ - 0
+ - - :level
+ - 1
+Ball:
+ :audio:
+ - - :input
+ - 0
+ - - :g
+ - 10
+ - - :damp
+ - 0
+ - - :friction
+ - 0.01
+BiPanB2:
+ :control:
+ - - :inA
+ -
+ - - :inB
+ -
+ - - :azimuth
+ -
+ - - :gain
+ - 1
+ :audio:
+ - - :inA
+ -
+ - - :inB
+ -
+ - - :azimuth
+ -
+ - - :gain
+ - 1
+Blip:
+ :audio:
+ - - :freq
+ - 440
+ - - :numharm
+ - 200
+BrownNoise:
+ :control: []
+
+ :audio: []
+
+BufAllpassC:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufAllpassL:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufAllpassN:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufChannels:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufCombC:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufCombL:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufCombN:
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+BufDelayC:
+ :control:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+BufDelayL:
+ :control:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+BufDelayN:
+ :control:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :buf
+ - 0
+ - - :input
+ - 0
+ - - :delaytime
+ - 0.2
+BufDur:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufFrames:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufRateScale:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufRd:
+ :control:
+ - - :bufnum
+ - 0
+ - - :phase
+ - 0
+ - - :loop
+ - 1
+ - - :interpolation
+ - 2
+ :audio:
+ - - :bufnum
+ - 0
+ - - :phase
+ - 0
+ - - :loop
+ - 1
+ - - :interpolation
+ - 2
+BufSampleRate:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufSamples:
+ :scalar:
+ - - :bufnum
+ -
+ :control:
+ - - :bufnum
+ -
+BufWr:
+ :control:
+ - - :bufnum
+ - 0
+ - - :phase
+ - 0
+ - - :loop
+ - 1
+ - - :inputArray
+ - "[]"
+ :audio:
+ - - :bufnum
+ - 0
+ - - :phase
+ - 0
+ - - :loop
+ - 1
+ - - :inputArray
+ - "[]"
+COsc:
+ :control:
+ - - :bufnum
+ -
+ - - :freq
+ - 440
+ - - :beats
+ - 0.5
+ :audio:
+ - - :bufnum
+ -
+ - - :freq
+ - 440
+ - - :beats
+ - 0.5
+Clip:
+ :control:
+ - - :input
+ - 0
+ - - :lo
+ - 0
+ - - :hi
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :lo
+ - 0
+ - - :hi
+ - 1
+ClipNoise:
+ :control: []
+
+ :audio: []
+
+CoinGate:
+ :control:
+ - - :prob
+ -
+ - - :input
+ -
+ :audio:
+ - - :prob
+ -
+ - - :input
+ -
+CombC:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+CombL:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+CombN:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ - - :decaytime
+ - 1
+Compander:
+ :audio:
+ - - :input
+ - 0
+ - - :control
+ - 0
+ - - :thresh
+ - 0.5
+ - - :slopeBelow
+ - 1
+ - - :slopeAbove
+ - 1
+ - - :clampTime
+ - 0.01
+ - - :relaxTime
+ - 0.1
+ControlRate:
+ :scalar: []
+
+Convolution2:
+ :audio:
+ - - :input
+ -
+ - - :bufnum
+ -
+ - - :trigger
+ -
+ - - :framesize
+ - 512
+Convolution:
+ :audio:
+ - - :input
+ -
+ - - :kernel
+ -
+ - - :framesize
+ - 512
+Crackle:
+ :control:
+ - - :chaosParam
+ - 1.5
+ :audio:
+ - - :chaosParam
+ - 1.5
+CuspL:
+ :audio:
+ - - :freq
+ - 22050
+ - - :a
+ - 1
+ - - :b
+ - 1.9
+ - - :xi
+ - 0
+CuspN:
+ :audio:
+ - - :freq
+ - 22050
+ - - :a
+ - 1
+ - - :b
+ - 1.9
+ - - :xi
+ - 0
+DC:
+ :control:
+ - - :input
+ -
+ :audio:
+ - - :input
+ -
+Dbrown:
+ :demand:
+ - - :lo
+ -
+ - - :hi
+ -
+ - - :step
+ -
+ - - :length
+ - 0
+Decay2:
+ :control:
+ - - :input
+ - 0
+ - - :attackTime
+ - 0.01
+ - - :decayTime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :attackTime
+ - 0.01
+ - - :decayTime
+ - 1
+Decay:
+ :control:
+ - - :input
+ - 0
+ - - :decayTime
+ - 1
+ :audio:
+ - - :input
+ - 0
+ - - :decayTime
+ - 1
+DecodeB2:
+ :control:
+ - - :w
+ -
+ - - :x
+ -
+ - - :y
+ -
+ - - :orientation
+ - 0.5
+ :audio:
+ - - :w
+ -
+ - - :x
+ -
+ - - :y
+ -
+ - - :orientation
+ - 0.5
+DegreeToKey:
+ :control:
+ - - :bufnum
+ -
+ - - :input
+ - 0
+ - - :octave
+ - 12
+ :audio:
+ - - :bufnum
+ -
+ - - :input
+ - 0
+ - - :octave
+ - 12
+Delay1:
+ :control:
+ - - :input
+ - 0
+ :audio:
+ - - :input
+ - 0
+Delay2:
+ :control:
+ - - :input
+ - 0
+ :audio:
+ - - :input
+ - 0
+DelayC:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+DelayL:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+DelayN:
+ :control:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+ :audio:
+ - - :input
+ - 0
+ - - :maxdelaytime
+ - 0.2
+ - - :delaytime
+ - 0.2
+Demand:
+ :control:
+ - - :trig
+ -
+ - - :reset
+ -
+ - - :demandUgens
+ -
+ :audio:
+ - - :trig
+ -
+ - - :reset
+ -
+ - - :demandUgens
+ -
+DemandEnvGen:
+ :control:
+ - - :level
+ -
+ - - :dur
+ -
+ - - :shape
+ - 1
+ - - :curve
+ - 0
+ - - :gate
+ - 1
+ - - :reset
+ - 1
+ - - :levelScale
+ - 1
+ - - :levelBias
+ - 0
+ - - :timeScale
+ - 1
+ - - :doneAction
+ - 0
+ :audio:
+ - - :level
+ -
+ - - :dur
+ -
+ - - :shape
+ - 1
+ - - :curve
+ - 0
+ - - :gate
+ - 1
+ - - :reset
+ - 1
+ - - :levelScale
+ - 1
+ - - :levelBias
+ - 0
+ - - :timeScale
+ - 1
+ - - :doneAction
+ - 0
+DetectSilence:
+ :control:
+ - - :input
+ - 0
+ - - :amp
+ - 0.0001
+ - - :time
+ - 0.1
+ - - :doneAction
+ - 0
+ :audio:
+ - - :input
+ - 0
+ - - :amp
+ - 0.0001
+ - - :time
+ - 0.1
+ - - :doneAction
+ - 0
+Dgeom:
+ :demand:
+ - - :start
+ - 1
+ - - :grow
+ - 2
+ - - :length
+ - 100
+Dibrown:
+ :demand:
+ - - :lo
+ -
+ - - :hi
+ -
+ - - :step
+ -
+ - - :length
+ - 0
+DiskIn:
+ :audio:
+ - - :bufnum
+ -
+DiskOut:
+ :audio:
+ - - :bufnum
+ -
+ - - :channelsArray
+ -
+Diwhite:
+ :demand:
+ - - :lo
+ -
+ - - :hi
+ -
+ - - :length
+ - 0
+Done:
+ :control:
+ - - :src
+ -
+Drand:
+ :demand:
+ - - :repeats
+ - 1
+ - - :list
+ -
+Dseq:
+ :demand:
+ - - :repeats
+ - 1
+ - - :list
+ -
+Dser:
+ :demand:
+ - - :repeats
+ - 1
+ - - :list
+ -
+Dseries:
+ :demand:
+ - - :start
+ - 1
+ - - :step
+ - 1
+ - - :length
+ - 100
+Dswitch1:
+ :demand:
+ - - :index
+ -
+ - - :list
+ -
+Dust2:
+ :control:
+ - - :density
+ - 0
+ :audio:
+ - - :density
+ - 0
+Dust:
+ :control:
+ - - :density
+ - 0
+ :audio:
+ - - :density
+ - 0
+Duty: