maca-Scruby 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.rdoc +26 -0
  2. data/Rakefile +10 -0
  3. data/Scruby.gemspec +36 -0
  4. data/bin/live_session.rb +12 -0
  5. data/changes +1 -0
  6. data/lib/live/session.rb +144 -0
  7. data/lib/scruby.rb +60 -0
  8. data/lib/scruby/audio/control_name.rb +29 -0
  9. data/lib/scruby/audio/env.rb +97 -0
  10. data/lib/scruby/audio/node.rb +20 -0
  11. data/lib/scruby/audio/server.rb +112 -0
  12. data/lib/scruby/audio/synth.rb +15 -0
  13. data/lib/scruby/audio/synthdef.rb +114 -0
  14. data/lib/scruby/audio/ugens/env_gen.rb +18 -0
  15. data/lib/scruby/audio/ugens/in_out.rb +43 -0
  16. data/lib/scruby/audio/ugens/multi_out_ugens.rb +48 -0
  17. data/lib/scruby/audio/ugens/operation_indices.yaml +92 -0
  18. data/lib/scruby/audio/ugens/operation_ugens.rb +64 -0
  19. data/lib/scruby/audio/ugens/ugen.rb +154 -0
  20. data/lib/scruby/audio/ugens/ugen_defs.yaml +3421 -0
  21. data/lib/scruby/audio/ugens/ugen_operations.rb +44 -0
  22. data/lib/scruby/audio/ugens/ugens.rb +34 -0
  23. data/lib/scruby/control/metro.rb +6 -0
  24. data/lib/scruby/extensions.rb +109 -0
  25. data/lib/scruby/typed_array.rb +64 -0
  26. data/spec/audio/env_gen_specs.rb +25 -0
  27. data/spec/audio/in_out_spec.rb +107 -0
  28. data/spec/audio/integration_spec.rb +106 -0
  29. data/spec/audio/lib_spec.rb +14 -0
  30. data/spec/audio/multiout_ugen_spec.rb +112 -0
  31. data/spec/audio/node_spec.rb +60 -0
  32. data/spec/audio/operation_ugens_spec.rb +189 -0
  33. data/spec/audio/server_spec.rb +68 -0
  34. data/spec/audio/synth_spec.rb +46 -0
  35. data/spec/audio/synthdef_spec.rb +275 -0
  36. data/spec/audio/ugen_operations_spec.rb +146 -0
  37. data/spec/audio/ugen_spec.rb +333 -0
  38. data/spec/audio/ugens_spec.rb +61 -0
  39. data/spec/env_spec.rb +64 -0
  40. data/spec/extensions_spec.rb +133 -0
  41. data/spec/helper.rb +11 -0
  42. data/spec/typed_array_spec.rb +95 -0
  43. metadata +129 -0
data/README.rdoc ADDED
@@ -0,0 +1,26 @@
1
+
2
+
3
+
4
+ == LICENSE:
5
+
6
+ Copyright (c) 2008 Macario Ortega
7
+
8
+ This program is free software: you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation, either version 3 of the License, or
11
+ (at your option) any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ == NOTES
22
+
23
+ Ruby has operation precendence
24
+
25
+
26
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('Scruby', '0.0.8') do |p|
6
+ p.description = "Small client for doing sound synthesis from ruby using the SuperCollider synth, usage is quite similar from SuperCollider."
7
+ p.url = 'http://github.com/maca/scruby'
8
+ p.author = "Macario Ortega"
9
+ p.email = "macarui@gmail.com"
10
+ end
data/Scruby.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{Scruby}
5
+ s.version = "0.0.8"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Macario Ortega"]
9
+ s.date = %q{2009-02-05}
10
+ s.default_executable = %q{live_session.rb}
11
+ s.description = %q{Small client for doing sound synthesis from ruby using the SuperCollider synth, usage is quite similar from SuperCollider.}
12
+ s.email = %q{macarui@gmail.com}
13
+ s.executables = ["live_session.rb"]
14
+ s.extra_rdoc_files = ["bin/live_session.rb", "lib/live/session.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/metro.rb", "lib/scruby/extensions.rb", "lib/scruby/typed_array.rb", "lib/scruby.rb", "README.rdoc"]
15
+ s.files = ["bin/live_session.rb", "changes", "lib/live/session.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/metro.rb", "lib/scruby/extensions.rb", "lib/scruby/typed_array.rb", "lib/scruby.rb", "Rakefile", "README.rdoc", "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_spec.rb", "spec/extensions_spec.rb", "spec/helper.rb", "spec/typed_array_spec.rb", "Manifest", "Scruby.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/maca/scruby}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Scruby", "--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{scruby}
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{Small client for doing sound synthesis from ruby using the SuperCollider synth, usage is quite similar from SuperCollider.}
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 2
27
+
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
+ s.add_development_dependency(%q<echoe>, [">= 0"])
30
+ else
31
+ s.add_dependency(%q<echoe>, [">= 0"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<echoe>, [">= 0"])
35
+ end
36
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ live_session_dir = File.join( File.expand_path(File.dirname(__FILE__) ), '..', 'lib', 'live' )
3
+
4
+ require 'tempfile'
5
+ require "#{live_session_dir}/session"
6
+
7
+
8
+ Live::Session.new
9
+
10
+
11
+
12
+
data/changes ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,144 @@
1
+ require 'tempfile'
2
+ require 'rubygems'
3
+ require 'highline'
4
+ require 'parse_tree'
5
+ require 'ruby2ruby'
6
+
7
+ module Kernel
8
+ alias :l :lambda
9
+
10
+ # Calls Kernel#eval with the given args but catches posible errors
11
+ def resilient_eval( *args )
12
+ begin
13
+ begin
14
+ eval( *args )
15
+ rescue SyntaxError => e
16
+ e
17
+ end
18
+ rescue => e
19
+ e
20
+ end
21
+ end
22
+
23
+ def p( obj ) #:nodoc:
24
+ puts obj.to_live_output
25
+ end
26
+
27
+ end
28
+
29
+ class Object
30
+
31
+ # Outputs an ANSI colored string with the object representation
32
+ def to_live_output
33
+ case self
34
+ when Exception
35
+ "\e[41m\e[33m#{self.inspect}\e[0m"
36
+ when Numeric, Symbol, TrueClass, FalseClass, NilClass
37
+ "\e[35m#{self.inspect}\e[0m"
38
+ when Notice
39
+ "\e[42m\e[30m#{self}\e[0m"
40
+ when Warning
41
+ "\e[43m\e[30m#{self}\e[0m"
42
+ when Special
43
+ "\e[44m\e[37m#{self}\e[0m"
44
+ when String
45
+ "\e[32m#{self.inspect}\e[0m"
46
+ when Array
47
+ "[#{ self.collect{ |i| i.to_live_output}.join(', ') }]"
48
+ when Hash
49
+ "{#{ self.collect{ |i| i.collect{|e| e.to_live_output}.join(' => ') } }}"
50
+ else
51
+ "\e[36m#{self}\e[0m"
52
+ end
53
+ end
54
+ end
55
+
56
+ class Notice < String; end
57
+ class Warning < String; end
58
+ class Special < String; end
59
+
60
+ module Live
61
+ class Pipe < Tempfile
62
+ def make_tmpname( *args )
63
+ "ruby_live.pipe"
64
+ end
65
+ end
66
+
67
+ class Session
68
+ include HighLine::SystemExtensions
69
+
70
+ # Starts a live session using a named pipe to receive code from a remote source and evaluates it within a context, a bit like an IRB session but evaluates code sent from a text editor
71
+ def initialize
72
+ return p( Exception.new("Another session sems to be running") ) if File.exist?( "#{Dir.tmpdir}/ruby_live.pipe" )
73
+ p( Notice.new("Live Session") )
74
+ get_binding
75
+ init_pipe
76
+ expect_input
77
+ serve
78
+ end
79
+
80
+ def init_pipe
81
+ @pipe_path = Pipe.new('').path
82
+ `rm #{@pipe_path}; mkfifo #{@pipe_path}`
83
+ end
84
+
85
+ # Starts a loop that checks the named pipe and evaluate its contents, will be called on initialize
86
+ def serve
87
+ File.open( @pipe_path, File::RDONLY | File::NONBLOCK) do |f|
88
+ loop { p evaluate( f.gets.to_s.gsub("∂", "\n") ) }
89
+ end
90
+ end
91
+
92
+ # Starts a new Thread that will loop capturing keystrokes and evaluating the bound block within the @context Binding, will be called on initialize
93
+ def expect_input
94
+ Thread.new do
95
+ loop do
96
+ char = get_character
97
+ @bindings ||= []
98
+ bind = @bindings[ char ]
99
+ p evaluate( bind ) if bind
100
+ end
101
+ end
102
+ end
103
+
104
+ # Expects a one char Symbol or String which will bind to a passed block so it can be called later with a keystroke
105
+ def bind( key, &block )
106
+ @bindings = [] unless @bindings.instance_of?(Array)
107
+ block ||= Proc.new{}
108
+ @bindings[ key.to_s[0] ] = Ruby2Ruby.new.process( [:block, block.to_sexp.last] )
109
+ Notice.new( "Key '#{key}' is bound to an action")
110
+ end
111
+
112
+ # Evaluates a ruby expression within the @context Binding
113
+ def evaluate( string = nil )
114
+ return resilient_eval( string, @context ) if string
115
+ end
116
+
117
+ def clear
118
+ print "\e[2J\e[f"
119
+ end
120
+
121
+ def get_binding #:nodoc:
122
+ @context = binding
123
+ end
124
+
125
+ def run_updates( code )
126
+ source = ParseTree.new.parse_tree_for_string( code ).first
127
+ final = []
128
+ while iter = source.assoc(:iter)
129
+ source -= [iter]
130
+ final << [:block, iter.last] if iter[1].include?(:update)
131
+ end
132
+ evaluate( final.collect{ |exp| Ruby2Ruby.new.process(exp) }.join("\n") )
133
+ Notice.new('Update blocks evaluated')
134
+ end
135
+
136
+ def update # Allmost a stub
137
+ yield
138
+ end
139
+
140
+ alias :reaload! :get_binding
141
+ end
142
+ end
143
+
144
+
data/lib/scruby.rb ADDED
@@ -0,0 +1,60 @@
1
+ #--
2
+ # Copyright (c) 2008 Macario Ortega
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #++
17
+ require 'rubygems'
18
+ require 'ruby2ruby'
19
+ require "named_arguments"
20
+ require 'osc'
21
+ require 'yaml'
22
+
23
+ SCRUBY_DIR = File.join( File.expand_path(File.dirname(__FILE__) ), 'scruby' )
24
+
25
+
26
+ require "#{SCRUBY_DIR}/typed_array"
27
+
28
+ require "#{SCRUBY_DIR}/audio/ugens/ugen_operations"
29
+ require "#{SCRUBY_DIR}/audio/ugens/ugen"
30
+ require "#{SCRUBY_DIR}/audio/ugens/multi_out_ugens"
31
+ require "#{SCRUBY_DIR}/audio/ugens/in_out"
32
+
33
+ require "#{SCRUBY_DIR}/audio/ugens/operation_ugens"
34
+ require "#{SCRUBY_DIR}/audio/ugens/ugen"
35
+
36
+ require "#{SCRUBY_DIR}/audio/ugens/ugens"
37
+ require "#{SCRUBY_DIR}/audio/control_name"
38
+ require "#{SCRUBY_DIR}/audio/synthdef"
39
+ require "#{SCRUBY_DIR}/extensions"
40
+
41
+ require "#{SCRUBY_DIR}/audio/server"
42
+
43
+ require "#{SCRUBY_DIR}/audio/env"
44
+ require "#{SCRUBY_DIR}/audio/ugens/env_gen"
45
+
46
+ require "#{SCRUBY_DIR}/audio/node"
47
+ require "#{SCRUBY_DIR}/audio/synth"
48
+
49
+
50
+ include Scruby
51
+ include Audio
52
+ include Ugens
53
+ include OperationUgens
54
+
55
+
56
+ class Notice < String; end
57
+ class Warning < String; end
58
+ class Special < String; end
59
+
60
+
@@ -0,0 +1,29 @@
1
+ module Scruby
2
+ module Audio
3
+ class ControlName
4
+ attr_accessor :name, :value, :rate, :index
5
+ RATES = { 'n_' => :noncontrol, 'i_' => :scalar, 'k_' => :control, 't_' => :trigger }
6
+
7
+ def initialize( name, value, rate, index )
8
+ @name, @value, @rate, @index = name.to_s, value.to_f, set_rate( name, rate ), index
9
+ end
10
+
11
+ def set_rate( name, rate )
12
+ RATES.has_value?( rate ) ? rate : rate_from_name( name )
13
+ end
14
+
15
+ def rate_from_name( name )
16
+ RATES[ name.to_s[0..1] ] || :control
17
+ end
18
+
19
+ def non_control?
20
+ @rate == :noncontrol
21
+ end
22
+
23
+ def valid_ugen_input?
24
+ true
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,97 @@
1
+ module Scruby
2
+ class Env
3
+ attr_accessor :levels, :times, :curves, :release_node, :array
4
+ SHAPE_NAMES = {
5
+ :step => 0,
6
+ :lin => 1,
7
+ :linear => 1,
8
+ :exp => 2,
9
+ :exponential => 2,
10
+ :sin => 3,
11
+ :sine => 3,
12
+ :wel => 4,
13
+ :welch => 4,
14
+ :sqr => 6,
15
+ :squared => 6,
16
+ :cub => 7,
17
+ :cubed => 7
18
+ }
19
+
20
+ def initialize( levels, times, curves = :lin, release_node = nil, loop_node = nil )
21
+ @levels, @times, @curves, @release_node, @loop_node = levels, times, curves.to_array, release_node, loop_node
22
+ raise ArgumentError, "levels and times should be array" unless levels.instance_of?(Array) and times.instance_of?(Array)
23
+ end
24
+
25
+ class << self
26
+ # fixed duration envelopes
27
+ def triangle(dur = 1.0, level = 1.0)
28
+ dur = (dur * 0.5)
29
+ new( [0, level, 0], [dur, dur] )
30
+ end
31
+
32
+ def sine(dur = 1.0, level = 1.0)
33
+ dur = (dur * 0.5)
34
+ new( [0, level, 0], [dur, dur], :sine)
35
+ end
36
+
37
+ def perc( attackTime=0.01, releaseTime=1.0, level=1.0, curve = -4.0 )
38
+ new( [0, level, 0], [attackTime, releaseTime], curve )
39
+ end
40
+
41
+ def linen( attackTime=0.01, sustainTime=1.0, releaseTime=1.0, level=1.0, curve = :lin )
42
+ new [0, level, level, 0], [attackTime, sustainTime, releaseTime], curve
43
+ end
44
+
45
+ def cutoff( releaseTime = 0.1, level = 1.0, curve = :lin )
46
+ new( [level, 0], [releaseTime], curve, 0 )
47
+ end
48
+
49
+ def dadsr( delayTime=0.1, attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0 )
50
+ new( [0, 0, peakLevel, peakLevel * sustainLevel, 0].collect{ |e| e + bias }, [delayTime, attackTime, decayTime, releaseTime], curve, 3 )
51
+ end
52
+
53
+ def adsr( attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0 )
54
+ new( [0, peakLevel, peakLevel * sustainLevel, 0].collect{ |e| e + bias }, [attackTime, decayTime, releaseTime], curve, 2 )
55
+ end
56
+
57
+ def asr( attackTime=0.01, sustainLevel=1.0, releaseTime=1.0, curve = -4.0 )
58
+ new( [0, sustainLevel, 0], [attackTime, releaseTime], curve, 1 )
59
+ end
60
+
61
+ named_args_for :triangle, :sine, :perc, :linen, :cutoff, :dadsr, :adsr, :asr
62
+ end
63
+
64
+ def to_array
65
+ *contents = levels[0], times.size, release_node, loop_node
66
+ contents + levels[1..-1].wrap_and_zip( times, shape_numbers, curve_values ).flatten
67
+ end
68
+
69
+ def shape_numbers
70
+ curves.collect do |curve|
71
+ curve.valid_ugen_input? ? 5 : SHAPE_NAMES[curve]
72
+ end
73
+ end
74
+
75
+ def curve_values
76
+ curves.collect do |curve|
77
+ curve.valid_ugen_input? ? curve : 0
78
+ end
79
+ end
80
+
81
+ def release_node
82
+ @release_node ||= -99
83
+ end
84
+
85
+ def loop_node
86
+ @loop_node ||= -99
87
+ end
88
+
89
+ def valid_ugen_input? #returns true
90
+ true
91
+ end
92
+
93
+ def collect_constants #:nodoc:
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,20 @@
1
+ module Scruby
2
+ class Node
3
+ @@base_id = 2000
4
+ attr_reader :name, :servers
5
+
6
+ def initialize( name, *servers )
7
+ @name = name.to_s
8
+ servers = *servers
9
+ @servers = servers ? TypedArray.new( Server, [*servers] ) : Server.all
10
+ end
11
+
12
+ def id
13
+ @id ||= ( @@base_id = @@base_id + 1 )
14
+ end
15
+
16
+ def self.reset!
17
+ @@base_id = 2000
18
+ end
19
+ end
20
+ end