osc-ruby 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/VERSION +1 -1
- data/lib/osc-ruby.rb +0 -2
- data/lib/osc-ruby/address_pattern.rb +34 -32
- data/lib/osc-ruby/bundle.rb +14 -12
- data/lib/osc-ruby/em_server.rb +22 -22
- data/lib/osc-ruby/message.rb +18 -15
- data/lib/osc-ruby/network_packet.rb +14 -13
- data/lib/osc-ruby/osc_argument.rb +15 -5
- data/lib/osc-ruby/osc_packet.rb +26 -27
- data/lib/osc-ruby/osc_types.rb +36 -11
- data/lib/osc-ruby/server.rb +31 -32
- data/spec/builders/message_builder.rb +25 -26
- data/spec/unit/address_pattern_spec.rb +49 -49
- data/spec/unit/message_builder_spec.rb +19 -21
- data/spec/unit/message_bundle_spec.rb +1 -1
- data/spec/unit/message_spec.rb +27 -27
- data/spec/unit/network_packet_spec.rb +18 -18
- data/spec/unit/osc_argument_spec.rb +2 -2
- data/spec/unit/osc_complex_packets_spec.rb +16 -16
- data/spec/unit/osc_packet_unknown_type_spec.rb +3 -8
- data/spec/unit/osc_simple_packets_spec.rb +37 -43
- data/spec/unit/osc_types_spec.rb +6 -6
- metadata +4 -4
data/lib/osc-ruby/osc_types.rb
CHANGED
@@ -1,28 +1,53 @@
|
|
1
|
-
require File.join(
|
1
|
+
require File.join(File.dirname(__FILE__), "osc_argument")
|
2
2
|
|
3
3
|
module OSC
|
4
4
|
class OSCInt32 < OSCArgument
|
5
|
-
def tag
|
6
|
-
|
5
|
+
def tag
|
6
|
+
'i'
|
7
|
+
end
|
8
|
+
|
9
|
+
def encode
|
10
|
+
[@val].pack('N').force_encoding("BINARY")
|
11
|
+
end
|
7
12
|
end
|
8
13
|
|
9
14
|
class OSCFloat32 < OSCArgument
|
10
|
-
def tag
|
11
|
-
|
15
|
+
def tag
|
16
|
+
'f'
|
17
|
+
end
|
18
|
+
|
19
|
+
def encode
|
20
|
+
[@val].pack('g').force_encoding("BINARY")
|
21
|
+
end
|
12
22
|
end
|
13
23
|
|
14
24
|
class OSCDouble64 < OSCArgument
|
15
|
-
def tag
|
16
|
-
|
25
|
+
def tag
|
26
|
+
'd'
|
27
|
+
end
|
28
|
+
|
29
|
+
def encode
|
30
|
+
[@val].pack('G').force_encoding("BINARY")
|
31
|
+
end
|
17
32
|
end
|
18
33
|
|
19
34
|
class OSCString < OSCArgument
|
20
|
-
def tag
|
21
|
-
|
35
|
+
def tag
|
36
|
+
's'
|
37
|
+
end
|
38
|
+
|
39
|
+
def encode
|
40
|
+
padding(@val.sub(/\000.*\z/, '') + "\000").force_encoding("BINARY")
|
41
|
+
end
|
22
42
|
end
|
23
43
|
|
24
44
|
class OSCBlob < OSCArgument
|
25
|
-
def tag
|
26
|
-
|
45
|
+
def tag
|
46
|
+
'b'
|
47
|
+
end
|
48
|
+
|
49
|
+
def encode
|
50
|
+
padding([@val.size].pack('N') + @val).force_encoding("BINARY")
|
51
|
+
end
|
27
52
|
end
|
28
53
|
end
|
data/lib/osc-ruby/server.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module OSC
|
2
|
-
class
|
3
|
-
def initialize(
|
2
|
+
class Server
|
3
|
+
def initialize(port)
|
4
4
|
@socket = UDPSocket.new
|
5
|
-
@socket.bind(
|
5
|
+
@socket.bind('', port)
|
6
6
|
@matchers = []
|
7
7
|
@queue = Queue.new
|
8
8
|
end
|
@@ -17,76 +17,75 @@ module OSC
|
|
17
17
|
@socket.close
|
18
18
|
end
|
19
19
|
|
20
|
-
def add_method(
|
21
|
-
matcher = AddressPattern.new(
|
20
|
+
def add_method(address_pattern, &proc)
|
21
|
+
matcher = AddressPattern.new(address_pattern)
|
22
22
|
|
23
23
|
@matchers << [matcher, proc]
|
24
24
|
end
|
25
25
|
|
26
|
-
private
|
26
|
+
private
|
27
27
|
|
28
28
|
def start_detector
|
29
29
|
begin
|
30
|
-
|
30
|
+
detector
|
31
31
|
rescue
|
32
|
-
|
32
|
+
Thread.main.raise($!)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def start_dispatcher
|
37
37
|
Thread.fork do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
begin
|
39
|
+
dispatcher
|
40
|
+
rescue
|
41
|
+
Thread.main.raise($!)
|
42
|
+
end
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
def dispatcher
|
47
47
|
loop do
|
48
|
-
|
49
|
-
dispatch_message(
|
48
|
+
mesg = @queue.pop
|
49
|
+
dispatch_message(mesg)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def dispatch_message(
|
54
|
-
diff = (
|
53
|
+
def dispatch_message(message)
|
54
|
+
diff = (message.time || 0) - Time.now.to_ntp
|
55
55
|
|
56
56
|
if diff <= 0
|
57
|
-
sendmesg(
|
57
|
+
sendmesg(message)
|
58
58
|
else # spawn a thread to wait until it's time
|
59
59
|
Thread.fork do
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
sleep(diff)
|
61
|
+
sendmesg(mesg)
|
62
|
+
Thread.exit
|
63
|
+
end
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
def sendmesg(mesg)
|
68
68
|
@matchers.each do |matcher, proc|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
if matcher.match?(mesg.address)
|
70
|
+
proc.call(mesg)
|
71
|
+
end
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
def detector
|
76
76
|
loop do
|
77
|
-
|
78
|
-
|
77
|
+
osc_data, network = @socket.recvfrom(16384)
|
78
|
+
begin
|
79
79
|
ip_info = Array.new
|
80
80
|
ip_info << network[1]
|
81
81
|
ip_info.concat(network[2].split('.'))
|
82
|
-
|
83
|
-
|
82
|
+
OSCPacket.messages_from_network( osc_data, ip_info ).each do |message|
|
83
|
+
@queue.push(message)
|
84
84
|
end
|
85
85
|
|
86
|
-
|
87
|
-
|
86
|
+
rescue(EOFError)
|
87
|
+
end
|
88
88
|
end
|
89
89
|
end
|
90
|
-
|
91
90
|
end
|
92
91
|
end
|
@@ -1,56 +1,55 @@
|
|
1
1
|
class MessageBuilder
|
2
|
-
|
3
2
|
def initialize
|
4
3
|
@address = ""
|
5
4
|
@tags = []
|
6
5
|
@values = []
|
7
6
|
@time = nil
|
8
7
|
end
|
9
|
-
|
10
|
-
def with_address(
|
8
|
+
|
9
|
+
def with_address(addr)
|
11
10
|
@address = addr
|
12
11
|
self
|
13
12
|
end
|
14
|
-
|
15
|
-
def with_float(
|
16
|
-
with_arg(
|
13
|
+
|
14
|
+
def with_float(float)
|
15
|
+
with_arg("f", float)
|
17
16
|
self
|
18
17
|
end
|
19
18
|
|
20
|
-
def with_double(
|
21
|
-
with_arg(
|
19
|
+
def with_double(double)
|
20
|
+
with_arg("d", double)
|
22
21
|
self
|
23
22
|
end
|
24
|
-
|
25
|
-
def with_int(
|
26
|
-
with_arg(
|
23
|
+
|
24
|
+
def with_int(int)
|
25
|
+
with_arg("i", int)
|
27
26
|
self
|
28
27
|
end
|
29
|
-
|
30
|
-
def with_string(
|
31
|
-
with_arg(
|
28
|
+
|
29
|
+
def with_string(string)
|
30
|
+
with_arg("s", string)
|
32
31
|
self
|
33
32
|
end
|
34
|
-
|
35
|
-
def with_blob(
|
36
|
-
with_arg( "b", blob
|
33
|
+
|
34
|
+
def with_blob(blob)
|
35
|
+
with_arg( "b", blob)
|
37
36
|
self
|
38
37
|
end
|
39
|
-
|
40
|
-
def with_time(
|
38
|
+
|
39
|
+
def with_time(time)
|
41
40
|
@time = time
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
def build
|
45
|
-
message = OSC::Message.new(
|
44
|
+
message = OSC::Message.new(@address , *@values)
|
46
45
|
message.time = @time
|
47
46
|
message
|
48
47
|
end
|
49
|
-
|
50
|
-
private
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
private
|
50
|
+
|
51
|
+
def with_arg(tag, value)
|
52
|
+
@tags << tag
|
53
|
+
@values << value
|
55
54
|
end
|
56
55
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(
|
1
|
+
require File.join(File.dirname(__FILE__) , '..', 'spec_helper')
|
2
2
|
|
3
3
|
describe OSC::AddressPattern do
|
4
4
|
# it "..." do
|
@@ -13,81 +13,81 @@ describe OSC::AddressPattern do
|
|
13
13
|
# end
|
14
14
|
|
15
15
|
it "should match anything if the pattern is nil" do
|
16
|
-
ap = OSC::AddressPattern.new(
|
16
|
+
ap = OSC::AddressPattern.new(nil)
|
17
17
|
|
18
|
-
ap.match?(
|
19
|
-
ap.match?(
|
18
|
+
_(ap.match?("/some/nonsense")).must_equal(true)
|
19
|
+
_(ap.match?("/completely.different")).must_equal(true)
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should match based on a regex" do
|
23
|
-
ap = OSC::AddressPattern.new(
|
23
|
+
ap = OSC::AddressPattern.new(/hi/)
|
24
24
|
|
25
|
-
ap.match?(
|
26
|
-
ap.match?(
|
25
|
+
_(ap.match?('/hi')).must_equal(true)
|
26
|
+
_(ap.match?('/hidden')).must_equal(true)
|
27
27
|
|
28
|
-
ap.match?(
|
28
|
+
_(ap.match?('/bye')).must_equal(false)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should return a regex if the pattern is a string" do
|
32
|
-
ap = OSC::AddressPattern.new(
|
32
|
+
ap = OSC::AddressPattern.new("/hi")
|
33
33
|
|
34
|
-
ap.match?(
|
34
|
+
_(ap.match?('/hi')).must_equal(true)
|
35
35
|
|
36
|
-
ap.match?(
|
37
|
-
ap.match?(
|
38
|
-
ap.match?(
|
39
|
-
ap.match?(
|
36
|
+
_(ap.match?(' /hi')).must_equal(false)
|
37
|
+
_(ap.match?('/ahi')).must_equal(false)
|
38
|
+
_(ap.match?('/hidden')).must_equal(false)
|
39
|
+
_(ap.match?('/bye')).must_equal(false)
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should match with question mark" do
|
43
|
-
ap = OSC::AddressPattern.new(
|
44
|
-
|
45
|
-
ap.match?(
|
46
|
-
ap.match?(
|
47
|
-
ap.match?(
|
48
|
-
ap.match?(
|
49
|
-
ap.match?(
|
50
|
-
ap.match?(
|
43
|
+
ap = OSC::AddressPattern.new("/h?l")
|
44
|
+
|
45
|
+
_(ap.match?('/hal')).must_equal(true)
|
46
|
+
_(ap.match?('/hel')).must_equal(true)
|
47
|
+
_(ap.match?('/hil')).must_equal(true)
|
48
|
+
_(ap.match?('/hol')).must_equal(true)
|
49
|
+
_(ap.match?('/hul')).must_equal(true)
|
50
|
+
_(ap.match?('/hub')).must_equal(false)
|
51
51
|
end
|
52
52
|
|
53
53
|
it "should match with *" do
|
54
|
-
ap = OSC::AddressPattern.new(
|
54
|
+
ap = OSC::AddressPattern.new("/believ*d")
|
55
55
|
|
56
|
-
ap.match?(
|
57
|
-
ap.match?(
|
58
|
-
ap.match?(
|
59
|
-
ap.match?(
|
60
|
-
ap.match?(
|
56
|
+
_(ap.match?('/believd')).must_equal(true)
|
57
|
+
_(ap.match?('/believed')).must_equal(true)
|
58
|
+
_(ap.match?('/believeeed')).must_equal(true)
|
59
|
+
_(ap.match?('/believaeeeioud')).must_equal(true)
|
60
|
+
_(ap.match?('/believaeeeioud')).must_equal(true)
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should match with []" do
|
64
|
-
ap = OSC::AddressPattern.new(
|
65
|
-
|
66
|
-
ap.match?(
|
67
|
-
ap.match?(
|
68
|
-
ap.match?(
|
69
|
-
ap.match?(
|
70
|
-
ap.match?(
|
71
|
-
ap.match?(
|
64
|
+
ap = OSC::AddressPattern.new("/believ[aeiou]d")
|
65
|
+
|
66
|
+
_(ap.match?('/believad')).must_equal(true)
|
67
|
+
_(ap.match?('/believed')).must_equal(true)
|
68
|
+
_(ap.match?('/believid')).must_equal(true)
|
69
|
+
_(ap.match?('/believod')).must_equal(true)
|
70
|
+
_(ap.match?('/believud')).must_equal(true)
|
71
|
+
_(ap.match?('/believkd')).must_equal(false)
|
72
72
|
end
|
73
73
|
|
74
74
|
it "should match with [!]" do
|
75
|
-
ap = OSC::AddressPattern.new(
|
76
|
-
|
77
|
-
ap.match?(
|
78
|
-
ap.match?(
|
79
|
-
ap.match?(
|
80
|
-
ap.match?(
|
81
|
-
ap.match?(
|
82
|
-
ap.match?(
|
83
|
-
ap.match?(
|
75
|
+
ap = OSC::AddressPattern.new("/believ[!aeiou]d")
|
76
|
+
|
77
|
+
_(ap.match?('/believad')).must_equal(false)
|
78
|
+
_(ap.match?('/believed')).must_equal(false)
|
79
|
+
_(ap.match?('/believid')).must_equal(false)
|
80
|
+
_(ap.match?('/believod')).must_equal(false)
|
81
|
+
_(ap.match?('/believud')).must_equal(false)
|
82
|
+
_(ap.match?('/believkd')).must_equal(true)
|
83
|
+
_(ap.match?('/believzd')).must_equal(true)
|
84
84
|
end
|
85
85
|
|
86
86
|
it "should match with {}" do
|
87
|
-
ap = OSC::AddressPattern.new(
|
87
|
+
ap = OSC::AddressPattern.new("/{hi,bye}")
|
88
88
|
|
89
|
-
ap.match?(
|
90
|
-
ap.match?(
|
91
|
-
ap.match?(
|
89
|
+
_(ap.match?('/hi')).must_equal(true)
|
90
|
+
_(ap.match?('/bye')).must_equal(true)
|
91
|
+
_(ap.match?('/greetings')).must_equal(false)
|
92
92
|
end
|
93
93
|
end
|
@@ -1,45 +1,43 @@
|
|
1
|
-
# sanity checks
|
2
1
|
require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
|
3
2
|
|
4
3
|
describe MessageBuilder do
|
5
4
|
before :each do
|
6
5
|
@builder = MessageBuilder.new
|
7
6
|
end
|
8
|
-
|
7
|
+
|
9
8
|
it "encodes just the address" do
|
10
9
|
mesg = @builder.with_address("/hi")
|
11
|
-
|
10
|
+
_(mesg.build.encode).must_equal binary_string("/hi\000,\000\000\000")
|
12
11
|
end
|
13
|
-
|
12
|
+
|
14
13
|
it "encodes single int values" do
|
15
14
|
mesg = @builder.with_address("/hi").
|
16
|
-
|
17
|
-
|
18
|
-
mesg.build.encode.must_equal binary_string("/hi\000,i\000\000\000\000\000!")
|
15
|
+
with_int(33)
|
16
|
+
_(mesg.build.encode).must_equal binary_string("/hi\000,i\000\000\000\000\000!")
|
19
17
|
end
|
20
|
-
|
18
|
+
|
21
19
|
it "encodes single string values" do
|
22
20
|
mesg = @builder.with_address("/hi").
|
23
|
-
|
24
|
-
|
25
|
-
mesg.build.encode.must_equal binary_string("/hi\000,s\000\000hello\000\000\000")
|
21
|
+
with_string("hello")
|
22
|
+
|
23
|
+
_(mesg.build.encode).must_equal binary_string("/hi\000,s\000\000hello\000\000\000")
|
26
24
|
end
|
27
|
-
|
25
|
+
|
28
26
|
it "encodes single float values" do
|
29
27
|
mesg = @builder.with_address("/hi").
|
30
|
-
|
31
|
-
|
32
|
-
mesg.build.encode.must_equal binary_string("/hi\000,f\000\000@I\017\320")
|
28
|
+
with_float(3.14159)
|
29
|
+
|
30
|
+
_(mesg.build.encode).must_equal binary_string("/hi\000,f\000\000@I\017\320")
|
33
31
|
end
|
34
|
-
|
32
|
+
|
35
33
|
it "encodes multiple floats" do
|
36
34
|
mesg = @builder.with_address("/hi").
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
mesg.build.encode.must_equal [47, 104, 105, 0, 44, 102, 102, 0, 64, 73, 15, 208, 64, 144, 0, 0].pack("C*")
|
35
|
+
with_float(3.14159).
|
36
|
+
with_float(4.5)
|
37
|
+
|
38
|
+
_(mesg.build.encode).must_equal [47, 104, 105, 0, 44, 102, 102, 0, 64, 73, 15, 208, 64, 144, 0, 0].pack("C*")
|
41
39
|
end
|
42
|
-
|
40
|
+
|
43
41
|
def binary_string(string)
|
44
42
|
string.force_encoding("BINARY")
|
45
43
|
end
|