ruck 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,67 +1,35 @@
1
1
  A port of ChucK's strong timing to Ruby!
2
2
 
3
- Use Ruck's "shreds" to coordinate interleaved execution
4
- of threads (continuations) with precise virtual timing.
5
- Actual run-time is abstracted and shreds declare how much
6
- virtual time they took to execute. Scheduling of shreds
7
- is done by a ...
3
+ ruck lets you easily create a virtual clock against
4
+ which precise timing of execution can be guaranteed. The
5
+ virtual clock can be kept roughly in sync with real time
6
+ if you want it to, but you don't have to. For example, in
7
+ ChucK, even if your scripts take too long to generate
8
+ samples in real time, the audio stream isn't compromised
9
+ because it's timed against the virtual clock.
8
10
 
9
- SHREDULER
11
+ ruck provides an easily extended scheduler for non-preemptive
12
+ shreds (threads) implemented using continuations.
13
+ Cooperatively scheduled threads usually don't require
14
+ synchronization since execution is never interrupted.
10
15
 
11
- UGenShreduler:
12
-
13
- This shreduler calculates an audio unit generator graph's
14
- output in virtual time. The graph can be modified by
15
- shreds all the while.
16
-
17
- The graph is written in Ruby for flexibility, so it's
18
- too slow (on my computer) for real time, so there is no
19
- real-time playback. You can use WavOut, though.
20
- (See ex01.rb)
21
-
22
- Check out the library of built-in unit generators in ugen/
23
- and make your own.
16
+ A few example shredulers (schedulers) are provided:
24
17
 
25
- Unit Generator Usage
26
- ====================
27
-
28
- Play a sine wave (ex02.rb):
29
-
30
- s = SinOsc.new(:freq => 440)
31
- w = WavOut.new(:filename => "ex02.wav")
32
- s >> w >> blackhole
33
- play 3.seconds
34
-
35
- Attach lambdas to unit generator attributes (ex03.rb):
18
+ UGenShreduler:
36
19
 
37
- wav = WavOut.new(:filename => "ex03.wav")
38
- sin2 = SinOsc.new(:freq => 3)
39
- sin = SinOsc.new(:freq => L{ sin2.last * 220 + 660 },
40
- :gain => L{ 0.5 + sin2.last * 0.5 })
41
- [sin >> wav, sin2] >> blackhole
42
- play 3.seconds
20
+ Recently moved to its own gem: ruck-ugen
43
21
 
44
22
  RealTimeShreduler
45
23
 
46
- This shreduler attempts to keep virtual time in line with
47
- real time.
48
- (See ex10.rb)
24
+ Recently moved to its own gem: ruck-realtime
49
25
 
50
26
  MIDIShreduler
51
27
 
52
- This shreduler uses MIDIator and midilib to support live
53
- MIDI playback and saving MIDI to disk. An example runner
54
- is provided in midi_runner.rb which you invoke like this:
55
-
56
- $ ruck_midi MIDI_FILENAME NUM_TRACKS LIVE SCRIPT_FILENAME [...]
57
-
58
- where LIVE is "no" to only save the MIDI output, or "yes"
59
- to also play in real-time.
28
+ Recently moved to its own gem: ruck-midi
60
29
 
61
30
  GLAppShreduler
62
31
 
63
- You don't want to know. (But the scripts are included so
64
- you can find them if you're really curious.)
32
+ You don't want to know. But see ruck-glapp if you do.
65
33
 
66
34
  USAGE
67
35
  =====
@@ -77,4 +45,4 @@ examples/ directory. Those scripts contain no boilerplate includes
77
45
  because they are written to be invoked on the command line by
78
46
  one of the bin/ scripts. For example:
79
47
 
80
- $ ruck_ugen examples/ex01.rb
48
+ $ ruck_ugen examples/ugen/ex01.rb
data/Rakefile CHANGED
@@ -1,25 +1,25 @@
1
+ require 'rubygems'
2
+ require 'rake'
1
3
 
2
4
  begin
3
5
  require "jeweler"
4
- Jeweler::Tasks.new do |gemspec|
5
- gemspec.name = "ruck"
6
- gemspec.email = "tom@alltom.com"
7
- gemspec.homepage = "http://github.com/alltom/ruck"
8
- gemspec.authors = ["Tom Lieber"]
9
- gemspec.summary = "strong timing for Ruby: cooperative threads on a virtual clock"
10
- gemspec.description = <<-EOF
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ruck"
8
+ gem.email = "tom@alltom.com"
9
+ gem.homepage = "http://github.com/alltom/ruck"
10
+ gem.authors = ["Tom Lieber"]
11
+ gem.summary = "strong timing for Ruby: cooperative threads on a virtual clock"
12
+ gem.description = <<-EOF
11
13
  Ruck uses continuations and a simple scheduler to ensure "shreds"
12
- (threads in Ruck) are woken at precisely the right time according
14
+ (Ruck threads) are woken at precisely the right time according
13
15
  to its virtual clock. Schedulers can map virtual time to samples
14
16
  in a WAV file, real time, time in a MIDI file, or anything else
15
17
  by overriding "sim_to" in the Shreduler class.
16
-
17
- A small library of useful unit generators and plenty of examples
18
- are provided. See the README or the web page for details.
19
18
  EOF
20
- gemspec.has_rdoc = false
19
+ gem.has_rdoc = false
20
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
21
  end
22
22
  Jeweler::GemcutterTasks.new
23
23
  rescue LoadError
24
- puts "Jewler not available. Install it with: sudo gem install jeweler"
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
25
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -4,6 +4,7 @@ module Ruck
4
4
  class Shred
5
5
  attr_accessor :now
6
6
  attr_accessor :finished
7
+ attr_accessor :name
7
8
 
8
9
  def initialize(shreduler, now, name, &block)
9
10
  @shreduler = shreduler
@@ -28,6 +29,7 @@ module Ruck
28
29
  end
29
30
 
30
31
  @finished = true
32
+ @shreduler.remove_shred self
31
33
  end
32
34
 
33
35
  def yield(samples)
@@ -41,7 +43,12 @@ module Ruck
41
43
  end
42
44
 
43
45
  def finish
44
- @resume.call # last save point
46
+ @finished = true
47
+ @shreduler.remove_shred self
48
+
49
+ if @shreduler.current_shred == self
50
+ @resume.call # last save point
51
+ end
45
52
  end
46
53
 
47
54
  # shreds sort in order of position in time
@@ -66,14 +73,15 @@ module Ruck
66
73
  @running = false
67
74
  end
68
75
 
69
- def spork(name = "", &shred)
70
- LOG.debug "Adding shred \"#{name}\" at #{@now}"
71
- @shreds << Shred.new(self, @now, name, &shred)
72
- @shred
76
+ def spork(name = "", &shred_block)
77
+ shred = Shred.new(self, @now, name, &shred_block)
78
+ LOG.debug "Adding shred \"#{shred.name}\" at #{@now}"
79
+ @shreds << shred
80
+ shred
73
81
  end
74
82
 
75
83
  def remove_shred(shred)
76
- LOG.debug "Removing shred \"#{name}\" at #{@now}"
84
+ LOG.debug "Removing shred \"#{shred.name}\" at #{@now}"
77
85
  @shreds.delete shred
78
86
  end
79
87
 
@@ -82,7 +90,7 @@ module Ruck
82
90
  end
83
91
 
84
92
  # called when shreds allow time to pass
85
- # a convnient method to override
93
+ # a convenient method to override
86
94
  def sim_to(new_now)
87
95
  @now = new_now
88
96
  end
@@ -101,11 +109,11 @@ module Ruck
101
109
 
102
110
  sim_to(shred.now)
103
111
 
104
- invoke_shred shred
112
+ invoke_shred(shred)
105
113
 
106
114
  if @current_shred.finished
107
115
  LOG.debug "#{shred} finished"
108
- @shreds.delete(shred)
116
+ remove_shred(shred)
109
117
  end
110
118
  end
111
119
 
@@ -123,36 +131,5 @@ module Ruck
123
131
  @running = false
124
132
  end
125
133
  end
126
-
127
- class UGenShreduler < Shreduler
128
- def run
129
- require File.join(File.dirname(__FILE__), "misc", "pcm_time_helpers")
130
- super
131
- end
132
-
133
- def sim_to(new_now)
134
- while @now < new_now.to_i
135
- BLACKHOLE.next @now
136
- @now += 1
137
- end
138
- end
139
- end
140
-
141
- class RealTimeShreduler < Shreduler
142
- def run
143
- @start_time = Time.now
144
- super
145
- end
146
-
147
- def sim_to(new_now)
148
- actual_now = Time.now
149
- simulated_now = @start_time + (new_now.to_f / SAMPLE_RATE)
150
- if simulated_now > actual_now
151
- sleep(simulated_now - actual_now)
152
- end
153
-
154
- @now = new_now
155
- end
156
- end
157
134
 
158
135
  end
data/lib/ruck.rb CHANGED
@@ -6,8 +6,3 @@ module Ruck
6
6
  end
7
7
 
8
8
  require File.join(File.dirname(__FILE__), "ruck", "shreduling")
