mvlc 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 +11 -0
- data/lib/mvlc.rb +34 -0
- data/lib/mvlc/context.rb +67 -0
- data/lib/mvlc/helper/numbers.rb +26 -0
- data/lib/mvlc/instructions.rb +9 -0
- data/lib/mvlc/instructions/midi.rb +46 -0
- data/lib/mvlc/instructions/player.rb +50 -0
- data/lib/mvlc/midi.rb +14 -0
- data/lib/mvlc/midi/message_handler.rb +112 -0
- data/lib/mvlc/midi/wrapper.rb +115 -0
- data/lib/mvlc/player.rb +14 -0
- data/lib/mvlc/player/state.rb +44 -0
- data/lib/mvlc/player/wrapper.rb +148 -0
- data/lib/mvlc/thread.rb +28 -0
- data/test/context_test.rb +65 -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 +66 -0
- data/test/media/1.mov +0 -0
- data/test/media/2.mov +0 -0
- data/test/media/3.mov +0 -0
- data/test/midi/message_handler_test.rb +315 -0
- data/test/midi/wrapper_test.rb +229 -0
- data/test/player/wrapper_test.rb +51 -0
- metadata +250 -0
data/lib/mvlc/player.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module MVLC
|
2
|
+
|
3
|
+
module Player
|
4
|
+
|
5
|
+
class State
|
6
|
+
|
7
|
+
attr_accessor :eof, :pause, :play
|
8
|
+
alias_method :eof?, :eof
|
9
|
+
alias_method :pause?, :pause
|
10
|
+
alias_method :paused?, :pause
|
11
|
+
alias_method :play?, :play
|
12
|
+
alias_method :playing?, :play
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@eof = false
|
16
|
+
@play = false
|
17
|
+
@pause = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def toggle_pause
|
21
|
+
@pause = !@pause
|
22
|
+
end
|
23
|
+
|
24
|
+
def progressing?
|
25
|
+
@play && !@pause
|
26
|
+
end
|
27
|
+
|
28
|
+
def eof_reached?
|
29
|
+
@play && !@eof && !@pause
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle_eof
|
33
|
+
@eof = true
|
34
|
+
@play = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_start
|
38
|
+
@play = true
|
39
|
+
@eof = false
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module MVLC
|
2
|
+
|
3
|
+
module Player
|
4
|
+
|
5
|
+
# Wrapper for MPlayer functionality
|
6
|
+
class Wrapper
|
7
|
+
|
8
|
+
VOLUME_FACTOR = 2.4
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
attr_reader :state, :player
|
13
|
+
|
14
|
+
# @param [Hash] options
|
15
|
+
def initialize(options = {})
|
16
|
+
@callback = {}
|
17
|
+
@state = State.new
|
18
|
+
@player = VLC::System.new(headless: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def volume(value)
|
22
|
+
@player.volume(value * VOLUME_FACTOR)
|
23
|
+
end
|
24
|
+
|
25
|
+
def seek_percent(percent)
|
26
|
+
begin
|
27
|
+
length_in_seconds = @player.length
|
28
|
+
seconds = length_in_seconds * (percent / 100.0)
|
29
|
+
@player.seek(seconds)
|
30
|
+
rescue VLC::ReadTimeoutError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Play a media file
|
35
|
+
# @param [String] file
|
36
|
+
# @return [Boolean]
|
37
|
+
def play(file)
|
38
|
+
if @player.nil?
|
39
|
+
false
|
40
|
+
else
|
41
|
+
@player.play(file)
|
42
|
+
handle_start
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Is MPlayer active?
|
48
|
+
# @return [Boolean]
|
49
|
+
def active?
|
50
|
+
!@player.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
# Toggles pause
|
54
|
+
# @return [Boolean]
|
55
|
+
def pause
|
56
|
+
@state.toggle_pause
|
57
|
+
@player.pause
|
58
|
+
@state.pause?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Handle events while the player is running
|
62
|
+
# @return [Boolean]
|
63
|
+
def playback_loop
|
64
|
+
loop do
|
65
|
+
handle_eof if handle_eof?
|
66
|
+
sleep(0.05)
|
67
|
+
end
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add a callback to be called when progress is updated during playback
|
72
|
+
# @param [Proc] block
|
73
|
+
# @return [Boolean]
|
74
|
+
def add_progress_callback(&block)
|
75
|
+
@callback[:progress] = block
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
# Add a callback to be called at the end of playback of a media file
|
80
|
+
# @param [Proc] block
|
81
|
+
# @return [Boolean]
|
82
|
+
def add_end_of_file_callback(&block)
|
83
|
+
@callback[:end_of_file] = block
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
# Cause MPlayer to exit
|
88
|
+
# @return [Boolean]
|
89
|
+
def quit
|
90
|
+
@player.connection.write("quit")
|
91
|
+
@player.connection.write("logout")
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
# Add all of the MPlayer::Slave methods to the context as instructions
|
96
|
+
def method_missing(method, *args, &block)
|
97
|
+
if @player.respond_to?(method)
|
98
|
+
@player.send(method, *args, &block)
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Add all of the MPlayer::Slave methods to the context as instructions
|
105
|
+
def respond_to_missing?(method, include_private = false)
|
106
|
+
super || @player.respond_to?(method)
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def handle_progress?
|
112
|
+
@state.progressing? && progress_callback?
|
113
|
+
end
|
114
|
+
|
115
|
+
def progress_callback?
|
116
|
+
!@callback[:progress].nil?
|
117
|
+
end
|
118
|
+
|
119
|
+
def eof_callback?
|
120
|
+
!@callback[:end_of_file].nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
def handle_eof?
|
124
|
+
eof? && eof_callback?
|
125
|
+
end
|
126
|
+
|
127
|
+
# Handle the end of playback for a single media file
|
128
|
+
def handle_eof
|
129
|
+
@callback[:end_of_file].call
|
130
|
+
@state.handle_eof
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
# Handle the beginning of playback for a single media file
|
135
|
+
def handle_start
|
136
|
+
@state.handle_start
|
137
|
+
end
|
138
|
+
|
139
|
+
# Has the end of a media file been reached?
|
140
|
+
# @return [Boolean]
|
141
|
+
def eof?
|
142
|
+
@state.eof_reached? && !@player.playing?
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
data/lib/mvlc/thread.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module MVLC
|
2
|
+
|
3
|
+
module Thread
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def new(options = {}, &block)
|
8
|
+
thread = ::Thread.new do
|
9
|
+
begin
|
10
|
+
if options[:timeout] === false
|
11
|
+
yield
|
12
|
+
else
|
13
|
+
duration = options[:timeout] || 1
|
14
|
+
Timeout::timeout(duration) { yield }
|
15
|
+
end
|
16
|
+
rescue Timeout::Error
|
17
|
+
::Thread.current.kill
|
18
|
+
rescue Exception => exception
|
19
|
+
::Thread.main.raise(exception)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
thread.abort_on_exception = true
|
23
|
+
thread
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class MVLC::ContextTest < Minitest::Test
|
4
|
+
|
5
|
+
context "Context" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
VLC::System.stubs(:new)
|
9
|
+
@input = Object.new
|
10
|
+
@context = MVLC::Context.new(@input)
|
11
|
+
@player = Object.new
|
12
|
+
@context.player.stubs(:player).returns(@player)
|
13
|
+
@context.player.stubs(:quit).returns(true)
|
14
|
+
@context.player.stubs(:active?).returns(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
teardown do
|
18
|
+
@context.player.unstub(:player)
|
19
|
+
@context.player.unstub(:quit)
|
20
|
+
@context.player.unstub(:active?)
|
21
|
+
end
|
22
|
+
|
23
|
+
context "#start" do
|
24
|
+
|
25
|
+
setup do
|
26
|
+
@context.midi.listener.expects(:on_message).once
|
27
|
+
@context.midi.listener.expects(:start).once
|
28
|
+
end
|
29
|
+
|
30
|
+
teardown do
|
31
|
+
@context.midi.listener.unstub(:on_message)
|
32
|
+
@context.midi.listener.unstub(:start)
|
33
|
+
end
|
34
|
+
|
35
|
+
should "activate player" do
|
36
|
+
assert @context.start(:background => true)
|
37
|
+
assert @context.stop
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
context "#stop" do
|
43
|
+
|
44
|
+
setup do
|
45
|
+
@context.midi.listener.expects(:on_message).once
|
46
|
+
@context.midi.listener.expects(:start).once
|
47
|
+
@context.midi.listener.expects(:stop).once
|
48
|
+
@context.player.expects(:quit).once
|
49
|
+
assert @context.start(:background => true)
|
50
|
+
end
|
51
|
+
|
52
|
+
teardown do
|
53
|
+
@context.midi.listener.unstub(:on_message)
|
54
|
+
@context.midi.listener.unstub(:start)
|
55
|
+
@context.player.unstub(:quit)
|
56
|
+
end
|
57
|
+
|
58
|
+
should "stop player" do
|
59
|
+
assert @context.stop
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class MVLC::Helper::NumbersTest < Minitest::Test
|
4
|
+
|
5
|
+
context "Numbers" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@util = Object.new
|
9
|
+
@util.class.send(:include, MVLC::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 MVLC::Instructions::MIDITest < Minitest::Test
|
4
|
+
|
5
|
+
context "MIDI" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@input = Object.new
|
9
|
+
@context = MVLC::Context.new(@input)
|
10
|
+
assert @context.kind_of?(MVLC::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
|