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.
@@ -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.
@@ -0,0 +1,62 @@
1
+ # mmplayer
2
+
3
+ ![image](http://i.imgur.com/Te9nymX.png)
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)
@@ -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
@@ -0,0 +1,6 @@
1
+ $:.unshift(File.join("..", "lib"))
2
+
3
+ require "minitest/autorun"
4
+ require "mocha/test_unit"
5
+ require "shoulda-context"
6
+ require "mmplayer"
@@ -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
@@ -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
@@ -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: []