aberant-osc-ruby 0.1.5

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.
data/README ADDED
@@ -0,0 +1,14 @@
1
+ An "OSC" module
2
+ ==============
3
+
4
+ OSC is an "OpenSound Control" module for an object‐oriented
5
+ scripting language Ruby.
6
+
7
+
8
+
9
+
10
+
11
+ Originally created by...
12
+ Tadayoshi Funaba
13
+ mailto:tadf@funaba.org
14
+ http://www.funaba.org/en/
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 5
4
+ :major: 0
@@ -0,0 +1,16 @@
1
+ # osc.rb: Written by Tadayoshi Funaba 2005,2006
2
+ # $Id: osc.rb,v 1.4 2006-11-10 21:54:37+09 tadf Exp $
3
+
4
+ require 'forwardable'
5
+ require 'socket'
6
+ require 'thread'
7
+
8
+ require 'osc-ruby/osc_types'
9
+ require 'osc-ruby/packet'
10
+ require 'osc-ruby/message'
11
+ require 'osc-ruby/bundle'
12
+
13
+ require 'osc-ruby/simple_server'
14
+ require 'osc-ruby/simple_client'
15
+
16
+
@@ -0,0 +1,55 @@
1
+ module OSC
2
+ class Bundle < Packet
3
+ extend Forwardable
4
+ include Enumerable
5
+
6
+ attr_accessor :timetag
7
+
8
+ undef_method :zip
9
+
10
+ de = (Array.instance_methods - self.instance_methods)
11
+ de -= %w(assoc flatten flatten! pack rassoc transpose)
12
+ de += %w(include? sort)
13
+
14
+ def_delegators(:@args, *de)
15
+
16
+
17
+ def initialize(timetag=nil, *args)
18
+ @timetag = timetag
19
+ @args = args
20
+ end
21
+
22
+ def encode()
23
+ s = OSCString.new('#bundle').encode
24
+ s << encode_timetag(@timetag)
25
+ s << @args.collect do |x|
26
+ x2 = x.encode; [x2.size].pack('N') + x2
27
+ end.join
28
+ end
29
+
30
+
31
+ def to_a() @args.collect{|x| x.to_a} end
32
+
33
+
34
+
35
+ private
36
+
37
+ def encode_timetag(t)
38
+ case t
39
+ when NIL # immediately
40
+ t1 = 0
41
+ t2 = 1
42
+ when Numeric
43
+ t1, fr = t.divmod(1)
44
+ t2 = (fr * (2**32)).to_i
45
+ when Time
46
+ t1, fr = (t.to_f + 2208988800).divmod(1)
47
+ t2 = (fr * (2**32)).to_i
48
+ else
49
+ raise ArgumentError, 'invalid time'
50
+ end
51
+ [t1, t2].pack('N2')
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ module OSC
2
+ class Message < Packet
3
+ extend Forwardable
4
+ include Enumerable
5
+
6
+ attr_accessor :address
7
+ undef_method :zip
8
+
9
+ de = (Array.instance_methods - self.instance_methods)
10
+ de -= %w(assoc flatten flatten! pack rassoc transpose)
11
+ de += %w(include? sort)
12
+
13
+ def_delegators(:@args, *de)
14
+
15
+
16
+ def initialize(address, tags=nil, *args)
17
+ @address = address
18
+ @args = []
19
+ args.each_with_index do |arg, i|
20
+ if tags && tags[i]
21
+ case tags[i]
22
+ when ?i; @args << OSCInt32.new(arg)
23
+ when ?f; @args << OSCFloat32.new(arg)
24
+ when ?s; @args << OSCString.new(arg)
25
+ when ?b; @args << OSCBlob.new(arg)
26
+ when ?*; @args << arg
27
+ else; raise ArgumentError, 'unknown type'
28
+ end
29
+ else
30
+ case arg
31
+ when Integer; @args << OSCInt32.new(arg)
32
+ when Float; @args << OSCFloat32.new(arg)
33
+ when String; @args << OSCString.new(arg)
34
+ when OSCArgument; @args << arg
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+
41
+ def tags() ',' + @args.collect{|x| x.tag}.join end
42
+
43
+ def encode
44
+ s = OSCString.new(@address).encode
45
+ s << OSCString.new(tags).encode
46
+ s << @args.collect{|x| x.encode}.join
47
+ end
48
+
49
+ def to_a() @args.collect{|x| x.val} end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ module OSC
2
+ class OSCArgument
3
+
4
+ def initialize(val) @val = val end
5
+
6
+ attr_accessor :val
7
+
8
+ def to_i() @val.to_i end
9
+ def to_f() @val.to_f end
10
+ def to_s() @val.to_s end
11
+
12
+ def padding(s)
13
+ s + ("\000" * ((4 - (s.size % 4)) % 4))
14
+ end
15
+
16
+ private :padding
17
+
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ require 'osc-ruby/osc_argument'
2
+
3
+ module OSC
4
+ class OSCInt32 < OSCArgument
5
+
6
+ def tag() 'i' end
7
+ def encode() [@val].pack('N') end
8
+
9
+ end
10
+
11
+ class OSCFloat32 < OSCArgument
12
+
13
+ def tag() 'f' end
14
+ def encode() [@val].pack('g') end # fake
15
+
16
+ end
17
+
18
+ class OSCString < OSCArgument
19
+
20
+ def tag() 's' end
21
+ def encode() padding(@val.sub(/\000.*\z/, '') + "\000") end
22
+
23
+ end
24
+
25
+ class OSCBlob < OSCArgument
26
+
27
+ def tag() 'b' end
28
+ def encode() padding([@val.size].pack('N') + @val) end
29
+
30
+ end
31
+ end
@@ -0,0 +1,120 @@
1
+ module OSC
2
+ class Packet
3
+
4
+ class PO
5
+ def initialize(str) @str, @index = str, 0 end
6
+ def rem() @str.length - @index end
7
+ def eof? () rem <= 0 end
8
+ def skip(n) @index += n end
9
+ def skip_padding() skip((4 - (@index % 4)) % 4) end
10
+
11
+ def getn(n)
12
+ raise EOFError if rem < n
13
+ s = @str[@index, n]
14
+ skip(n)
15
+ s
16
+ end
17
+
18
+ def getc
19
+ raise EOFError if rem < 1
20
+ c = @str[@index]
21
+ skip(1)
22
+ c
23
+ end
24
+ end
25
+
26
+ def self.decode_int32(io)
27
+ i = io.getn(4).unpack('N')[0]
28
+ i -= 2**32 if i > (2**31-1)
29
+ i
30
+ end
31
+
32
+ def self.decode_float32(io)
33
+ f = io.getn(4).unpack('g')[0]
34
+ f
35
+ end
36
+
37
+ def self.decode_string(io)
38
+ s = ''
39
+ until (c = io.getc) == 0
40
+ s << c
41
+ end
42
+ io.skip_padding
43
+ s
44
+ end
45
+
46
+ def self.decode_blob(io)
47
+ l = io.getn(4).unpack('N')[0]
48
+ b = io.getn(l)
49
+ io.skip_padding
50
+ b
51
+ end
52
+
53
+ def self.decode_timetag(io)
54
+ t1 = io.getn(4).unpack('N')[0]
55
+ t2 = io.getn(4).unpack('N')[0]
56
+ [t1, t2]
57
+ end
58
+
59
+ def self.decode2(time, packet, list)
60
+ io = PO.new(packet)
61
+ id = decode_string(io)
62
+ if id =~ /\A\#/
63
+ if id == '#bundle'
64
+ t1, t2 = decode_timetag(io)
65
+ if t1 == 0 && t2 == 1
66
+ time = nil
67
+ else
68
+ time = t1 + t2.to_f / (2**32)
69
+ end
70
+ until io.eof?
71
+ l = io.getn(4).unpack('N')[0]
72
+ s = io.getn(l)
73
+ decode2(time, s, list)
74
+ end
75
+ end
76
+ elsif id =~ /\//
77
+ address = id
78
+ if io.getc == ?,
79
+ tags = decode_string(io)
80
+ args = []
81
+ tags.scan(/./) do |t|
82
+ case t
83
+ when 'i'
84
+ i = decode_int32(io)
85
+ args << OSCInt32.new(i)
86
+ when 'f'
87
+ f = decode_float32(io)
88
+ args << OSCFloat32.new(f)
89
+ when 's'
90
+ s = decode_string(io)
91
+ args << OSCString.new(s)
92
+ when 'b'
93
+ b = decode_blob(io)
94
+ args << OSCBlob.new(b)
95
+ when /[htd]/; io.read(8)
96
+ when 'S'; decode_string(io)
97
+ when /[crm]/; io.read(4)
98
+ when /[TFNI\[\]]/;
99
+ end
100
+ end
101
+ list << [time, Message.new(address, nil, *args)]
102
+ end
103
+ end
104
+ end
105
+
106
+ private_class_method :decode_int32,
107
+ :decode_float32,
108
+ :decode_string,
109
+ :decode_blob,
110
+ :decode_timetag,
111
+ :decode2
112
+
113
+ def self.decode(packet)
114
+ list = []
115
+ decode2(nil, packet, list)
116
+ list
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,14 @@
1
+ module OSC
2
+ class SimpleClient
3
+
4
+ def initialize(host, port)
5
+ @so = UDPSocket.new
6
+ @so.connect(host, port)
7
+ end
8
+
9
+ def send(mesg)
10
+ @so.send(mesg.encode, 0)
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,93 @@
1
+ module OSC
2
+ class SimpleServer
3
+
4
+ def initialize(port)
5
+ @so = UDPSocket.new
6
+ @so.bind('', port)
7
+ @cb = []
8
+ @qu = Queue.new
9
+ end
10
+
11
+ def add_method(pat, obj=nil, &proc)
12
+ case pat
13
+ when NIL; re = pat
14
+ when Regexp; re = pat
15
+ when String
16
+ pat = pat.dup
17
+ pat.gsub!(/[.^(|)]/, '\\1')
18
+ pat.gsub!(/\?/, '[^/]')
19
+ pat.gsub!(/\*/, '[^/]*')
20
+ pat.gsub!(/\[!/, '[^')
21
+ pat.gsub!(/\{/, '(')
22
+ pat.gsub!(/,/, '|')
23
+ pat.gsub!(/\}/, ')')
24
+ pat.gsub!(/\A/, '\A')
25
+ pat.gsub!(/\z/, '\z')
26
+ re = Regexp.new(pat)
27
+ else
28
+ raise ArgumentError, 'invalid pattern'
29
+ end
30
+
31
+ unless ( obj && !proc) ||
32
+ (!obj && proc)
33
+ raise ArgumentError, 'wrong number of arguments'
34
+ end
35
+ @cb << [re, (obj || proc)]
36
+ end
37
+
38
+ def sendmesg(mesg)
39
+ @cb.each do |re, obj|
40
+ if re.nil? || re =~ mesg.address
41
+ obj.send(if Proc === obj then :call else :accept end, mesg)
42
+ end
43
+ end
44
+ end
45
+
46
+ def dispatcher
47
+ loop do
48
+ time, mesg = @qu.pop
49
+ now = Time.now.to_f + 2208988800
50
+ diff = if time.nil?
51
+ then 0 else time - now end
52
+
53
+ if diff <= 0
54
+ sendmesg(mesg)
55
+ else
56
+ Thread.fork do
57
+ sleep(diff)
58
+ sendmesg(mesg)
59
+ Thread.exit
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def detector
66
+ loop do
67
+ pa = @so.recv(16384)
68
+ begin
69
+ Packet.decode(pa).each{|x| @qu.push(x)}
70
+ rescue EOFError
71
+ end
72
+ end
73
+ end
74
+
75
+ private :sendmesg, :dispatcher, :detector
76
+
77
+ def run
78
+ Thread.fork do
79
+ begin
80
+ dispatcher
81
+ rescue
82
+ Thread.main.raise $!
83
+ end
84
+ end
85
+
86
+ begin
87
+ detector
88
+ rescue
89
+ Thread.main.raise $!
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,25 @@
1
+ # require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+ # TODO: figure out what thread magic i need to get this to work
3
+
4
+ # describe "send and receive" do
5
+ # it "should be able to send and receive messages" do
6
+ # server = OSC::SimpleServer.new( 3333 )
7
+ #
8
+ # watcher = Object.new
9
+ # stub( watcher ).called
10
+ #
11
+ # server.add_method( "/hi") do |m|
12
+ # watcher.called
13
+ # end
14
+ #
15
+ # Thread.new do
16
+ # server.run
17
+ # end
18
+ #
19
+ #
20
+ # client = OSC::SimpleClient.new( "localhost", 3333 )
21
+ # client.send( OSC::Message.new( "/hi" ) )
22
+ #
23
+ # watcher.should have_received.called
24
+ # end
25
+ # end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'rr'
4
+
5
+ $:.unshift( File.join( File.dirname( __FILE__), '..', 'lib' ) )
6
+
7
+ require 'osc-ruby'
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with RR::Adapters::Rspec
11
+ end
@@ -0,0 +1,7 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+ describe OSC::OSCArgument do
4
+ it "should not blow up" do
5
+ OSC::OSCArgument.new 1
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+ describe OSC::OSCInt32 do
4
+ it "should not blow up" do
5
+ OSC::OSCInt32.new 1
6
+ end
7
+
8
+ end
9
+
10
+ describe OSC::OSCFloat32 do
11
+ it "should not blow up" do
12
+ OSC::OSCFloat32.new 1.0
13
+ end
14
+ end
15
+
16
+ describe OSC::OSCString do
17
+ it "should not blow up" do
18
+ OSC::OSCString.new "1"
19
+ end
20
+ end
21
+
22
+ describe OSC::OSCBlob do
23
+ it "should not blow up" do
24
+ OSC::OSCBlob.new 1
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require File.join( File.dirname(__FILE__) , '..', 'spec_helper' )
2
+
3
+ describe OSC::SimpleClient do
4
+ it "should not blow up" do
5
+ udp = Object.new
6
+ stub( udp ).connect
7
+ stub( UDPSocket ).new.returns( udp )
8
+
9
+ OSC::SimpleClient.new( "localhost", 3333 )
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aberant-osc-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - aberant
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: qzzzq1@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - VERSION.yml
26
+ - lib/osc-ruby
27
+ - lib/osc-ruby/bundle.rb
28
+ - lib/osc-ruby/message.rb
29
+ - lib/osc-ruby/osc_argument.rb
30
+ - lib/osc-ruby/osc_types.rb
31
+ - lib/osc-ruby/packet.rb
32
+ - lib/osc-ruby/simple_client.rb
33
+ - lib/osc-ruby/simple_server.rb
34
+ - lib/osc-ruby.rb
35
+ - spec/integration
36
+ - spec/integration/send_receive_spec.rb
37
+ - spec/spec_helper.rb
38
+ - spec/unit
39
+ - spec/unit/osc_argument_spec.rb
40
+ - spec/unit/osc_types_spec.rb
41
+ - spec/unit/simple_client_spec.rb
42
+ - README
43
+ has_rdoc: true
44
+ homepage: http://github.com/aberant/osc-ruby
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --inline-source
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: inital gem
70
+ test_files: []
71
+