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 +4 -4
- data/README.md +7 -5
- data/lib/mmplayer.rb +2 -1
- data/lib/mmplayer/message_handler.rb +84 -0
- data/lib/mmplayer/midi.rb +14 -36
- data/lib/mmplayer/player.rb +56 -31
- data/test/context_test.rb +4 -4
- data/test/message_handler_test.rb +254 -0
- data/test/midi_test.rb +13 -8
- data/test/player_test.rb +18 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eaf5bf960208966f12d484c199d7146229f81f4f
|
4
|
+
data.tar.gz: dc4d8cfbaa2f8554e5f9bd97cbc05be74482f75c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
|
data/lib/mmplayer.rb
CHANGED
@@ -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.
|
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
|
data/lib/mmplayer/midi.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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
|
73
|
+
# Populate the MIDI listener callback
|
75
74
|
def populate_listener
|
76
|
-
|
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
|
-
|
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
|
data/lib/mmplayer/player.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/context_test.rb
CHANGED
@@ -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).
|
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).
|
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
|
data/test/midi_test.rb
CHANGED
@@ -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).
|
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.
|
39
|
-
assert_equal Proc, @midi.
|
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.
|
53
|
-
assert_equal Proc, @midi.
|
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.
|
67
|
-
assert_equal Proc, @midi.
|
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).
|
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
|
data/test/player_test.rb
CHANGED
@@ -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.
|
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-
|
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
|