mmplayer 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b444046bc6129a272ad1354fd79e0226d3fed0f6
4
- data.tar.gz: 7a58cbaec278585178e5ea420e3be977711a5f65
3
+ metadata.gz: eaf5bf960208966f12d484c199d7146229f81f4f
4
+ data.tar.gz: dc4d8cfbaa2f8554e5f9bd97cbc05be74482f75c
5
5
  SHA512:
6
- metadata.gz: 7d73ce2e7db56b04f05bde2ce3a713a0b15cb6ed37f944d6d9de8d45859ad6e70265c3f818056aa6e5e8b70f536ae64f265301e39b2986829c0f7080b26ba2aa
7
- data.tar.gz: 137bf592cad461210938a051ffad361b48019a55d87a788f76a48bdde80cd767c3729238fcb9c983c5094e44337bef934a13eeed852d1a57799e1ab483eb6689
6
+ metadata.gz: c269438f243f8a018f7382a39eecf518308162cfc27c27cf3dbda806fe2b9f0cf3a4c0b83533279b5a755305ab76f6f15352a5bac2f1af2471f9e0ed4f5bf6a6
7
+ data.tar.gz: 7d0dc1ca64157413bb42910dcbf7001e1ea874b074090c7125bf353b3bd817b4d559000de3193ba50b41bb29f28c7c1fc6459aec40076f64c60cacb350188002
data/README.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  Control [MPlayer](http://en.wikipedia.org/wiki/MPlayer) with MIDI
6
6
 
7
+ MPlayer is a free, cross-platform, command-line driven, highly configurable, (often) GUI-less open-source media player.
8
+
9
+ Enabling MPlayer to be controlled by MIDI opens up a host of possibilities for live video performance, media automation and more
10
+
11
+ This project provides a Ruby DSL to define realtime interactions between MIDI input and MPlayer
12
+
7
13
  ## Install
8
14
 
9
15
  You'll need to install MPlayer before using this. That can usually be accomplished with a package manager eg `brew install mplayer` depending on what OS you're using.
@@ -18,8 +24,6 @@ Or if you're using Bundler, add this to your Gemfile
18
24
 
19
25
  ## Usage
20
26
 
21
- MMplayer provides a Ruby DSL to define interactions between MIDI input and MPlayer
22
-
23
27
  ```ruby
24
28
  require "mmplayer"
25
29
 
@@ -47,9 +51,7 @@ An annotated breakdown of this example can be found [here](https://github.com/ar
47
51
 
48
52
  [The MPlayer Man Page](http://www.mplayerhq.hu/DOCS/man/en/mplayer.1.html#GENERAL OPTIONS) has a full list of MPlayer startup flags
49
53
 
50
- All MPlayer runtime commands enabled by the [mplayer-ruby](https://rubygems.org/gems/mplayer-ruby) project are available here too. (eg `seek` and `volume` in the example above)
51
-
52
- [The RDOC for mplayer-ruby](http://mplayer-ruby.rubyforge.org/mplayer-ruby/index.html) has a full list of runtime commands
54
+ All MPlayer runtime commands enabled by the [mplayer-ruby](https://rubygems.org/gems/mplayer-ruby) project are available here too. (eg `seek` and `volume` in the example above). [The RDOC for mplayer-ruby](http://mplayer-ruby.rubyforge.org/mplayer-ruby/index.html) has a full list of runtime commands
53
55
 
54
56
  ##Author
55
57
 
@@ -18,12 +18,13 @@ require "mmplayer/instructions/player"
18
18
 
19
19
  # classes
20
20
  require "mmplayer/context"
21
+ require "mmplayer/message_handler"
21
22
  require "mmplayer/midi"
22
23
  require "mmplayer/player"
23
24
 
24
25
  module MMPlayer
25
26
 
26
- VERSION = "0.0.1"
27
+ VERSION = "0.0.2"
27
28
 
28
29
  # Shortcut to Context constructor
29
30
  def self.new(*args, &block)
@@ -0,0 +1,84 @@
1
+ module MMPlayer
2
+
3
+ # Directs what should happen when messages are received
4
+ class MessageHandler
5
+
6
+ attr_reader :callback
7
+
8
+ def initialize
9
+ @callback = {
10
+ :cc => {},
11
+ :note => {},
12
+ :system => {}
13
+ }
14
+ end
15
+
16
+ # Add a callback for a given MIDI system message type
17
+ # @param [Symbol] type The MIDI message type (eg :note, :cc)
18
+ # @param [String, Symbol] key
19
+ # @param [Proc] callback The callback to execute when the given MIDI command is received
20
+ # @return [Hash]
21
+ def add_callback(type, key, &callback)
22
+ @callback[type][key] = callback
23
+ @callback[type]
24
+ end
25
+
26
+ # Process a message for the given channel
27
+ # @param [Fixnum, nil] channel
28
+ # @param [MIDIMessage] message
29
+ # @return [Boolean, nil]
30
+ def process(channel, message)
31
+ case message
32
+ when MIDIMessage::SystemRealtime then system_message(message)
33
+ else
34
+ channel_message(channel, message)
35
+ end
36
+ end
37
+
38
+ # Find and call a note received callback if it exists
39
+ # @param [MIDIMessage] message
40
+ # @return [Boolean, nil]
41
+ def note_message(message)
42
+ unless (callback = @callback[:note][message.note] || @callback[:note][message.name]).nil?
43
+ callback.call(message.velocity)
44
+ true
45
+ end
46
+ end
47
+
48
+ # Find and call a cc received callback if it exists
49
+ # @param [MIDIMessage] message
50
+ # @return [Boolean, nil]
51
+ def cc_message(message)
52
+ unless (callback = @callback[:cc][message.index] || @callback[:cc][message.name]).nil?
53
+ callback.call(message.value)
54
+ true
55
+ end
56
+ end
57
+
58
+ # Find and call a system message callback if it exists
59
+ # @param [MIDIMessage] message
60
+ # @return [Boolean, nil]
61
+ def system_message(message)
62
+ name = message.name.downcase.to_sym
63
+ unless (callback = @callback[:system][name]).nil?
64
+ callback.call
65
+ true
66
+ end
67
+ end
68
+
69
+ # Find and call a channel message callback if it exists for the given message and channel
70
+ # @param [Fixnum, nil] channel
71
+ # @param [MIDIMessage] message
72
+ # @return [Boolean, nil]
73
+ def channel_message(channel, message)
74
+ if channel.nil? || message.channel == channel
75
+ case message
76
+ when MIDIMessage::NoteOn then note_message(message)
77
+ when MIDIMessage::ControlChange then cc_message(message)
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -3,18 +3,14 @@ module MMPlayer
3
3
  # Wrapper for MIDI functionality
4
4
  class MIDI
5
5
 
6
- attr_reader :channel, :config, :listener
6
+ attr_reader :channel, :config, :listener, :message_handler
7
7
 
8
8
  # @param [UniMIDI::Input] input
9
9
  # @param [Hash] options
10
10
  # @option options [Fixnum] :receive_channel A MIDI channel to subscribe to. By default, responds to all
11
11
  def initialize(input, options = {})
12
12
  @channel = options[:receive_channel]
13
- @config = {
14
- :cc => {},
15
- :note => {},
16
- :system => {}
17
- }
13
+ @message_handler = MessageHandler.new
18
14
  @listener = MIDIEye::Listener.new(input)
19
15
  end
20
16
 
@@ -23,8 +19,7 @@ module MMPlayer
23
19
  # @param [Proc] callback The callback to execute when the given MIDI command is received
24
20
  # @return [Hash]
25
21
  def add_system_callback(command, &callback)
26
- @config[:system][command] = callback
27
- @config[:system]
22
+ @message_handler.add_callback(:system, command, &callback)
28
23
  end
29
24
 
30
25
  # Add a callback for a given MIDI note
@@ -32,8 +27,7 @@ module MMPlayer
32
27
  # @param [Proc] callback The callback to execute when the given MIDI note is received
33
28
  # @return [Hash]
34
29
  def add_note_callback(note, &callback)
35
- @config[:note][note] = callback
36
- @config[:note]
30
+ @message_handler.add_callback(:note, note, &callback)
37
31
  end
38
32
 
39
33
  # Add a callback for a given MIDI control change
@@ -41,8 +35,7 @@ module MMPlayer
41
35
  # @param [Proc] callback The callback to execute when the given MIDI control change is received
42
36
  # @return [Hash]
43
37
  def add_cc_callback(index, &callback)
44
- @config[:cc][index] = callback
45
- @config[:cc]
38
+ @message_handler.add_callback(:cc, index, &callback)
46
39
  end
47
40
 
48
41
  # Stop the MIDI listener
@@ -69,35 +62,20 @@ module MMPlayer
69
62
  true
70
63
  end
71
64
 
65
+ # Whether the player is subscribed to all channels
66
+ # @return [Boolean]
67
+ def omni?
68
+ @channel.nil?
69
+ end
70
+
72
71
  private
73
72
 
74
- # Populate the MIDI listener events
73
+ # Populate the MIDI listener callback
75
74
  def populate_listener
76
- # Channel messages
77
- listener_options = {}
78
- # omni by default
79
- listener_options[:channel] = @channel unless @channel.nil?
80
- @listener.on_message(listener_options.merge(:class => MIDIMessage::NoteOn)) do |event|
81
- message = event[:message]
82
- unless (callback = @config[:note][message.note] || @config[:note][message.name]).nil?
83
- callback.call(message.velocity)
84
- end
85
- end
86
- @listener.on_message(listener_options.merge(:class => MIDIMessage::ControlChange)) do |event|
87
- message = event[:message]
88
- unless (callback = @config[:cc][message.index] || @config[:cc][message.name]).nil?
89
- callback.call(message.value)
90
- end
91
- end
92
- # Short messages
93
- @listener.on_message(:class => MIDIMessage::SystemRealtime) do |event|
75
+ @listener.on_message do |event|
94
76
  message = event[:message]
95
- name = message.name.downcase.to_sym
96
- unless (callback = @config[:system][name]).nil?
97
- callback.call
98
- end
77
+ @message_handler.process(@channel, message)
99
78
  end
100
- true
101
79
  end
102
80
 
103
81
  end
@@ -6,9 +6,9 @@ module MMPlayer
6
6
  # @param [Hash] options
7
7
  # @option options [String] :flags MPlayer command-line flags to use on startup
8
8
  def initialize(options = {})
9
- @mplayer_messages = []
10
9
  @flags = "-fixed-vo -idle"
11
10
  @flags += " #{options[:flags]}" unless options[:flags].nil?
11
+ @messenger = Messenger.new
12
12
  end
13
13
 
14
14
  # Play a media file
@@ -51,7 +51,7 @@ module MMPlayer
51
51
  if @player.nil? && MPlayer::Slave.method_defined?(method)
52
52
  # warn
53
53
  else
54
- send_mplayer_message { @player.send(method, *args, &block) }
54
+ @messenger.send_message { @player.send(method, *args, &block) }
55
55
  end
56
56
  end
57
57
 
@@ -59,7 +59,7 @@ module MMPlayer
59
59
  # @return [Boolean]
60
60
  def mplayer_respond_to?(method, include_private = false)
61
61
  (@player.nil? && MPlayer::Slave.method_defined?(method)) ||
62
- @player.respond_to?(method)
62
+ @player.respond_to?(method)
63
63
  end
64
64
 
65
65
  # Cause MPlayer to exit
@@ -72,32 +72,6 @@ module MMPlayer
72
72
 
73
73
  private
74
74
 
75
- # Sweep for leftover/hanging message threads
76
- def sweep_messages
77
- if @mplayer_messages.empty?
78
- false
79
- else
80
- sleep(0.01)
81
- @mplayer_messages.each(&:kill)
82
- true
83
- end
84
- end
85
-
86
- # Send mplayer a message async
87
- def send_mplayer_message(&block)
88
- sweep_messages
89
- thread = Thread.new do
90
- begin
91
- yield
92
- rescue Exception => exception
93
- Thread.main.raise(exception)
94
- end
95
- end
96
- thread.abort_on_exception = true
97
- @mplayer_messages << thread
98
- thread
99
- end
100
-
101
75
  # Get progress percentage from the MPlayer report
102
76
  def get_percentage(report)
103
77
  percent = (report[:position] / report[:length]) * 100
@@ -107,7 +81,7 @@ module MMPlayer
107
81
  # Poll MPlayer for progress information
108
82
  def poll_mplayer_progress
109
83
  time = nil
110
- send_mplayer_message do
84
+ @messenger.send_message do
111
85
  time = {
112
86
  :length => get_mplayer_float("time_length"),
113
87
  :position => get_mplayer_float("time_pos")
@@ -125,7 +99,7 @@ module MMPlayer
125
99
  # @param [String] file The media file to invoke MPlayer with
126
100
  # @return [MPlayer::Slave]
127
101
  def ensure_player(file)
128
- if @player.nil?
102
+ if @player.nil? && @player_thread.nil?
129
103
  @player_thread = Thread.new do
130
104
  begin
131
105
  @player = MPlayer::Slave.new(file, :options => @flags)
@@ -137,6 +111,57 @@ module MMPlayer
137
111
  end
138
112
  end
139
113
 
114
+ # Handle sending MPlayer messages
115
+ class Messenger
116
+
117
+ FREQUENCY_LIMIT = 0.1 # Throttle messages to 1 per this number seconds
118
+
119
+ def initialize
120
+ @messages = []
121
+ end
122
+
123
+ # Send mplayer a message asynch
124
+ # @return [Hash, nil]
125
+ def send_message(&block)
126
+ timestamp = Time.now.to_f
127
+ if @messages.empty? || !throttle?(timestamp, @messages.last[:timestamp])
128
+ thread = Thread.new do
129
+ begin
130
+ yield
131
+ rescue Exception => exception
132
+ Thread.main.raise(exception)
133
+ end
134
+ end
135
+ thread.abort_on_exception = true
136
+ record_message(thread, timestamp)
137
+ end
138
+ end
139
+
140
+ private
141
+
142
+ # Should adding a message be throttled for the given timestamp?
143
+ # @param [Float] timestamp
144
+ # @param [Float] last_timestamp
145
+ # @return [Boolean]
146
+ def throttle?(timestamp, last_timestamp)
147
+ timestamp - last_timestamp <= FREQUENCY_LIMIT
148
+ end
149
+
150
+ # Record that a message has been sent
151
+ # @param [Thread] thread
152
+ # @param [Float] timestamp
153
+ # @return [Hash]
154
+ def record_message(thread, timestamp)
155
+ message = {
156
+ :thread => thread,
157
+ :timestamp => timestamp
158
+ }
159
+ @messages << message
160
+ message
161
+ end
162
+
163
+ end
164
+
140
165
  end
141
166
 
142
167
  end
@@ -22,7 +22,7 @@ class MMPlayer::ContextTest < Minitest::Test
22
22
  context "#start" do
23
23
 
24
24
  setup do
25
- @context.midi.listener.expects(:on_message).times(3)
25
+ @context.midi.listener.expects(:on_message).once
26
26
  @context.midi.listener.expects(:start).once
27
27
  end
28
28
 
@@ -33,7 +33,7 @@ class MMPlayer::ContextTest < Minitest::Test
33
33
 
34
34
  should "activate player" do
35
35
  assert @context.start(:background => true)
36
- @context.stop
36
+ assert @context.stop
37
37
  end
38
38
 
39
39
  end
@@ -41,7 +41,7 @@ class MMPlayer::ContextTest < Minitest::Test
41
41
  context "#stop" do
42
42
 
43
43
  setup do
44
- @context.midi.listener.expects(:on_message).times(3)
44
+ @context.midi.listener.expects(:on_message).once
45
45
  @context.midi.listener.expects(:start).once
46
46
  @context.midi.listener.expects(:stop).once
47
47
  @context.player.expects(:quit).once
@@ -55,7 +55,7 @@ class MMPlayer::ContextTest < Minitest::Test
55
55
  end
56
56
 
57
57
  should "stop player" do
58
- @context.stop
58
+ assert @context.stop
59
59
  end
60
60
 
61
61
  end
@@ -0,0 +1,254 @@
1
+ require "helper"
2
+
3
+ class MMPlayer::MessageHandlerTest < Minitest::Test
4
+
5
+ context "MessageHandler" do
6
+
7
+ setup do
8
+ @handler = MMPlayer::MessageHandler.new
9
+ end
10
+
11
+ context "#note_message" do
12
+
13
+ setup do
14
+ @message = MIDIMessage::NoteOn.new(0, 10, 100)
15
+ end
16
+
17
+ context "callback exists" do
18
+
19
+ setup do
20
+ @var = nil
21
+ @callback = proc { |vel| @var = vel }
22
+ @handler.add_callback(:note, @message.note, &@callback)
23
+ @callback.expects(:call).once
24
+ end
25
+
26
+ teardown do
27
+ @callback.unstub(:call)
28
+ end
29
+
30
+ should "call callback" do
31
+ assert @handler.send(:note_message, @message)
32
+ end
33
+
34
+ end
35
+
36
+ context "callback doesn't exist" do
37
+
38
+ should "do nothing" do
39
+ refute @handler.send(:note_message, @message)
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ context "#cc_message" do
47
+
48
+ setup do
49
+ @message = MIDIMessage::ControlChange.new(0, 8, 100)
50
+ end
51
+
52
+ context "callback exists" do
53
+
54
+ setup do
55
+ @var = nil
56
+ @callback = proc { |vel| @var = vel }
57
+ @handler.add_callback(:cc, @message.index, &@callback)
58
+ @callback.expects(:call).once
59
+ end
60
+
61
+ teardown do
62
+ @callback.unstub(:call)
63
+ end
64
+
65
+ should "call callback" do
66
+ assert @handler.send(:cc_message, @message)
67
+ end
68
+
69
+ end
70
+
71
+ context "callback doesn't exist" do
72
+
73
+ should "do nothing" do
74
+ refute @handler.send(:cc_message, @message)
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ context "#system_message" do
82
+
83
+ setup do
84
+ @message = MIDIMessage::SystemRealtime.new(0x8) # clock
85
+ end
86
+
87
+ context "callback exists" do
88
+
89
+ setup do
90
+ @var = nil
91
+ @callback = proc { |vel| @var = vel }
92
+ @handler.add_callback(:system, :clock, &@callback)
93
+ @callback.expects(:call).once
94
+ end
95
+
96
+ teardown do
97
+ @callback.unstub(:call)
98
+ end
99
+
100
+ should "call callback" do
101
+ assert @handler.send(:system_message, @message)
102
+ end
103
+
104
+ end
105
+
106
+ context "callback doesn't exist" do
107
+
108
+ should "do nothing" do
109
+ refute @handler.send(:system_message, @message)
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ context "#channel_message" do
117
+
118
+ context "omni" do
119
+
120
+ setup do
121
+ @channel = nil
122
+ end
123
+
124
+ context "control change" do
125
+
126
+ setup do
127
+ @message = MIDIMessage::ControlChange.new(0, 8, 100)
128
+ @handler.expects(:cc_message).once.with(@message).returns(true)
129
+ end
130
+
131
+ teardown do
132
+ @handler.unstub(:cc_message)
133
+ end
134
+
135
+ should "handle control change" do
136
+ assert @handler.send(:channel_message, @channel, @message)
137
+ end
138
+
139
+ end
140
+
141
+ context "note" do
142
+
143
+ setup do
144
+ @message = MIDIMessage::NoteOn.new(0, 10, 100)
145
+ @handler.expects(:note_message).once.with(@message).returns(true)
146
+ end
147
+
148
+ teardown do
149
+ @handler.unstub(:note_message)
150
+ end
151
+
152
+ should "handle note" do
153
+ assert @handler.send(:channel_message, @channel, @message)
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ context "with channel" do
161
+
162
+ setup do
163
+ @channel = 5
164
+ end
165
+
166
+ context "control change" do
167
+
168
+ setup do
169
+ @message = MIDIMessage::ControlChange.new(@channel, 8, 100)
170
+ end
171
+
172
+ context "matching channel" do
173
+
174
+ setup do
175
+ @handler.expects(:cc_message).once.with(@message).returns(true)
176
+ end
177
+
178
+ teardown do
179
+ @handler.unstub(:cc_message)
180
+ end
181
+
182
+ should "handle control change" do
183
+ assert @handler.send(:channel_message, @channel, @message)
184
+ end
185
+
186
+ end
187
+
188
+ context "non matching channel" do
189
+
190
+ setup do
191
+ @handler.expects(:cc_message).never
192
+ @other_message = MIDIMessage::ControlChange.new(@channel + 1, 8, 100)
193
+ end
194
+
195
+ teardown do
196
+ @handler.unstub(:cc_message)
197
+ end
198
+
199
+ should "do nothing" do
200
+ refute @handler.send(:channel_message, @channel, @other_message)
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+
207
+ context "note" do
208
+
209
+ setup do
210
+ @message = MIDIMessage::NoteOn.new(@channel, 10, 100)
211
+ end
212
+
213
+ context "matching channel" do
214
+
215
+ setup do
216
+ @handler.expects(:note_message).once.with(@message).returns(true)
217
+ end
218
+
219
+ teardown do
220
+ @handler.unstub(:note_message)
221
+ end
222
+
223
+ should "call callback" do
224
+ assert @handler.send(:channel_message, @channel, @message)
225
+ end
226
+
227
+ end
228
+
229
+ context "non matching channel" do
230
+
231
+ setup do
232
+ @handler.expects(:note_message).never
233
+ @other_message = MIDIMessage::ControlChange.new(@channel + 1, 8, 100)
234
+ end
235
+
236
+ teardown do
237
+ @handler.unstub(:note_message)
238
+ end
239
+
240
+ should "not call callback" do
241
+ refute @handler.send(:channel_message, @channel, @other_message)
242
+ end
243
+
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ end
@@ -12,7 +12,7 @@ class MMPlayer::MIDITest < Minitest::Test
12
12
  context "#start" do
13
13
 
14
14
  setup do
15
- @midi.listener.expects(:on_message).times(3)
15
+ @midi.listener.expects(:on_message).once
16
16
  @midi.listener.expects(:start).once
17
17
  end
18
18
 
@@ -35,8 +35,8 @@ class MMPlayer::MIDITest < Minitest::Test
35
35
  end
36
36
 
37
37
  should "store callback" do
38
- refute_nil @midi.config[:note][10]
39
- assert_equal Proc, @midi.config[:note][10].class
38
+ refute_nil @midi.message_handler.callback[:note][10]
39
+ assert_equal Proc, @midi.message_handler.callback[:note][10].class
40
40
  end
41
41
 
42
42
  end
@@ -49,8 +49,8 @@ class MMPlayer::MIDITest < Minitest::Test
49
49
  end
50
50
 
51
51
  should "store callback" do
52
- refute_nil @midi.config[:system][:start]
53
- assert_equal Proc, @midi.config[:system][:start].class
52
+ refute_nil @midi.message_handler.callback[:system][:start]
53
+ assert_equal Proc, @midi.message_handler.callback[:system][:start].class
54
54
  end
55
55
 
56
56
  end
@@ -63,8 +63,8 @@ class MMPlayer::MIDITest < Minitest::Test
63
63
  end
64
64
 
65
65
  should "store callback" do
66
- refute_nil @midi.config[:cc][2]
67
- assert_equal Proc, @midi.config[:cc][2].class
66
+ refute_nil @midi.message_handler.callback[:cc][2]
67
+ assert_equal Proc, @midi.message_handler.callback[:cc][2].class
68
68
  end
69
69
 
70
70
  end
@@ -96,11 +96,13 @@ class MMPlayer::MIDITest < Minitest::Test
96
96
  should "change channel" do
97
97
  assert_equal 3, @midi.channel = 3
98
98
  assert_equal 3, @midi.channel
99
+ refute @midi.omni?
99
100
  end
100
101
 
101
102
  should "set channel nil" do
102
103
  assert_equal nil, @midi.channel = nil
103
104
  assert_nil @midi.channel
105
+ assert @midi.omni?
104
106
  end
105
107
  end
106
108
 
@@ -109,17 +111,19 @@ class MMPlayer::MIDITest < Minitest::Test
109
111
  setup do
110
112
  @listener.stubs(:running?).returns(true)
111
113
  @listener.expects(:clear).once
112
- @listener.expects(:on_message).times(3)
114
+ @listener.expects(:on_message).once
113
115
  end
114
116
 
115
117
  should "change channel" do
116
118
  assert_equal 3, @midi.channel = 3
117
119
  assert_equal 3, @midi.channel
120
+ refute @midi.omni?
118
121
  end
119
122
 
120
123
  should "set channel nil" do
121
124
  assert_equal nil, @midi.channel = nil
122
125
  assert_nil @midi.channel
126
+ assert @midi.omni?
123
127
  end
124
128
 
125
129
  end
@@ -127,4 +131,5 @@ class MMPlayer::MIDITest < Minitest::Test
127
131
  end
128
132
 
129
133
  end
134
+
130
135
  end
@@ -120,6 +120,24 @@ class MMPlayer::PlayerTest < Minitest::Test
120
120
 
121
121
  end
122
122
 
123
+ context "Messenger" do
124
+
125
+ context "#throttle?" do
126
+
127
+ setup do
128
+ @messenger = MMPlayer::Player::Messenger.new
129
+ @limit = MMPlayer::Player::Messenger::FREQUENCY_LIMIT
130
+ end
131
+
132
+ should "respect message frequency" do
133
+ assert @messenger.send(:throttle?, 1234, 1234 - @limit / 2)
134
+ refute @messenger.send(:throttle?, 1234, 1234 - @limit * 2)
135
+ end
136
+
137
+ end
138
+
139
+ end
140
+
123
141
  end
124
142
 
125
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mmplayer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ari Russo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-24 00:00:00.000000000 Z
11
+ date: 2015-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -204,6 +204,7 @@ files:
204
204
  - lib/mmplayer/helper/numbers.rb
205
205
  - lib/mmplayer/instructions/midi.rb
206
206
  - lib/mmplayer/instructions/player.rb
207
+ - lib/mmplayer/message_handler.rb
207
208
  - lib/mmplayer/midi.rb
208
209
  - lib/mmplayer/player.rb
209
210
  - test/context_test.rb
@@ -211,6 +212,7 @@ files:
211
212
  - test/helper/numbers_test.rb
212
213
  - test/instructions/midi_test.rb
213
214
  - test/instructions/player_test.rb
215
+ - test/message_handler_test.rb
214
216
  - test/midi_test.rb
215
217
  - test/player_test.rb
216
218
  homepage: http://github.com/arirusso/mmplayer