midi-topaz 0.0.4 → 0.0.5

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.
@@ -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