mmplayer 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -4
- data/lib/mmplayer.rb +1 -1
- data/lib/mmplayer/context.rb +20 -4
- data/lib/mmplayer/instructions/player.rb +11 -0
- data/lib/mmplayer/player.rb +70 -11
- data/test/player_test.rb +6 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7696f764235df86a1aa44baa06e9aac9f3d2aa3
|
4
|
+
data.tar.gz: 79bb9a6de61e332396a1ca14fba2f7bcf5e7c153
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83026c50689a282c33c8463ec018159cc4f984d6e6cc51308dbe7440210e7452f3096e76f5a361b601666458c22885740b290a35d729f84ca8478bfb445dc66d
|
7
|
+
data.tar.gz: 2b84b86a16ee4a02ac0290575697967c5f1cb7e387ef6998d4478cd9e708f80c25822dbcf9f62907a07c2b5f5cc69a72c67fc86938fe46cf4381a34f1bebeb81
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Control [MPlayer](http://en.wikipedia.org/wiki/MPlayer) with MIDI
|
6
6
|
|
7
|
-
MPlayer is a free, cross-platform, command-line driven, highly configurable, (often) GUI-less open-source media player.
|
7
|
+
MPlayer is a free, cross-platform, command-line driven, highly configurable, (often) GUI-less open-source media player.
|
8
8
|
|
9
9
|
Enabling MPlayer to be controlled by MIDI opens up a host of possibilities for live video performance, media automation and more
|
10
10
|
|
@@ -14,9 +14,9 @@ This project provides a Ruby DSL to define realtime interactions between MIDI in
|
|
14
14
|
|
15
15
|
You'll need to install MPlayer before using this. That can usually be accomplished with a package manager eg `brew install mplayer` depending on what OS you're using.
|
16
16
|
|
17
|
-
This project itself can be installed as a Ruby Gem using
|
17
|
+
This project itself can be installed as a Ruby Gem using
|
18
18
|
|
19
|
-
`gem install mmplayer`
|
19
|
+
`gem install mmplayer`
|
20
20
|
|
21
21
|
Or if you're using Bundler, add this to your Gemfile
|
22
22
|
|
@@ -34,13 +34,15 @@ require "mmplayer"
|
|
34
34
|
rx_channel 0
|
35
35
|
|
36
36
|
system(:start) { play("1.mov") }
|
37
|
-
|
37
|
+
|
38
38
|
note(1) { play("2.mov") }
|
39
39
|
note("C2") { play("3.mov") }
|
40
40
|
|
41
41
|
cc(1) { |value| volume(:set, value) }
|
42
42
|
cc(20) { |value| seek(to_percent(value), :percent) }
|
43
43
|
|
44
|
+
eof { puts "finished" }
|
45
|
+
|
44
46
|
end
|
45
47
|
|
46
48
|
@player.start
|
data/lib/mmplayer.rb
CHANGED
data/lib/mmplayer/context.rb
CHANGED
@@ -27,10 +27,8 @@ module MMPlayer
|
|
27
27
|
# @return [Boolean]
|
28
28
|
def start(options = {})
|
29
29
|
@midi.start
|
30
|
-
|
31
|
-
|
32
|
-
loop { sleep(0.1) } while @player.active?
|
33
|
-
end
|
30
|
+
@playback_thread = playback_loop
|
31
|
+
@playback_thread.join unless !!options[:background]
|
34
32
|
true
|
35
33
|
end
|
36
34
|
|
@@ -42,6 +40,24 @@ module MMPlayer
|
|
42
40
|
true
|
43
41
|
end
|
44
42
|
|
43
|
+
private
|
44
|
+
|
45
|
+
# Main playback loop
|
46
|
+
def playback_loop
|
47
|
+
thread = Thread.new do
|
48
|
+
begin
|
49
|
+
until @player.active?
|
50
|
+
sleep(0.1)
|
51
|
+
end
|
52
|
+
@player.playback_loop
|
53
|
+
rescue Exception => exception
|
54
|
+
Thread.main.raise(exception)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
thread.abort_on_exception = true
|
58
|
+
thread
|
59
|
+
end
|
60
|
+
|
45
61
|
end
|
46
62
|
|
47
63
|
end
|
@@ -5,6 +5,17 @@ module MMPlayer
|
|
5
5
|
# Instructions dealing with the MPlayer
|
6
6
|
module Player
|
7
7
|
|
8
|
+
# Assign a callback for when a file finishes playback
|
9
|
+
# @param [Proc] callback The callback to execute when a file finishes playback
|
10
|
+
# @return [Hash]
|
11
|
+
def on_end_of_file(&callback)
|
12
|
+
@player.add_end_of_file_callback(&callback)
|
13
|
+
end
|
14
|
+
alias_method :end_of_file, :on_end_of_file
|
15
|
+
alias_method :eof, :on_end_of_file
|
16
|
+
|
17
|
+
private
|
18
|
+
|
8
19
|
# Add delegators to local player methods
|
9
20
|
def self.included(base)
|
10
21
|
base.send(:extend, Forwardable)
|
data/lib/mmplayer/player.rb
CHANGED
@@ -9,6 +9,10 @@ module MMPlayer
|
|
9
9
|
@flags = "-fixed-vo -idle"
|
10
10
|
@flags += " #{options[:flags]}" unless options[:flags].nil?
|
11
11
|
@messenger = Messenger.new
|
12
|
+
@callback = {}
|
13
|
+
@is_playing = false
|
14
|
+
@is_eof_handled = true
|
15
|
+
@player_threads = []
|
12
16
|
end
|
13
17
|
|
14
18
|
# Play a media file
|
@@ -19,7 +23,10 @@ module MMPlayer
|
|
19
23
|
if @player.nil?
|
20
24
|
false
|
21
25
|
else
|
22
|
-
|
26
|
+
with_player_thread do
|
27
|
+
@player.load_file(file)
|
28
|
+
handle_start
|
29
|
+
end
|
23
30
|
true
|
24
31
|
end
|
25
32
|
end
|
@@ -27,7 +34,28 @@ module MMPlayer
|
|
27
34
|
# Is MPlayer active?
|
28
35
|
# @return [Boolean]
|
29
36
|
def active?
|
30
|
-
!@player.nil?
|
37
|
+
!@player.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Handle events while the player is running
|
41
|
+
# @return [Boolean]
|
42
|
+
def playback_loop
|
43
|
+
loop do
|
44
|
+
if @is_playing && !@is_eof_handled && get_player_output.size < 1
|
45
|
+
handle_eof
|
46
|
+
else
|
47
|
+
sleep(0.05)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
# Add a callback to be called at the end of playback of a media file
|
54
|
+
# @param [Proc] block
|
55
|
+
# @return [Boolean]
|
56
|
+
def add_end_of_file_callback(&block)
|
57
|
+
@callback[:end_of_file] = block
|
58
|
+
true
|
31
59
|
end
|
32
60
|
|
33
61
|
# Media progress information
|
@@ -66,12 +94,33 @@ module MMPlayer
|
|
66
94
|
# @return [Boolean]
|
67
95
|
def quit
|
68
96
|
@player.quit
|
69
|
-
@
|
97
|
+
@player_threads.each(&:kill)
|
70
98
|
true
|
71
99
|
end
|
72
100
|
|
73
101
|
private
|
74
102
|
|
103
|
+
# Get player output from stdout
|
104
|
+
def get_player_output
|
105
|
+
@player.stdout.gets.inspect.strip.gsub(/(\\n|[\\"])/, '').strip
|
106
|
+
end
|
107
|
+
|
108
|
+
# Handle the end of playback for a single media file
|
109
|
+
def handle_eof
|
110
|
+
@is_eof_handled = true
|
111
|
+
@is_playing = false
|
112
|
+
STDOUT.flush
|
113
|
+
@callback[:end_of_file].call unless @callback[:end_of_file].nil?
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
# Handle the beginning of playback for a single media file
|
118
|
+
def handle_start
|
119
|
+
loop until get_player_output.size > 1
|
120
|
+
@is_playing = true
|
121
|
+
@is_eof_handled = false
|
122
|
+
end
|
123
|
+
|
75
124
|
# Get progress percentage from the MPlayer report
|
76
125
|
def get_percentage(report)
|
77
126
|
percent = (report[:position] / report[:length]) * 100
|
@@ -95,19 +144,29 @@ module MMPlayer
|
|
95
144
|
@player.get(key).strip.to_f
|
96
145
|
end
|
97
146
|
|
147
|
+
# Call the given block within a new thread
|
148
|
+
def with_player_thread(&block)
|
149
|
+
thread = Thread.new do
|
150
|
+
begin
|
151
|
+
yield
|
152
|
+
rescue Exception => exception
|
153
|
+
Thread.main.raise(exception)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
thread.abort_on_exception = true
|
157
|
+
@player_threads << thread
|
158
|
+
thread
|
159
|
+
end
|
160
|
+
|
98
161
|
# Ensure that the MPlayer process is invoked
|
99
162
|
# @param [String] file The media file to invoke MPlayer with
|
100
163
|
# @return [MPlayer::Slave]
|
101
164
|
def ensure_player(file)
|
102
|
-
if @player.nil? && @
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
rescue Exception => exception
|
107
|
-
Thread.main.raise(exception)
|
108
|
-
end
|
165
|
+
if @player.nil? && @player_threads.empty?
|
166
|
+
with_player_thread do
|
167
|
+
@player = MPlayer::Slave.new(file, :options => @flags)
|
168
|
+
handle_start
|
109
169
|
end
|
110
|
-
@player_thread.abort_on_exception = true
|
111
170
|
end
|
112
171
|
end
|
113
172
|
|
data/test/player_test.rb
CHANGED
@@ -10,12 +10,15 @@ class MMPlayer::PlayerTest < Minitest::Test
|
|
10
10
|
def get(*args)
|
11
11
|
"0.1\n"
|
12
12
|
end
|
13
|
+
|
14
|
+
def load_file(something)
|
15
|
+
end
|
13
16
|
end
|
14
17
|
@player = MMPlayer::Player.new
|
15
18
|
@mplayer = MPlayer.new
|
16
19
|
@player.stubs(:ensure_player).returns(@mplayer)
|
17
20
|
@player.instance_variable_set("@player", @mplayer)
|
18
|
-
@player.instance_variable_set("@
|
21
|
+
@player.instance_variable_set("@player_threads", [Thread.new {}])
|
19
22
|
@player.send(:ensure_player, "")
|
20
23
|
end
|
21
24
|
|
@@ -68,12 +71,12 @@ class MMPlayer::PlayerTest < Minitest::Test
|
|
68
71
|
|
69
72
|
setup do
|
70
73
|
@mplayer.expects(:quit).once
|
71
|
-
@player.instance_variable_get("@
|
74
|
+
@player.instance_variable_get("@player_threads").first.expects(:kill).once
|
72
75
|
end
|
73
76
|
|
74
77
|
teardown do
|
75
78
|
@mplayer.unstub(:quit)
|
76
|
-
@player.instance_variable_get("@
|
79
|
+
@player.instance_variable_get("@player_threads").first.unstub(:kill)
|
77
80
|
end
|
78
81
|
|
79
82
|
should "exit MPlayer and kill the player thread" do
|
@@ -105,12 +108,10 @@ class MMPlayer::PlayerTest < Minitest::Test
|
|
105
108
|
|
106
109
|
setup do
|
107
110
|
@player.expects(:ensure_player).once.returns(@mplayer)
|
108
|
-
@mplayer.expects(:load_file).once
|
109
111
|
end
|
110
112
|
|
111
113
|
teardown do
|
112
114
|
@player.unstub(:ensure_player)
|
113
|
-
@mplayer.unstub(:load_file)
|
114
115
|
end
|
115
116
|
|
116
117
|
should "lazily invoke mplayer and play" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mmplayer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ari Russo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|