mmplayer 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a60391f734494cf22b9e343379660079567721e8
4
- data.tar.gz: 4d75bfe1d744172b82fc9866ef9e4af6735d68e4
3
+ metadata.gz: a7696f764235df86a1aa44baa06e9aac9f3d2aa3
4
+ data.tar.gz: 79bb9a6de61e332396a1ca14fba2f7bcf5e7c153
5
5
  SHA512:
6
- metadata.gz: 64d867081ec9fb0b087076da7981aa978b7cc7ca704f01f7c6c8b4d0fa440c40383ecdc93171370e87ba91d0282d4bb6325aa7669c69118d60124c0bc1013054
7
- data.tar.gz: 18ca9e448f75dc6d2d97cb071060ea5e49af680a991bb184cb55b9e752454f2a1a45d0073986b97e60182f9afc1d2688b20e87648a8d447a6589e26cbb563943
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
@@ -24,7 +24,7 @@ require "mmplayer/player"
24
24
 
25
25
  module MMPlayer
26
26
 
27
- VERSION = "0.0.5"
27
+ VERSION = "0.0.6"
28
28
 
29
29
  # Shortcut to Context constructor
30
30
  def self.new(*args, &block)
@@ -27,10 +27,8 @@ module MMPlayer
27
27
  # @return [Boolean]
28
28
  def start(options = {})
29
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
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)
@@ -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
- @player.load_file(file)
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? && !@player.stdout.gets.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
- @player_thread.kill
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? && @player_thread.nil?
103
- @player_thread = Thread.new do
104
- begin
105
- @player = MPlayer::Slave.new(file, :options => @flags)
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
 
@@ -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("@player_thread", Thread.new {})
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("@player_thread").expects(:kill).once
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("@player_thread").unstub(:kill)
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.5
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-02 00:00:00.000000000 Z
11
+ date: 2015-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest