osc-crystal
Open Sound Control implementation in Crystal.
This implementation is based on the The Open Sound Control 1.0 Specification and including some extensions (extra type-tag and dispatching).
Features
- encode/decode OSC message
- support extra type-tags associated with the tyeps in Crystal
- on receiving message, pattern match the address and callback concurrently
Arguments and Type Tags
This supports basic tags and some additional ones that be shown below:
|OSC Type Tag|Type in Crystal | |:-----------|:-------------- | |i |Int32 | |f |Float32 | |s |String | |b |OSC::Type::Blob(alias of Array(UIn8))| |h |Int64 | |d |Float64 | |t |Time | |c |Char | |r |OSC::Type::RGBA | |m |OSC::Type::Midi | |T |OSC::Type::True | |F |OSC::Type::False | |N |Nil | |I |OSC::Type::Inf |
Tags are inferred form the type of each argument. See Usage.
Installation
-
Add the dependency to your
shard.yml
:dependencies: osc-crystal: github: astellon/osc-crystal
-
Run
shards install
Usage
Getting start, send OSC Message via UDP soket in localhost.
require "osc-crystal"
# make message
m1 = OSC::Message.new("/addr", 0_i32)
# set up UDP server/client
server = UDPSocket.new
server.bind "localhost", 8000
client = UDPSocket.new
client.connect "localhost", 8000
# send message
client.send m1
# receive massage
message, client_addr = server.receive
# decode from bytes
m2 = OSC::Message.new(message.bytes)
# get argumanent
m2.arg(0) # => 0
Tags are inferred form the type of each argument like:
m = OSC::Message.new(
"/foo",
0_i32,
0_f32,
"String",
[0_u8, 0_u8, 0_u8, 0_u8],
0_i64,
0_f64,
Time.utc_now,
'0',
OSC::Type::RGBA.new(0_u8, 0_u8, 0_u8, 0_u8),
OSC::Type::Midi.new(0_u8, 0_u8, 0_u8, 0_u8),
OSC::Type::True,
OSC::Type::False,
Nil,
OSC::Type::Inf
)
m.address # => "/foo"
m.tag # => ifsbhdtcrmTFNI
m.arg(0) # => 0
The best way to handle the messages is to use OSC::Server
and OSC::Client
. You can specify the address and the process that will be involked when the given socket receives OSC messages. Example:
require "socket"
require "osc-crystal"
# set up UDP server/client and wrap sockets with OSC classes
server = UDPSocket.new
server.bind "localhost", 8000
osc_server = OSC::Server.new(server)
client = UDPSocket.new
client.connect "localhost", 8000
osc_client = OSC::Client.new(client)
# initialize `OSC::Message`s
m1 = OSC::Message.new(
"/*/*",
1_i32
)
m2 = OSC::Message.new(
"/*/hoge",
1_i32
)
# add methods for specific address
osc_server.dispatch("/foo/hoge") do |m|
puts "dispatched: /foo/hoge for #{m.address}"
end
osc_server.dispatch("/foo/fuga") do |m|
puts "dispatched: /foo/fuga for #{m.address}"
end
# run the server concurrently (return immediately)
osc_server.run
# send messages
osc_client.send m1
# => dispatched: /foo/hoge for /*/*
# dispatched: /foo/fuga for /*/*
osc_client.send m2
# => dispatched: /foo/hoge for /*/hoge
# Sleep a second
sleep(1)
client.close
server.close
Contributing
- Fork it (https://github.com/astellon/osc-crystal/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Contributors
- astellon - creator and maintainer
- Tobaloidee - logo