9
- require File.join(File.dirname(__FILE__), "ruck", "misc", "metaid")
10
- require File.join(File.dirname(__FILE__), "ruck", "misc", "linkage")
11
- require File.join(File.dirname(__FILE__), "ruck", "ugen", "general")
12
- require File.join(File.dirname(__FILE__), "ruck", "ugen", "wav")
13
- require File.join(File.dirname(__FILE__), "ruck", "ugen", "oscillators")
data/ruck.gemspec CHANGED
@@ -5,22 +5,18 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruck}
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tom Lieber"]
12
- s.date = %q{2009-11-21}
12
+ s.date = %q{2010-07-10}
13
13
  s.description = %q{ Ruck uses continuations and a simple scheduler to ensure "shreds"
14
- (threads in Ruck) are woken at precisely the right time according
14
+ (Ruck threads) are woken at precisely the right time according
15
15
  to its virtual clock. Schedulers can map virtual time to samples
16
16
  in a WAV file, real time, time in a MIDI file, or anything else
17
17
  by overriding "sim_to" in the Shreduler class.
18
-
19
- A small library of useful unit generators and plenty of examples
20
- are provided. See the README or the web page for details.
21
18
  }
22
19
  s.email = %q{tom@alltom.com}
23
- s.executables = ["ruck_glapp", "ruck_midi", "ruck_sleep", "ruck_ugen"]
24
20
  s.extra_rdoc_files = [
25
21
  "README"
26
22
  ]
@@ -29,64 +25,15 @@ Gem::Specification.new do |s|
29
25
  "README",
30
26
  "Rakefile",
31
27
  "VERSION",
32
- "bin/ruck_glapp",
33
- "bin/ruck_midi",
34
- "bin/ruck_sleep",
35
- "bin/ruck_ugen",
36
- "examples/glapp/ex01.rb",
37
- "examples/glapp/ex02.rb",
38
- "examples/glapp/ex03.rb",
39
- "examples/midi/ex01.rb",
40
- "examples/midi/ex02.rb",
41
- "examples/ugen/ex01.rb",
42
- "examples/ugen/ex02.rb",
43
- "examples/ugen/ex03.rb",
44
- "examples/ugen/ex04.rb",
45
- "examples/ugen/ex05.rb",
46
- "examples/ugen/ex06.rb",
47
- "examples/ugen/ex07.rb",
48
- "examples/ugen/ex08.rb",
49
- "examples/ugen/ex09.rb",
50
- "examples/ugen/ex10.rb",
51
- "examples/ugen/ex11.rb",
52
- "examples/ugen/ex12.rb",
53
28
  "lib/ruck.rb",
54
- "lib/ruck/bench.rb",
55
- "lib/ruck/misc/linkage.rb",
56
- "lib/ruck/misc/metaid.rb",
57
- "lib/ruck/misc/pcm_time_helpers.rb",
58
- "lib/ruck/misc/riff.rb",
59
- "lib/ruck/misc/wavparse.rb",
60
29
  "lib/ruck/shreduling.rb",
61
- "lib/ruck/ugen/general.rb",
62
- "lib/ruck/ugen/oscillators.rb",
63
- "lib/ruck/ugen/wav.rb",
64
30
  "ruck.gemspec"
65
31
  ]
