midi-topaz 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,12 +3,13 @@ module Topaz
3
3
 
4
4
  # trigger an event based on received midi clock messages
5
5
  class ExternalMIDITempo
6
+
7
+ include TempoSource
6
8
 
7
- attr_accessor :action
8
9
  attr_reader :clock
9
10
 
10
- def initialize(input, options = {})
11
- @action = options[:action]
11
+ def initialize(actions, input, options = {})
12
+ @actions = actions
12
13
  self.interval = options[:interval] || 4
13
14
  @tempo_calculator = TempoCalculator.new
14
15
  @clock = MIDIEye::Listener.new(input)
@@ -21,14 +22,12 @@ module Topaz
21
22
  @tempo_calculator.find_tempo
22
23
  end
23
24
 
24
- def start(*a)
25
- @action[:on_start].call unless @action[:on_start].nil?
25
+ def start(*a)
26
26
  @clock.start(*a)
27
27
  self
28
28
  end
29
29
 
30
30
  def stop(*a)
31
- @action[:on_stop].call unless @action[:on_stop].nil?
32
31
  @clock.start(*a)
33
32
  self
34
33
  end
@@ -61,17 +60,12 @@ module Topaz
61
60
 
62
61
  def initialize_clock
63
62
  @counter = 0
64
- @clock.listen_for(:name => "Clock") do |msg|
65
- if !@action[:stop_when].nil? && @action[:stop_when].call
66
- stop
67
- return
68
- end
69
- @action[:destinations].each do |output|
70
- output.on_tick
71
- end
63
+ @clock.listen_for(:name => "Clock") do |msg|
64
+ (stop and return) if stop?
65
+ do_midi_clock
72
66
  @tempo_calculator.timestamps << msg[:timestamp]
73
67
  if @counter.eql?(@per_tick)
74
- @action[:on_tick].call
68
+ do_tick
75
69
  @counter = 0
76
70
  else
77
71
  @counter += 1
@@ -3,12 +3,13 @@ module Topaz
3
3
 
4
4
  class InternalTempo < Gamelan::Timer
5
5
 
6
+ include TempoSource
7
+
6
8
  attr_accessor :action
7
9
 
8
- def initialize(tempo, options = {})
9
- @action = options[:action]
10
+ def initialize(actions, tempo, options = {})
11
+ @actions = actions
10
12
  self.interval = options[:interval] || 4
11
- @destinations = options[:destinations]
12
13
  @last = 0
13
14
  @last_sync = 0
14
15
  super({:tempo => tempo})
@@ -17,7 +18,6 @@ module Topaz
17
18
  # start the internal timer
18
19
  # pass :background => true to keep the timer in a background thread
19
20
  def start(options = {})
20
- @action[:on_start].call unless @action[:on_start].nil?
21
21
  run
22
22
  join unless options[:background]
23
23
  self
@@ -34,7 +34,6 @@ module Topaz
34
34
 
35
35
  # stop the timer
36
36
  def stop(*a)
37
- @action[:on_stop].call unless @action[:on_stop].nil?
38
37
  super()
39
38
  self
40
39
  end
@@ -49,21 +48,28 @@ module Topaz
49
48
  # Run all ready tasks.
50
49
  def dispatch
51
50
  # stuff to do on every tick
52
- unless @last_sync.eql?((@phase * 24).to_i)
51
+ if time_for_midi_clock?
53
52
  # look for stop
54
- if !@action[:stop_when].nil? && @action[:stop_when].call
55
- stop
56
- return
57
- end
58
- @action[:destinations].each { |dest| dest.on_tick }
53
+ (stop and return) if stop?
54
+ do_midi_clock
59
55
  @last_sync = (@phase * 24).to_i
60
56
  end
61
57
  # stuff to do on @interval
62
- unless @last.eql?((@phase * @interval).to_i)
63
- @action[:on_tick].call
58
+ if time_for_tick?
59
+ do_tick
64
60
  @last = (@phase * @interval).to_i
65
61
  end
66
62
  end
63
+
64
+ private
65
+
66
+ def time_for_midi_clock?
67
+ !@last_sync.eql?((@phase * 24).to_i)
68
+ end
69
+
70
+ def time_for_tick?
71
+ !@last.eql?((@phase * @interval).to_i)
72
+ end
67
73
 
68
74
  end
69
75
 
@@ -9,17 +9,17 @@ module Topaz
9
9
  end
10
10
 
11
11
  # send a start message
12
- def on_start
12
+ def start(*a)
13
13
  @output.puts(MIDIMessage::SystemRealtime["Start"].new.to_a)
14
14
  end
15
15
 
16
16
  # send a stop message
17
- def on_stop
17
+ def stop(*a)
18
18
  @output.puts(MIDIMessage::SystemRealtime["Stop"].new.to_a)
19
19
  end
20
20
 
21
21
  # send a clock message
22
- def on_tick
22
+ def midi_clock(*a)
23
23
  @output.puts(MIDIMessage::SystemRealtime["Clock"].new.to_a)
24
24
  end
25
25
 
data/lib/topaz/tempo.rb CHANGED
@@ -6,27 +6,30 @@ module Topaz
6
6
 
7
7
  extend Forwardable
8
8
 
9
- attr_reader :source
9
+ attr_reader :source, :destinations
10
10
 
11
11
  def_delegators :source, :tempo, :interval, :interval=, :join
12
12
 
13
13
  def initialize(*args, &event)
