gamelan 0.3-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ = Gamelan
2
+
3
+ Gamelan is a good-enough soft real-time event scheduler especially for music
4
+ applications. It exposes a simple API for executing Ruby code at a required
5
+ time. Uses include sending MIDI or OSC messages to external applications or
6
+ hardware.
7
+
8
+ Gamelan also makes life easier by supporting logical time. Logical time is
9
+ reflected in the scheduler's phase. The unit in logical time is the beat, and
10
+ the Scheduler's phase will increment by 1.0 with every beat.
11
+
12
+ Logical time varies with real time according to the tempo, which is specified
13
+ in bpm. For example, the Scheduler's phase will increment by 2.0 for every
14
+ second that elapses when using the default tempo of 120bpm. Applications are
15
+ free to alter the tempo at any time, including from within tasks.
16
+
17
+ = Notes
18
+
19
+ The author admits that Ruby is not at all friendly to realtime applications.
20
+ No guarantees are made about the scheduler's performance. It will not drift
21
+ (it will always stay in sync with the system clock), but jitter is inevitable.
22
+ This is minimized by using a hybrid spinlock implementation to wait between
23
+ dispatches, and by using a reasonably efficient priority queue to store Tasks.
24
+
25
+ The design is an elaboration of Topher Cyll's Timer implementation from his
26
+ book, <em>Practical Ruby Projects</em>, and the Priority Queue implementation
27
+ comes from Brian Amberg.
@@ -0,0 +1,15 @@
1
+ # Gamelan is a good-enough soft real-time event scheduler,
2
+ # written in Ruby, especially for music applications.
3
+ #
4
+ # Copyright (c) 2008 Jeremy Voorhis <jvoorhis@gmail.com>
5
+ #
6
+ # This code released under the terms of the MIT license.
7
+
8
+ def jruby?
9
+ defined?(JRUBY_VERSION)
10
+ end
11
+
12
+ require 'rubygems'
13
+ require 'gamelan/scheduler'
14
+ require 'gamelan/task'
15
+
@@ -0,0 +1,55 @@
1
+ module Gamelan
2
+
3
+ if jruby?
4
+
5
+ class Queue
6
+ include Java
7
+ include_package 'java.util'
8
+
9
+ def initialize(sched)
10
+ @scheduler = sched
11
+ comparator = lambda { |a,b| a.delay <=> b.delay }
12
+ @queue = PriorityQueue.new(10000, &comparator)
13
+ end
14
+
15
+ def push(task)
16
+ @queue.add(task)
17
+ end
18
+ alias << push
19
+
20
+ def pop
21
+ @queue.remove
22
+ end
23
+
24
+ def ready?
25
+ @queue.peek && @queue.peek.delay < @scheduler.phase
26
+ end
27
+ end
28
+
29
+ else
30
+
31
+ require 'priority_queue/c_priority_queue'
32
+ require 'priority_queue'
33
+
34
+ class Queue
35
+ def initialize(sched)
36
+ @scheduler = sched
37
+ @queue = ::PriorityQueue.new
38
+ end
39
+
40
+ def push(task)
41
+ @queue.push(task, task.delay)
42
+ end
43
+ alias << push
44
+
45
+ def pop
46
+ @queue.delete_min[0]
47
+ end
48
+
49
+ def ready?
50
+ @queue.min && @queue.min[1] < @scheduler.phase
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ require 'gamelan/timer'
2
+ require 'gamelan/queue'
3
+
4
+ module Gamelan
5
+ # The scheduler allows the user to schedule tasks, represented by +Gamelan::Task+.
6
+ class Scheduler < Timer
7
+
8
+ # Construct a new scheduler. +Scheduler#run+ must be called explicitly once a Scheduler is created. Accepts two options, +:tempo+ and +:rate+.
9
+ # [+:tempo+] The tempo's scheduler, in bpm. For example, at +:tempo => 120+, the scheduler's logical +phase+ will advance by 2.0 every 60 seconds.
10
+ # [+:rate+] Frequency in Hz at which the scheduler will attempt to run ready tasks. For example, The scheduler will poll for tasks 100 times in one
11
+ # second when +:rate+ is 100.
12
+ def initialize(options = {})
13
+ super
14
+ @queue = Gamelan::Queue.new(self)
15
+ end
16
+
17
+ # Schedule a task to be performed at +delay+ beats.
18
+ def at(delay, *params, &task)
19
+ @queue << Task.new(self, delay.to_f, *params, &task)
20
+ end
21
+
22
+ protected
23
+ # Run all ready tasks.
24
+ def dispatch
25
+ @queue.pop.run while @queue.ready?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ require 'forwardable'
2
+
3
+ module Gamelan
4
+
5
+ # Tasks run by the Scheduler. A task is a combination of a block to be
6
+ # run, a delay, in beats, that specifies when to run the Task, and an
7
+ # optional list of args. A reference to the Scheduler is also stored, so it
8
+ # can be manipulatd by tasks.
9
+ class Task
10
+ extend Forwardable
11
+ def_delegators :@scheduler, :at, :phase, :rate, :time
12
+ attr_reader :delay, :args, :scheduler
13
+
14
+ # Construct a Task with a Scheduler reference, a delay in beats, an
15
+ # optional list of args, and a block.
16
+ def initialize(sched, delay, *args, &block)
17
+ @scheduler, @delay, @proc, @args = sched, delay, block, args
18
+ end
19
+
20
+ # The scheduler will invoke Task#run is called with the Task's +delay+ at
21
+ # the scheduled time. Any optional +args+, if given, will follow.
22
+ # are yielded to the block.
23
+ def run; @proc[@delay, *@args] end
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ module Gamelan
2
+ # The Timer is responsible for executing code at a fixed rate. Users must
3
+ # subclass +Gamelan::Timer+. See +Gamelan::Scheduler+ for an example.
4
+ class Timer
5
+ attr_reader :phase, :rate, :time
6
+
7
+ # Construct a new timer. +Timer#run+ must be called explicitly once a Timer
8
+ # is created. Accepts two options, +:tempo+ and +:rate+.
9
+ # [+:tempo+] The timer's tempo, in bpm. For example, at +:tempo => 120+,
10
+ # the timer's logical +phase+ will advance by 2.0 every 60 seconds.
11
+ # [+:rate+] Frequency in Hz at which the scheduler will dispatch.
12
+ def initialize(options = {})
13
+ self.tempo = options.fetch(:tempo, 120)
14
+ @rate = 1.0 / options.fetch(:rate, 1000)
15
+ @sleep_for = rate / 10.0
16
+ end
17
+
18
+ # Initialize the scheduler's clock, and begin executing tasks.
19
+ def run
20
+ return if @running
21
+ @running = true
22
+ @thread = Thread.new do
23
+ @phase = 0.0
24
+ @origin = @time = Time.now.to_f
25
+ loop { dispatch; advance }
26
+ end
27
+ end
28
+
29
+ # Halt the scheduler. Note that the scheduler may be restarted, but is
30
+ # not resumable.
31
+ def stop
32
+ @running = false
33
+ @thread.kill
34
+ end
35
+
36
+ # Current tempo, in bpm.
37
+ def tempo
38
+ @tempo * 60.0
39
+ end
40
+
41
+ # Set the tempo in bpm.
42
+ def tempo=(bpm)
43
+ @tempo = bpm / 60.0
44
+ end
45
+
46
+ def join; @thread.join end
47
+
48
+ private
49
+ # Advances the internal clock time and spins until it is reached.
50
+ def advance
51
+ @time += @rate
52
+ @phase += (@time - @origin) * @tempo
53
+ @origin = @time
54
+ sleep(@sleep_for) until Time.now.to_f >= @time
55
+ end
56
+
57
+ # Run all ready tasks.
58
+ def dispatch
59
+ raise NotImplementedError, "subclass responsibility"
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ extensions: []
3
+
4
+ homepage: http://github.com/jvoorhis/gamelan
5
+ executables: []
6
+
7
+ version: !ruby/object:Gem::Version
8
+ version: "0.3"
9
+ post_install_message:
10
+ date: 2009-01-21 08:00:00 +00:00
11
+ files:
12
+ - lib/gamelan.rb
13
+ - lib/gamelan/queue.rb
14
+ - lib/gamelan/scheduler.rb
15
+ - lib/gamelan/task.rb
16
+ - lib/gamelan/timer.rb
17
+ - README.rdoc
18
+ rubygems_version: 1.3.1
19
+ rdoc_options:
20
+ - --title
21
+ - Gamelan
22
+ - --main
23
+ - README.rdoc
24
+ - --line-numbers
25
+ signing_key:
26
+ cert_chain: []
27
+
28
+ name: gamelan
29
+ has_rdoc: true
30
+ platform: java
31
+ summary: Gamelan is a good-enough soft real-time event scheduler, written in Ruby,
32
+ especially for music applications.
33
+ default_executable:
34
+ bindir: bin
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ version:
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ version:
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ require_paths:
48
+ - lib
49
+ specification_version: 2
50
+ test_files: []
51
+
52
+ dependencies: []
53
+
54
+ description:
55
+ email: jvoorhis@gmail.com
56
+ authors:
57
+ - Jeremy Voorhis
58
+ extra_rdoc_files:
59
+ - README.rdoc
60
+ requirements: []
61
+
62
+ rubyforge_project: gamelan
63
+ autorequire: