fast_osc 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24934bf4851d8faf6a3f60a298f51519118c5865
4
+ data.tar.gz: 81d1d5472ae0928587879ffb2ecdee3d265b832f
5
+ SHA512:
6
+ metadata.gz: 104becd81c316514e4171614079d7aee8ba4d33c5788cfd82558ac834374d127ae468dd64c188e89ce94416cdbb692d40d2de00b67b7987a24018284cec031de
7
+ data.tar.gz: 4eeef0b840558a8a51fcecea56776b734d3e79793421ab13bbce4f75074fe61affc7fe8adbd2b13da6a2b6066cda07b2f350e360402a8e80205077de8c66a110
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ lib/*.bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fast_osc.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,48 @@
1
+ # rtosc licence
2
+
3
+ Copyright (c) 2012 Mark McCurry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a
6
+ copy of this software and associated documentation files (the "Software"),
7
+ to deal in the Software without restriction, including without limitation
8
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ and/or sell copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice (including the next
13
+ paragraph) shall be included in all copies or substantial portions of the
14
+ Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ DEALINGS IN THE SOFTWARE.
24
+
25
+ # fast_osc gem wrapper licence
26
+
27
+ Copyright (c) 2016 Xavier Riley
28
+
29
+ MIT License
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ "Software"), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
46
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
47
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
48
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # FastOsc
2
+
3
+ `WARNING - Work in progress. Probably not safe for production yet`
4
+
5
+ A Ruby wrapper around [rtosc](https://github.com/fundamental/rtosc/) to encode and decode OSC messages.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'fast_osc'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install fast_osc
20
+
21
+ This will only work on a mac at the moment as that's what the `librtosc.a` was compiled on.
22
+
23
+ ## Is it fast?
24
+
25
+ Let's see...
26
+
27
+ Key:
28
+
29
+ * `fast_osc` - this gem
30
+ * `osc` - [`osc-ruby`](https://github.com/aberant/osc-ruby)
31
+ * `samsosc` - `OSC` classes from Sonic Pi (which are optimised pure Ruby based on `pack` and `unpack`)
32
+
33
+ ### Encoding Benchmark
34
+
35
+ ```
36
+ ["/feeooblah", ["beans", 1, 2.0]]
37
+ Calculating -------------------------------------
38
+ fast_osc 54.101k i/100ms
39
+ osc 7.688k i/100ms
40
+ samsosc 21.406k i/100ms
41
+ -------------------------------------------------
42
+ fast_osc 909.680k (±21.4%) i/s - 4.328M
43
+ osc 94.678k (±14.5%) i/s - 468.968k
44
+ samsosc 271.908k (±19.3%) i/s - 1.327M
45
+ ```
46
+
47
+ ## Decoding Bencmark
48
+
49
+ ```
50
+ ["/feeooblah", ["beans", 1, 2.0]]
51
+ Calculating -------------------------------------
52
+ fast_osc 91.434k i/100ms
53
+ samsosc 22.095k i/100ms
54
+ oscruby 3.522k i/100ms
55
+ -------------------------------------------------
56
+ fast_osc 2.635M (±22.2%) i/s - 12.435M
57
+ samsosc 264.614k (±16.1%) i/s - 1.304M
58
+ oscruby 36.362k (±16.3%) i/s - 179.622k
59
+ ```
60
+
61
+ Benchmark adapted from https://github.com/samaaron/sonic-pi/blob/master/app/server/sonicpi/test/performance/test_osc_perf.rb
62
+
63
+ I'll include a better test in the repo in time.
64
+
65
+ ## Usage
66
+
67
+ ```
68
+ >> FastOsc.serialize("/foo", ["baz", 1, 2.0])
69
+ => "/foo\x00\x00\x00\x00,sif\x00\x00\x00\x00baz\x00\x00\x00\x00\x01@\x00\x00\x00"
70
+ >> res = _
71
+ >> FastOsc.deserialize(res)
72
+ => ["baz", 1, 2.0]
73
+ ```
74
+
75
+ ## Still todo
76
+
77
+ * Implement more types
78
+ * return address with `deserialize` (doh!)
79
+ * add tests at the Ruby level (rtosc C code is already tested)
80
+ * figure out build process
81
+
82
+ ## Development notes
83
+
84
+ bundle install
85
+ rake compile
86
+
87
+ https://gist.github.com/xavriley/507eff0a75d4552fa56e
88
+
89
+ ## Contributing
90
+
91
+ 1. Fork it ( http://github.com/<my-github-username>/fast_osc/fork )
92
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
93
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
94
+ 4. Push to the branch (`git push origin my-new-feature`)
95
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/extensiontask'
4
+ spec = Gem::Specification.load('fast_osc.gemspec')
5
+ Rake::ExtensionTask.new('fast_osc', spec)
@@ -0,0 +1,28 @@
1
+ require 'mkmf'
2
+
3
+ LIBDIR = RbConfig::CONFIG['libdir']
4
+ INCLUDEDIR = RbConfig::CONFIG['includedir']
5
+
6
+ #HEADER_DIRS = ["/Users/xriley/Projects/rtosc/include/rtosc", INCLUDEDIR]
7
+ HEADER_DIRS = [INCLUDEDIR]
8
+
9
+ # # setup constant that is equal to that of the file path that holds that static libraries that will need to be compiled against
10
+ # LIB_DIRS = [LIBDIR, File.expand_path(File.join(File.dirname(__FILE__), "lib"))]
11
+ LIB_DIRS = [LIBDIR]
12
+
13
+ # # array of all libraries that the C extension should be compiled against
14
+ # libs = ['-lrtosc']
15
+
16
+ extension_name = 'fast_osc'
17
+ dir_config(extension_name, HEADER_DIRS, LIB_DIRS)
18
+
19
+ # iterate though the libs array, and append them to the $LOCAL_LIBS array used for the makefile creation
20
+ # libs.each do |lib|
21
+ # $LOCAL_LIBS << "#{lib} "
22
+ # end
23
+
24
+ $srcs = ["fast_osc_wrapper.c"]
25
+
26
+ $CFLAGS << " -std=c99 -Wall -Wextra -Wno-unused-parameter"
27
+
28
+ create_makefile(extension_name)
@@ -0,0 +1,155 @@
1
+ #include <ruby.h>
2
+ #include <rtosc.h>
3
+ #include <rtosc.c>
4
+
5
+ // Allocate VALUE variables to hold the modules we'll create. Ruby values
6
+ // are all of type VALUE. Qnil is the C representation of Ruby's nil.
7
+ VALUE FastOsc = Qnil;
8
+
9
+ // Declare a couple of functions. The first is initialization code that runs
10
+ // when this file is loaded, and the second is the actual business logic we're
11
+ // implementing.
12
+ void Init_fast_osc();
13
+ VALUE method_fast_osc_deserialize(VALUE self, VALUE msg);
14
+ VALUE method_fast_osc_serialize(VALUE self, VALUE address, VALUE args);
15
+
16
+ // Initial setup function, takes no arguments and returns nothing. Some API
17
+ // notes:
18
+ //
19
+ // * rb_define_module() creates and returns a top-level module by name
20
+ //
21
+ // * rb_define_module_under() takes a module and a name, and creates a new
22
+ // module within the given one
23
+ //
24
+ // * rb_define_singleton_method() take a module, the method name, a reference to
25
+ // a C function, and the method's arity, and exposes the C function as a
26
+ // single method on the given module
27
+ //
28
+ void Init_fast_osc() {
29
+ FastOsc = rb_define_module("FastOsc");
30
+ rb_define_singleton_method(FastOsc, "deserialize", method_fast_osc_deserialize, 1);
31
+ rb_define_singleton_method(FastOsc, "serialize", method_fast_osc_serialize, 2);
32
+ }
33
+
34
+ VALUE method_fast_osc_deserialize(VALUE self, VALUE msg) {
35
+ rtosc_arg_itr_t itr;
36
+ char* data = StringValuePtr(msg);
37
+ itr = rtosc_itr_begin(data);
38
+ VALUE output = rb_ary_new();
39
+
40
+ rtosc_arg_val_t next_val;
41
+
42
+ while(!rtosc_itr_end(itr)) {
43
+
44
+ next_val = rtosc_itr_next(&itr);
45
+
46
+ switch(next_val.type) {
47
+ case 'i' :
48
+ // INT2FIX() for integers within 31bits.
49
+ rb_ary_push(output, INT2FIX(next_val.val.i));
50
+ break;
51
+ case 'f' :
52
+ rb_ary_push(output, rb_float_new(next_val.val.f));
53
+ break;
54
+ case 's' :
55
+ rb_ary_push(output, rb_str_new2(next_val.val.s));
56
+ break;
57
+ case 'b' :
58
+ rb_ary_push(output, rb_str_new((const char*)next_val.val.b.data, next_val.val.b.len));
59
+ break;
60
+ case 'h' :
61
+ // INT2NUM() for arbitrary sized integers
62
+ rb_ary_push(output, INT2NUM(next_val.val.h));
63
+ break;
64
+ case 't' :
65
+ // OSC time tag
66
+ // not implemented
67
+ break;
68
+ case 'd' :
69
+ rb_ary_push(output, rb_float_new(next_val.val.d));
70
+ break;
71
+ case 'S' :
72
+ rb_ary_push(output, ID2SYM(rb_intern(next_val.val.s)));
73
+ break;
74
+ case 'c' :
75
+ rb_ary_push(output, rb_str_concat(rb_str_new2(""), INT2FIX(next_val.val.i)));
76
+ break;
77
+ }
78
+
79
+ }
80
+
81
+ return output;
82
+ }
83
+
84
+ int buffer_size_for_ruby_string(VALUE rstring) {
85
+ int str_bytesize = FIX2INT(LONG2FIX(RSTRING_LEN(rstring)));
86
+ return (int)((str_bytesize + sizeof(int) - 1) & ~(sizeof(int) - 1));
87
+ }
88
+
89
+ VALUE method_fast_osc_serialize(VALUE self, VALUE address, VALUE args) {
90
+ char* c_address = StringValueCStr(address);
91
+
92
+ int no_of_args = NUM2INT(LONG2NUM(RARRAY_LEN(args)));
93
+ int i;
94
+ int max_buffer_size = 0;
95
+ VALUE current_arg;
96
+
97
+ //output tags and args list
98
+ VALUE tagstring = rb_str_new2(""); //rtosc will handle comma
99
+ rtosc_arg_t output_args[no_of_args];
100
+
101
+ for(i = 0; i < no_of_args; i++) {
102
+ current_arg = rb_ary_entry(args, i);
103
+
104
+ switch(TYPE(current_arg)) {
105
+ case T_FIXNUM:
106
+ // max bytes for a single numeric representation
107
+ max_buffer_size += 8;
108
+
109
+ if(FIX2LONG(current_arg) < ~(1 << 31)) {
110
+ rb_str_concat(tagstring, rb_str_new2("i"));
111
+ output_args[i].i = FIX2INT(current_arg);
112
+ } else {
113
+ rb_str_concat(tagstring, rb_str_new2("h"));
114
+ output_args[i].h = FIX2LONG(current_arg);
115
+ }
116
+ break;
117
+ case T_FLOAT:
118
+ // now align to 4 byte boundary for sizing output buffer
119
+ max_buffer_size += 8;
120
+
121
+ rb_str_concat(tagstring, rb_str_new2("f"));
122
+ output_args[i].f = NUM2DBL(current_arg);
123
+ break;
124
+ case T_STRING:
125
+ // now align to 4 byte boundary for sizing output buffer
126
+ max_buffer_size += buffer_size_for_ruby_string(current_arg);
127
+
128
+ rb_str_concat(tagstring, rb_str_new2("s"));
129
+ output_args[i].s = StringValueCStr(current_arg);
130
+ break;
131
+ }
132
+ }
133
+
134
+ //add space for the address and tag strings to the buffer
135
+ max_buffer_size += buffer_size_for_ruby_string(address);
136
+ max_buffer_size += buffer_size_for_ruby_string(tagstring);
137
+
138
+ // Get next largest power of two for buffer
139
+ max_buffer_size--;
140
+ max_buffer_size |= max_buffer_size >> 1;
141
+ max_buffer_size |= max_buffer_size >> 2;
142
+ max_buffer_size |= max_buffer_size >> 4;
143
+ max_buffer_size |= max_buffer_size >> 8;
144
+ max_buffer_size |= max_buffer_size >> 16;
145
+ max_buffer_size++;
146
+
147
+ char buffer[max_buffer_size];
148
+
149
+
150
+ int len = rtosc_amessage(buffer, sizeof(buffer), c_address, StringValueCStr(tagstring), output_args);
151
+
152
+ VALUE output = rb_str_new(buffer, len);
153
+
154
+ return output;
155
+ }