14
- @destinations = []
14
+ @destinations = []
15
+ @actions = {
16
+ :start => nil,
17
+ :stop => nil,
18
+ :tick => nil,
19
+ :midi_clock => Proc.new { @destinations.each { |d| d.send(:midi_clock) if d.respond_to?(:midi_clock) } },
20
+ :stop_when => nil
21
+ }
22
+
23
+ on_tick(&event)
15
24
 
16
25
  if args.first.kind_of?(Numeric)
17
- @source = InternalTempo.new(args.shift)
26
+ @source = InternalTempo.new(@actions, args.shift)
18
27
  end
19
28
  options = args.first
20
29
 
21
30
  initialize_midi_io(options)
22
31
  raise "You must specify an internal tempo rate or an external tempo source" if @source.nil?
23
- @source.action = {
24
- :on_start => nil,
25
- :on_stop => nil,
26
- :on_tick => event,
27
- :destinations => @destinations,
28
- :stop_when => nil
29
- }
32
+
30
33
  @source.interval = options[:interval] unless options.nil? || options[:interval].nil?
31
34
  end
32
35
 
@@ -45,22 +48,26 @@ module Topaz
45
48
 
46
49
  # pass in a callback that is called when start is called
47
50
  def on_start(&block)
48
- @source.action[:on_start] = block
51
+ @actions[:start] = block
49
52
  end
50
53
 
51
54
  # pass in a callback that is called when stop is called
52
55
  def on_stop(&block)
53
- @source.action[:on_stop] = block
56
+ @actions[:stop] = block
54
57
  end
55
58
 
56
59
  # pass in a callback which will
57
60
  def stop_when(&block)
58
- @source.action[:stop_when] = block
61
+ @actions[:stop_when] = block
59
62
  end
60
63
 
61
64
  # pass in a callback which will be fired on each tick
62
65
  def on_tick(&block)
63
- @source.action[:on_tick] = block
66
+ proc = Proc.new do |dests|
67
+ @destinations.each { |d| d.send(:tick) if d.respond_to?(:tick) }
68
+ yield
69
+ end
70
+ @actions[:tick] = proc
64
71
  end
65
72
 
66
73
  # this will start the generator
@@ -70,14 +77,16 @@ module Topaz
70
77
  #
71
78
  def start(options = {})
72
79
  @start_time = Time.now
73
- @destinations.each { |dest| dest.on_start }
74
- @source.start(options)
80
+ @destinations.each { |dest| dest.start(:parent => self) }
81
+ @source.start(options) if options[:parent].nil?
82
+ @actions[:start].call unless @actions[:start].nil?
75
83
  end
76
84
 
77
85
  # this will stop tempo
78
86
  def stop(options = {})
79
- @destinations.each { |dest| dest.on_stop }
80
- @source.stop(options)
87
+ @destinations.each { |dest| dest.stop(:parent => self) }
88
+ @source.stop(options) if options[:parent].nil?
89
+ @actions[:stop].call unless @actions[:stop].nil?
81
90
  @start_time = nil
82
91
  end
83
92
 
@@ -87,6 +96,19 @@ module Topaz
87
96
  end
88
97
  alias_method :time_since_start, :time
89
98
 
99
+ # add a destination
100
+ # accepts MIDISyncOutput or another Tempo object
101
+ def add_destination(tempo)
102
+ @destinations << tempo
103
+ end
104
+ alias_method :<<, :add_destination
105
+
106
+ protected
107
+
108
+ def tick
109
+ @actions[:tick].call
110
+ end
111
+
90
112
  private
91
113
 
92
114
  def initialize_midi_io(args)
@@ -95,7 +117,7 @@ module Topaz
95
117
  if ports.kind_of?(Array)
96
118
  ports.each { |port| initialize_midi_io(port) }
97
119
  elsif ports.type.eql?(:input) && @source.nil?
98
- @source = ExternalMIDITempo.new(ports)
120
+ @source = ExternalMIDITempo.new(@actions, ports)
99
121
  elsif ports.type.eql?(:output)
100
122
  @destinations << MIDISyncOutput.new(ports)
101
123
  end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ module Topaz
3
+
4
+ module TempoSource
5
+
6
+ def do_midi_clock
7
+ @actions[:midi_clock].call
8
+ end
9
+
10
+ def do_tick
11
+ @actions[:tick].call
12
+ end
13
+
14
+ def stop?
15
+ !@actions[:stop_when].nil? && @actions[:stop_when].call
16
+ end
17
+
18
+ end
19
+
20
+ end
data/lib/topaz.rb CHANGED
@@ -9,6 +9,7 @@ require 'gamelan'
9
9
  require 'midi-eye'
10
10
  require 'midi-message'
11
11
 
12
+ require 'topaz/tempo_source'
12
13
  require 'topaz/external_midi_tempo'
13
14
  require 'topaz/internal_tempo'
14
15
  require 'topaz/midi_sync_output'
@@ -17,6 +18,6 @@ require 'topaz/tempo'
17
18
 
18
19
  module Topaz
19
20
 
20
- VERSION = "0.0.4"
21
+ VERSION = "0.0.5"
21
22
 
22
23
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: midi-topaz
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.4
5
+ version: 0.0.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ari Russo
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-23 00:00:00 -04:00
13
+ date: 2011-06-25 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -71,6 +71,7 @@ files:
71
71
  - lib/topaz/midi_sync_output.rb
72
72
  - lib/topaz/internal_tempo.rb
73
73
  - lib/topaz/tempo_calculator.rb
74
+ - lib/topaz/tempo_source.rb
74
75
  - lib/topaz/external_midi_tempo.rb
75
76
  - lib/topaz/tempo.rb
76
77
  - test/helper.rb