mmplayer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []