Hey all Thanks for your submissions, Cyrille and Patrice. I put my 4 versions and yours into a single patch to make it easy for comparing. It turns out I'm not clearly in favor of any of them. All work fine and none is perfect. In netpd, I went for table_lookup, however, it later turned out that CPU wise, it's not that significantly faster than the others and may not justify to use 2x4x65536 (which is a half MB!) of memory.
All of them are significantly faster than the message based version, which is not that surprising. Cyrilly, I think the table_lookup variant is what you described in your mail. It turns out that the difficult part is to find a way to implement an [int~] with Pd-vanilla objects. Once, you have an [int~], you have a [div~], and when you have [div~], you have a [mod~]. However, making a good [int~] is not that trivial. One can make one with [wrap~], but it exhibits the strange behaviour that it outputs '1' with '0' as input. To work-around that, I add an integer constant to the input of [wrap~] so that its input is always greater than 0. But because we're dealing with floating point numbers, the fractional part of [wrap~] output is less precise than the fractional part of its input (before constant was added), which leads to rounding errors. uint8_table uses a pre-computed table with values from 0 to 255, which can be used as [int~] for said range. float_rounding implements an [int~] by adding (and subsequently subtracting) a constant which is high enough so that the fractional part of the floating point number disappears. This approach might be interesting for the purpose of this exercise, but it shoudln't be used. It would break in an environment with a different floating point number format. Cyrille Henry's approach assumes the receiving side automatically wraps negative numbers around. It turns out to be true for the object classes I'm interested in ([packOSC], [tcpclient], [netsend -b]), so his version is quite clean and because of the lack of implementing another [mod], it uses less arithmetic operations than my 'wrap' approach. It totally lacks divisions. Thumbs up! Patrice Colet's version uses [expr~] for some parts, which is fine, I think. Somehow, for positive inputs the LSB is always higher by one compared to the others. This leads to even more severe side effect for input 1: 127 0 (should be 127 255). Please share your opinions. I now think Cyrille's version is the best. Roman On Tue, 2016-11-08 at 12:06 +0100, cyrille henry wrote: > hello, > > in your patch, the input signal is truncated, so strange things > append near 0. > I think rounding to inferior value will gives better result. > > > here is a version done with 2 wrap~. > the result for negative number is a bit different than in your > example for 2 reason : > - it round to inferior value and not truncate the input. > - it return negative int, but in uint8 : 255 and -1 are the same > number anyhow. > > sometimes rounding error result in 1 being 0.9999. So i guess this > patch is useless. > > The other easy solution I can think of is using 2 tables with 65K > point each, and reading the tables with tabread~. > it is easy to populate the table with the value you want. > > sorry, i don't have time to provide a patch. > > cheers > Cyrille > > > Le 07/11/2016 à 16:24, Roman Haefeli a écrit : > > > > Hi all > > > > In order to store audio data more efficiently in netpd presets and > > also > > to transmit live audio through OSC, I'm thinking of ways to convert > > an > > signal to a 16-bit stream represented as two signals, one for each > > byte, the first for MSB and the second for LSB. I already came up > > with > > a few solutions, but I'm not totally happy with any of them because > > they are not very efficient or/and have strange edge cases. It > > turns > > out what seems a simple task is a bit more complex and probably has > > quiet a few totally different solutions. > > > > I would be interested to see with what solutions people come up > > with. > > Consider it a puzzle, a brain teaser (in case you're done writing > > your > > paper for pdcon and need some distraction). > > > > Requirements: > > * It must be done in signal domain (I was doing it in message > > domain > > yet, but performance is obviously bad) > > * Only vanilla objects are allowed. > > * Input is in the range -1 to 1. Input outside this range should > > be > > clipped and not wrapped around. > > * Output is two signals, each consisting of an integer value > > between > > 0 and 255 > > * The two bytes represent a 16-bit _signed_ integer > > > > You can compare your output with the message version in attached > > patch. > > If this generates interest and makes some people participate, I'll > > disclose my solutions after people submitted their solutions. > > > > > > > > _______________________________________________ > > [email protected] mailing list > > UNSUBSCRIBE and account-management -> https://lists.puredata.info/l > > istinfo/pd-list > >
#N canvas 115 119 1300 386 10; #X obj 55 67 hsl 300 15 -1 1 0 0 empty empty empty -2 -8 0 10 -262144 -1 -1 26100 1; #X floatatom 52 40 5 0 0 0 - - -, f 5; #X obj 201 157 sig~; #X floatatom 201 311 5 0 0 0 - - -, f 5; #X floatatom 261 311 5 0 0 0 - - -, f 5; #X floatatom 52 311 5 0 0 0 - - -, f 5; #X floatatom 151 311 5 0 0 0 - - -, f 5; #N canvas 0 43 355 239 float-to-16bit 0; #X obj 28 47 * 32768; #X obj 28 94 t a a; #X obj 28 134 div 256; #X obj 28 154 mod 256; #X obj 91 139 mod 256; #X obj 28 22 inlet; #X obj 28 190 outlet; #X obj 91 190 outlet; #X obj 28 67 clip -32768 32767; #X connect 0 0 8 0; #X connect 1 0 2 0; #X connect 1 1 4 0; #X connect 2 0 3 0; #X connect 3 0 6 0; #X connect 4 0 7 0; #X connect 5 0 0 0; #X connect 8 0 1 0; #X restore 52 186 pd float-to-16bit; #X msg 83 11 0; #X msg 20 11 -1; #X msg 48 11 -0.5; #X msg 113 11 0.5; #X msg 141 11 1; #X obj 201 283 snapshot~; #X obj 261 283 snapshot~; #X obj 512 32 metro 100; #X obj 512 13 loadbang; #N canvas 0 43 562 527 wrap 0; #X obj 160 238 wrap~; #X obj 144 259 -~; #X obj 145 191 /~ 256; #X obj 242 285 *~ 256; #X obj 226 312 -~; #X obj 242 116 wrap~; #X obj 226 139 -~; #X text 308 95 <- work-around [wrap~] bug; #X text 203 217 <- work-around [wrap~] bug; #X obj 226 46 *~ 32768; #X obj 111 353 wrap~; #X obj 95 374 -~; #X obj 96 306 /~ 256; #X obj 95 394 *~ 256; #X obj 80 420 -~; #X obj 242 97 +~ 65356; #X obj 161 218 +~ 256; #X obj 112 333 +~ 2; #X obj 225 17 inlet~; #X obj 79 453 outlet~; #X obj 226 457 outlet~; #X obj 226 67 clip~ -32768 32767; #X connect 0 0 1 1; #X connect 1 0 3 0; #X connect 1 0 12 0; #X connect 1 0 14 0; #X connect 2 0 1 0; #X connect 2 0 16 0; #X connect 3 0 4 1; #X connect 4 0 20 0; #X connect 5 0 6 1; #X connect 6 0 2 0; #X connect 6 0 4 0; #X connect 9 0 21 0; #X connect 10 0 11 1; #X connect 11 0 13 0; #X connect 12 0 11 0; #X connect 12 0 17 0; #X connect 13 0 14 1; #X connect 14 0 19 0; #X connect 15 0 5 0; #X connect 16 0 0 0; #X connect 17 0 10 0; #X connect 18 0 9 0; #X connect 21 0 6 0; #X connect 21 0 15 0; #X restore 201 187 pd wrap; #N canvas 0 43 467 334 uint8_table 0; #X obj 117 245 outlet~; #X obj 44 245 outlet~; #X obj 41 49 inlet~; #N canvas 0 43 344 153 div_256 0; #X obj 18 16 inlet~; #X obj 18 43 /~ 256; #X obj 18 87 outlet~; #X obj 19 63 tabread~ \$0.uint8; #X connect 0 0 1 0; #X connect 1 0 3 0; #X connect 3 0 2 0; #X restore 42 131 pd div_256; #X obj 42 81 *~ 32768; #X obj 42 101 +~ 32768; #X obj 42 167 +~ 128; #N canvas 0 43 355 235 mod_256 0; #X obj 27 19 inlet~; #X obj 54 72 /~ 256; #X obj 54 112 *~ 256; #X obj 27 136 -~; #X obj 27 162 outlet~; #X obj 54 92 tabread~ \$0.uint8; #X connect 0 0 3 0; #X connect 0 0 1 0; #X connect 1 0 5 0; #X connect 2 0 3 1; #X connect 3 0 4 0; #X connect 5 0 2 0; #X restore 43 191 pd mod_256; #X obj 115 170 -~; #X obj 130 150 *~ 256; #N canvas 136 357 294 267 generate_uint8 0; #X obj 19 17 inlet; #X obj 58 59 switch~ 256 1 1; #X obj 19 165 f; #X msg 19 185 0 \, 256 \$1; #X obj 19 205 line~; #X obj 38 80 samplerate~; #X msg 38 100 1000 \$1; #X obj 38 120 /; #X obj 38 140 * 256; #X obj 19 37 t b b b; #X obj 19 225 tabsend~ \$0.uint8; #X connect 0 0 9 0; #X connect 2 0 3 0; #X connect 3 0 4 0; #X connect 4 0 10 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X connect 7 0 8 0; #X connect 8 0 2 1; #X connect 9 0 2 0; #X connect 9 1 5 0; #X connect 9 2 1 0; #X restore 291 129 pd generate_uint8; #X obj 291 152 table \$0.uint8 256; #X obj 116 192 tabread~ \$0.uint8; #X obj 291 77 r init_tables; #X obj 291 97 t b b; #X text 331 100 <- why?; #X connect 2 0 4 0; #X connect 3 0 6 0; #X connect 3 0 9 0; #X connect 4 0 5 0; #X connect 5 0 3 0; #X connect 5 0 8 0; #X connect 6 0 7 0; #X connect 7 0 1 0; #X connect 8 0 12 0; #X connect 9 0 8 1; #X connect 12 0 0 0; #X connect 13 0 14 0; #X connect 14 0 10 0; #X connect 14 1 10 0; #X restore 341 187 pd uint8_table; #N canvas 0 43 398 538 float_rounding 0; #X obj 52 195 /~ 256; #X obj 150 275 *~ 256; #X obj 134 302 -~; #X obj 134 330 outlet~; #X obj 51 460 outlet~; #X obj 134 10 inlet~; #X obj 134 36 *~ 32768; #X obj 68 301 /~ 256; #X obj 52 428 -~; #X obj 67 390 *~ 256; #N canvas 0 43 450 300 int~ 0; #X obj 178 105 pow 23; #X obj 178 66 loadbang; #X msg 178 86 2; #X obj 92 113 +~; #X obj 92 134 -~; #X obj 92 63 inlet~; #X obj 92 153 outlet~; #X obj 178 125 + 65536; #X obj 92 84 -~ 0.5; #X connect 0 0 7 0; #X connect 1 0 2 0; #X connect 2 0 0 0; #X connect 3 0 4 0; #X connect 4 0 6 0; #X connect 5 0 8 0; #X connect 7 0 3 1; #X connect 7 0 4 1; #X connect 8 0 3 0; #X restore 135 80 pd int~; #N canvas 0 43 450 300 int~ 0; #X obj 178 105 pow 23; #X obj 178 66 loadbang; #X msg 178 86 2; #X obj 91 110 +~; #X obj 91 131 -~; #X obj 92 63 inlet~; #X obj 91 150 outlet~; #X obj 178 125 + 65536; #X obj 91 84 -~ 0.5; #X connect 0 0 7 0; #X connect 1 0 2 0; #X connect 2 0 0 0; #X connect 3 0 4 0; #X connect 4 0 6 0; #X connect 5 0 8 0; #X connect 7 0 3 1; #X connect 7 0 4 1; #X connect 8 0 3 0; #X restore 52 218 pd int~; #N canvas 0 43 450 300 int~ 0; #X obj 178 105 pow 23; #X obj 178 66 loadbang; #X msg 178 86 2; #X obj 91 116 +~; #X obj 91 137 -~; #X obj 92 63 inlet~; #X obj 91 156 outlet~; #X obj 178 125 + 65536; #X obj 91 84 -~ 0.5; #X connect 0 0 7 0; #X connect 1 0 2 0; #X connect 2 0 0 0; #X connect 3 0 4 0; #X connect 4 0 6 0; #X connect 5 0 8 0; #X connect 7 0 3 1; #X connect 7 0 4 1; #X connect 8 0 3 0; #X restore 67 330 pd int~; #X obj 134 57 clip~ -32768 32767.1; #X connect 0 0 11 0; #X connect 1 0 2 1; #X connect 2 0 3 0; #X connect 5 0 6 0; #X connect 6 0 13 0; #X connect 7 0 12 0; #X connect 8 0 4 0; #X connect 9 0 8 1; #X connect 10 0 2 0; #X connect 10 0 0 0; #X connect 11 0 7 0; #X connect 11 0 1 0; #X connect 11 0 8 0; #X connect 12 0 9 0; #X connect 13 0 10 0; #X restore 501 187 pd float_rounding; #N canvas 0 43 430 268 table_lookup 0; #X obj 12 116 table \$0.msb 65536; #X obj 12 134 table \$0.lsb 65536; #N canvas 301 281 348 267 generate_msb 0; #X obj 19 17 inlet; #X obj 70 65 switch~ 256 1 1; #N canvas 546 437 450 300 upsampled_by_256 0; #X obj 12 21 inlet; #X obj 12 63 switch~ 65536 1 256; #X obj 205 24 inlet~ hold; #X obj 204 55 tabsend~ \$0.msb; #X connect 0 0 1 0; #X connect 2 0 3 0; #X restore 19 226 pd upsampled_by_256; #X obj 36 120 samplerate~; #X obj 36 140 / 256; #X obj 36 160 phasor~; #X obj 36 180 *~ 256; #X msg 75 138 0.5; #X obj 19 37 t b b b b; #X connect 0 0 8 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 6 0; #X connect 6 0 2 1; #X connect 7 0 5 1; #X connect 8 0 2 0; #X connect 8 1 3 0; #X connect 8 2 7 0; #X connect 8 3 1 0; #X restore 22 71 pd generate_msb; #N canvas 40 267 398 198 generate_lsb 0; #X obj 11 12 inlet; #X obj 11 66 switch~ 65536 1 1; #X obj 197 12 loadbang; #X obj 197 32 samplerate~; #X obj 197 52 / 256; #X obj 197 78 phasor~; #X obj 197 98 *~ 256; #X obj 197 118 tabsend~ \$0.lsb; #X connect 0 0 1 0; #X connect 2 0 3 0; #X connect 3 0 4 0; #X connect 4 0 5 0; #X connect 5 0 6 0; #X connect 6 0 7 0; #X restore 13 90 pd generate_lsb; #X obj 173 18 inlet~; #X obj 173 76 *~ 32768; #X obj 174 202 outlet~; #X obj 270 204 outlet~; #X obj 173 134 tabread~ \$0.msb; #X obj 271 135 tabread~ \$0.lsb; #X obj 173 48 +~ 1; #X obj 13 8 r init_tables; #X obj 13 28 t b b; #X obj 13 48 t b; #X text 52 31 <- why?; #X connect 4 0 10 0; #X connect 5 0 8 0; #X connect 5 0 9 0; #X connect 8 0 6 0; #X connect 9 0 7 0; #X connect 10 0 5 0; #X connect 11 0 12 0; #X connect 12 0 13 0; #X connect 12 1 13 0; #X connect 13 0 2 0; #X connect 13 0 3 0; #X restore 691 187 pd table_lookup; #X obj 52 87 s \$0.input; #X obj 52 137 r \$0.input; #X obj 201 135 r \$0.input; #X obj 512 52 s \$0.refresh; #X obj 233 257 r \$0.refresh; #X obj 341 157 sig~; #X floatatom 341 311 5 0 0 0 - - -, f 5; #X floatatom 421 311 5 0 0 0 - - -, f 5; #X obj 341 283 snapshot~; #X obj 421 283 snapshot~; #X obj 341 135 r \$0.input; #X obj 373 257 r \$0.refresh; #X obj 501 157 sig~; #X floatatom 501 311 5 0 0 0 - - -, f 5; #X floatatom 601 311 5 0 0 0 - - -, f 5; #X obj 501 283 snapshot~; #X obj 601 283 snapshot~; #X obj 501 135 r \$0.input; #X obj 533 257 r \$0.refresh; #X obj 691 157 sig~; #X floatatom 691 311 5 0 0 0 - - -, f 5; #X floatatom 779 311 5 0 0 0 - - -, f 5; #X obj 691 283 snapshot~; #X obj 779 283 snapshot~; #X obj 691 135 r \$0.input; #X obj 723 257 r \$0.refresh; #X obj 725 21 loadbang; #X msg 725 41 \; pd dsp 1 \; init_tables bang \;; #N canvas 355 670 249 368 cyrille_henry 0; #X obj 17 26 inlet~; #X obj 20 301 outlet~; #X obj 70 301 outlet~; #X obj 35 171 wrap~; #X obj 19 194 -~; #X obj 18 127 *~ 128; #X obj 85 249 wrap~; #X obj 69 272 -~; #X obj 69 205 *~ 256; #X obj 85 229 +~ 1; #X obj 36 150 +~ 1; #X obj 17 106 +~ 2; #X obj 19 219 -~ 256; #X connect 0 0 11 0; #X connect 3 0 4 1; #X connect 3 0 8 0; #X connect 4 0 12 0; #X connect 5 0 4 0; #X connect 5 0 10 0; #X connect 6 0 7 1; #X connect 7 0 2 0; #X connect 8 0 7 0; #X connect 8 0 9 0; #X connect 9 0 6 0; #X connect 10 0 3 0; #X connect 11 0 5 0; #X connect 12 0 1 0; #X restore 891 187 pd cyrille_henry; #N canvas 663 138 566 427 patrice_colet 0; #X obj 42 5 inlet~; #X obj 40 351 outlet~; #X obj 294 306 outlet~; #X obj 40 157 -~; #X obj 59 131 -~; #X obj 78 109 /~ 256; #X obj 39 79 clip~ -32768 32767; #X obj 41 51 *~ 32728; #X obj 41 221 max~ 0; #X obj 95 221 min~ 0; #X obj 137 247 +~ 256; #X obj 137 267 min~ 255; #X obj 97 286 *~; #X obj 96 259 <~ 0; #X obj 40 321 expr~ int(floor($v1)); #X obj 293 61 expr~ ceil(fmod(($v1+1)* 32768 \, 256)); #X obj 293 40 clip~ -1 1; #X connect 0 0 7 0; #X connect 0 0 16 0; #X connect 3 0 8 0; #X connect 3 0 9 0; #X connect 4 0 3 1; #X connect 5 0 4 1; #X connect 6 0 3 0; #X connect 6 0 4 0; #X connect 6 0 5 0; #X connect 7 0 6 0; #X connect 8 0 14 0; #X connect 9 0 10 0; #X connect 9 0 13 0; #X connect 10 0 11 0; #X connect 11 0 12 1; #X connect 12 0 14 0; #X connect 13 0 12 0; #X connect 14 0 1 0; #X connect 15 0 2 0; #X connect 16 0 15 0; #X restore 1100 187 pd patrice_colet; #X obj 891 157 sig~; #X floatatom 891 311 5 0 0 0 - - -, f 5; #X floatatom 985 311 5 0 0 0 - - -, f 5; #X obj 891 283 snapshot~; #X obj 985 283 snapshot~; #X obj 891 135 r \$0.input; #X obj 923 257 r \$0.refresh; #X obj 1101 157 sig~; #X floatatom 1101 311 5 0 0 0 - - -, f 5; #X floatatom 1193 311 5 0 0 0 - - -, f 5; #X obj 1101 283 snapshot~; #X obj 1193 283 snapshot~; #X obj 1101 135 r \$0.input; #X obj 1133 257 r \$0.refresh; #X connect 0 0 21 0; #X connect 1 0 0 0; #X connect 2 0 17 0; #X connect 7 0 5 0; #X connect 7 1 6 0; #X connect 8 0 1 0; #X connect 9 0 1 0; #X connect 10 0 1 0; #X connect 11 0 1 0; #X connect 12 0 1 0; #X connect 13 0 3 0; #X connect 14 0 4 0; #X connect 15 0 24 0; #X connect 16 0 15 0; #X connect 17 0 13 0; #X connect 17 1 14 0; #X connect 18 0 29 0; #X connect 18 1 30 0; #X connect 19 0 36 0; #X connect 19 1 37 0; #X connect 20 0 43 0; #X connect 20 1 44 0; #X connect 22 0 7 0; #X connect 23 0 2 0; #X connect 25 0 13 0; #X connect 25 0 14 0; #X connect 26 0 18 0; #X connect 29 0 27 0; #X connect 30 0 28 0; #X connect 31 0 26 0; #X connect 32 0 29 0; #X connect 32 0 30 0; #X connect 33 0 19 0; #X connect 36 0 34 0; #X connect 37 0 35 0; #X connect 38 0 33 0; #X connect 39 0 36 0; #X connect 39 0 37 0; #X connect 40 0 20 0; #X connect 43 0 41 0; #X connect 44 0 42 0; #X connect 45 0 40 0; #X connect 46 0 43 0; #X connect 46 0 44 0; #X connect 47 0 48 0; #X connect 49 0 54 0; #X connect 49 1 55 0; #X connect 50 0 61 0; #X connect 50 1 62 0; #X connect 51 0 49 0; #X connect 54 0 52 0; #X connect 55 0 53 0; #X connect 56 0 51 0; #X connect 57 0 54 0; #X connect 57 0 55 0; #X connect 58 0 50 0; #X connect 61 0 59 0; #X connect 62 0 60 0; #X connect 63 0 58 0; #X connect 64 0 61 0; #X connect 64 0 62 0;
signature.asc
Description: This is a digitally signed message part
_______________________________________________ [email protected] mailing list UNSUBSCRIBE and account-management -> https://lists.puredata.info/listinfo/pd-list