66
32
  s.homepage = %q{http://github.com/alltom/ruck}
67
33
  s.rdoc_options = ["--charset=UTF-8"]
68
34
  s.require_paths = ["lib"]
69
- s.rubygems_version = %q{1.3.5}
35
+ s.rubygems_version = %q{1.3.6}
70
36
  s.summary = %q{strong timing for Ruby: cooperative threads on a virtual clock}
71
- s.test_files = [
72
- "examples/glapp/ex01.rb",
73
- "examples/glapp/ex02.rb",
74
- "examples/glapp/ex03.rb",
75
- "examples/midi/ex01.rb",
76
- "examples/midi/ex02.rb",
77
- "examples/ugen/ex01.rb",
78
- "examples/ugen/ex02.rb",
79
- "examples/ugen/ex03.rb",
80
- "examples/ugen/ex04.rb",
81
- "examples/ugen/ex05.rb",
82
- "examples/ugen/ex06.rb",
83
- "examples/ugen/ex07.rb",
84
- "examples/ugen/ex08.rb",
85
- "examples/ugen/ex09.rb",
86
- "examples/ugen/ex10.rb",
87
- "examples/ugen/ex11.rb",
88
- "examples/ugen/ex12.rb"
89
- ]
90
37
 
91
38
  if s.respond_to? :specification_version then
92
39
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Tom Lieber
@@ -9,17 +14,14 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-11-21 00:00:00 -08:00
17
+ date: 2010-07-10 00:00:00 -07:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
16
- description: " Ruck uses continuations and a simple scheduler to ensure \"shreds\"\n (threads in Ruck) are woken at precisely the right time according\n to its virtual clock. Schedulers can map virtual time to samples\n in a WAV file, real time, time in a MIDI file, or anything else\n by overriding \"sim_to\" in the Shreduler class.\n \n A small library of useful unit generators and plenty of examples\n are provided. See the README or the web page for details.\n"
21
+ description: " Ruck uses continuations and a simple scheduler to ensure \"shreds\"\n (Ruck threads) are woken at precisely the right time according\n to its virtual clock. Schedulers can map virtual time to samples\n in a WAV file, real time, time in a MIDI file, or anything else\n by overriding \"sim_to\" in the Shreduler class.\n"
17
22
  email: tom@alltom.com
18
- executables:
19
- - ruck_glapp
20
- - ruck_midi
21
- - ruck_sleep
22
- - ruck_ugen
23
+ executables: []
24
+
23
25
  extensions: []
24
26
 
25
27
  extra_rdoc_files:
@@ -29,38 +31,8 @@ files:
29
31
  - README
30
32
  - Rakefile
31
33
  - VERSION
32
- - bin/ruck_glapp
33
- - bin/ruck_midi
34
- - bin/ruck_sleep
35
- - bin/ruck_ugen
36
- - examples/glapp/ex01.rb
37
- - examples/glapp/ex02.rb
38
- - examples/glapp/ex03.rb
39
- - examples/midi/ex01.rb
40
- - examples/midi/ex02.rb
41
- - examples/ugen/ex01.rb
42
- - examples/ugen/ex02.rb
43
- - examples/ugen/ex03.rb
44
- - examples/ugen/ex04.rb
45
- - examples/ugen/ex05.rb
46
- - examples/ugen/ex06.rb
47
- - examples/ugen/ex07.rb
48
- - examples/ugen/ex08.rb
49
- - examples/ugen/ex09.rb
50
- - examples/ugen/ex10.rb
51
- - examples/ugen/ex11.rb
52
- - examples/ugen/ex12.rb
53
34
  - lib/ruck.rb
54
- - lib/ruck/bench.rb
55
- - lib/ruck/misc/linkage.rb
56
- - lib/ruck/misc/metaid.rb
57
- - lib/ruck/misc/pcm_time_helpers.rb
58
- - lib/ruck/misc/riff.rb
59
- - lib/ruck/misc/wavparse.rb
60
35
  - lib/ruck/shreduling.rb
61
- - lib/ruck/ugen/general.rb
62
- - lib/ruck/ugen/oscillators.rb
63
- - lib/ruck/ugen/wav.rb
64
36
  - ruck.gemspec
65
37
  has_rdoc: true
66
38
  homepage: http://github.com/alltom/ruck
@@ -75,36 +47,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
75
47
  requirements:
76
48
  - - ">="
77
49
  - !ruby/object:Gem::Version
50
+ segments:
51
+ - 0
78
52
  version: "0"
79
- version:
80
53
  required_rubygems_version: !ruby/object:Gem::Requirement
81
54
  requirements:
82
55
  - - ">="
83
56
  - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
84
59
  version: "0"
85
- version:
86
60
  requirements: []
87
61
 
88
62
  rubyforge_project:
89
- rubygems_version: 1.3.5
63
+ rubygems_version: 1.3.6
90
64
  signing_key:
91
65
  specification_version: 3
92
66
  summary: "strong timing for Ruby: cooperative threads on a virtual clock"
93
- test_files:
94
- - examples/glapp/ex01.rb
95
- - examples/glapp/ex02.rb
96
- - examples/glapp/ex03.rb
97
- - examples/midi/ex01.rb
98
- - examples/midi/ex02.rb
99
- - examples/ugen/ex01.rb
100
- - examples/ugen/ex02.rb
101
- - examples/ugen/ex03.rb
102
- - examples/ugen/ex04.rb
103
- - examples/ugen/ex05.rb
104
- - examples/ugen/ex06.rb
105
- - examples/ugen/ex07.rb
106
- - examples/ugen/ex08.rb
107
- - examples/ugen/ex09.rb
108
- - examples/ugen/ex10.rb
109
- - examples/ugen/ex11.rb
110
- - examples/ugen/ex12.rb
67
+ test_files: []
68
+
data/bin/ruck_glapp DELETED
@@ -1,162 +0,0 @@
1
- #!/usr/bin/env ruby
2
- $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
-
4
- # requires glapp gem
5
- # sudo gem install alltom-glapp
6
- # see http://alltom.com/pages/glapp for more details
7
- # UPDATE: ugh, github stopped producing gems.
8
- # find a way to get it on your own 'til I fix that.
9
-
10
- require "ruck"
11
-
12
- require "rubygems"
13
- require "glapp"
14
-
15
- class GLAppShreduler < Ruck::Shreduler
16
- def initialize
17
- @shred_queues = {}
18
- [:frame,
19
- :key_down, :key_up,
20
- :mouse_down, :mouse_up, :mouse_move].each do |q|
21
- @shred_queues[q] = []
22
- end
23
- super
24
- end
25
-
26
- def starting
27
- @start_time = Time.now
28
- end
29
-
30
- def actual_now
31
- Time.now - @start_time
32
- end
33
-
34
- def sleep_current_til(queue)
35
- shred = current_shred
36
- @shreds.delete(shred)
37
- @shred_queues[queue] << shred
38
- shred.yield(0)
39
-
40
- @ev
41
- end
42
-
43
- def raise_event(ev, queue)
44
- # should use actual_now,
45
- # but we don't want to put it into the future
46
- new_now = actual_now
47
- new_now = [new_now, next_shred.now].min if next_shred
48
- @now = new_now
49
-
50
- @ev = ev # returned by sleep_current_til
51
-
52
- shreds = @shred_queues[queue]
53
- @shred_queues[queue] = []
54
-
55
- shreds.each do |shred|
56
- shred.now = new_now
57
- @shreds << shred
58
- invoke_shred shred
59
- end
60
- end
61
-
62
- def catch_up
63
- while shreds.length > 0 && next_shred.now < actual_now
64
- run_one
65
- end
66
- end
67
- end
68
-
69
- module ShredLocal
70
- def spork(name = "unnamed", &shred)
71
- SHREDULER.spork(name, &shred)
72
- end
73
-
74
- def wait(seconds)
75
- SHREDULER.current_shred.yield(seconds)
76
- end
77
-
78
- def wait_for_frame
79
- SHREDULER.sleep_current_til(:frame)
80
- end
81
-
82
- def wait_for_key_down
83
- SHREDULER.sleep_current_til(:key_down)
84
- end
85
-
86
- def wait_for_key_up
87
- SHREDULER.sleep_current_til(:key_down)
88
- end
89
-
90
- def wait_for_mouse_down
91
- SHREDULER.sleep_current_til(:mouse_down)
92
- end
93
-
94
- def wait_for_mouse_up
95
- SHREDULER.sleep_current_til(:mouse_up)
96
- end
97
-
98
- def wait_for_mouse_move
99
- SHREDULER.sleep_current_til(:mouse_move)
100
- end
101
- end
102
-
103
- class MySketch
104
- include GLApp
105
-
106
- def setup
107
- ARGV.each do |filename|
108
- SHREDULER.spork(filename) do
109
- require filename
110
- end
111
- end
112
- @events = []
113
-
114
- SHREDULER.starting
115
- end
116
-
117
- def draw
118
- @events.each do |pair|
119
- ev, queue = pair
120
- SHREDULER.raise_event ev, queue
121
- end
122
- @events = []
123
-
124
- SHREDULER.catch_up # execute shreds whose time came while drawing previous frame
125
-
126
- SHREDULER.raise_event Object.new, :frame
127
- end
128
-
129
- def keyboard_down(key, modifiers)
130
- @events << [Struct.new(:key).new(key), :key_down]
131
- end
132
-
133
- def keyboard_up(key, modifiers)
134
- @events << [Struct.new(:key).new(key), :key_up]
135
- end
136
-
137
- def special_keyboard_down(key, modifiers)
138
- @events << [Struct.new(:key).new(key), :key_down]
139
- end
140
-
141
- def special_keyboard_up(key, modifiers)
142
- @events << [Struct.new(:key).new(key), :key_up]
143
- end
144
-
145
- def mouse_click(button, state, x, y)
146
- if state == 0
147
- @events << [Struct.new(:button, :x, :y).new(button, x, y), :mouse_down]
148
- else
149
- @events << [Struct.new(:button, :x, :y).new(button, x, y), :mouse_up]
150
- end
151
- end
152
-
153
- def mouse_motion(x, y)
154
- @events << [Struct.new(:x, :y).new(x, y), :mouse_move]
155
- end
156
- end
157
-
158
- SHREDULER = GLAppShreduler.new
159
-
160
- include GLApp::Helpers
161
- include ShredLocal
162
- MySketch.new.show 800, 600, "My Sketch"