fast_osc 0.0.3

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.
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
+ }