midi-topaz 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/topaz/api.rb +19 -0
- data/lib/topaz/clock.rb +187 -0
- data/lib/topaz/midi_clock_input.rb +186 -0
- data/lib/topaz/midi_clock_output.rb +49 -0
- data/lib/topaz/pausable.rb +32 -0
- data/lib/topaz/tempo_calculator.rb +32 -15
- data/lib/topaz/tempo_source.rb +27 -0
- data/lib/topaz/timer.rb +132 -0
- data/lib/topaz.rb +10 -6
- data/test/clock_test.rb +63 -0
- data/test/helper.rb +12 -2
- data/test/midi_clock_input_test.rb +51 -0
- data/test/midi_clock_output_test.rb +50 -0
- data/test/tempo_calculator_test.rb +39 -0
- data/test/tempo_source_test.rb +33 -0
- data/test/timer_test.rb +76 -0
- metadata +15 -9
- data/lib/topaz/events.rb +0 -44
- data/lib/topaz/external_midi_tempo.rb +0 -81
- data/lib/topaz/internal_tempo.rb +0 -88
- data/lib/topaz/midi_sync_output.rb +0 -33
- data/lib/topaz/tempo.rb +0 -164
- data/test/config.rb +0 -11
- data/test/internal_tempo_test.rb +0 -51
data/lib/topaz/timer.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
module Topaz
|
2
|
+
|
3
|
+
class Timer < Gamelan::Timer
|
4
|
+
|
5
|
+
include Pausable
|
6
|
+
|
7
|
+
attr_reader :phase, :running
|
8
|
+
alias_method :running?, :running
|
9
|
+
|
10
|
+
# @param [Fixnum] tempo
|
11
|
+
# @param [Hash] options
|
12
|
+
# @option options [Clock::Event] :event
|
13
|
+
def initialize(tempo, options = {})
|
14
|
+
@event = options[:event]
|
15
|
+
@last_tick_event = 0
|
16
|
+
@last_midi_clock = 0
|
17
|
+
@pause = false
|
18
|
+
@running = false
|
19
|
+
self.interval = options[:interval] || 4
|
20
|
+
|
21
|
+
super({ :tempo => tempo })
|
22
|
+
end
|
23
|
+
|
24
|
+
# Start the internal timer
|
25
|
+
# @param [Hash] options
|
26
|
+
# @option options [Boolean] :background Whether to run the timer in a background thread (default: false)
|
27
|
+
# @return [Timer]
|
28
|
+
def start(options = {})
|
29
|
+
run
|
30
|
+
!@event.nil? && @event.do_start
|
31
|
+
join unless !!options[:background]
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the timer's click interval
|
36
|
+
# @param [Fixnum] value
|
37
|
+
# @return [Fixnum]
|
38
|
+
def interval=(value)
|
39
|
+
@interval = value / 4
|
40
|
+
end
|
41
|
+
|
42
|
+
# The timer's click interval
|
43
|
+
# @return [Fixnum]
|
44
|
+
def interval
|
45
|
+
@interval * 4
|
46
|
+
end
|
47
|
+
|
48
|
+
# Stop the timer
|
49
|
+
# @return [Timer]
|
50
|
+
def stop(*a)
|
51
|
+
super()
|
52
|
+
!@event.nil? && @event.do_stop
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Join the timer thread
|
57
|
+
# @return [Timer]
|
58
|
+
def join
|
59
|
+
super()
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Initialize the scheduler's clock, and begin executing tasks
|
66
|
+
# @return [Boolean]
|
67
|
+
def run
|
68
|
+
unless @running
|
69
|
+
@thread = Thread.new do
|
70
|
+
begin
|
71
|
+
initialize_running_state
|
72
|
+
loop do
|
73
|
+
dispatch
|
74
|
+
advance
|
75
|
+
end
|
76
|
+
rescue Exception => exception
|
77
|
+
Thread.main.raise(exception)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
@thread.abort_on_exception = true
|
81
|
+
true
|
82
|
+
else
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Run all ready tasks.
|
88
|
+
# @return [Boolean]
|
89
|
+
def dispatch
|
90
|
+
# Stuff to do on every tick
|
91
|
+
if time_for_midi_clock?
|
92
|
+
# look for stop
|
93
|
+
!@event.nil? && @event.do_clock
|
94
|
+
@last_midi_clock = (@phase * 24).to_i
|
95
|
+
true
|
96
|
+
end
|
97
|
+
# Stuff to do on @interval
|
98
|
+
if time_for_tick?
|
99
|
+
!@event.nil? && !@pause && @event.do_tick
|
100
|
+
@last_tick_event = (@phase * @interval).to_i
|
101
|
+
true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Initialize the variables that handle the running process of the timer
|
108
|
+
# @return [Boolean]
|
109
|
+
def initialize_running_state
|
110
|
+
@running = true
|
111
|
+
@phase = 0.0
|
112
|
+
@origin = @time = Time.now.to_f
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
# Is the current phase appropriate for MIDI clock output?
|
117
|
+
# @return [Boolean]
|
118
|
+
def time_for_midi_clock?
|
119
|
+
phase = (@phase * 24).to_i
|
120
|
+
!@last_midi_clock.eql?(phase)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Is the current phase appropriate for the tick event?
|
124
|
+
# @return [Boolean]
|
125
|
+
def time_for_tick?
|
126
|
+
phase = (@phase * @interval).to_i
|
127
|
+
!@last_tick_event.eql?(phase)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
data/lib/topaz.rb
CHANGED
@@ -9,16 +9,20 @@ require "gamelan"
|
|
9
9
|
require "midi-eye"
|
10
10
|
require "midi-message"
|
11
11
|
|
12
|
+
# modules
|
13
|
+
require "topaz/api"
|
14
|
+
require "topaz/pausable"
|
15
|
+
require "topaz/tempo_source"
|
16
|
+
|
12
17
|
# classes
|
13
|
-
require "topaz/
|
14
|
-
require "topaz/
|
15
|
-
require "topaz/
|
16
|
-
require "topaz/midi_sync_output"
|
18
|
+
require "topaz/clock"
|
19
|
+
require "topaz/midi_clock_input"
|
20
|
+
require "topaz/midi_clock_output"
|
17
21
|
require "topaz/tempo_calculator"
|
18
|
-
require "topaz/
|
22
|
+
require "topaz/timer"
|
19
23
|
|
20
24
|
module Topaz
|
21
25
|
|
22
|
-
VERSION = "0.1
|
26
|
+
VERSION = "0.2.1"
|
23
27
|
|
24
28
|
end
|
data/test/clock_test.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::ClockTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Clock" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@counter = 0
|
9
|
+
@count_to = 5
|
10
|
+
@tempo = Topaz::Clock.new(120) { @counter += 1 }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#interval=" do
|
14
|
+
|
15
|
+
should "change interval" do
|
16
|
+
assert_equal(4, @tempo.interval)
|
17
|
+
@tempo.interval = 8
|
18
|
+
assert_equal(8, @tempo.interval)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
context "Event" do
|
24
|
+
|
25
|
+
context "#tick" do
|
26
|
+
|
27
|
+
should "change tick" do
|
28
|
+
@is_running = false
|
29
|
+
@tempo.event.tick { @is_running = true }
|
30
|
+
refute @is_running
|
31
|
+
|
32
|
+
@tempo.start(:background => true)
|
33
|
+
loop until @tempo.running?
|
34
|
+
loop until @is_running
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context "Trigger" do
|
43
|
+
|
44
|
+
context "#stop" do
|
45
|
+
|
46
|
+
setup do
|
47
|
+
@tempo.trigger.stop { @counter.eql?(@count_to) }
|
48
|
+
end
|
49
|
+
|
50
|
+
should "stop" do
|
51
|
+
@tempo.start
|
52
|
+
assert_equal(@count_to, @counter)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
data/test/helper.rb
CHANGED
@@ -2,9 +2,19 @@ dir = File.dirname(File.expand_path(__FILE__))
|
|
2
2
|
$LOAD_PATH.unshift dir + "/../lib"
|
3
3
|
|
4
4
|
require "test/unit"
|
5
|
+
require "mocha/test_unit"
|
6
|
+
require "shoulda-context"
|
5
7
|
require "topaz"
|
6
8
|
|
7
|
-
module TestHelper
|
9
|
+
module TestHelper
|
10
|
+
|
11
|
+
def self.select_devices
|
12
|
+
$test_device ||= {}
|
13
|
+
{ :input => UniMIDI::Input, :output => UniMIDI::Output }.each do |type, klass|
|
14
|
+
$test_device[type] = klass.gets
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
end
|
9
19
|
|
10
|
-
|
20
|
+
TestHelper.select_devices
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::MIDIClockInputTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "MIDIClockInput" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@input = Object.new
|
9
|
+
@event = Object.new
|
10
|
+
@clock = Topaz::MIDIClockInput.new(@input, :event => @event)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#thru" do
|
14
|
+
|
15
|
+
should "fire clock event" do
|
16
|
+
@event.expects(:do_clock).once
|
17
|
+
assert @clock.send(:thru)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "#tick" do
|
23
|
+
|
24
|
+
should "fire tick event" do
|
25
|
+
@event.expects(:do_tick).once
|
26
|
+
assert @clock.send(:tick)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
context "#tick?" do
|
32
|
+
|
33
|
+
should "tick when counter has reached tick threshold" do
|
34
|
+
assert_equal 4, @clock.interval
|
35
|
+
23.times do
|
36
|
+
refute @clock.send(:tick?)
|
37
|
+
@clock.send(:advance)
|
38
|
+
end
|
39
|
+
assert @clock.send(:tick?)
|
40
|
+
@clock.send(:advance)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::MIDIClockOutputTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "MIDIClockOutput" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@output = Object.new
|
9
|
+
@clock = Topaz::MIDIClockOutput.new(:device => @output)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "#do_start" do
|
13
|
+
|
14
|
+
should "emit start message" do
|
15
|
+
@output.expects(:puts).once.with(250)
|
16
|
+
result = @clock.do_start
|
17
|
+
assert result
|
18
|
+
@output.unstub(:puts)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
context "#do_stop" do
|
24
|
+
|
25
|
+
should "emit stop message" do
|
26
|
+
@output.expects(:puts).once.with(252)
|
27
|
+
result = @clock.do_stop
|
28
|
+
assert result
|
29
|
+
@output.unstub(:puts)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
context "#do_clock" do
|
35
|
+
|
36
|
+
should "emit clock message" do
|
37
|
+
@output.expects(:puts).once.with(248)
|
38
|
+
result = @clock.do_clock
|
39
|
+
assert result
|
40
|
+
@output.unstub(:puts)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::TempoCalculatorTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "TempoCalculator" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@calc = Topaz::TempoCalculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
context "#calculate" do
|
12
|
+
|
13
|
+
should "wait for two timestamps to start calculation" do
|
14
|
+
@calc.timestamps << 1
|
15
|
+
assert_nil @calc.calculate
|
16
|
+
@calc.timestamps << 2
|
17
|
+
@calc.timestamps << 3
|
18
|
+
assert_not_nil @calc.calculate
|
19
|
+
end
|
20
|
+
|
21
|
+
should "limit timestamps do within the threshold" do
|
22
|
+
10.times { |i| @calc.timestamps << i }
|
23
|
+
@calc.calculate
|
24
|
+
assert_equal Topaz::TempoCalculator::THRESHOLD, @calc.timestamps.count
|
25
|
+
end
|
26
|
+
|
27
|
+
should "express tempo" do
|
28
|
+
5.times { |i| @calc.timestamps << Time.now.to_f; sleep(1.0 / 24.0) }
|
29
|
+
result = @calc.calculate
|
30
|
+
assert_not_nil result
|
31
|
+
assert (58..62).include?(result)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::TempoSourceTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "TempoSource" do
|
6
|
+
|
7
|
+
context ".new" do
|
8
|
+
|
9
|
+
should "construct a timer" do
|
10
|
+
result = Topaz::TempoSource.new(120)
|
11
|
+
assert_not_nil result
|
12
|
+
assert_equal Topaz::Timer, result.class
|
13
|
+
end
|
14
|
+
|
15
|
+
should "construct a midi input clock" do
|
16
|
+
result = Topaz::TempoSource.new($test_device[:input])
|
17
|
+
assert_not_nil result
|
18
|
+
assert_equal Topaz::MIDIClockInput, result.class
|
19
|
+
end
|
20
|
+
|
21
|
+
should "throw an exception" do
|
22
|
+
assert_raise RuntimeError do
|
23
|
+
Topaz::TempoSource.new("something")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
data/test/timer_test.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class Topaz::TimerTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Timer" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@timer = Topaz::Timer.new(120)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "#dispatch" do
|
12
|
+
|
13
|
+
setup do
|
14
|
+
@event = Object.new
|
15
|
+
@timer = Topaz::Timer.new(120, :event => @event)
|
16
|
+
@timer.send(:initialize_running_state)
|
17
|
+
end
|
18
|
+
|
19
|
+
should "fire MIDI clock event" do
|
20
|
+
@event.expects(:do_clock).once.returns(true)
|
21
|
+
@timer.send(:dispatch)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "fire tick event" do
|
25
|
+
@event.expects(:do_tick).once.returns(true)
|
26
|
+
@timer.send(:dispatch)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
context "#start" do
|
32
|
+
|
33
|
+
should "start running" do
|
34
|
+
assert_nil @timer.phase
|
35
|
+
@timer.start(:background => true)
|
36
|
+
loop until @timer.running?
|
37
|
+
|
38
|
+
assert @timer.running?
|
39
|
+
assert_not_nil @timer.phase
|
40
|
+
assert_not_equal 0.0, @timer.phase
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
context "#stop" do
|
46
|
+
|
47
|
+
setup do
|
48
|
+
assert_nil @timer.phase
|
49
|
+
@timer.start(:background => true)
|
50
|
+
loop until @timer.running?
|
51
|
+
|
52
|
+
assert @timer.running?
|
53
|
+
end
|
54
|
+
|
55
|
+
should "stop running" do
|
56
|
+
assert_not_nil @timer.phase
|
57
|
+
assert_not_equal 0.0, @timer.phase
|
58
|
+
@timer.stop
|
59
|
+
refute @timer.running?
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
context "#interval=" do
|
65
|
+
|
66
|
+
should "change interval" do
|
67
|
+
assert_equal(4, @timer.interval)
|
68
|
+
@timer.interval = 8
|
69
|
+
assert_equal(8, @timer.interval)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: midi-topaz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ari Russo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gamelan
|
@@ -94,15 +94,21 @@ files:
|
|
94
94
|
- LICENSE
|
95
95
|
- README.md
|
96
96
|
- lib/topaz.rb
|
97
|
-
- lib/topaz/
|
98
|
-
- lib/topaz/
|
99
|
-
- lib/topaz/
|
100
|
-
- lib/topaz/
|
101
|
-
- lib/topaz/
|
97
|
+
- lib/topaz/api.rb
|
98
|
+
- lib/topaz/clock.rb
|
99
|
+
- lib/topaz/midi_clock_input.rb
|
100
|
+
- lib/topaz/midi_clock_output.rb
|
101
|
+
- lib/topaz/pausable.rb
|
102
102
|
- lib/topaz/tempo_calculator.rb
|
103
|
-
-
|
103
|
+
- lib/topaz/tempo_source.rb
|
104
|
+
- lib/topaz/timer.rb
|
105
|
+
- test/clock_test.rb
|
104
106
|
- test/helper.rb
|
105
|
-
- test/
|
107
|
+
- test/midi_clock_input_test.rb
|
108
|
+
- test/midi_clock_output_test.rb
|
109
|
+
- test/tempo_calculator_test.rb
|
110
|
+
- test/tempo_source_test.rb
|
111
|
+
- test/timer_test.rb
|
106
112
|
homepage: http://github.com/arirusso/topaz
|
107
113
|
licenses:
|
108
114
|
- Apache-2.0
|
data/lib/topaz/events.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Topaz
|
2
|
-
|
3
|
-
# User defined callbacks for tempo events
|
4
|
-
class Events
|
5
|
-
|
6
|
-
attr_reader :tick
|
7
|
-
attr_accessor :midi_clock, :midi_start, :midi_stop, :start, :stop, :stop_when
|
8
|
-
|
9
|
-
def initialize()
|
10
|
-
@start = []
|
11
|
-
@stop = []
|
12
|
-
@tick = []
|
13
|
-
|
14
|
-
@midi_clock = nil
|
15
|
-
@midi_start = nil
|
16
|
-
@midi_stop = nil
|
17
|
-
@stop_when = nil
|
18
|
-
end
|
19
|
-
|
20
|
-
def do_midi_clock
|
21
|
-
@midi_clock.call
|
22
|
-
end
|
23
|
-
|
24
|
-
def do_start
|
25
|
-
@midi_start.call
|
26
|
-
@start.each(&:call)
|
27
|
-
end
|
28
|
-
|
29
|
-
def do_stop
|
30
|
-
@midi_stop.call
|
31
|
-
@stop.each(&:call)
|
32
|
-
end
|
33
|
-
|
34
|
-
def do_tick
|
35
|
-
@tick.each(&:call)
|
36
|
-
end
|
37
|
-
|
38
|
-
def stop?
|
39
|
-
@stop_when.call unless @stop_when.nil?
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
module Topaz
|
2
|
-
|
3
|
-
# Trigger an event based on received midi clock messages
|
4
|
-
class ExternalMIDITempo
|
5
|
-
|
6
|
-
attr_reader :clock
|
7
|
-
|
8
|
-
def initialize(events, input, options = {})
|
9
|
-
@events = events
|
10
|
-
@tempo_calculator = TempoCalculator.new
|
11
|
-
@clock = MIDIEye::Listener.new(input)
|
12
|
-
self.interval = options[:interval] || 4
|
13
|
-
|
14
|
-
initialize_clock
|
15
|
-
end
|
16
|
-
|
17
|
-
# This will return a calculated tempo
|
18
|
-
def tempo
|
19
|
-
@tempo_calculator.find_tempo
|
20
|
-
end
|
21
|
-
|
22
|
-
def start(*a)
|
23
|
-
@clock.start(*a)
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def stop(*a)
|
28
|
-
@clock.stop
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
def join
|
33
|
-
@clock.join
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# change the clock interval
|
39
|
-
# defaults to click once every 24 ticks or one quarter note which is the MIDI standard.
|
40
|
-
# however, if you wish to fire the on_tick event twice as often
|
41
|
-
# (or once per 12 clicks), pass 8
|
42
|
-
#
|
43
|
-
# 1 = whole note
|
44
|
-
# 2 = half note
|
45
|
-
# 4 = quarter note
|
46
|
-
# 6 = dotted quarter
|
47
|
-
# 8 = eighth note
|
48
|
-
# 16 = sixteenth note
|
49
|
-
# etc
|
50
|
-
#
|
51
|
-
def interval=(val)
|
52
|
-
per_qn = val / 4
|
53
|
-
@per_tick = 24 / per_qn
|
54
|
-
end
|
55
|
-
|
56
|
-
# Return the interval at which the tick event is fired
|
57
|
-
def interval
|
58
|
-
4 * (24 / @per_tick)
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def initialize_clock
|
64
|
-
@counter = 0
|
65
|
-
# Note that this doesn't wait for a start signal
|
66
|
-
@clock.listen_for(:name => "Clock") do |msg|
|
67
|
-
(stop and return) if @events.stop?
|
68
|
-
@events.do_midi_clock # thru
|
69
|
-
@tempo_calculator.timestamps << msg[:timestamp]
|
70
|
-
if @counter.eql?(@per_tick)
|
71
|
-
@events.do_tick
|
72
|
-
@counter = 0
|
73
|
-
else
|
74
|
-
@counter += 1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|