mmplayer 0.0.1
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 +7 -0
- data/LICENSE +13 -0
- data/README.md +62 -0
- data/lib/mmplayer.rb +33 -0
- data/lib/mmplayer/context.rb +47 -0
- data/lib/mmplayer/helper/numbers.rb +26 -0
- data/lib/mmplayer/instructions/midi.rb +46 -0
- data/lib/mmplayer/instructions/player.rb +31 -0
- data/lib/mmplayer/midi.rb +105 -0
- data/lib/mmplayer/player.rb +142 -0
- data/test/context_test.rb +64 -0
- data/test/helper.rb +6 -0
- data/test/helper/numbers_test.rb +57 -0
- data/test/instructions/midi_test.rb +78 -0
- data/test/instructions/player_test.rb +46 -0
- data/test/midi_test.rb +130 -0
- data/test/player_test.rb +125 -0
- metadata +240 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: b444046bc6129a272ad1354fd79e0226d3fed0f6
|
|
4
|
+
data.tar.gz: 7a58cbaec278585178e5ea420e3be977711a5f65
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7d73ce2e7db56b04f05bde2ce3a713a0b15cb6ed37f944d6d9de8d45859ad6e70265c3f818056aa6e5e8b70f536ae64f265301e39b2986829c0f7080b26ba2aa
|
|
7
|
+
data.tar.gz: 137bf592cad461210938a051ffad361b48019a55d87a788f76a48bdde80cd767c3729238fcb9c983c5094e44337bef934a13eeed852d1a57799e1ab483eb6689
|
data/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2015 Ari Russo
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# mmplayer
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Control [MPlayer](http://en.wikipedia.org/wiki/MPlayer) with MIDI
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
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.
|
|
10
|
+
|
|
11
|
+
This project itself can be installed as a Ruby Gem using
|
|
12
|
+
|
|
13
|
+
`gem install mmplayer`
|
|
14
|
+
|
|
15
|
+
Or if you're using Bundler, add this to your Gemfile
|
|
16
|
+
|
|
17
|
+
`gem "mmplayer"`
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
MMplayer provides a Ruby DSL to define interactions between MIDI input and MPlayer
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
require "mmplayer"
|
|
25
|
+
|
|
26
|
+
@input = UniMIDI::Input.gets
|
|
27
|
+
|
|
28
|
+
@player = MMPlayer.new(@input, :mplayer_flags => "-fs") do
|
|
29
|
+
|
|
30
|
+
rx_channel 0
|
|
31
|
+
|
|
32
|
+
system(:start) { play("1.mov") }
|
|
33
|
+
|
|
34
|
+
note(1) { play("2.mov") }
|
|
35
|
+
note("C2") { play("3.mov") }
|
|
36
|
+
|
|
37
|
+
cc(1) { |value| volume(:set, value) }
|
|
38
|
+
cc(20) { |value| seek(to_percent(value), :percent) }
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@player.start
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
An annotated breakdown of this example can be found [here](https://github.com/arirusso/mmplayer/blob/master/examples/simple.rb)
|
|
47
|
+
|
|
48
|
+
[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
|
+
|
|
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
|
|
53
|
+
|
|
54
|
+
##Author
|
|
55
|
+
|
|
56
|
+
* [Ari Russo](http://github.com/arirusso) <ari.russo at gmail.com>
|
|
57
|
+
|
|
58
|
+
##License
|
|
59
|
+
|
|
60
|
+
Apache 2.0, See LICENSE file
|
|
61
|
+
|
|
62
|
+
Copyright (c) 2015 [Ari Russo](http://arirusso.com)
|
data/lib/mmplayer.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# MMPlayer
|
|
2
|
+
# Control MPlayer with MIDI
|
|
3
|
+
#
|
|
4
|
+
# (c)2015 Ari Russo
|
|
5
|
+
# Apache 2.0 License
|
|
6
|
+
|
|
7
|
+
# libs
|
|
8
|
+
require "forwardable"
|
|
9
|
+
require "midi-eye"
|
|
10
|
+
require "mplayer-ruby"
|
|
11
|
+
require "scale"
|
|
12
|
+
require "unimidi"
|
|
13
|
+
|
|
14
|
+
# modules
|
|
15
|
+
require "mmplayer/helper/numbers"
|
|
16
|
+
require "mmplayer/instructions/midi"
|
|
17
|
+
require "mmplayer/instructions/player"
|
|
18
|
+
|
|
19
|
+
# classes
|
|
20
|
+
require "mmplayer/context"
|
|
21
|
+
require "mmplayer/midi"
|
|
22
|
+
require "mmplayer/player"
|
|
23
|
+
|
|
24
|
+
module MMPlayer
|
|
25
|
+
|
|
26
|
+
VERSION = "0.0.1"
|
|
27
|
+
|
|
28
|
+
# Shortcut to Context constructor
|
|
29
|
+
def self.new(*args, &block)
|
|
30
|
+
Context.new(*args, &block)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
# DSL context for interfacing an instance of MPlayer with MIDI
|
|
4
|
+
class Context
|
|
5
|
+
|
|
6
|
+
include Helper::Numbers
|
|
7
|
+
include Instructions::MIDI
|
|
8
|
+
include Instructions::Player
|
|
9
|
+
|
|
10
|
+
attr_reader :midi, :player
|
|
11
|
+
|
|
12
|
+
# @param [UniMIDI::Input] midi_input
|
|
13
|
+
# @param [Hash] options
|
|
14
|
+
# @option options [String] :mplayer_flags The command-line flags to invoke MPlayer with
|
|
15
|
+
# @option options [Fixnum] :receive_channel (also: :rx_channel) A MIDI channel to subscribe to. By default, responds to all
|
|
16
|
+
# @yield
|
|
17
|
+
def initialize(midi_input, options = {}, &block)
|
|
18
|
+
@midi = MIDI.new(midi_input, :receive_channel => options[:receive_channel] || options[:rx_channel])
|
|
19
|
+
@player = Player.new(:flags => options[:mplayer_flags])
|
|
20
|
+
instance_eval(&block) if block_given?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Start listening for MIDI
|
|
24
|
+
# Note that MPlayer will start when Context#play (aka Instructions::Player#play) is called
|
|
25
|
+
# @param [Hash] options
|
|
26
|
+
# @option options [Boolean] :background Whether to run in a background thread
|
|
27
|
+
# @return [Boolean]
|
|
28
|
+
def start(options = {})
|
|
29
|
+
@midi.start
|
|
30
|
+
unless !!options[:background]
|
|
31
|
+
loop { sleep(0.1) } until @player.active?
|
|
32
|
+
loop { sleep(0.1) } while @player.active?
|
|
33
|
+
end
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Stop the player
|
|
38
|
+
# @return [Boolean]
|
|
39
|
+
def stop
|
|
40
|
+
@midi.stop
|
|
41
|
+
@player.quit
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
module Helper
|
|
4
|
+
|
|
5
|
+
# Number conversion
|
|
6
|
+
module Numbers
|
|
7
|
+
|
|
8
|
+
# Converts a percentage to a 7-bit int value eg 50 -> 0x40
|
|
9
|
+
# @param [Fixnum] num
|
|
10
|
+
# @return [Fixnum]
|
|
11
|
+
def to_midi_value(num)
|
|
12
|
+
Scale.transform(num).from(0..100).to(0..127.0).round
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Converts a MIDI 7-bit int value to a percentage eg 0x40 -> 50
|
|
16
|
+
# @param [Fixnum] num
|
|
17
|
+
# @return [Fixnum]
|
|
18
|
+
def to_percent(num)
|
|
19
|
+
Scale.transform(num).from(0..127).to(0..100.0).round
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
module Instructions
|
|
4
|
+
|
|
5
|
+
# Instructions for dealing with MIDI
|
|
6
|
+
module MIDI
|
|
7
|
+
|
|
8
|
+
# Set the MIDI channel to receive messages on
|
|
9
|
+
# @param [Fixnum, nil] num The channel number 0-15 or nil for all
|
|
10
|
+
def receive_channel(num)
|
|
11
|
+
@midi.channel = num
|
|
12
|
+
end
|
|
13
|
+
alias_method :rx_channel, :receive_channel
|
|
14
|
+
|
|
15
|
+
# Assign a callback for a given MIDI system command
|
|
16
|
+
# @param [String, Symbol] note A MIDI system command eg :start, :continue, :stop
|
|
17
|
+
# @param [Proc] callback The callback to execute when a matching message is received
|
|
18
|
+
# @return [Hash]
|
|
19
|
+
def on_system(command, &callback)
|
|
20
|
+
@midi.add_system_callback(command, &callback)
|
|
21
|
+
end
|
|
22
|
+
alias_method :system, :on_system
|
|
23
|
+
|
|
24
|
+
# Assign a callback for a given MIDI note
|
|
25
|
+
# @param [Fixnum, String] note A MIDI note eg 64 "F4"
|
|
26
|
+
# @param [Proc] callback The callback to execute when a matching message is received
|
|
27
|
+
# @return [Hash]
|
|
28
|
+
def on_note(note, &callback)
|
|
29
|
+
@midi.add_note_callback(note, &callback)
|
|
30
|
+
end
|
|
31
|
+
alias_method :note, :on_note
|
|
32
|
+
|
|
33
|
+
# Assign a callback for the given MIDI control change
|
|
34
|
+
# @param [Fixnum] index The MIDI control change index to assign the callback for
|
|
35
|
+
# @param [Proc] callback The callback to execute when a matching message is received
|
|
36
|
+
# @return [Hash]
|
|
37
|
+
def on_cc(index, &callback)
|
|
38
|
+
@midi.add_cc_callback(index, &callback)
|
|
39
|
+
end
|
|
40
|
+
alias_method :cc, :on_cc
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
module Instructions
|
|
4
|
+
|
|
5
|
+
# Instructions dealing with the MPlayer
|
|
6
|
+
module Player
|
|
7
|
+
|
|
8
|
+
# Add delegators to local player methods
|
|
9
|
+
def self.included(base)
|
|
10
|
+
base.send(:extend, Forwardable)
|
|
11
|
+
base.send(:def_delegators, :@player, :active?, :play, :progress)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Add all of the MPlayer::Slave methods to the context as instructions
|
|
15
|
+
def method_missing(method, *args, &block)
|
|
16
|
+
if @player.mplayer_respond_to?(method)
|
|
17
|
+
@player.mplayer_send(method, *args, &block)
|
|
18
|
+
else
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Add all of the MPlayer::Slave methods to the context as instructions
|
|
24
|
+
def respond_to_missing?(method, include_private = false)
|
|
25
|
+
super || @player.mplayer_respond_to?(method)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
# Wrapper for MIDI functionality
|
|
4
|
+
class MIDI
|
|
5
|
+
|
|
6
|
+
attr_reader :channel, :config, :listener
|
|
7
|
+
|
|
8
|
+
# @param [UniMIDI::Input] input
|
|
9
|
+
# @param [Hash] options
|
|
10
|
+
# @option options [Fixnum] :receive_channel A MIDI channel to subscribe to. By default, responds to all
|
|
11
|
+
def initialize(input, options = {})
|
|
12
|
+
@channel = options[:receive_channel]
|
|
13
|
+
@config = {
|
|
14
|
+
:cc => {},
|
|
15
|
+
:note => {},
|
|
16
|
+
:system => {}
|
|
17
|
+
}
|
|
18
|
+
@listener = MIDIEye::Listener.new(input)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Add a callback for a given MIDI system message
|
|
22
|
+
# @param [String, Symbol] command The MIDI system command eg :start, :stop
|
|
23
|
+
# @param [Proc] callback The callback to execute when the given MIDI command is received
|
|
24
|
+
# @return [Hash]
|
|
25
|
+
def add_system_callback(command, &callback)
|
|
26
|
+
@config[:system][command] = callback
|
|
27
|
+
@config[:system]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Add a callback for a given MIDI note
|
|
31
|
+
# @param [Fixnum, String] note The MIDI note to add a callback for eg 64 "E4"
|
|
32
|
+
# @param [Proc] callback The callback to execute when the given MIDI note is received
|
|
33
|
+
# @return [Hash]
|
|
34
|
+
def add_note_callback(note, &callback)
|
|
35
|
+
@config[:note][note] = callback
|
|
36
|
+
@config[:note]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Add a callback for a given MIDI control change
|
|
40
|
+
# @param [Fixnum] index The MIDI control change index to add a callback for eg 10
|
|
41
|
+
# @param [Proc] callback The callback to execute when the given MIDI control change is received
|
|
42
|
+
# @return [Hash]
|
|
43
|
+
def add_cc_callback(index, &callback)
|
|
44
|
+
@config[:cc][index] = callback
|
|
45
|
+
@config[:cc]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Stop the MIDI listener
|
|
49
|
+
# @return [Boolean]
|
|
50
|
+
def stop
|
|
51
|
+
@listener.stop
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Change the subscribed MIDI channel (or nil for all)
|
|
55
|
+
# @param [Fixnum, nil] channel
|
|
56
|
+
# @return [Fixnum, nil]
|
|
57
|
+
def channel=(channel)
|
|
58
|
+
@listener.event.clear
|
|
59
|
+
@channel = channel
|
|
60
|
+
populate_listener if @listener.running?
|
|
61
|
+
@channel
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Start the MIDI listener
|
|
65
|
+
# @return [Boolean]
|
|
66
|
+
def start
|
|
67
|
+
populate_listener
|
|
68
|
+
@listener.start(:background => true)
|
|
69
|
+
true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Populate the MIDI listener events
|
|
75
|
+
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|
|
|
94
|
+
message = event[:message]
|
|
95
|
+
name = message.name.downcase.to_sym
|
|
96
|
+
unless (callback = @config[:system][name]).nil?
|
|
97
|
+
callback.call
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
module MMPlayer
|
|
2
|
+
|
|
3
|
+
# Wrapper for MPlayer functionality
|
|
4
|
+
class Player
|
|
5
|
+
|
|
6
|
+
# @param [Hash] options
|
|
7
|
+
# @option options [String] :flags MPlayer command-line flags to use on startup
|
|
8
|
+
def initialize(options = {})
|
|
9
|
+
@mplayer_messages = []
|
|
10
|
+
@flags = "-fixed-vo -idle"
|
|
11
|
+
@flags += " #{options[:flags]}" unless options[:flags].nil?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Play a media file
|
|
15
|
+
# @param [String] file
|
|
16
|
+
# @return [Boolean]
|
|
17
|
+
def play(file)
|
|
18
|
+
ensure_player(file)
|
|
19
|
+
if @player.nil?
|
|
20
|
+
false
|
|
21
|
+
else
|
|
22
|
+
@player.load_file(file)
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Is MPlayer active?
|
|
28
|
+
# @return [Boolean]
|
|
29
|
+
def active?
|
|
30
|
+
!@player.nil? && !@player.stdout.gets.nil?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Media progress information
|
|
34
|
+
# eg {
|
|
35
|
+
# :length => 90.3,
|
|
36
|
+
# :percent => 44,
|
|
37
|
+
# :position => 40.1
|
|
38
|
+
# }
|
|
39
|
+
# Length and position are in seconds
|
|
40
|
+
# @return [Hash, nil]
|
|
41
|
+
def progress
|
|
42
|
+
unless (time = poll_mplayer_progress).nil?
|
|
43
|
+
time[:percent] = get_percentage(time)
|
|
44
|
+
time
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Shortcut to send a message to the MPlayer
|
|
49
|
+
# @return [Object]
|
|
50
|
+
def mplayer_send(method, *args, &block)
|
|
51
|
+
if @player.nil? && MPlayer::Slave.method_defined?(method)
|
|
52
|
+
# warn
|
|
53
|
+
else
|
|
54
|
+
send_mplayer_message { @player.send(method, *args, &block) }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Does the MPlayer respond to the given message?
|
|
59
|
+
# @return [Boolean]
|
|
60
|
+
def mplayer_respond_to?(method, include_private = false)
|
|
61
|
+
(@player.nil? && MPlayer::Slave.method_defined?(method)) ||
|
|
62
|
+
@player.respond_to?(method)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Cause MPlayer to exit
|
|
66
|
+
# @return [Boolean]
|
|
67
|
+
def quit
|
|
68
|
+
@player.quit
|
|
69
|
+
@player_thread.kill
|
|
70
|
+
true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
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
|
+
# Get progress percentage from the MPlayer report
|
|
102
|
+
def get_percentage(report)
|
|
103
|
+
percent = (report[:position] / report[:length]) * 100
|
|
104
|
+
percent.round
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Poll MPlayer for progress information
|
|
108
|
+
def poll_mplayer_progress
|
|
109
|
+
time = nil
|
|
110
|
+
send_mplayer_message do
|
|
111
|
+
time = {
|
|
112
|
+
:length => get_mplayer_float("time_length"),
|
|
113
|
+
:position => get_mplayer_float("time_pos")
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
time
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Poll a single MPlayer value for the given key
|
|
120
|
+
def get_mplayer_float(key)
|
|
121
|
+
@player.get(key).strip.to_f
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Ensure that the MPlayer process is invoked
|
|
125
|
+
# @param [String] file The media file to invoke MPlayer with
|
|
126
|
+
# @return [MPlayer::Slave]
|
|
127
|
+
def ensure_player(file)
|
|
128
|
+
if @player.nil?
|
|
129
|
+
@player_thread = Thread.new do
|
|
130
|
+
begin
|
|
131
|
+
@player = MPlayer::Slave.new(file, :options => @flags)
|
|
132
|
+
rescue Exception => exception
|
|
133
|
+
Thread.main.raise(exception)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
@player_thread.abort_on_exception = true
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::ContextTest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "Context" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@input = Object.new
|
|
9
|
+
@context = MMPlayer::Context.new(@input)
|
|
10
|
+
@player = Object.new
|
|
11
|
+
@context.player.stubs(:ensure_player).returns(@player)
|
|
12
|
+
@context.player.stubs(:quit).returns(true)
|
|
13
|
+
@context.player.stubs(:active?).returns(true)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
teardown do
|
|
17
|
+
@context.player.unstub(:ensure_player)
|
|
18
|
+
@context.player.unstub(:quit)
|
|
19
|
+
@context.player.unstub(:active?)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "#start" do
|
|
23
|
+
|
|
24
|
+
setup do
|
|
25
|
+
@context.midi.listener.expects(:on_message).times(3)
|
|
26
|
+
@context.midi.listener.expects(:start).once
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
teardown do
|
|
30
|
+
@context.midi.listener.unstub(:on_message)
|
|
31
|
+
@context.midi.listener.unstub(:start)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
should "activate player" do
|
|
35
|
+
assert @context.start(:background => true)
|
|
36
|
+
@context.stop
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "#stop" do
|
|
42
|
+
|
|
43
|
+
setup do
|
|
44
|
+
@context.midi.listener.expects(:on_message).times(3)
|
|
45
|
+
@context.midi.listener.expects(:start).once
|
|
46
|
+
@context.midi.listener.expects(:stop).once
|
|
47
|
+
@context.player.expects(:quit).once
|
|
48
|
+
assert @context.start(:background => true)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
teardown do
|
|
52
|
+
@context.midi.listener.unstub(:on_message)
|
|
53
|
+
@context.midi.listener.unstub(:start)
|
|
54
|
+
@context.player.unstub(:quit)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
should "stop player" do
|
|
58
|
+
@context.stop
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
data/test/helper.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::Helper::NumbersTest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "Numbers" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@util = Object.new
|
|
9
|
+
@util.class.send(:include, MMPlayer::Helper::Numbers)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context "#to_midi_value" do
|
|
13
|
+
|
|
14
|
+
should "convert 0" do
|
|
15
|
+
val = @util.to_midi_value(0)
|
|
16
|
+
refute_nil val
|
|
17
|
+
assert_equal 0x0, val
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
should "convert 64" do
|
|
21
|
+
val = @util.to_midi_value(50)
|
|
22
|
+
refute_nil val
|
|
23
|
+
assert_equal 0x40, val
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should "convert 127" do
|
|
27
|
+
val = @util.to_midi_value(100)
|
|
28
|
+
refute_nil val
|
|
29
|
+
assert_equal 0x7F, val
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "#to_percent" do
|
|
35
|
+
|
|
36
|
+
should "convert 0%" do
|
|
37
|
+
val = @util.to_percent(0x0)
|
|
38
|
+
refute_nil val
|
|
39
|
+
assert_equal 0, val
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
should "convert 50%" do
|
|
43
|
+
val = @util.to_percent(0x40)
|
|
44
|
+
refute_nil val
|
|
45
|
+
assert_equal 50, val
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
should "convert 100%" do
|
|
49
|
+
val = @util.to_percent(0x7F)
|
|
50
|
+
refute_nil val
|
|
51
|
+
assert_equal 100, val
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::Instructions::MIDITest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "MIDI" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@input = Object.new
|
|
9
|
+
@context = MMPlayer::Context.new(@input)
|
|
10
|
+
assert @context.kind_of?(MMPlayer::Instructions::MIDI)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "#note" do
|
|
14
|
+
|
|
15
|
+
setup do
|
|
16
|
+
@context.midi.expects(:add_note_callback).once.returns({})
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
teardown do
|
|
20
|
+
@context.midi.unstub(:add_note_callback)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
should "assign callback" do
|
|
24
|
+
refute_nil @context.note(1) { something }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "#cc" do
|
|
30
|
+
|
|
31
|
+
setup do
|
|
32
|
+
@context.midi.expects(:add_cc_callback).once.returns({})
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
teardown do
|
|
36
|
+
@context.midi.unstub(:add_cc_callback)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should "assign callback" do
|
|
40
|
+
refute_nil @context.cc(1) { |val| something }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context "#system" do
|
|
46
|
+
|
|
47
|
+
setup do
|
|
48
|
+
@context.midi.expects(:add_system_callback).once.returns({})
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
teardown do
|
|
52
|
+
@context.midi.unstub(:add_system_callback)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
should "assign callback" do
|
|
56
|
+
refute_nil @context.system(:stop) { something }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "#receive_channel" do
|
|
62
|
+
|
|
63
|
+
setup do
|
|
64
|
+
@context.midi.expects(:channel=).once.with(3).returns(3)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
teardown do
|
|
68
|
+
@context.midi.unstub(:channel=)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
should "assign callback" do
|
|
72
|
+
refute_nil @context.receive_channel(3)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::Instructions::PlayerTest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "Player" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@input = Object.new
|
|
9
|
+
@context = MMPlayer::Context.new(@input)
|
|
10
|
+
assert @context.kind_of?(MMPlayer::Instructions::Player)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "#method_missing" do
|
|
14
|
+
|
|
15
|
+
setup do
|
|
16
|
+
@context.player.expects(:mplayer_send).once.with(:seek, 50, :percent).returns(true)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
teardown do
|
|
20
|
+
@context.player.unstub(:mplayer_send)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
should "delegate" do
|
|
24
|
+
refute_nil @context.seek(50, :percent)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "#respond_to?" do
|
|
30
|
+
|
|
31
|
+
setup do
|
|
32
|
+
@context.player.expects(:mplayer_respond_to?).once.with(:seek).returns(true)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
teardown do
|
|
36
|
+
@context.player.unstub(:mplayer_respond_to?)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should "delegate" do
|
|
40
|
+
refute_nil @context.respond_to?(:seek)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
data/test/midi_test.rb
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::MIDITest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "MIDI" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
@input = Object.new
|
|
9
|
+
@midi = MMPlayer::MIDI.new(@input)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context "#start" do
|
|
13
|
+
|
|
14
|
+
setup do
|
|
15
|
+
@midi.listener.expects(:on_message).times(3)
|
|
16
|
+
@midi.listener.expects(:start).once
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
teardown do
|
|
20
|
+
@midi.listener.unstub(:on_message)
|
|
21
|
+
@midi.listener.unstub(:start)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
should "activate callbacks" do
|
|
25
|
+
assert @midi.start
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "#add_note_callback" do
|
|
31
|
+
|
|
32
|
+
setup do
|
|
33
|
+
@var = nil
|
|
34
|
+
@midi.add_note_callback(10) { |vel| @var = vel }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
should "store callback" do
|
|
38
|
+
refute_nil @midi.config[:note][10]
|
|
39
|
+
assert_equal Proc, @midi.config[:note][10].class
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "#add_system_callback" do
|
|
45
|
+
|
|
46
|
+
setup do
|
|
47
|
+
@var = nil
|
|
48
|
+
@midi.add_system_callback(:start) { |val| @var = val }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
should "store callback" do
|
|
52
|
+
refute_nil @midi.config[:system][:start]
|
|
53
|
+
assert_equal Proc, @midi.config[:system][:start].class
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "#add_cc_callback" do
|
|
59
|
+
|
|
60
|
+
setup do
|
|
61
|
+
@var = nil
|
|
62
|
+
@midi.add_cc_callback(2) { |val| @var = val }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
should "store callback" do
|
|
66
|
+
refute_nil @midi.config[:cc][2]
|
|
67
|
+
assert_equal Proc, @midi.config[:cc][2].class
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "#channel=" do
|
|
73
|
+
|
|
74
|
+
setup do
|
|
75
|
+
# stub out MIDIEye
|
|
76
|
+
@listener = Object.new
|
|
77
|
+
@listener.stubs(:event).returns([])
|
|
78
|
+
@midi.instance_variable_set("@listener", @listener)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
teardown do
|
|
82
|
+
@listener.unstub(:clear)
|
|
83
|
+
@listener.unstub(:on_message)
|
|
84
|
+
@listener.unstub(:event)
|
|
85
|
+
@listener.unstub(:running?)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "before listener is started" do
|
|
89
|
+
|
|
90
|
+
setup do
|
|
91
|
+
@listener.stubs(:running?).returns(false)
|
|
92
|
+
@listener.expects(:clear).never
|
|
93
|
+
@listener.expects(:on_message).never
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
should "change channel" do
|
|
97
|
+
assert_equal 3, @midi.channel = 3
|
|
98
|
+
assert_equal 3, @midi.channel
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
should "set channel nil" do
|
|
102
|
+
assert_equal nil, @midi.channel = nil
|
|
103
|
+
assert_nil @midi.channel
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "after listener is started" do
|
|
108
|
+
|
|
109
|
+
setup do
|
|
110
|
+
@listener.stubs(:running?).returns(true)
|
|
111
|
+
@listener.expects(:clear).once
|
|
112
|
+
@listener.expects(:on_message).times(3)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
should "change channel" do
|
|
116
|
+
assert_equal 3, @midi.channel = 3
|
|
117
|
+
assert_equal 3, @midi.channel
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
should "set channel nil" do
|
|
121
|
+
assert_equal nil, @midi.channel = nil
|
|
122
|
+
assert_nil @midi.channel
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
end
|
data/test/player_test.rb
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require "helper"
|
|
2
|
+
|
|
3
|
+
class MMPlayer::PlayerTest < Minitest::Test
|
|
4
|
+
|
|
5
|
+
context "Player" do
|
|
6
|
+
|
|
7
|
+
setup do
|
|
8
|
+
# Stub out MPlayer completely
|
|
9
|
+
class MPlayer
|
|
10
|
+
def get(*args)
|
|
11
|
+
"0.1\n"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
@player = MMPlayer::Player.new
|
|
15
|
+
@mplayer = MPlayer.new
|
|
16
|
+
@player.stubs(:ensure_player).returns(@mplayer)
|
|
17
|
+
@player.instance_variable_set("@player", @mplayer)
|
|
18
|
+
@player.instance_variable_set("@player_thread", Thread.new {})
|
|
19
|
+
@player.send(:ensure_player, "")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "#mplayer_send" do
|
|
23
|
+
|
|
24
|
+
setup do
|
|
25
|
+
@mplayer.expects(:hello).once.returns(true)
|
|
26
|
+
@mplayer.expects(:send).once.with(:hello).returns(true)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
teardown do
|
|
30
|
+
@mplayer.unstub(:send)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
should "send messages to mplayer" do
|
|
34
|
+
assert @player.mplayer_send(:hello)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "#mplayer_respond_to?" do
|
|
40
|
+
|
|
41
|
+
setup do
|
|
42
|
+
@player.send(:ensure_player, "")
|
|
43
|
+
@mplayer.expects(:respond_to?).with(:hello).once.returns(true)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
teardown do
|
|
47
|
+
@mplayer.unstub(:respond_to?)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
should "send messages to mplayer" do
|
|
51
|
+
assert @player.mplayer_respond_to?(:hello)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context "#get_percentage" do
|
|
57
|
+
|
|
58
|
+
should "calcuate percentage" do
|
|
59
|
+
val = @player.send(:get_percentage, { :length => 10.1, :position => 5.5 })
|
|
60
|
+
refute_nil val
|
|
61
|
+
assert_equal Fixnum, val.class
|
|
62
|
+
assert_equal 54, val
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context "#quit" do
|
|
68
|
+
|
|
69
|
+
setup do
|
|
70
|
+
@mplayer.expects(:quit).once
|
|
71
|
+
@player.instance_variable_get("@player_thread").expects(:kill).once
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
teardown do
|
|
75
|
+
@mplayer.unstub(:quit)
|
|
76
|
+
@player.instance_variable_get("@player_thread").unstub(:kill)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
should "exit MPlayer and kill the player thread" do
|
|
80
|
+
assert @player.quit
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "#progress" do
|
|
86
|
+
# TODO
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context "#poll_mplayer_progress" do
|
|
90
|
+
# TODO
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "#get_mplayer_float" do
|
|
94
|
+
|
|
95
|
+
should "convert string to float" do
|
|
96
|
+
val = @player.send(:get_mplayer_float, "key")
|
|
97
|
+
refute_nil val
|
|
98
|
+
assert_equal Float, val.class
|
|
99
|
+
assert_equal 0.1, val
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
context "#play" do
|
|
105
|
+
|
|
106
|
+
setup do
|
|
107
|
+
@player.expects(:ensure_player).once.returns(@mplayer)
|
|
108
|
+
@mplayer.expects(:load_file).once
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
teardown do
|
|
112
|
+
@player.unstub(:ensure_player)
|
|
113
|
+
@mplayer.unstub(:load_file)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
should "lazily invoke mplayer and play" do
|
|
117
|
+
assert @player.play("file.mov")
|
|
118
|
+
refute_nil @player.instance_variable_get("@player")
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mmplayer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ari Russo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-04-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.5'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 5.5.0
|
|
23
|
+
type: :development
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '5.5'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 5.5.0
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: mocha
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.1'
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: 1.1.0
|
|
43
|
+
type: :development
|
|
44
|
+
prerelease: false
|
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - "~>"
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: '1.1'
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: 1.1.0
|
|
53
|
+
- !ruby/object:Gem::Dependency
|
|
54
|
+
name: rake
|
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '10.4'
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: 10.4.2
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - "~>"
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '10.4'
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: 10.4.2
|
|
73
|
+
- !ruby/object:Gem::Dependency
|
|
74
|
+
name: shoulda-context
|
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - "~>"
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: '1.2'
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 1.2.1
|
|
83
|
+
type: :development
|
|
84
|
+
prerelease: false
|
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.2'
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 1.2.1
|
|
93
|
+
- !ruby/object:Gem::Dependency
|
|
94
|
+
name: analog
|
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - "~>"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0.3'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0.3'
|
|
113
|
+
- !ruby/object:Gem::Dependency
|
|
114
|
+
name: midi-eye
|
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - "~>"
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '0.3'
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: 0.3.9
|
|
123
|
+
type: :runtime
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - "~>"
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '0.3'
|
|
130
|
+
- - ">="
|
|
131
|
+
- !ruby/object:Gem::Version
|
|
132
|
+
version: 0.3.9
|
|
133
|
+
- !ruby/object:Gem::Dependency
|
|
134
|
+
name: midi-message
|
|
135
|
+
requirement: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - "~>"
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: '0.4'
|
|
140
|
+
- - ">="
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: 0.4.1
|
|
143
|
+
type: :runtime
|
|
144
|
+
prerelease: false
|
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
146
|
+
requirements:
|
|
147
|
+
- - "~>"
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
version: '0.4'
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: 0.4.1
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: mplayer-ruby
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0.2'
|
|
160
|
+
- - ">="
|
|
161
|
+
- !ruby/object:Gem::Version
|
|
162
|
+
version: 0.2.0
|
|
163
|
+
type: :runtime
|
|
164
|
+
prerelease: false
|
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
166
|
+
requirements:
|
|
167
|
+
- - "~>"
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: '0.2'
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: 0.2.0
|
|
173
|
+
- !ruby/object:Gem::Dependency
|
|
174
|
+
name: unimidi
|
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
|
176
|
+
requirements:
|
|
177
|
+
- - "~>"
|
|
178
|
+
- !ruby/object:Gem::Version
|
|
179
|
+
version: '0.4'
|
|
180
|
+
- - ">="
|
|
181
|
+
- !ruby/object:Gem::Version
|
|
182
|
+
version: 0.4.3
|
|
183
|
+
type: :runtime
|
|
184
|
+
prerelease: false
|
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
186
|
+
requirements:
|
|
187
|
+
- - "~>"
|
|
188
|
+
- !ruby/object:Gem::Version
|
|
189
|
+
version: '0.4'
|
|
190
|
+
- - ">="
|
|
191
|
+
- !ruby/object:Gem::Version
|
|
192
|
+
version: 0.4.3
|
|
193
|
+
description: Define interactions between MIDI input and MPlayer
|
|
194
|
+
email:
|
|
195
|
+
- ari.russo@gmail.com
|
|
196
|
+
executables: []
|
|
197
|
+
extensions: []
|
|
198
|
+
extra_rdoc_files: []
|
|
199
|
+
files:
|
|
200
|
+
- LICENSE
|
|
201
|
+
- README.md
|
|
202
|
+
- lib/mmplayer.rb
|
|
203
|
+
- lib/mmplayer/context.rb
|
|
204
|
+
- lib/mmplayer/helper/numbers.rb
|
|
205
|
+
- lib/mmplayer/instructions/midi.rb
|
|
206
|
+
- lib/mmplayer/instructions/player.rb
|
|
207
|
+
- lib/mmplayer/midi.rb
|
|
208
|
+
- lib/mmplayer/player.rb
|
|
209
|
+
- test/context_test.rb
|
|
210
|
+
- test/helper.rb
|
|
211
|
+
- test/helper/numbers_test.rb
|
|
212
|
+
- test/instructions/midi_test.rb
|
|
213
|
+
- test/instructions/player_test.rb
|
|
214
|
+
- test/midi_test.rb
|
|
215
|
+
- test/player_test.rb
|
|
216
|
+
homepage: http://github.com/arirusso/mmplayer
|
|
217
|
+
licenses:
|
|
218
|
+
- Apache 2.0
|
|
219
|
+
metadata: {}
|
|
220
|
+
post_install_message:
|
|
221
|
+
rdoc_options: []
|
|
222
|
+
require_paths:
|
|
223
|
+
- lib
|
|
224
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
|
+
requirements:
|
|
226
|
+
- - ">="
|
|
227
|
+
- !ruby/object:Gem::Version
|
|
228
|
+
version: '0'
|
|
229
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
|
+
requirements:
|
|
231
|
+
- - ">="
|
|
232
|
+
- !ruby/object:Gem::Version
|
|
233
|
+
version: 1.3.6
|
|
234
|
+
requirements: []
|
|
235
|
+
rubyforge_project: mmplayer
|
|
236
|
+
rubygems_version: 2.4.6
|
|
237
|
+
signing_key:
|
|
238
|
+
specification_version: 4
|
|
239
|
+
summary: Control MPlayer with MIDI
|
|
240
|
+
test_files: []
|