Permalink
Browse files

implemented Bus without server callbacks

  • Loading branch information...
1 parent f383bc0 commit 448fa7e0f69308fb5322a03712a790f5c86ef058 @maca maca committed Jul 22, 2009
View
2 bin/livecode.rb
@@ -6,3 +6,5 @@
require "#{ live_session_dir }/session"
Live::Session.new
+
+
View
7 lib/live/session.rb
@@ -20,7 +20,10 @@ def resilient_eval *args
def p obj #:nodoc:
puts obj.to_live_output
end
-
+
+ def warn string
+ p Live::Warning.new "warning: #{ string }"
+ end
end
class Object
@@ -43,7 +46,7 @@ def to_live_output
when Array
"[#{ self.collect{ |i| i.to_live_output}.join(', ') }]"
when Hash
- "{#{ self.collect{ |i| i.collect{|e| e.to_live_output}.join(' => ') } }}"
+ "{#{ self.collect{ |i| i.collect{|e| e.to_live_output}.join(' => ') }.join(', ') }}"
else
"\e[36m#{self}\e[0m"
end
View
7 lib/scruby.rb
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
+require 'date'
require 'rubygems'
require 'arguments'
require 'rosc'
@@ -55,15 +56,11 @@ module Scruby
require "scruby/audio/node"
require "scruby/audio/synth"
-
+require "scruby/audio/bus"
require "scruby/audio/buffer"
include Scruby
include Audio
include Ugens
-
-
-
-
View
77 lib/scruby/audio/buffer.rb
@@ -1,19 +1,16 @@
module Scruby
+ def expand_path path
+ path = "~/Scruby/#{ path }" unless path.match %r{^(?:/|~)}
+ File.expand_path path
+ end
+
class Buffer
-
-
- # read
- # readChannel
# readNoUpdate
- # cueSoundFile
# loadCollection
# sendCollection
# streamCollection
# loadToFloatArray
# getToFloatArray
- # write
- # writeMsg
- # zero
# set
# setn
# get
@@ -25,7 +22,6 @@ class Buffer
# ...
# copy
# copyData
- # close
# query
# updateInfo
# queryDone
@@ -37,13 +33,51 @@ class Buffer
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.allocate :buffers, self
@server.send '/b_alloc', buffnum, frames, channels, message.value(self)
self
end
@@ -52,6 +86,7 @@ def buffnum
@server.buffers.index self
end
alias :as_ugen_input :buffnum
+ alias :index :buffnum
# alias :as_control_input :buffnum
def free &message
@@ -62,19 +97,19 @@ def free &message
# :nodoc:
def allocate_and_read path, start, frames, &message
- @server.allocate_buffers self
+ @server.allocate :buffers, self
message ||= ["/b_query", buffnum]
- @server.send "/b_allocRead", buffnum, @path = path, start, frames, message.value(self)
+ @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
+ @server.allocate :buffers, self
message ||= ["/b_query", buffnum]
- @server.send *(["/b_allocReadChannel", buffnum, path, start, frames] + channels << message.value(self))
+ @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
@@ -83,31 +118,29 @@ def allocate server, frames = -1, channels = 1, &message
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, path, start, buff_size, 0, true, message.value(buffer)]
+ ['/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 path, start, frames
+ 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 path, start, frames, 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
+ server.allocate :buffers, buffers
message ||= 0
buffers.each do |buff|
server.send '/b_alloc', buff.buffnum, frames, channels, message.value(buff)
end
end
-
- # def send_collection server, collection, channels = 1, wait = 0.0, &message
- # end
+
named_arguments_for :allocate, :read, :cue_sound_file, :alloc_consecutive, :read_channel
# readNoUpdate
View
67 lib/scruby/audio/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
20 lib/scruby/audio/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
101 lib/scruby/audio/node.rb
@@ -1,21 +1,106 @@
module Scruby
class Node
@@base_id = 2000
- attr_reader :name, :servers
+ attr_reader :servers, :group, :id
+ alias :node_id :id
+
+ ACTIONS = [:head, :tail, :before, :after, :replace]
- def initialize name, *servers
- servers.peel!
- servers.compact!
- @name = name.to_s
- @servers = servers.empty? ? Server.all : TypedArray.new( Server, servers )
+ 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 id
- @id ||= ( @@base_id = @@base_id + 1 )
+ 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
81 lib/scruby/audio/server.rb
@@ -15,6 +15,8 @@ def initialize command, *args
1
when false
0
+ when Symbol
+ arg.to_s
else
arg
end
@@ -44,21 +46,41 @@ def send_message message, host, port
$UDP_Sender = UDPSender.instance
class Server
- attr_reader :host, :port, :path, :buffers
-
+ 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
- def initialize host = 'localhost', port = 57111, path = '/Applications/SuperCollider/scsynth'
- @host = host
- @port = port
- @path = path
- @buffers = []
+ # 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
- named_arguments_for :initialize
# 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')
@@ -80,8 +102,8 @@ def boot
end
end
end
- sleep 0.1 until ready or !@thread.alive?
- sleep 0.5 # just to be shure
+ sleep 0.01 until ready or !@thread.alive?
+ sleep 0.01 # just to be shure
send "/g_new", 1
self
end
@@ -98,6 +120,7 @@ def stop
# Sends the /quit OSC signal to the scsynth
def quit
+ Server.all.delete self
send '/quit'
end
@@ -113,26 +136,30 @@ def send message, *args
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
-
- # This method should not be directly called, it will add passed +buffers+ to the @buffers array, the +Buffer#buffnum+
- # will be it's index in this array. Max number of buffers is 1024.
- # It will try to fill first consecutive nil indices of the array and if there are not enough consecutive nil indices for the +buffers+
- # passed and the maximum number is not reached it will push the buffers to the array, otherwise will raise an error.
- def allocate_buffers *buffers
- buffers.peel!
- if @buffers.compact.size + buffers.size > 1024
- raise SCError, 'No more buffer numbers -- free some buffers before allocating more.'
+
+ # 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 @buffers += buffers unless @buffers.index nil # just concat arrays if no nil item in @buffers
+ return collection.concat elements unless collection.index nil # just concat arrays if no nil item
indices = []
- @buffers.each_with_index do |item, index| # find n number of consecutive nil indices
- break if indices.size >= buffers.size
+ 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
@@ -141,12 +168,12 @@ def allocate_buffers *buffers
end
case
- when indices.size >= buffers.size
- @buffers[indices.first, buffers.size] = buffers
- when @buffers.size + buffers.size <= 1024
- @buffers += buffers
+ 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 #{ buffers.size } consecutive buffer slots is available."
+ raise SCError, "No block of #{ elements.size } consecutive #{ kind } indices is available."
end
end
View
67 lib/scruby/audio/synth.rb
@@ -1,20 +1,61 @@
-module Scruby
- class Synth < Node
- def initialize name, opts = {}
- raise ArgumentError, 'Second argument must be a Hash' unless opts.kind_of? Hash
- super name, opts.delete(:servers)
- @servers.each{ |s| s.send 9, @name, self.id, 0, 1, *opts.to_a.flatten } #Node?
- end
- def set args = {}
- @servers.each{ |s| s.send 15, self.id, *args.to_a.flatten }
- self
+
+module Scruby
+
+
+ class Synth < Node
+ attr_reader :name
+
+ def initialize name, servers
+ super servers
+ @name = name.to_s
end
- def free
- @servers.each{ |s| s.send 9, self.id }
- self
+ 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
View
19 lib/scruby/audio/ugens/env_gen.rb
@@ -1,6 +1,24 @@
module Scruby
module Audio
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
@@ -13,7 +31,6 @@ def kr envelope, gate = 1, levelScale = 1, levelBias = 0, timeScale = 1, doneAct
end
named_arguments_for :ar, :kr
-
private
def new *args; super; end
end
View
11 lib/scruby/audio/ugens/in_out.rb
@@ -15,10 +15,14 @@ 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, num_channels = 1
+ 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
@@ -47,6 +51,11 @@ def kr bus, *inputs
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
View
37 lib/scruby/audio/ugens/ugen.rb
@@ -61,10 +61,10 @@ class Ugen
@@synthdef = nil
def initialize rate, *inputs
- @rate, @inputs = rate, inputs.compact
+ @rate, @inputs = rate, inputs.compact
@special_index ||= 0
- @output_index ||= 0
- @channels ||= [1]
+ @output_index ||= 0
+ @channels ||= [1]
@index = add_to_synthdef || 0
end
@@ -110,12 +110,10 @@ def new rate, *inputs
raise ArgumentError.new( "#{rate} not a defined rate") unless RATES.include?( rate.to_sym )
inputs.peel!
- inputs.collect! do |input|
- input = input.as_ugen_input if input.respond_to?(:as_ugen_input)
+ inputs.each_with_index do |input, index|
+ inputs[index] = input = input.as_ugen_input if input.respond_to?(:as_ugen_input)
raise ArgumentError.new( "#{ input.inspect } is not a valid ugen input") unless valid_input? input
- input
end
-
size = inputs.select{ |a| a.kind_of? Array }.map{ |a| a.size }.max || 1 #get the size of the largest array element if present
inputs.flatten! if size == 1 #if there is one or more arrays with just one element flatten the input array
@@ -125,15 +123,8 @@ def new rate, *inputs
inputs.map{ |new_inputs| new rate, *new_inputs }
end
- #:nodoc:
- def instantiate *args
- obj = allocate
- obj.__send__ :initialize, *args
- obj
- end
-
- #:nodoc:
- def synthdef
+
+ def synthdef #:nodoc:
@@synthdef
end
@@ -142,13 +133,23 @@ def synthdef= synthdef #:nodoc:
end
def valid_input? obj
- not [Ugen, ControlName, Env, UgenOperations, Buffer].collect do |m|
+ not [Ugen, ControlName, Env, UgenOperations].collect do |m|
true if obj.kind_of? m
end.compact.empty?
end
+
+ def params
+ {}
+ end
+
+ private
+ def instantiate *args
+ obj = allocate
+ obj.__send__ :initialize, *args
+ obj
+ end
end
end
end
end
-
end
View
29 lib/scruby/audio/ugens/ugen_defs.yaml
@@ -927,33 +927,6 @@ Dxrand:
- 1
- - :list
-
-# EnvGen:
-# :control:
-# - - :envelope
-# -
-# - - :gate
-# - 1
-# - - :levelScale
-# - 1
-# - - :levelBias
-# - 0
-# - - :timeScale
-# - 1
-# - - :doneAction
-# - 0
-# :audio:
-# - - :envelope
-# -
-# - - :gate
-# - 1
-# - - :levelScale
-# - 1
-# - - :levelBias
-# - 0
-# - - :timeScale
-# - 1
-# - - :doneAction
-# - 0
ExpRand:
:scalar:
- - :lo
@@ -2516,9 +2489,7 @@ Phasor:
- 0
PinkNoise:
:control: []
-
:audio: []
-
Pitch:
:control:
- - :input
View
13 lib/scruby/audio/ugens/ugens.rb
@@ -42,9 +42,9 @@ module Ugens
def self.define_ugen name, rates
rate_name = {:audio => :ar, :control => :kr, :scalar => :ir, :demand => :new}
rates.delete_if{ |key, value| key == :demand } #I don't know what to do with these
-
+
methods = rates.collect do |rate, args|
- args += [[:mul, 1], [:add, 0]]
+ args.push [:mul, 1], [:add, 0]
args.uniq!
assigns = []
args.each_with_index do |arg, index|
@@ -55,18 +55,23 @@ def self.define_ugen name, rates
}
end
- args = [":#{rate}"] + args[0...-2].collect{ |a| a.first }
+ args = [":#{ rate }"] + args[0...-2].collect{ |a| a.first }
<<-RUBY_EVAL
def #{ rate_name[rate] } *args
opts = args.last.kind_of?( Hash ) ? args.pop : {}
#{ assigns.join("\n") }
new( #{ args.join(', ') } ).muladd( mul, add )
end
+
+ def params
+ @params
+ end
RUBY_EVAL
end.join("\n")
self.class_eval <<-RUBY_EVAL
class #{ name } < Ugen
+ @params = #{ rates.inspect }
class << self
#{ methods }
end
@@ -75,6 +80,8 @@ class << self
# # TODO: Load from ~/Ugens directory
end
+
+
YAML::load( File.open( File.dirname(__FILE__) + "/ugen_defs.yaml" ) ).each_pair do |key, value|
self.define_ugen key, value
end
View
120 spec/audio/buffer_spec.rb
@@ -1,33 +1,25 @@
require File.join( File.expand_path(File.dirname(__FILE__)), '..',"helper")
+require 'date'
require 'arguments'
require 'tempfile'
require 'osc'
require "scruby/audio/buffer"
+require "scruby/audio/bus"
require "scruby/audio/server"
+require File.join( File.expand_path(File.dirname(__FILE__)), "server")
include Scruby
include Audio
-class Scruby::Audio::Server
- attr_reader :output
- def puts string
- @output ||= ""
- @output << string
- string
- end
-end
describe Buffer do
describe "messaging" do
before :all do
@server = Server.new
@server.boot
- 2.times do # ???
- @server.send "/status"
- sleep 0.2
- @server.send "/dumpOSC", 3
- end
+ @server.send "/dumpOSC", 3
+ sleep 0.05
end
after :all do
@@ -37,13 +29,12 @@ def puts string
describe 'Buffer.read' do
before do
@buffer = Buffer.read @server, "sounds/a11wlk01-44_1.aiff"
- sleep 0.1
+ sleep 0.005
end
it "should instantiate and send /b_allocRead message" do
@buffer.should be_a(Buffer)
- @server.output.should =~ %r{\[ "/b_allocRead", #{ @buffer.buffnum }, "sounds/a11wlk01-44_1.aiff", 0, -1, DATA\[20\] \]}
- @server.output.should =~ /00 00 00 14 2f 62 5f 71 75 65 72 79 00 00 00 00/
+ @server.output.should =~ %r{\[ "/b_allocRead", #{ @buffer.buffnum }, "/.+/Scruby/sounds/a11wlk01-44_1.aiff", 0, -1, DATA\[20\] \]}
end
it "should allow passing a completion message"
@@ -52,7 +43,7 @@ def puts string
describe 'Buffer.allocate' do
before do
@buffer = Buffer.allocate @server, 44100 * 8.0, 2
- sleep 0.1
+ sleep 0.005
end
it "should call allocate and send /b_alloc message" do
@@ -66,15 +57,14 @@ def puts string
describe 'Buffer.cueSoundFile' do
before do
- @buffer = Buffer.cue_sound_file @server, "sounds/a11wlk01-44_1.aiff", 0, 1
- sleep 0.1
+ @buffer = Buffer.cue_sound_file @server, "/sounds/a11wlk01-44_1.aiff", 0, 1
+ sleep 0.005
end
it "should send /b_alloc message and instantiate" do
@buffer.should be_a(Buffer)
@server.output.should =~ %r{\[ "/b_alloc", #{ @buffer.buffnum }, 32768, 1, DATA\[72\] \]}
- @server.output.should =~ /64 73 2f 61 31 31 77 6c 6b 30 31 2d 34 34 5f 31/
- @server.output.should =~ /2e 61 69 66 66 00 00 00 00 00 00 00 00 00 80 00/
+ @server.output.should =~ /6e 64 73 2f 61 31 31 77 6c 6b 30 31 2d 34 34 5f/
end
it "should allow passing a completion message"
@@ -86,7 +76,7 @@ def puts string
@buffer2 = Buffer.allocate @server, 44100 * 10.0, 2
@bnum = @buffer2.buffnum
@buffer2.free
- sleep 0.1
+ sleep 0.005
end
it "should remove itself from the server @buffers array and send free message" do
@@ -101,7 +91,7 @@ def puts string
describe 'Buffer.alloc_consecutive' do
before do
@buffers = Buffer.alloc_consecutive 8, @server, 4096, 2
- sleep 0.1
+ sleep 0.005
end
it "should send alloc message for each Buffer and instantiate" do
@@ -117,14 +107,92 @@ def puts string
describe 'Buffer.read_channel' do
before do
@buffer = Buffer.read_channel @server, "sounds/SinedPink.aiff", :channels => [0]
- sleep 0.1
+ sleep 0.005
end
it "should allocate and send /b_allocReadChannel message" do
@buffer.should be_a(Buffer)
- @server.output.should =~ %r{\[ "/b_allocReadChannel", #{ @buffer.buffnum }, "sounds/SinedPink.aiff", 0, -1, 0, DATA\[20\] \]}
- @server.output.should =~ /73 6f 75 6e 64 73 2f 53 69 6e 65 64 50 69 6e 6b/
+ @server.output.should =~ %r{\[ "/b_allocReadChannel", #{ @buffer.buffnum }, "/.+/Scruby/sounds/SinedPink.aiff", 0, -1, 0, DATA\[20\] \]}
end
end
+
+ describe '#read' do
+ before do
+ @buffer = Buffer.allocate( @server, 44100 * 10.0, 2 ).read( "sounds/robot.aiff" )
+ sleep 0.005
+ end
+
+ it "should send message" do
+ @buffer.should be_a(Buffer)
+ @server.output.should =~ %r{\[ "/b_read", #{ @buffer.buffnum }, "/.+/Scruby/sounds/robot.aiff", 0, -1, 0, 0, DATA\[20\] \]}
+ end
+
+ it "should allow passing a completion message"
+ end
+
+ describe '#close' do
+ before do
+ @buffer = Buffer.read( @server, "sounds/a11wlk01-44_1.aiff" ).close
+ sleep 0.005
+ end
+
+ it "should send message" do
+ @buffer.should be_a(Buffer)
+ @server.output.should =~ %r{\[ "/b_close", #{ @buffer.buffnum }, 0 \]}
+ end
+
+ it "should allow passing a completion message"
+ end
+
+ describe '#zero' do
+ before do
+ @buffer = Buffer.read( @server, "sounds/a11wlk01-44_1.aiff" ).zero
+ sleep 0.005
+ end
+
+ it "should send message" do
+ @buffer.should be_a(Buffer)
+ @server.output.should =~ %r{\[ "/b_zero", #{ @buffer.buffnum }, 0 \]}
+ end
+
+ it "should allow passing a completion message"
+ end
+
+ describe '#cue_sound_file' do
+ before do
+ @buffer = Buffer.allocate( @server, 44100, 2 ).cue_sound_file( "sounds/robot.aiff" )
+ sleep 0.005
+ end
+
+ it "should send message" do
+ @buffer.should be_a(Buffer)
+ @server.output.should =~ %r{\[ "/b_read", #{ @buffer.buffnum }, "/.+/Scruby/sounds/robot.aiff", 0, 44100, 0, 1, 0 \]}
+ end
+
+ it "should allow passing a completion message"
+ end
+
+ describe '#write' do
+ before do
+ @buffer = Buffer.allocate( @server, 44100 * 10.0, 2 ).write(
+ "sounds/test.aiff", "aiff", "int16", 0, 0, true
+ );
+ sleep 0.005
+ end
+
+ it "should send message" do
+ @buffer.should be_a(Buffer)
+ @server.output.should =~ %r{\[ "/b_write", #{ @buffer.buffnum }, "/.+/Scruby/sounds/test.aiff", "aiff", "int16", 0, 0, 1, 0 \]}
+ end
+
+ it "should have a default path" do
+ @server.flush
+ buffer = Buffer.allocate( @server, 44100 * 10.0, 2 ).write( nil, "aiff", "int16", 0, 0, true );
+ sleep 0.005
+ @server.output.should =~ %r{\[ "/b_write", #{ buffer.buffnum }, "/.+/Scruby/\d\d\d\d.+\.aiff", "aiff", "int16", 0, 0, 1, 0 \]}
+ end
+
+ it "should allow passing a completion message"
+ end
end
end
View
186 spec/audio/bus_spec.rb
@@ -0,0 +1,186 @@
+require File.join( File.expand_path(File.dirname(__FILE__)), '..',"helper")
+
+require 'tempfile'
+require 'osc'
+require "scruby/core_ext/numeric"
+require "scruby/audio/bus"
+require "scruby/audio/server"
+require File.join( File.expand_path(File.dirname(__FILE__)), "server")
+
+include Scruby
+include Audio
+
+
+
+describe Bus do
+ describe 'instantiation' do
+ before do
+ @server = Server.new
+ @audio = Bus.audio @server
+ @control = Bus.control @server
+ end
+
+ it "should be a bus" do
+ @audio.should be_a(Bus)
+ @control.should be_a(Bus)
+ end
+
+ it "should not instantiate with new" do
+ lambda { Bus.new @server, :control, 1 }.should raise_error(NoMethodError)
+ end
+
+ it "should set server" do
+ @audio.server.should == @server
+ end
+
+ it "should set audio rate" do
+ @audio.rate.should == :audio
+ end
+
+ it "should set control rate" do
+ Bus.control(@server).rate.should == :control
+ end
+
+ it "should allocate in server on instantiation and have index" do
+ @server.audio_buses.should include(@audio)
+ @server.control_buses.should include(@control)
+ end
+
+ it "should have index" do
+ @audio.index.should == 16
+ @control.index.should == 0
+ end
+
+ it "should free and null index" do
+ @audio.free
+ @server.audio_buses.should_not include(@audio)
+ @audio.index.should == nil
+ @control.free
+ @server.audio_buses.should_not include(@control)
+ @control.index.should == nil
+ end
+
+ it "should return as map if control" do
+ @control.to_map.should == "c0"
+ end
+
+ it "should raise error if calling to_map on an audio bus" do
+ lambda { @audio.to_map }.should raise_error(SCError)
+ end
+
+ it "should print usefull information with to_s"
+
+ it "should be hardware out" do
+ @server.audio_buses[0].should be_audio_out
+ @audio.should_not be_audio_out
+ end
+
+ describe 'multichannel' do
+ before do
+ @server = Server.new
+ @audio = Bus.audio @server, 4
+ @control = Bus.control @server, 4
+ end
+
+ it "should allocate consecutive when passing more than one channel for audio" do
+ @audio.index.should == 16
+ buses = @server.audio_buses
+ buses[16..-1].should have(4).elements
+ Bus.audio(@server).index.should == 20
+ end
+
+ it "should allocate consecutive when passing more than one channel for control" do
+ @control.index.should == 0
+ @server.control_buses.should have(4).elements
+ Bus.control(@server).index.should == 4
+ end
+
+ it "should set the number of channels" do
+ @audio.channels.should == 4
+ @control.channels.should == 4
+ end
+
+ it "should depend on a main bus" do
+ @server.audio_buses[16].main_bus.should == @audio #main bus
+ @server.audio_buses[17].main_bus.should == @audio #main bus
+ @server.control_buses[0].main_bus.should == @control #main bus
+ @server.control_buses[1].main_bus.should == @control #main bus
+ end
+ end
+ end
+
+ describe "messaging" do
+ before :all do
+ @server = Server.new
+ @server.boot
+ @server.send "/dumpOSC", 3
+ @bus = Bus.control @server, 4
+ sleep 0.05
+ end
+
+ after :all do
+ @server.quit
+ end
+
+ before do
+ @server.flush
+ end
+
+ describe 'set' do
+ it "should send set message with one value" do
+ @bus.set 101
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_set", #{ @bus.index }, 101 \]}
+ end
+
+ it "should accept value list and send set with them" do
+ @bus.set 101, 202
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_set", #{ @bus.index }, 101, #{ @bus.index + 1}, 202 \]}
+ end
+
+ it "should accept an array and send set with them" do
+ @bus.set [101, 202]
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_set", #{ @bus.index }, 101, #{ @bus.index + 1}, 202 \]}
+ end
+
+ it "should warn but not set if trying to set more values than channels" do
+ @bus.should_receive(:warn).with("You tried to set 5 values for bus #{ @bus.index } that only has 4 channels, extra values are ignored.")
+ @bus.set 101, 202, 303, 404, 505
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_set", #{ @bus.index }, 101, #{ @bus.index + 1}, 202, #{ @bus.index + 2}, 303, #{ @bus.index + 3}, 404 \]}
+ end
+ end
+
+ describe 'set' do
+ it "should send fill just one channel" do
+ @bus.fill 101, 1
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_fill", #{ @bus.index }, 1, 101 \]}
+ end
+
+ it "should fill all channels" do
+ @bus.fill 101
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_fill", #{ @bus.index }, 4, 101 \]}
+ end
+
+ it "should raise error if trying to fill more than assigned channels" do
+ @bus.should_receive(:warn).with("You tried to set 5 values for bus #{ @bus.index } that only has 4 channels, extra values are ignored.")
+ @bus.fill 101, 5
+ sleep 0.01
+ @server.output.should =~ %r{\[ "/c_fill", #{ @bus.index }, 4, 101 \]}
+ end
+ end
+
+ describe 'get' do
+ it "should send get message with one value"
+ it "should send get message for various channels"
+ it "should accept an array and send set with them"
+ it "should raise error if trying to set more values than channels"
+ it "should actually get the response from the server"
+ end
+
+ end
+end
View
72 spec/audio/group_spec.rb
@@ -0,0 +1,72 @@
+require File.join( File.expand_path(File.dirname(__FILE__)), '..',"helper")
+
+
+require "scruby/core_ext/typed_array"
+require "scruby/audio/node"
+require "scruby/audio/group"
+require 'scruby/audio/bus'
+require 'osc'
+require 'scruby/audio/server'
+require File.join( File.expand_path(File.dirname(__FILE__)), "server")
+
+
+include Scruby
+include Audio
+class Bus; end # mock
+
+describe Group do
+ before :all do
+ end
+
+ before do
+ Node.reset!
+ Server.stub!(:all).and_return([@server])
+ end
+
+ describe 'Server interaction' do
+ before :all do
+ @server = Server.new
+ @server.boot
+ @server.send "/dumpOSC", 3
+ sleep 0.05
+ end
+
+ after :all do
+ @server.quit
+ end
+
+ before do
+ @server.flush
+ @group = Group.new @server
+ @node = Node.new @server
+ end
+
+ describe 'position' do
+ end
+
+ it "should send free all message" do
+ @group.free_all.should be_a(Group)
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/g_freeAll", #{ @group.id } \]}
+ end
+
+ it "should send deepFree message" do
+ @group.deep_free.should be_a(Group)
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/g_deepFree", #{ @group.id } \]}
+ end
+
+ it "should send dump tree message" do
+ @group.dump_tree.should be_a(Group)
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/g_dumpTree", #{ @group.id }, 0 \]}
+ @group.dump_tree true
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/g_dumpTree", #{ @group.id }, 1 \]}
+ end
+
+ it "should send dump tree message with arg"
+ it "should query_tree"
+ end
+
+end
View
82 spec/audio/node_spec.rb
@@ -1,12 +1,16 @@
require File.join( File.expand_path(File.dirname(__FILE__)), '..',"helper")
+
require "scruby/core_ext/typed_array"
require "scruby/audio/node"
+require "scruby/audio/bus"
require 'osc'
require 'scruby/audio/server'
+require File.join( File.expand_path(File.dirname(__FILE__)), "server")
+
-class Server; end
include Scruby
+include Audio
describe Node do
before :all do
@@ -20,38 +24,86 @@ class Server; end
it "should have incremental uniq id" do
10.times do |i|
- Node.new( 'nodo' ).id.should == 2001 + i
+ Node.new.id.should == 2001 + i
end
end
it "should reset" do
- Node.new( 'nodo' ).id.should == 2001
+ Node.new.id.should == 2001
end
describe 'instantiation' do
-
- it "should have a name" do
- Node.new('nodo').name.should == 'nodo'
- end
-
+
it "should not accept non servers" do
- lambda{ Node.new('nodo', 1,2) }.should raise_error(TypeError)
- lambda{ Node.new('nodo', [1,2]) }.should raise_error(TypeError)
+ lambda{ Node.new(1,2) }.should raise_error(TypeError)
+ lambda{ Node.new([1,2]) }.should raise_error(TypeError)
end
it "should accept a server and have a TypedArray of Servers" do
- @server.should_receive(:instance_of?).exactly(:twice).and_return(true)
- n = Node.new( 'nodo', @server )
- n.servers.should == [@server]
- n = Node.new( 'nodo', [@server] )
+ @server.should_receive(:instance_of?).exactly(:once).and_return(true)
+ n = Node.new @server
n.servers.should == [@server]
end
it "should have default servers if no server is passed" do
- n = Node.new( 'nodo' )
+ n = Node.new
n.servers.should == [@server]
end
end
+ describe 'Server interaction' do
+ before :all do
+ @server = Server.new
+ @server.boot
+ @server.send "/dumpOSC", 3
+ sleep 0.05
+ end
+
+ after :all do
+ @server.quit
+ end
+
+ before do
+ @node = Node.new @server
+ end
+
+ it "should send free" do
+ @node.free
+ @node.should_not be_running
+ @node.group.should be_nil
+ @node.should_not be_playing
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/n_free", #{ @node.id } \]}
+ end
+
+ it "should send run" do
+ @node.run
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/n_run", #{ @node.id }, 1 \]}
+ @node.run false
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/n_run", #{ @node.id }, 0 \]}
+ end
+
+ describe 'map' do
+ it "should just accept instances of Bus" do
+ b1 = mock 'Bus', :index => 1, :channels => 1, :rate => :audio
+ b1.should_receive(:kind_of?).and_return(false)
+ lambda { @node.map :freq1 => b1 }.should raise_error(ArgumentError)
+ end
+
+ it "should send map" do
+ b1 = mock 'Bus', :index => 1, :channels => 1, :rate => :control
+ b1.should_receive(:kind_of?).and_return(true)
+ b2 = mock 'Bus', :index => 2, :channels => 2, :rate => :audio
+ b2.should_receive(:kind_of?).and_return(true)
+ @node.map( :freq1 => b1, :freq2 => b2 ).should be_instance_of(Node)
+ sleep 0.05
+ @server.output.should =~ %r{\[ \"#bundle\", 1, \n \[ \"/n_mapn\", #{ @node.id }, \"freq1\", #{ b1.index }, 1 \],\n \[ \"/n_mapan\", #{ @node.id }, \"freq2\", #{ b2.index }, 2 \]\n\]}
+ end
+ end
+
+ end
+
end
View
12 spec/audio/server.rb
@@ -0,0 +1,12 @@
+class Scruby::Audio::Server
+ attr_reader :output
+ def puts string
+ @output ||= ""
+ @output << string
+ string
+ end
+
+ def flush
+ @output = ''
+ end
+end
View
107 spec/audio/server_spec.rb
@@ -6,13 +6,17 @@
require 'scruby/audio/node'
require 'scruby/core_ext/array'
require 'scruby/core_ext/typed_array'
-require 'scruby/audio/buffer'
+require 'scruby/audio/bus'
require "scruby/audio/server"
-
include Scruby
include Audio
+module Mocks
+ class Bus; end
+ class Buffer; end
+end
+
Thread.abort_on_exception = true
class Scruby::Audio::Server
@@ -23,6 +27,7 @@ def puts string
@output << string
string
end
+
end
class Scruby::Audio::Buffer
@@ -58,6 +63,12 @@ def == other
Thread.should_not_receive(:new)
@server.boot
end
+
+ it "should remove server from server list" do
+ @server.boot
+ @server.quit
+ Server.all.should be_empty
+ end
it "should raise scsynth not found error" do
lambda{ @server = Server.new(:path => '/not_scsynth'); @server.boot }.should raise_error(Server::SCError)
@@ -73,11 +84,8 @@ def == other
before :all do
@server = Server.new
@server.boot
- 2.times do # ???
- @server.send "/status"
- sleep 0.2
- @server.send "/dumpOSC", 1
- end
+ @server.send "/dumpOSC", 3
+ sleep 0.05
end
after :all do
@@ -98,48 +106,81 @@ def == other
end
end
- describe 'buffers' do
- before do
- @server = Server.new
- end
-
- it "should allow less than 1024 buffers" do
- @server.allocate_buffers( (1..1024).map{ mock(Buffer) } )
- @server.buffers.size.should == 1024
+ shared_examples_for 'allocator' do
+ it "should allow less than @max_size elements" do
+ @server.__send__( :allocate, @kind, (1..@allowed_elements).map{ @class.new } )
+ @server.__send__(@kind).size.should == @max_size
end
- it "should not allow more than 1024 buffers" do
- lambda { @server.allocate_buffers( (1..1025).map{ Buffer.new } ) }.should raise_error(SCError)
+ it "should not allow more than @max_size elements" do
+ lambda { @server.__send__( :allocate, @kind, (1..@max_size+1).map{ @class.new } ) }.should raise_error(SCError)
end
it "should try to allocate lowest nil slot" do
- @server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
- @server.allocate_buffers buffer = Buffer.new
- @server.buffers.index(buffer).should == 0
+ @server.__send__(@kind).concat([nil, nil, @class.new, nil, nil, nil, @class.new])
+ @server.__send__ :allocate, @kind, buffer = @class.new
+ @server.__send__(@kind).index(buffer).should == @index_start
end
- it "should allocate various buffers in available indices" do
- @server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
- @server.allocate_buffers Buffer.new, Buffer.new, Buffer.new
- @server.buffers.should == [nil, nil, Buffer.new, Buffer.new, Buffer.new, Buffer.new, Buffer.new]
+ it "should allocate various elements in available contiguous indices" do
+ @server.__send__(@kind).concat([nil, nil, @class.new, nil, nil, nil, @class.new])
+ @server.__send__ :allocate, @kind, @class.new, @class.new, @class.new
+ elements = @server.__send__(@kind)[@max_size-@allowed_elements..-1].compact
+ elements.should have(5).elements
end
- it "should allocate by appending various buffers" do
- @server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
- @server.allocate_buffers Buffer.new, Buffer.new, Buffer.new, Buffer.new
- @server.buffers.should == [nil, nil, Buffer.new, nil, nil, nil, Buffer.new, Buffer.new, Buffer.new, Buffer.new, Buffer.new]
+ it "should allocate by appending various elements" do
+ @server.__send__(@kind).concat([nil, nil, @class.new, nil, nil, nil, @class.new])
+ @server.__send__ :allocate, @kind, @class.new, @class.new, @class.new, @class.new
+ elements = @server.__send__(@kind)[@max_size-@allowed_elements..-1].compact
+ elements.should have(6).elements
end
it "should not surpass the max buffer limit" do
- @server.allocate_buffers( (1..1022).map{ |i| Buffer.new if i % 2 == 0 } )
- lambda { @server.allocate_buffers Buffer.new, Buffer.new, Buffer.new }.should raise_error
+ @server.__send__( :allocate, @kind, (1..@allowed_elements-2).map{ |i| @class.new if i % 2 == 0 } )
+ lambda { @server.__send__ :allocate, @kind, @class.new, @class.new, @class.new }.should raise_error
end
it "should allocate by appending" do
- @server.allocate_buffers( (1..1021).map{ |i| Buffer.new if i % 2 == 0 } )
- @server.allocate_buffers Buffer.new, Buffer.new, Buffer.new
- @server.buffers.size.should == 1024
+ @server.__send__( :allocate, @kind, (1..@allowed_elements-3).map{ |i| @class.new if i % 2 == 0 } )
+ @server.__send__ :allocate, @kind, @class.new, @class.new, @class.new
+ @server.__send__(@kind).size.should == @max_size
+ end
+ end
+
+ describe 'buffers allocation' do
+ before do
+ @server = Server.new
+ @kind = :buffers
+ @class = Mocks::Buffer
+ @allowed_elements = @max_size = 1024
+ @index_start = 0
+ end
+ it_should_behave_like 'allocator'
+ end
+
+ describe 'control_buses allocation' do
+ before do
+ @server = Server.new
+ @kind = :control_buses
+ @class = Mocks::Bus
+ @allowed_elements = @max_size = 4096
+ @index_start = 0
end
+ it_should_behave_like 'allocator'
end
+
+ describe 'audio_buses allocation' do
+ before do
+ @server = Server.new
+ @kind = :audio_buses
+ @class = Mocks::Bus
+ @allowed_elements = 112
+ @max_size = 128
+ @index_start = 16
+ end
+ it_should_behave_like 'allocator'
+ end
+
end
View
63 spec/audio/synth_spec.rb
@@ -1,51 +1,66 @@
require File.join( File.expand_path(File.dirname(__FILE__)), '..',"helper")
+require 'osc'
require "scruby/core_ext/typed_array"
require "scruby/audio/node"
+require "scruby/audio/group"
require "scruby/audio/synth"
+require "scruby/audio/server"
+require File.join( File.expand_path(File.dirname(__FILE__)), "server")
+
include Scruby
+include Audio
describe Synth do
before :all do
- ::Server = mock('Server')
end
before do
Node.reset!
- @servers = (0..3).map{ s = mock( 'server'); s.stub!(:send); s }
- @synth = Synth.new :synth, :attack => 10, :servers => @servers
+ @target = Node.new( (0..3).map{ Server.new } )
+ @synth = Synth.new :synth, {:attack => 10}, @target
end
it "should initialize" do
- s = Synth.new 'synth', :attack => 10, :servers => @servers
- s.name.should == 'synth'
- s.servers.should == @servers
- end
-
- it do
- lambda { Synth.new 'synth', :hola }.should raise_error(ArgumentError)
+ @synth.name.should == 'synth'
+ @synth.servers.should == @target.servers
end
-
+
it "should initialize not passing servers and have default servers" do
- Server.should_receive(:all).and_return(@servers)
s = Synth.new( 'synth' )
- s.servers.should == @servers
+ s.servers.should == Server.all
end
- it "should send /s_new message" do
- servers = (0..3).map{ s = mock( 'server') }
- servers.each{ |s| s.should_receive(:send).with( 9, 'synth', 2002, 0, 1, :attack, 10 ) }
- s = Synth.new( :synth, :attack => 10, :servers => servers )
- end
+ describe 'Server interaction' do
+ before :all do
+ Server.clear
+ @server = Server.new
+ @server.boot
+ @server.send "/dumpOSC", 3
+ sleep 0.05
+ end
+
+ after :all do
+ @server.quit
+ end
+
+ before do
+ @server.flush
+ @synth = Synth.new :synth, :attack => 10
+ end
+
+ it "should send /s_new message" do
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/s_new", "#{ @synth.name }", #{ @synth.id }, 0, 1, "attack", 10 \]}
+ end
- it "should send set message and return self" do
- s = mock('server')
- s.should_receive(:send).with( 15, 2002, :attack, 20 )
- s.should_receive(:send).with( 9, "synth", 2002, 0, 1 )
- synth = Synth.new( :synth, :servers => s)
- synth.set( :attack => 20 ).should == synth
+ it "should send set message and return self" do
+ @synth.set( :attack => 20 ).should == @synth
+ sleep 0.05
+ @server.output.should =~ %r{\[ "/n_set", #{ @synth.id }, "attack", 20 \]}
+ end
end
end
View
1 spec/audio/ugen_spec.rb
@@ -47,7 +47,6 @@ def as_ugen_input; 0; end
it "should tell if valid input" do
Ugen.send( :valid_input?, SinOsc.ar ).should be_true
Ugen.send( :valid_input?, Env.asr ).should be_true
- Ugen.send( :valid_input?, Buffer.new ).should be_true
Ugen.send( :valid_input?, 'string' ).should be_false
end
View
5 spec/audio/ugens_spec.rb
@@ -44,6 +44,11 @@ class Klass
Gendy1.stub!(:new)
lambda { Gendy1.ar }.should raise_error(ArgumentError)
end
+
+ it "should print description" do
+ p PanAz.params
+ PanAz.params.should be_a(Hash)
+ end
# it "should work with arrays"
end
View
1 spec/control/timer_spec.rb
@@ -1 +0,0 @@
-require File.join( File.expand_path(File.dirname(__FILE__)), '..', "helper")
View
91 test.live.rb
@@ -1,17 +1,20 @@
load File.expand_path( File.dirname( __FILE__ ) + '/../scruby.rb' )
+s = Server.new('localhost', 57140)
+s.boot
# Lamonte Young - Just in tone afination
# Nan Carrow
+# Stockhausen
44100
-s = Server.new('localhost', 57140)
-s.boot
s.send "/dumpOSC", 0
clear
+warn 'hi'
+
# Síntesis aditiva básica
SynthDef.new :add do
gate = EnvGen.kr( Env.perc(0, 0.2) )
@@ -43,38 +46,84 @@
s.stop
+warn 'hi'
+
+# Construcción de una onda cuadrada
SynthDef.new :simple do |freq, mul, dur|
gate = EnvGen.kr( Env.perc(0, 0.2) )
- env = EnvGen.kr Env.asr(dur * 0.01, dur * 0.2, dur * 0.1), gate, :doneAction => 2
+ env = EnvGen.kr Env.asr(dur * 0.1, dur * 0.2, dur * 0.8), gate, :doneAction => 2
sig = SinOsc.ar(freq) * env * mul
Out.ar 0, [sig, sig]
end.send
-Synth.new :simple, :freq => 200, :amp => 1, :dur => 1
+mults = 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29
+durs = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28
+base = 40
+dur = 1
+amp = 0.2
+
+mults.zip durs do |mult, dur|
+ Synth.new :simple, :freq => mult * base, :mul => amp/mult, :dur => dur
+end
-freqs = 100, 300, 500, 700, 900, 1100, 1300, 1500, 1700, 1900, 2100, 2300, 2500, 2700, 2900
-amps = 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31
-durs = 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28
+# Amplitud modulada
+# Alteración de la amplitud, fase o frecuencia por otra señal
+SynthDef.new :am do |mod_freq, mod_amp, amp, freq, dur|
+ gate = EnvGen.kr( Env.perc(0, 0.2) )
+ mod = SinOsc.kr mod_freq, :mul => mod_amp
+ sig = SinOsc.ar freq, :mul => mod + amp
+ sig = sig * EnvGen.kr( Env.asr(dur * 0.1, dur * 0.2, dur * 0.8), gate, :doneAction => 2 )
+ Out.ar 0, [sig, sig]
+end.send
+
+si = Synth.new :am, :mod_freq => 100, :mod_amp => 1, :amp => 0.5, :dur => 2, :freq => 60
-run = true
-while run
- freqs.zip amps, durs do |arr|
- freq, amp, dur = arr
- Synth.new :simple, :freq => freq * 1.2 * rand, :mul => 1.0/amp * 0.1 * rand, :dur => dur * 1 * rand
- Synth.new :simple, :freq => freq * 0.9 * rand, :mul => 1.0/amp * 0.2 * rand, :dur => dur * 1 * rand
- Synth.new :simple, :freq => freq * 0.6 * rand, :mul => 1.0/amp * 0.3 * rand, :dur => dur * 1 * rand
- end
- sleep 0.2
-end
-run = false
+# Modulación en anillo
+SynthDef.new :ring do |mod_freq, freq, amp, dur|
+ gate = EnvGen.kr Env.perc(0, 0.2)
+ sig = SinOsc.ar freq, :mul => SinOsc.ar(mod_freq, :mul => amp)
+ sig *= EnvGen.kr( Env.asr(dur * 0.1, dur * 0.2, dur * 0.8), gate, :doneAction => 2 )
+ Out.ar 0, [sig, sig]
+end.send
+
+si = Synth.new :ring, :freq => 2000, :amp => 2, :dur => 2, :mod_freq => 4
+
+
+si.to_s
+
+# Sound0.aiff
+# Modulación en anillo con sampleo
+# Modulación en anillo
+buffer = Buffer.read s, "sounds/huge.aiff"
+
+buffer2 = Buffer.read s, 'sounds/a11wlk01-44_1.aiff'
+buffer2.buffnum
-p Node.base_id
+buffer.read 'sounds/a11wlk01-44_1.aiff'
-s.quit
+SynthDef.new :ring do |mod_freq, amp, buffnum|
+ gate = EnvGen.kr Env.perc(0, 0.2)
+ sig = PlayBuf.ar buffnum, :rate => 1, :mul => SinOsc.ar(mod_freq, :mul => amp), :loop => 1.0
+ Out.ar 0, [sig, sig]
+end.send
+
+s1 = Synth.new :ring, :freq => 90, :amp => 2, :dur => 2, :mod_freq => 4, :buffnum => buffer.buffnum
+s2 = Synth.new :ring, :freq => 90, :amp => 2, :dur => 2, :mod_freq => 4, :buffnum => buffer.buffnum
+
+s1.set :mod_freq => 80
+s2.set :mod_freq => 9000
+s1.set :buffnum => buffer2.buffnum
-Buffer.read s, "sounds/robot.aiff"
+s1.free
+s2.free
+# node ids should depend on server
+
+s1
+
+s.stop
+In

0 comments on commit 448fa7e

Please sign in to comment.