fast_osc 0.0.11 → 0.0.12
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 +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
|