Re: Open Sound Control



On May 14, 10:42 pm, "dave.joub...@xxxxxxxxxxxxxx"
<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 14, 8:11 pm, "dave.joub...@xxxxxxxxxxxxxx"





<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 13, 12:41 am, Alexandre Ferrieux <alexandre.ferri...@xxxxxxxxx>
wrote:

On May 13, 12:17 am, "dave.joub...@xxxxxxxxxxxxxx"

<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 12, 10:54 pm, Alexandre Ferrieux <alexandre.ferri...@xxxxxxxxx>
wrote:

On May 12, 11:30 pm, "dave.joub...@xxxxxxxxxxxxxx"

<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 12, 10:13 pm, Alexandre Ferrieux <alexandre.ferri...@xxxxxxxxx>
wrote:

On May 12, 11:02 pm, "dave.joub...@xxxxxxxxxxxxxx"

<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 12, 8:51 pm, Alexandre Ferrieux <alexandre.ferri...@xxxxxxxxx>
wrote:

On May 12, 4:35 pm, "dave.joub...@xxxxxxxxxxxxxx"

<dave.joub...@xxxxxxxxxxxxxx> wrote:
On May 12, 1:54 pm, Uwe Klein <uwe_klein_habertw...@xxxxxxxxxxx>
wrote:

dave.joub...@xxxxxxxxxxxxxx wrote:
I had a read through my code again, and I can see that a re-write that
sticks to binary (rather than working in hex) would probably speed it
up.

Dave

What about enhancing binary scan with a "zero terminated string" format/object?

        binary scan $buffer IzI..

uwe

Hi Uwe,

Such an enhancement would only be useful in an OSC context, if it
could follow the OSC rule that there will be between 1 and 4 bytes of
\0s at the end of the string to pad it to a 32bit boundary.

Unfortunately, one of the other OSC objects, the blob, will still
require additional passes, because it is specified as [32bit len][X
bytes of data][0-3 bytes of padding to bring it to a boundary]. The
two most obvious implementations of a 'z' specifier (consume one null
byte / consume all null bytes (might chomp a byte out of the following
32bit int)) will not work with the OSC spec.

While I admit that OSC payload format is not really [binary]-friendly,
there may be an acceptable middle ground, taking advantage of the
32bit-aligned scheme:

  - first pass, scan the whole packet as i*, returning a list of
integers.
  - indexing pass, scan this list one variable-length thing at a time,
looking for null-padding with

     if {!($value & 0xFF)} {
          # the string ends in this word
          # a few more tests with 0xFF00, 0xFF0000 and 0xFF000000
          # to get the precise length

  and also keeping track of blob-lengths. While this scanning takes
place, you're building up a new formatString made of i (integers), f
(floats), aNUMBER(strings), xNUMBER(padding).

  - final pass, one single [binary] with the built formatString (and
var list) swallows it all in one gulp.

Since I have no real OSC cases to play with, I have not yet written
the code, but if you send me a large sample of payload, we could go
into a nice timing race. Just tell me.

-Alex

Hi Alex,

That sounds like a good approach. I would suggest that you use the
code I put in the link, on the sender side. That way you can control
the payload and test the individual cases, ie you can keep using the
old library on the one side, and start writing the new unpack routines
on the other side.

I will sit down build a bulk-sender, in such a way that lots of UDP
packets are pre-calculated, and then fired off as quickly as possible.
I will not be able to do anything for the next 24 hours; we have a
company meeting to which I have to travel to.

OK. To optimize both our schedules, I would appreciate a raw binary
file to decode, instead of having to set up whatever contraption makes
sense in that strange OSC world. In case you wondered, I'm more
interested in helping you exploit 100% of Tcl's abilities and playing
with the technical challenge, than in learning much about OSC ;-)

There is a OSC spec issue that you need to be aware of. In one place,
the writer got himself confused, and said a string is terminated with
0-3 nulls, and in another place, the example he shows, uses 1 to 4
nulls. The 1 to 4 nulls is the correct spec for strings, and 0-3
correct for blobs. He forgot that the string has to have a termination
null (whereas the blob has a length (32bit int) to help it).

OK, I had somewhat groked that, thanks.

-Alex

A binary file containing one UDP packet or many? If many, what you you
like as the separator between the packets ?

Many, to be realistic.
For this I usually do the following simple text/binary alternance:

     fconfigure stdout -translation binary
     foreach packet $l {
          puts [string length $packet]
          puts -nonewline $packet
     }

which is simply read back with

     fconfigure stdin -translation binary
     while {1} {
          if {[gets stdin len]<0} break
          set packet [read stdin $len]
          ...
     }

-Alex

Initially, I have put sampledata.bin on the website, as well as a new
test program, tcl4c.tcl, which produce when decoded (via tcl4a.tcl):
path=/alpha/beta/gamma , types={iiissiiTsFNIssfisbssmssts} ,
values=[32767 32768 32769 omega gamma 32768 0 alpha beta alpha
12345.6787109 1 a 001133557799bbddff00 a alpha 195051776 beta alpha
-3759595228763401487 beta]

The only non-standard feature is that the blob is displayed in hex
(001133557799bbddff00)

OK two things:

(1) The spec is not buggy, it says "followed by a null, followed by
0-3 additional null", which in my book is really 1-4 ;-)

(2) The code below implements an OSC decoder which avoids any
pointwise [binary]. It is slightly different from my initial
suggestion in that it does not build a typestring for [binary];
instead it extracts both the I* and R* lists (integer and float) once
for all, and then peeks into them when needed.

Please try it out and tell me if it's faster than yours.
You'll notice a few discrepancies from the spec, due to my laziness
tonight:
  - 64-bit ints are rendered as pairs of integers
  - non-ifbs types are treated as aliases to ifbs (except for the
constants TFNI)

-Alex

---------------------------------------------------------------------------­-------------

proc osc_decode_bin buf {
    binary scan $buf I* l
    binary scan $buf R* m
    osc_decode $l $m $buf

}

proc osc_blob {vpos l b} {
    upvar $vpos pos
    set len [lindex $l $pos]
    set out [string range $b [expr {4*($pos+1)}] [expr {4*($pos+1)+
$len-1}]]
    set pos [expr {$pos+1+(($len+3)/4)}]
    return $out

}

proc osc_string {vpos l b} {
    upvar $vpos pos
    set n 0
    while {1} {
        set x [lindex $l [expr {$pos+$n}]]
        if {!($x&0xFF)} break
        incr n
    }
    if {$x&0xFF00} {
        set pad 1
    } elseif {$x&0xFF0000} {
        set pad 2
    } elseif {$x&0xFF000000} {
        set pad 3
    } else {
        set pad 4
    }
    set out [string range $b [expr {4*$pos}] [expr {4*($pos+$n+1)-1-
$pad}]]
    set pos [expr {$pos+$n+1}]
    return $out

}

proc osc_wide {vpos l} {
    upvar $vpos pos
    set out [lrange $l $pos [expr {$pos+1}]]
    incr pos 2
    return $out

}

proc hex b {
    binary scan $b H* x
    return $x

}

proc osc_decode {l m b} {
    set pos 0
    set len [llength $l]
    set path [osc_string pos $l $b]
    if {$path=="#bundle"} {
        set t [osc_wide pos $l $b]
        set out [list bundle $t]
        while {$pos<$len} {
            set n [expr {[lindex $l $pos]/4}]

            set l2 [lrange $l [expr {$pos+1}] [expr {$pos+$n}]]
            set m2 [lrange $m [expr {$pos+1}] [expr {$pos+$n}]]
            set b2 [string range $b [expr {4*($pos+1)}] [expr {4*($pos+$n)}]]
            lappend out [osc_decode $l2 $m2 $b2]
            set pos [expr {$pos+$n+1}]
        }
        return $out
    }
    set types [osc_string pos $l $b]
    if {![regexp {^,(.*)$} $types pipo types]} {
        error "Typestring not starting with comma: $types"
    }
    set out [list message $path]

    foreach t [split $types ""] {
        switch -exact -- $t {
            i - c - r - m {lappend out $t [lindex $l $pos];incr pos}
            f {lappend out $t [lindex $m $pos];incr pos}
            s - S {lappend out $t [osc_string pos $l $b]}
            b {lappend out $t [hex [osc_blob pos $l $b]]}
            h - t - d {lappend out $t [osc_wide pos $l]}
            T {lappend out $t True}
            F {lappend out $t False}
            N {lappend out $t Nil}
            I {lappend out $t Inifinitum}
            default {error "Unsupported type tag '$t'"}
        }
    }
    return $out

}

The first speed tests indicate that the new code written by Alex is
about 10 times faster. I am now doing some cleanup work, so that the
'wide' items are decoded properly, and that the code will work with
8.4 (8.4 does not have binary scan R). The float values are suspect
anyway, since they are dependent on the TCL implementing IEEE 754

Dave

Hmm...Building on Alex's approach, decoding the 64bit items properly
is even faster by doing it according to the spec. I will post complete
code later on.

The trick is to add:
    binary scan $buf W* w1
    binary scan [string range $buf 4 end] W* w2
to osc_decode_bin, and then returning an item from w1 or w2 as needed.

Yes, I had thought of that too, but in my heart it was slightly less
elegant than the following:

proc pair2wide {x y} {expr {($x<<32)|($y&0xFFFFFFFF)}}

(actually I'm not sure whether internally it builds a Wide or a Big,
but for your calling program that shouldn't be a concern)
Have not done much timing analysis though. Maybe you can give it a
try ?

-Alex

-Alex
.



Relevant Pages

  • Re: Godel proved maths inconsistent not incompleteness theorem
    ... proof checker for ZF, PA or what have you would be to implement some ... elementary pattern matching routines for the axioms/schemas of your ...   a. ... tell how big a task is until you spec it out. ...
    (sci.logic)
  • Re: FunctionExpressions and memory consumptions
    ...   if { ... is an increased memory consumption in such cases. ... So, as far as I understand, function expression in "unreached" block ... Does spec actually define such behavior (object ...
    (comp.lang.javascript)
  • Re: Zoom H2 Handy Recorder - Brilliant!
    ... a device say its "USB 2" means nothing without it also saying what mode ...     USB2.0 Full-Speed compatible ... And the USB 2 spec says... ...
    (rec.audio.pro)