Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base: d0b3022e35
...
compare: e3a51e45db
Checking mergeability… Don't worry, you can still create the pull request.
  • 9 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
View
1  .gitignore
@@ -1 +1,2 @@
+*.swp
*.beam
View
2  ebin/osc.app
@@ -2,7 +2,7 @@
{application, osc,
[{description, "Open Sound Control Application"},
{vsn, "1.0.0"},
- {modules, [osc_app, osc_sup, osc_lib, osc_server]},
+ {modules, [osc_app, osc_sup, osc_lib, osc_server, osc_methods]},
{registered, [osc_sup, osc_server]},
{applications, [kernel, stdlib]},
{mod, {osc_app, []}},
View
142 src/osc_lib.erl
@@ -1,20 +1,22 @@
%% @author Ruslan Babayev <ruslan@babayev.com>
+%% @author Tobias Rodaebel <tobias.rodaebel@googlemail.com>
%% @copyright 2009 Ruslan Babayev
-%% @doc OSC Decoding Library.
+%% @doc OSC Decoding/Encoding Library.
-module(osc_lib).
-author("ruslan@babayev.com").
+-author("tobias.rodaebel@googlemail.com").
--export([decode/1]).
+-export([decode/1, encode/1]).
-include_lib("eunit/include/eunit.hrl").
%% @type message() = {message, Address::string(), args()}
%% @type args() = [integer() | float() | binary() | time() | atom() | time() |
%% rgba() | midi() | true | false | null | impulse | args()]
-%% @type time() = immediately | {Seconds::integer(), Fractions::integer()}
-%% @type rgba() = {R::integer(), G::integer(), B::integer(), A::integer()}
-%% @type midi() = {Port::integer(), Status::integer(), binary(), binary()}
+%% @type time() = immediately | {time, Seconds::integer(), Fractions::integer()}
+%% @type rgba() = {rgba, R::integer(), G::integer(), B::integer(), A::integer()}
+%% @type midi() = {midi, Port::integer(), Status::integer(), binary(), binary()}
%% @type bundle() = {bundle, When::time(), [message() | bundle()]}
%% @doc Decodes messages.
@@ -47,7 +49,7 @@ decode_bundle_elems(<<Size:32, Bin:Size/binary, Rest/binary>>, Acc) ->
decode_time(<<1:64>>) ->
immediately;
decode_time(<<Seconds:32, Fractions:32>>) ->
- {Seconds, Fractions}.
+ {time, Seconds, Fractions}.
%% @doc Decodes a padded and zero-terminated string.
%% @spec decode_string(Bytes::binary()) -> {String::string(), Rest::binary()}
@@ -129,9 +131,9 @@ decode_args(Bin, [$S|T], Acc) ->
decode_args(<<Char:32, Rest/binary>>, [$c|T], Acc) ->
decode_args(Rest, T, [Char|Acc]);
decode_args(<<R, G, B, A, Rest/binary>>, [$r|T], Acc) ->
- decode_args(Rest, T, [{R,G,B,A}|Acc]);
+ decode_args(Rest, T, [{rgba,R,G,B,A}|Acc]);
decode_args(<<Port, Status, Data1, Data2, Rest/binary>>, [$m|T], Acc) ->
- decode_args(Rest, T, [{Port,Status,Data1,Data2}|Acc]);
+ decode_args(Rest, T, [{midi,Port,Status,Data1,Data2}|Acc]);
decode_args(Bin, [$T|T], Acc) ->
decode_args(Bin, T, [true|Acc]);
decode_args(Bin, [$F|T], Acc) ->
@@ -148,11 +150,41 @@ decode_args(Bin, [$]|T], Acc) ->
%% @hidden
decode_args_test() ->
- Bin = <<1:32,100,97,116,97,0,0,0,0,1:32,4:32,5:32,2:32,3:32>>,
- Types = "is[i[ii]i]i",
- Args = [1,"data",[1,[4,5],2],3],
+ Bin = <<1:32,102,111,111,0,1:32,4:32,5:32,2:32,3:32,255,255,255,255>>,
+ Types = "is[i[ii]i]ir",
+ Args = [1,"foo",[1,[4,5],2],3,{rgba, 255,255,255,255}],
?assertEqual({Args, <<>>}, decode_args(Bin, Types, [])).
+%% @doc Encodes messages.
+%% @spec encode(message()|bundle()) -> Bytes::binary()
+encode({message, Address, Args}) ->
+ Bytes = encode_string(Address),
+ {Data, Types} = encode_args(Args),
+ list_to_binary([<<Bytes/binary>>,[encode_types(Types, []),Data]]).
+
+%% @hidden
+encode_test_() ->
+ Message1 = {message, "/1/play", [1.0]},
+ Result1 = <<47,49,47,112,108,97,121,0,44,102,0,0,63,128,0,0>>,
+ Message2 = {message,"/1/xy1",[1.0,1.0]},
+ Result2 = <<47,49,47,120,121,49,0,0,44,102,102,0,63,128,0,0,63,128,0,0>>,
+ [?_assertEqual(Result1, encode(Message1)),
+ ?_assertEqual(Message1, decode(Result1)),
+ ?_assertEqual(Result2, encode(Message2)),
+ ?_assertEqual(Message2, decode(Result2))].
+
+%% @doc Encodes times.
+%% @spec encode_time(Time::time()) -> binary()
+encode_time(immediately) ->
+ <<1:64>>;
+encode_time({time, Seconds, Fractions}) ->
+ <<Seconds:32, Fractions:32>>.
+
+%% @hidden
+encode_time_test_() ->
+ [?_assertEqual(<<1:64>>, encode_time(immediately)),
+ ?_assertEqual(<<10:32,5:32>>, encode_time({time, 10, 5}))].
+
%% @doc Encodes the string by zero-terminating it and padding to 4 chars.
%% @spec encode_string(string()) -> binary()
encode_string(String) when is_list(String) ->
@@ -177,3 +209,91 @@ encode_blobs_test_() ->
?_assertEqual(<<0,0,0,2,1,2,0,0>>, encode_blob(<<1,2>>)),
?_assertEqual(<<0,0,0,3,1,2,3,0>>, encode_blob(<<1,2,3>>)),
?_assertEqual(<<0,0,0,4,1,2,3,4>>, encode_blob(<<1,2,3,4>>))].
+
+%% @doc Checks whether a list is a string.
+%% @spec is_string(List) -> true | false
+is_string([]) -> true;
+is_string([H|_]) when not is_integer(H) -> false;
+is_string([_|T]) -> is_string(T);
+is_string(_) -> false.
+
+%% @hidden
+is_string_test_() ->
+ [?_assertEqual(true, is_string("foo")),
+ ?_assertEqual(false, is_string([one,2]))].
+
+%% @doc Encodes args.
+%% @spec encode_args(Args::args()) -> Bytes::binary()
+encode_args(Args) ->
+ encode_args(Args, [], []).
+
+encode_args([], Acc, Types) ->
+ {list_to_binary(Acc), lists:flatten(Types)};
+encode_args([{i,Int32}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<Int32:32>>], [Types,$i]);
+encode_args([Int32|Rest], Acc, Types) when is_integer(Int32) ->
+ encode_args([{i,Int32}|Rest], Acc, Types);
+encode_args([{f,Float}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<Float:32/float>>], [Types,$f]);
+encode_args([Float|Rest], Acc, Types) when is_float(Float) ->
+ encode_args([{f,Float}|Rest], Acc, Types);
+encode_args([{s,String}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,encode_string(String)], [Types,$s]);
+encode_args([{b,Blob}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,encode_blob(Blob)], [Types,$b]);
+encode_args([{h,Int64}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<Int64:64>>], [Types,$h]);
+encode_args([{time,Seconds,Fractions}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,encode_time({time,Seconds,Fractions})], [Types,$t]);
+encode_args([immediately|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,encode_time(immediately)], [Types,$t]);
+encode_args([{d,Double}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<Double:64/float>>], [Types,$d]);
+encode_args([true|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<>>], [Types,$T]);
+encode_args([false|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<>>], [Types,$F]);
+encode_args([null|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<>>], [Types,$N]);
+encode_args([impulse|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<>>], [Types,$I]);
+encode_args([Symbol|Rest], Acc, Types) when is_atom(Symbol) ->
+ encode_args(Rest, [Acc,encode_string(atom_to_list(Symbol))], [Types,$S]);
+encode_args([{c,Char}|Rest], Acc, Types) when is_integer(Char) ->
+ encode_args(Rest, [Acc,<<Char:32>>], [Types,$c]);
+encode_args([{rgba,R,G,B,A}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<R/integer,G/integer,B/integer,A/integer>>],
+ [Types,$r]);
+encode_args([{midi,Port,Status,Data1,Data2}|Rest], Acc, Types) ->
+ encode_args(Rest, [Acc,<<Port/integer,Status/integer,Data1/binary,Data2/binary>>], [Types,$m]);
+encode_args([L|Rest], Acc, Types) when is_list(L) ->
+ case is_string(L) of
+ true ->
+ encode_args([{s,L}|Rest], Acc, Types);
+ false ->
+ {Bytes, Types2} = encode_args(L, [], []),
+ encode_args(Rest, [Acc,Bytes], [Types,$[,Types2,$]])
+ end.
+
+%% @hidden
+encode_args_test() ->
+ Bin = <<1:32,2:32,1:64,100,97,116,97,0,0,0,0,2.5:32/float,42:64,
+ 0,0,0,1,1,0,0,0,102,111,111,0,97:32,255,255,255,255>>,
+ Types = "i[it[sf]h]bScrTFI",
+ A = [{i,1},[{i,2},immediately,[{s,"data"},{f,2.5}],{h,42}],{b,<<1>>},foo,
+ {c,$a},{rgba,255,255,255,255},true,false,impulse],
+ ?assertEqual({Bin, Types}, encode_args(A)),
+ B = [1,[2,immediately,["data",2.5],{h,42}],{b,<<1>>},'foo',{c,$a},
+ {rgba,255,255,255,255},true,false,impulse],
+ ?assertEqual({Bin, Types}, encode_args(B)).
+
+%% @doc Encodes type identifiers
+%% @spec encode_types(Types, []) -> binary()
+encode_types([], Acc) ->
+ pad(list_to_binary([<<$,>>,Acc]), 4);
+encode_types([Type|Rest], Acc) ->
+ encode_types(Rest, [Acc,<<Type/integer>>]).
+
+%% @hidden
+encode_types_test() ->
+ ?assertEqual(<<44,102,102,0>>, encode_types("ff", [])).
View
24 src/osc_methods.erl
@@ -0,0 +1,24 @@
+%% @author Tobias Rodaebel
+%% @doc Adding OSC methods.
+
+-module(osc_methods).
+
+-export([add_methods/0, delete_methods/0, log_data/1]).
+
+-define(SERVER, {global, osc_server}).
+
+%% @doc Adds methods.
+%% @spec add_methods() -> ok
+add_methods() ->
+ gen_server:cast(?SERVER, {add_method, "/1/stop", ?MODULE, log_data}).
+
+%% @doc Deletes methods.
+%% @spec delete_methods() -> ok
+delete_methods() ->
+ gen_server:cast({global, osc_server}, {delete_method, "/1/stop"}).
+
+%% @doc Logs handled data.
+%% @spec log_data(Data) -> Data
+log_data(Data) ->
+ error_logger:info_msg("Received ~p", [Data]),
+ Data.
View
8 src/osc_server.erl
@@ -22,7 +22,7 @@
%% @doc Starts the server.
%% @spec start_link() -> {ok, Pid} | ignore | {error, Reason}
start_link() ->
- gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+ gen_server:start_link({global, ?SERVER}, ?MODULE, [], []).
%% @doc Adds a method.
%% @spec add_method(string(), atom(), atom()) -> ok
@@ -153,10 +153,10 @@ make_pattern2([H|T], Acc) ->
%% @doc Converts OSC time to milliseconds.
%% @spec when_to_millisecs(When) -> integer()
-%% When = immediately | {Seconds::integer(), Fractions::integer()}
+%% When = immediately | {time, Seconds::integer(), Fractions::integer()}
when_to_millisecs(immediately) ->
0;
-when_to_millisecs({Seconds, Fractions}) ->
+when_to_millisecs({time, Seconds, Fractions}) ->
{MegaSecs, Secs, MicroSecs} = now(),
S = (Seconds - 2208988800) - (MegaSecs * 1000000 + Secs),
F = Fractions - (MicroSecs * 1000000),
@@ -173,7 +173,7 @@ when_to_millisecs({Seconds, Fractions}) ->
%% Methods = [method()]
%% message() = {message, Address::string(), Args::[any()]}
%% bundle() = {bundle, When::time(), [message() | bundle()]}
-%% time() = immediately | {Seconds::integer(), Fractions::integer()}
+%% time() = immediately | {time, Seconds::integer(), Fractions::integer()}
%% method() = {Module::atom(), Function::atom()}
handle_bundle(_When, [], _Methods) ->
ok;

No commit comments for this range

Something went wrong with that request. Please try again.