midi-topaz 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,88 +0,0 @@
1
- module Topaz
2
-
3
- class InternalTempo < Gamelan::Timer
4
-
5
- def initialize(events, tempo, options = {})
6
- @events = events
7
- @last = 0
8
- @last_sync = 0
9
- self.interval = options[:interval] || 4
10
-
11
- super({:tempo => tempo})
12
- end
13
-
14
- # start the internal timer
15
- # pass :background => true to keep the timer in a background thread
16
- def start(options = {})
17
- run
18
- join unless !!options[:background]
19
- self
20
- end
21
-
22
- # change the timer's click interval
23
- def interval=(val)
24
- @interval = val / 4
25
- end
26
-
27
- def interval
28
- @interval * 4
29
- end
30
-
31
- # stop the timer
32
- def stop(*a)
33
- super()
34
- self
35
- end
36
-
37
- def join
38
- super()
39
- self
40
- end
41
-
42
- protected
43
-
44
- # Initialize the scheduler's clock, and begin executing tasks.
45
- def run
46
- return if @running
47
- @running = true
48
- @thread = Thread.new do
49
- begin
50
- @phase = 0.0
51
- @origin = @time = Time.now.to_f
52
- loop { dispatch; advance }
53
- rescue Exception => exception
54
- Thread.main.raise(exception)
55
- end
56
- end
57
- @thread.abort_on_exception = true
58
- end
59
-
60
- # Run all ready tasks.
61
- def dispatch
62
- # stuff to do on every tick
63
- if time_for_midi_clock?
64
- # look for stop
65
- (stop and return) if @events.stop?
66
- @events.do_midi_clock
67
- @last_sync = (@phase * 24).to_i
68
- end
69
- # stuff to do on @interval
70
- if time_for_tick?
71
- @events.do_tick
72
- @last = (@phase * @interval).to_i
73
- end
74
- end
75
-
76
- private
77
-
78
- def time_for_midi_clock?
79
- !@last_sync.eql?((@phase * 24).to_i)
80
- end
81
-
82
- def time_for_tick?
83
- !@last.eql?((@phase * @interval).to_i)
84
- end
85
-
86
- end
87
-
88
- end
@@ -1,33 +0,0 @@
1
- module Topaz
2
-
3
- # Send clock messages via MIDI
4
- class MIDISyncOutput
5
-
6
- attr_reader :output
7
-
8
- def initialize(output)
9
- @output = output
10
- end
11
-
12
- # Send a start message
13
- def start(*a)
14
- start = MIDIMessage::SystemRealtime["Start"].new.to_a
15
- @output.puts(start)
16
- end
17
-
18
- # Send a stop message
19
- def stop(*a)
20
- p "hi"
21
- stop = MIDIMessage::SystemRealtime["Stop"].new.to_a
22
- @output.puts(stop)
23
- end
24
-
25
- # Send a clock tick message
26
- def clock(*a)
27
- clock = MIDIMessage::SystemRealtime["Clock"].new.to_a
28
- @output.puts(clock)
29
- end
30
-
31
- end
32
-
33
- end
data/lib/topaz/tempo.rb DELETED
@@ -1,164 +0,0 @@
1
- module Topaz
2
-
3
- # Main tempo class
4
- class Tempo
5
-
6
- extend Forwardable
7
-
8
- attr_reader :source, :destinations
9
-
10
- def_delegators :source, :tempo, :interval, :interval=, :join
11
-
12
- def initialize(tempo_or_input, options = {}, &tick_event)
13
- @paused = false
14
- @destinations = []
15
- @events = Events.new
16
-
17
- configure(tempo_or_input, options, &tick_event)
18
- end
19
-
20
- # Change the tempo
21
- #
22
- # Caution that in the case that external MIDI tempo is being used, this will switch to internal
23
- # tempo at the desired rate.
24
- #
25
- def tempo=(val)
26
- if @source.respond_to?(:tempo=)
27
- @source.tempo = val
28
- else
29
- @source = InternalTempo.new(@events, val)
30
- end
31
- end
32
-
33
- # Pause the clock
34
- def pause
35
- @pause = true
36
- end
37
-
38
- # Unpause the clock
39
- def unpause
40
- @pause = false
41
- end
42
-
43
- # Is this clock paused?
44
- def paused?
45
- @pause
46
- end
47
-
48
- # Toggle pausing the clock
49
- def toggle_pause
50
- paused? ? unpause : pause
51
- end
52
-
53
- # Pass in a callback that is called when start is called
54
- def on_start(&callback)
55
- @events.start[0] = callback
56
- end
57
-
58
- # pass in a callback that is called when stop is called
59
- def on_stop(&callback)
60
- @events.stop[0] = callback
61
- end
62
-
63
- # Pass in a callback which will stop the clock if it evaluates to true
64
- def stop_when(&callback)
65
- @events.stop_when = callback
66
- end
67
-
68
- # Pass in a callback which will be fired on each tick
69
- def on_tick(&callback)
70
- wrapper = proc do
71
- unless paused?
72
- yield
73
- end
74
- end
75
- @events.tick[0] = wrapper
76
- end
77
-
78
- # this will start the generator
79
- #
80
- # in the case that external midi tempo is being used, this will wait for a start
81
- # or clock message
82
- #
83
- def start(options = {})
84
- begin
85
- @start_time = Time.now
86
- @events.do_start
87
- @source.start(options)
88
- rescue SystemExit, Interrupt => exception
89
- stop
90
- end
91
- end
92
-
93
- # This will stop the clock
94
- def stop(options = {})
95
- @source.stop(options)
96
- @events.do_stop
97
- @start_time = nil
98
- end
99
-
100
- # Seconds since start was called
101
- def time
102
- (Time.now - @start_time).to_f unless @start_time.nil?
103
- end
104
- alias_method :time_since_start, :time
105
-
106
- # Add a destination
107
- # @param [Array<UniMIDI::Output>, UniMIDI::Output] destinations
108
- def add_destination(destinations)
109
- destinations = [destinations].flatten.compact
110
- destinations.each do |destination|
111
- output = MIDISyncOutput.new(destination)
112
- @destinations << output
113
- end
114
- end
115
-
116
- # Remove a destination
117
- # @param [Array<UniMIDI::Output>, UniMIDI::Output] destinations
118
- def remove_destination(destinations)
119
- destinations = [destinations].flatten.compact
120
- destinations.each do |output|
121
- @destinations.each do |sync_output|
122
- @destinations.delete(sync_output) if sync_output.output == output
123
- end
124
- end
125
- end
126
-
127
- private
128
-
129
- def initialize_destinations(midi_outputs)
130
- midi_outputs = [midi_outputs].flatten.compact
131
- midi_outputs.each do |output|
132
- add_destination(output)
133
- end
134
- end
135
-
136
- def initialize_midi_clock_output
137
- [:clock, :start, :stop].each do |event|
138
- action = proc do
139
- @destinations.each { |destination| destination.send(event) }
140
- end
141
- @events.send("midi_#{event.to_s}=", action)
142
- end
143
- end
144
-
145
- def initialize_tempo_source(tempo_or_input)
146
- @source = case tempo_or_input
147
- when Numeric then InternalTempo.new(@events, tempo_or_input)
148
- when UniMIDI::Input then ExternalMIDITempo.new(@events, tempo_or_input)
149
- else
150
- raise "You must specify an internal tempo rate or an external tempo source"
151
- end
152
- end
153
-
154
- def configure(tempo_or_input, options = {}, &tick_event)
155
- initialize_tempo_source(tempo_or_input)
156
- initialize_destinations(options[:midi]) unless options[:midi].nil?
157
- initialize_midi_clock_output
158
- @source.interval = options[:interval] unless options[:interval].nil?
159
- on_tick(&tick_event)
160
- end
161
-
162
- end
163
-
164
- end
data/test/config.rb DELETED
@@ -1,11 +0,0 @@
1
- module TestHelper::Config
2
-
3
- include UniMIDI
4
-
5
- # Adjust these constants to suit your hardware configuration
6
- # before running tests
7
-
8
- TestInput = Input.gets # this is the device you wish to use to test input
9
- TestOutput = Output.gets # likewise for output
10
-
11
- end
@@ -1,51 +0,0 @@
1
- require "helper"
2
-
3
- class InternalTempoTest < Test::Unit::TestCase
4
-
5
- include Topaz
6
- include TestHelper
7
-
8
- def test_stop_when
9
- i = 0
10
- count_to = 5
11
-
12
- tempo = Tempo.new(120) { i += 1 }
13
- tempo.stop_when { i.eql?(count_to) }
14
- tempo.start
15
-
16
- assert_equal(count_to, i)
17
- end
18
-
19
- def test_change_on_tick
20
- i = 0
21
- count_to = 5
22
-
23
- tempo = Tempo.new(120) { i += 1 }
24
- tempo.stop_when { i == count_to }
25
- tempo.start
26
-
27
- assert_equal(count_to, i)
28
-
29
- i = 0
30
- count_to = 1000
31
-
32
- tempo.on_tick { i += 100 }
33
- tempo.stop_when { i == count_to }
34
- tempo.start
35
-
36
- assert_equal(count_to, i)
37
-
38
-
39
- end
40
-
41
- def test_internal_interval
42
- tempo = Tempo.new(120)
43
-
44
- assert_equal(4, tempo.interval)
45
-
46
- tempo.interval = 8
47
-
48
- assert_equal(8, tempo.interval)
49
- end
50
-
51
- end