fast_osc 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -24
- data/Rakefile +2 -0
- data/ext/fast_osc/fast_osc_wrapper.c +11 -30
- data/fast_osc.gemspec +1 -0
- data/lib/fast_osc.rb +16 -3
- data/lib/fast_osc/pure_ruby_fallback_decode.rb +134 -0
- data/lib/fast_osc/pure_ruby_fallback_encode.rb +163 -0
- data/lib/fast_osc/version.rb +1 -1
- data/test/benchmark_test.rb +51 -0
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4e7bff342d4a5632e0cf9f70c6d4370469a2a28
|
4
|
+
data.tar.gz: 471466562ba2ac1a9b7b98ccb3812e543dd97b77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 609e4d29594e0c230a0d8223e49612a292f0eac2e12f36a282af24fe5c149aaef2f0feafb8f40f931296cb9b419ea6e4ccbc30c6e6834355f5b8e4454daca408
|
7
|
+
data.tar.gz: 8e2508cb94292d344eab85becedff76948ce879240210eb0ddae5462fb2d18a0bc71e8e71ac8af7c5567429cd2172a1f9eba7578430ba843bdb6019c67c5c69e
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
A Ruby wrapper around [rtosc](https://github.com/fundamental/rtosc/) to encode and decode OSC messages.
|
6
6
|
|
7
|
+
This also includes a fallback implementation in pure Ruby in the case that the compiled version doesn't load properly. This can be forced by setting an environment variable of `FAST_OSC_USE_FALLBACK=1` where needed.
|
8
|
+
|
7
9
|
## Installation
|
8
10
|
|
9
11
|
Add this line to your application's Gemfile:
|
@@ -31,34 +33,30 @@ Key:
|
|
31
33
|
### Encoding Benchmark
|
32
34
|
|
33
35
|
```
|
34
|
-
|
36
|
+
Warming up --------------------------------------
|
37
|
+
fast_osc 64.995k i/100ms
|
38
|
+
samsosc 23.371k i/100ms
|
39
|
+
osc-ruby 7.691k i/100ms
|
35
40
|
Calculating -------------------------------------
|
36
|
-
fast_osc
|
37
|
-
|
38
|
-
|
39
|
-
-------------------------------------------------
|
40
|
-
fast_osc 909.680k (±21.4%) i/s - 4.328M
|
41
|
-
osc 94.678k (±14.5%) i/s - 468.968k
|
42
|
-
samsosc 271.908k (±19.3%) i/s - 1.327M
|
41
|
+
fast_osc 797.673k (±15.0%) i/s - 3.900M in 5.043770s
|
42
|
+
samsosc 258.331k (±12.8%) i/s - 1.285M in 5.063755s
|
43
|
+
osc-ruby 83.203k (±12.6%) i/s - 415.314k in 5.073578s
|
43
44
|
```
|
44
45
|
|
45
46
|
## Decoding Bencmark
|
46
47
|
|
47
48
|
```
|
48
|
-
|
49
|
+
Warming up --------------------------------------
|
50
|
+
fast_osc 102.344k i/100ms
|
51
|
+
samsosc 20.770k i/100ms
|
52
|
+
osc-ruby 3.145k i/100ms
|
49
53
|
Calculating -------------------------------------
|
50
|
-
fast_osc
|
51
|
-
samsosc
|
52
|
-
|
53
|
-
-------------------------------------------------
|
54
|
-
fast_osc 2.635M (±22.2%) i/s - 12.435M
|
55
|
-
samsosc 264.614k (±16.1%) i/s - 1.304M
|
56
|
-
oscruby 36.362k (±16.3%) i/s - 179.622k
|
54
|
+
fast_osc 1.650M (±14.5%) i/s - 8.085M in 5.017162s
|
55
|
+
samsosc 234.951k (±14.0%) i/s - 1.163M in 5.049167s
|
56
|
+
osc-ruby 34.266k (±13.3%) i/s - 169.830k in 5.048509s
|
57
57
|
```
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
I'll include a better test in the repo in time.
|
59
|
+
Benchmarks are now part of this repo - run `rake test` to see the results for yourself.
|
62
60
|
|
63
61
|
## Usage
|
64
62
|
|
@@ -83,11 +81,12 @@ $ rake clean && rake clobber && rake compile && rake test
|
|
83
81
|
|
84
82
|
## Still todo
|
85
83
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
84
|
+
-[x] Implement more types
|
85
|
+
-[x] Bring benchmarks into the repo
|
86
|
+
-[ ] Work out cross compilation story for easier packaging
|
87
|
+
-[ ] Implement multi message/nested bundles
|
88
|
+
-[ ] Documentation
|
89
|
+
-[ ] Travis
|
91
90
|
|
92
91
|
## Development notes
|
93
92
|
|
data/Rakefile
CHANGED
@@ -12,5 +12,7 @@ task :default => :spec
|
|
12
12
|
require 'rake/extensiontask'
|
13
13
|
spec = Gem::Specification.load('fast_osc.gemspec')
|
14
14
|
Rake::ExtensionTask.new('fast_osc') do |ext|
|
15
|
+
# ext.platform or ext.cross_config_options
|
16
|
+
# might work to enable universal builds on darwin for older processors
|
15
17
|
ext.lib_dir = "lib/fast_osc"
|
16
18
|
end
|
@@ -171,7 +171,6 @@ VALUE method_fast_osc_encode_single_message(int argc, VALUE* argv, VALUE self) {
|
|
171
171
|
|
172
172
|
int no_of_args = NUM2INT(LONG2NUM(RARRAY_LEN(args)));
|
173
173
|
int i;
|
174
|
-
int max_buffer_size = 0;
|
175
174
|
VALUE current_arg, strval;
|
176
175
|
|
177
176
|
//output tags and args list
|
@@ -183,9 +182,6 @@ VALUE method_fast_osc_encode_single_message(int argc, VALUE* argv, VALUE self) {
|
|
183
182
|
|
184
183
|
switch(TYPE(current_arg)) {
|
185
184
|
case T_FIXNUM:
|
186
|
-
// max bytes for a single numeric representation
|
187
|
-
max_buffer_size += 8;
|
188
|
-
|
189
185
|
if(FIX2LONG(current_arg) < ~(1 << 31)) {
|
190
186
|
rb_str_concat(tagstring, rb_str_new2("i"));
|
191
187
|
output_args[i].i = FIX2INT(current_arg);
|
@@ -195,23 +191,16 @@ VALUE method_fast_osc_encode_single_message(int argc, VALUE* argv, VALUE self) {
|
|
195
191
|
}
|
196
192
|
break;
|
197
193
|
case T_FLOAT:
|
198
|
-
// now align to 4 byte boundary for sizing output buffer
|
199
|
-
max_buffer_size += 8;
|
200
|
-
|
201
194
|
rb_str_concat(tagstring, rb_str_new2("f"));
|
202
195
|
output_args[i].f = NUM2DBL(current_arg);
|
203
196
|
break;
|
204
197
|
case T_STRING:
|
205
|
-
// now align to 4 byte boundary for sizing output buffer
|
206
|
-
max_buffer_size += buffer_size_for_ruby_string(current_arg);
|
207
|
-
|
208
198
|
rb_str_concat(tagstring, rb_str_new2("s"));
|
209
199
|
output_args[i].s = StringValueCStr(current_arg);
|
210
200
|
break;
|
211
201
|
case T_SYMBOL:
|
212
202
|
// now align to 4 byte boundary for sizing output buffer
|
213
203
|
strval = rb_sym_to_s(current_arg);
|
214
|
-
max_buffer_size += buffer_size_for_ruby_string(strval);
|
215
204
|
|
216
205
|
// encode as a string because not all implementation understand S as
|
217
206
|
// alternative string tag
|
@@ -221,8 +210,6 @@ VALUE method_fast_osc_encode_single_message(int argc, VALUE* argv, VALUE self) {
|
|
221
210
|
case T_DATA:
|
222
211
|
if (CLASS_OF(current_arg) == rb_cTime) {
|
223
212
|
// at present I only care about the Time as an object arg
|
224
|
-
max_buffer_size += 8;
|
225
|
-
|
226
213
|
rb_str_concat(tagstring, rb_str_new2("t"));
|
227
214
|
output_args[i].t = ruby_time_to_osc_timetag(current_arg);
|
228
215
|
}
|
@@ -230,26 +217,20 @@ VALUE method_fast_osc_encode_single_message(int argc, VALUE* argv, VALUE self) {
|
|
230
217
|
}
|
231
218
|
}
|
232
219
|
|
233
|
-
//add space for the address and tag strings to the buffer
|
234
|
-
max_buffer_size += buffer_size_for_ruby_string(address);
|
235
|
-
max_buffer_size += buffer_size_for_ruby_string(tagstring);
|
236
|
-
|
237
|
-
// Get next largest power of two for buffer
|
238
|
-
max_buffer_size--;
|
239
|
-
max_buffer_size |= max_buffer_size >> 1;
|
240
|
-
max_buffer_size |= max_buffer_size >> 2;
|
241
|
-
max_buffer_size |= max_buffer_size >> 4;
|
242
|
-
max_buffer_size |= max_buffer_size >> 8;
|
243
|
-
max_buffer_size |= max_buffer_size >> 16;
|
244
|
-
max_buffer_size++;
|
245
|
-
|
246
|
-
char buffer[max_buffer_size];
|
247
|
-
|
248
220
|
unsigned long int len;
|
221
|
+
// When buffer is NULL, the function returns the size of the buffer required to store the message
|
222
|
+
if(RSTRING_LEN(tagstring)) {
|
223
|
+
len = rtosc_amessage(NULL, 0, c_address, StringValueCStr(tagstring), output_args);
|
224
|
+
} else {
|
225
|
+
len = rtosc_message(NULL, 0, c_address, "");
|
226
|
+
}
|
227
|
+
|
228
|
+
// duplicate if/else due to compiler errors
|
229
|
+
char buffer[len];
|
249
230
|
if(RSTRING_LEN(tagstring)) {
|
250
|
-
|
231
|
+
rtosc_amessage(buffer, len, c_address, StringValueCStr(tagstring), output_args);
|
251
232
|
} else {
|
252
|
-
|
233
|
+
rtosc_message(buffer, len, c_address, "");
|
253
234
|
}
|
254
235
|
|
255
236
|
VALUE output = rb_str_new(buffer, len);
|
data/fast_osc.gemspec
CHANGED
data/lib/fast_osc.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
require "fast_osc/version"
|
2
|
-
require "fast_osc/fast_osc"
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
begin
|
4
|
+
require "fast_osc/fast_osc"
|
5
|
+
|
6
|
+
module FastOsc
|
7
|
+
# Your code goes here...
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
warn "Failed to load the fast_osc c-extension, falling back to pure Ruby version"
|
11
|
+
require "fast_osc/pure_ruby_fallback_encode.rb"
|
12
|
+
require "fast_osc/pure_ruby_fallback_decode.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
if ENV['FAST_OSC_USE_FALLBACK'] == "true"
|
16
|
+
warn "Using pure Ruby fallback"
|
17
|
+
require "fast_osc/pure_ruby_fallback_encode.rb"
|
18
|
+
require "fast_osc/pure_ruby_fallback_decode.rb"
|
6
19
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
#--
|
2
|
+
# This file was part of Sonic Pi: http://sonic-pi.net
|
3
|
+
# Full project source: https://github.com/samaaron/sonic-pi
|
4
|
+
# License: https://github.com/samaaron/sonic-pi/blob/master/LICENSE.md
|
5
|
+
#
|
6
|
+
# Copyright 2013, 2014, 2015, 2016 by Sam Aaron (http://sam.aaron.name).
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Permission is granted for use, copying, modification, and
|
10
|
+
# distribution of modified versions of this work as long as this
|
11
|
+
# notice is included.
|
12
|
+
#++
|
13
|
+
|
14
|
+
module SonicPi
|
15
|
+
module OSC
|
16
|
+
class OscDecode
|
17
|
+
|
18
|
+
def initialize(use_cache = false, cache_size=1000)
|
19
|
+
@float_cache = {}
|
20
|
+
@integer_cache = {}
|
21
|
+
@cache_size = cache_size
|
22
|
+
|
23
|
+
@num_cached_integers = 0
|
24
|
+
@num_cached_floats = 0
|
25
|
+
@string_terminator = "\x00".freeze
|
26
|
+
@args = []
|
27
|
+
@i_tag = "i".freeze
|
28
|
+
@f_tag = "f".freeze
|
29
|
+
@s_tag = "s".freeze
|
30
|
+
@d_tag = "d".freeze
|
31
|
+
@h_tag = "h".freeze
|
32
|
+
@b_tag = "b".freeze
|
33
|
+
|
34
|
+
@cap_n = 'N'.freeze
|
35
|
+
@cap_g = 'G'.freeze
|
36
|
+
@low_g = 'g'.freeze
|
37
|
+
@q_lt = 'q>'.freeze
|
38
|
+
@binary_encoding = "BINARY".freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_single_message(m)
|
42
|
+
## Note everything is inlined here for effienciency to remove the
|
43
|
+
## cost of method dispatch. Apologies if this makes it harder to
|
44
|
+
## read & understand. See http://opensoundcontrol.org for spec.
|
45
|
+
|
46
|
+
m.force_encoding(@binary_encoding)
|
47
|
+
|
48
|
+
args, idx = [], 0
|
49
|
+
|
50
|
+
# Get OSC address e.g. /foo
|
51
|
+
orig_idx = idx
|
52
|
+
idx = m.index(@string_terminator, orig_idx)
|
53
|
+
address, idx = m[orig_idx...idx], idx + 1 + ((4 - ((idx + 1) % 4)) % 4)
|
54
|
+
|
55
|
+
sep, idx = m[idx], idx + 1
|
56
|
+
|
57
|
+
# Let's see if we have some args..
|
58
|
+
if sep == ?,
|
59
|
+
|
60
|
+
# Get type tags
|
61
|
+
orig_idx = idx
|
62
|
+
idx = m.index(@string_terminator, orig_idx)
|
63
|
+
tags, idx = m[orig_idx...idx], idx + 1 + ((4 - ((idx + 1) % 4)) % 4)
|
64
|
+
|
65
|
+
tags.each_char do |t|
|
66
|
+
case t
|
67
|
+
when @i_tag
|
68
|
+
# int32
|
69
|
+
raw = m[idx, 4]
|
70
|
+
arg, idx = @integer_cache[raw], idx + 4
|
71
|
+
|
72
|
+
unless arg
|
73
|
+
arg = raw.unpack(@cap_n)[0]
|
74
|
+
# Values placed inline for efficiency:
|
75
|
+
# 2**32 == 4294967296
|
76
|
+
# 2**31 - 1 == 2147483647
|
77
|
+
arg -= 4294967296 if arg > 2147483647
|
78
|
+
if @num_cached_integers < @cache_size
|
79
|
+
@integer_cache[raw] = arg
|
80
|
+
@num_cached_integers += 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
when @f_tag
|
84
|
+
# float32
|
85
|
+
raw = m[idx, 4]
|
86
|
+
arg, idx = @float_cache[raw], idx + 4
|
87
|
+
unless arg
|
88
|
+
arg = raw.unpack(@low_g)[0]
|
89
|
+
if @num_cached_floats < @cache_size
|
90
|
+
@float_cache[raw] = arg
|
91
|
+
@num_cached_floats += 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
when @s_tag
|
95
|
+
# string
|
96
|
+
orig_idx = idx
|
97
|
+
idx = m.index(@string_terminator, orig_idx)
|
98
|
+
arg, idx = m[orig_idx...idx], idx + 1 + ((4 - ((idx + 1) % 4)) % 4)
|
99
|
+
when @d_tag
|
100
|
+
# double64
|
101
|
+
arg, idx = m[idx, 8].unpack(@cap_g)[0], idx + 8
|
102
|
+
when @h_tag
|
103
|
+
# int64
|
104
|
+
arg, idx = m[idx, 8].unpack(@q_lt)[0], idx + 8
|
105
|
+
when @b_tag
|
106
|
+
# binary blob
|
107
|
+
l = m[idx, 4].unpack(@cap_n)[0]
|
108
|
+
idx += 4
|
109
|
+
arg = m[idx, l]
|
110
|
+
idx += l
|
111
|
+
#Skip Padding
|
112
|
+
idx += ((4 - (idx % 4)) % 4)
|
113
|
+
else
|
114
|
+
raise "Unknown OSC type #{t}"
|
115
|
+
end
|
116
|
+
|
117
|
+
args << arg
|
118
|
+
end
|
119
|
+
end
|
120
|
+
return address, args
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Allow for loading above method in benmarks without clobbering c-ext
|
128
|
+
if ENV['FAST_OSC_USE_FALLBACK'] == "true"
|
129
|
+
module FastOsc
|
130
|
+
def decode_single_message(m)
|
131
|
+
SonicPi::OSC::OscEncode.new.decode_single_message(m)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#--
|
2
|
+
# This file was part of Sonic Pi: http://sonic-pi.net
|
3
|
+
# Full project source: https://github.com/samaaron/sonic-pi
|
4
|
+
# License: https://github.com/samaaron/sonic-pi/blob/master/LICENSE.md
|
5
|
+
#
|
6
|
+
# Copyright 2013, 2014, 2015, 2016 by Sam Aaron (http://sam.aaron.name).
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Permission is granted for use, copying, modification, and
|
10
|
+
# distribution of modified versions of this work as long as this
|
11
|
+
# notice is included.
|
12
|
+
#++
|
13
|
+
|
14
|
+
module SonicPi
|
15
|
+
module OSC
|
16
|
+
class OscEncode
|
17
|
+
# Apologies for the density of this code - I've inlined a lot of the
|
18
|
+
# code to reduce method dispatch overhead and to increase efficiency.
|
19
|
+
# See http://opensoundcontrol.org for spec.
|
20
|
+
|
21
|
+
def initialize(use_cache = false, cache_size=1000)
|
22
|
+
@literal_binary_str = "BINARY".freeze
|
23
|
+
@literal_cap_n = 'N'.freeze
|
24
|
+
@literal_cap_n2 = 'N2'.freeze
|
25
|
+
@literal_low_f = 'f'.freeze
|
26
|
+
@literal_low_i = 'i'.freeze
|
27
|
+
@literal_low_g = 'g'.freeze
|
28
|
+
@literal_low_s = 's'.freeze
|
29
|
+
@literal_empty_str = ''.freeze
|
30
|
+
@literal_str_encode_regexp = /\000.*\z/
|
31
|
+
@literal_str_pad = "\000".freeze
|
32
|
+
@literal_two_to_pow_2 = 2 ** 32
|
33
|
+
@literal_magic_time_offset = 2208988800
|
34
|
+
|
35
|
+
@use_cache = use_cache
|
36
|
+
@integer_cache = {}
|
37
|
+
@string_cache = {}
|
38
|
+
@float_cache = {}
|
39
|
+
@cache_size = cache_size
|
40
|
+
|
41
|
+
@num_cached_integers = 0
|
42
|
+
@num_cached_floats = 0
|
43
|
+
@num_cached_strings = 0
|
44
|
+
|
45
|
+
@bundle_header = get_from_or_add_to_string_cache("#bundle")
|
46
|
+
end
|
47
|
+
|
48
|
+
def encode_single_message(address, args=[])
|
49
|
+
args_encoded, tags = "", ","
|
50
|
+
|
51
|
+
# inlining this method was not faster surprisingly
|
52
|
+
address = get_from_or_add_to_string_cache(address)
|
53
|
+
|
54
|
+
args.each do |arg|
|
55
|
+
case arg
|
56
|
+
when Integer
|
57
|
+
tags << @literal_low_i
|
58
|
+
|
59
|
+
if @use_cache
|
60
|
+
if cached = @integer_cache[arg]
|
61
|
+
args_encoded << cached
|
62
|
+
else
|
63
|
+
res = [arg].pack(@literal_cap_n)
|
64
|
+
if @num_cached_integers < @cache_size
|
65
|
+
@integer_cache[arg] = res
|
66
|
+
@num_cached_integers += 1
|
67
|
+
# log "caching integer #{arg}"
|
68
|
+
end
|
69
|
+
args_encoded << res
|
70
|
+
end
|
71
|
+
else
|
72
|
+
args_encoded << [arg].pack(@literal_cap_n)
|
73
|
+
end
|
74
|
+
when Float, Rational
|
75
|
+
arg = arg.to_f
|
76
|
+
tags << @literal_low_f
|
77
|
+
|
78
|
+
if @use_cache
|
79
|
+
if cached = @float_cache[arg]
|
80
|
+
args_encoded << cached
|
81
|
+
else
|
82
|
+
res = [arg].pack(@literal_low_g)
|
83
|
+
if @num_cached_floats < @cache_size
|
84
|
+
@float_cache[arg] = res
|
85
|
+
@num_cached_floats += 1
|
86
|
+
# log "caching float #{arg}"
|
87
|
+
end
|
88
|
+
args_encoded << res
|
89
|
+
end
|
90
|
+
else
|
91
|
+
args_encoded << [arg].pack(@literal_low_g)
|
92
|
+
end
|
93
|
+
when String, Symbol
|
94
|
+
arg = arg.to_s
|
95
|
+
tags << @literal_low_s
|
96
|
+
|
97
|
+
args_encoded << get_from_or_add_to_string_cache(arg)
|
98
|
+
else
|
99
|
+
raise "Unknown arg type to encode: #{arg.inspect}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
tags_encoded = get_from_or_add_to_string_cache(tags)
|
104
|
+
# Address here needs to be a new string, not sure why
|
105
|
+
"#{address}#{tags_encoded}#{args_encoded}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def encode_single_bundle(ts, address, args=[])
|
109
|
+
message = encode_single_message(address, args)
|
110
|
+
message_encoded = [message.size].pack(@literal_cap_n) << message
|
111
|
+
"#{@bundle_header}#{time_encoded(ts)}#{message_encoded}"
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def get_from_or_add_to_string_cache(s)
|
116
|
+
if cached = @string_cache[s]
|
117
|
+
return cached
|
118
|
+
else
|
119
|
+
# This makes a null padded string rounded up to the nearest
|
120
|
+
# multiple of four
|
121
|
+
size = s.bytesize
|
122
|
+
res = [s].pack("Z#{size + 4 - (size % 4)}")
|
123
|
+
if @num_cached_strings < @cache_size
|
124
|
+
# only cache the first @cache_size strings to avoid a memory
|
125
|
+
# memory leak.
|
126
|
+
@string_cache[s] = res
|
127
|
+
@num_cached_strings += 1
|
128
|
+
# log "caching string #{s}"
|
129
|
+
end
|
130
|
+
return res
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def time_encoded(time)
|
135
|
+
t1, fr = (time.to_f + @literal_magic_time_offset).divmod(1)
|
136
|
+
|
137
|
+
t2 = (fr * @literal_two_to_pow_2).to_i
|
138
|
+
[t1, t2].pack(@literal_cap_n2)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class StreamOscEncode < OscEncode
|
143
|
+
def encode_single_message(address, args=[])
|
144
|
+
message = super
|
145
|
+
([message.length].pack(@literal_cap_n) << message).force_encoding(@literal_binary_str)
|
146
|
+
end
|
147
|
+
|
148
|
+
def encode_single_bundle(ts, address, args=[])
|
149
|
+
message = super
|
150
|
+
message.count.pack(@literal_cap_n) << message
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Allow for loading above method in benmarks without clobbering c-ext
|
157
|
+
if ENV['FAST_OSC_USE_FALLBACK'] == "true"
|
158
|
+
module FastOsc
|
159
|
+
def encode_single_message(address, args=[])
|
160
|
+
SonicPi::OSC::OscEncode.new.encode_single_message(address, args)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/fast_osc/version.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
#--
|
2
|
+
# This file was part of Sonic Pi: http://sonic-pi.net
|
3
|
+
# Full project source: https://github.com/samaaron/sonic-pi
|
4
|
+
# License: https://github.com/samaaron/sonic-pi/blob/master/LICENSE.md
|
5
|
+
#
|
6
|
+
# Copyright 2013, 2014, 2015, 2016 by Sam Aaron (http://sam.aaron.name).
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Permission is granted for use, copying, modification, and
|
10
|
+
# distribution of modified versions of this work as long as this
|
11
|
+
# notice is included.
|
12
|
+
#++
|
13
|
+
|
14
|
+
|
15
|
+
# requires benchmark/ips gem to be installed
|
16
|
+
|
17
|
+
require 'test_helper'
|
18
|
+
require 'benchmark/ips'
|
19
|
+
require 'osc-ruby'
|
20
|
+
require 'fast_osc/pure_ruby_fallback_encode'
|
21
|
+
require 'fast_osc/pure_ruby_fallback_decode'
|
22
|
+
|
23
|
+
samosc = SonicPi::OSC::OscDecode.new(true)
|
24
|
+
samoscenc = SonicPi::OSC::OscEncode.new(false)
|
25
|
+
oscruby = OSC::OSCPacket
|
26
|
+
|
27
|
+
address = "/feeooblah"
|
28
|
+
args = ["beans", 1, 2.0]
|
29
|
+
msg = OSC::Message.new(address, *args)
|
30
|
+
test_message = msg.encode
|
31
|
+
# puts test_message.inspect
|
32
|
+
|
33
|
+
# puts [address, args].inspect
|
34
|
+
puts "ENCODING TEST"
|
35
|
+
Benchmark.ips do |bencher|
|
36
|
+
bencher.report("fast_osc") { FastOsc.encode_single_message(address, args) }
|
37
|
+
bencher.report("samsosc") { samoscenc.encode_single_message(address, args) }
|
38
|
+
bencher.report("osc-ruby") { msg.encode }
|
39
|
+
|
40
|
+
bencher.compare
|
41
|
+
end
|
42
|
+
|
43
|
+
# puts samosc.decode_single_message(test_message).inspect
|
44
|
+
puts "DECODING TEST"
|
45
|
+
Benchmark.ips do |bencher|
|
46
|
+
bencher.report("fast_osc") { FastOsc.decode_single_message(test_message) }
|
47
|
+
bencher.report("samsosc") { samosc.decode_single_message(test_message) }
|
48
|
+
bencher.report("osc-ruby") { oscruby.messages_from_network(test_message) }
|
49
|
+
|
50
|
+
bencher.compare
|
51
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_osc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Xavier Riley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.1.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: benchmark-ips
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.7.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.7.2
|
83
97
|
description: Serialize and deserialize Open Sound Control messages using rtosc
|
84
98
|
email:
|
85
99
|
- xavriley@hotmail.com
|
@@ -99,7 +113,10 @@ files:
|
|
99
113
|
- ext/fast_osc/rtosc.h
|
100
114
|
- fast_osc.gemspec
|
101
115
|
- lib/fast_osc.rb
|
116
|
+
- lib/fast_osc/pure_ruby_fallback_decode.rb
|
117
|
+
- lib/fast_osc/pure_ruby_fallback_encode.rb
|
102
118
|
- lib/fast_osc/version.rb
|
119
|
+
- test/benchmark_test.rb
|
103
120
|
- test/fast_osc_test.rb
|
104
121
|
- test/test_helper.rb
|
105
122
|
homepage: https://github.com/xavriley/fast_osc
|
@@ -123,10 +140,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
140
|
version: '0'
|
124
141
|
requirements: []
|
125
142
|
rubyforge_project:
|
126
|
-
rubygems_version: 2.
|
143
|
+
rubygems_version: 2.6.7
|
127
144
|
signing_key:
|
128
145
|
specification_version: 4
|
129
146
|
summary: Serialize and deserialize Open Sound Control messages
|
130
147
|
test_files:
|
148
|
+
- test/benchmark_test.rb
|
131
149
|
- test/fast_osc_test.rb
|
132
150
|
- test/test_helper.rb
|