synchroscope (part 3)
This commit is contained in:
parent
7d4ba661e6
commit
2bad195b15
3 changed files with 83 additions and 68 deletions
52
README.org
52
README.org
|
@ -22,9 +22,9 @@ This implementation supports the [[https://opensoundcontrol.stanford.edu/spec-1_
|
|||
| *Type tag* | *type* | *description* | *v1.0* | *v1.1* | *cl-osc* |
|
||||
| i | int32 | 32-bit big-endian two’s complement integer | *R* | *R* | YES |
|
||||
| f | float32 | 32-bit big-endian IEEE 754 floating point number | *R* | *R* | YES |
|
||||
| s | OSC-string | A sequence of non-null ASCII characters followed by a null, | | *R* | |
|
||||
| s | OSC-string | A sequence of non-null ASCII characters followed by a null… | | *R* | |
|
||||
| | | followed by 0-3 additional null characters. Total bits is a multiple of 32. | *R* | N | YES |
|
||||
| b | OSC-blob | An int32 size count, followed by that many 8-bit bytes of arbitrary binary data, | | *R* | |
|
||||
| b | OSC-blob | An int32 size count, followed by that many 8-bit bytes of arbitrary binary data… | | *R* | |
|
||||
| | | followed by 0-3 additional zero bytes. Total bits is a multiple of 32. | *R* | N | YES |
|
||||
| T | True | No bytes are allocated in the argument data. | O | *R* | |
|
||||
| F | False | No bytes are allocated in the argument data. | O | *R* | |
|
||||
|
@ -32,7 +32,7 @@ This implementation supports the [[https://opensoundcontrol.stanford.edu/spec-1_
|
|||
| I | Impulse | (aka “bang”), used for event triggers. No bytes are allocated in the argument data. | O | *R* | |
|
||||
| t | OSC-timetag | an OSC timetag in NTP format, encoded in the data section | O | *R* | |
|
||||
| h | int64 | 64 bit big-endian two’s complement integer | O | O | YES |
|
||||
| d | float64 | 64 bit (“double”) IEEE 754 floating point number | O | O | |
|
||||
| d | float64 | 64 bit (“double”) IEEE 754 floating point number | O | O | YES |
|
||||
| S | OSC-string | Alternate type represented as an OSC-string (e.g to differentiate “symbols” from “strings”) | O | O | YES |
|
||||
| c | | an ascii character, sent as 32 bits | O | O | |
|
||||
| r | | 32 bit RGBA color | O | O | |
|
||||
|
@ -41,49 +41,5 @@ This implementation supports the [[https://opensoundcontrol.stanford.edu/spec-1_
|
|||
| ] | | Indicates the end of an array. | O | O | YES? |
|
||||
|
||||
|
||||
- *R*equired, *O*ptional and *N*ot supported (or *N*ot required).
|
||||
- Required, Optional and Not supported (or Not required).
|
||||
- data is encoded as =(vector (unsigned 8))= by =cl-osc=
|
||||
|
||||
* Float encoding & decoding
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(defun encode-float32 (f)
|
||||
"Encode an ieee754 float as a 4 byte vector. currently sbcl/cmucl specific."
|
||||
(encode-int32 (ieee-floats:encode-float32 f)))
|
||||
;; #+sbcl (encode-int32 (sb-kernel:single-float-bits f))
|
||||
;; #+cmucl (encode-int32 (kernel:single-float-bits f))
|
||||
;; #+openmcl (encode-int32 (CCL::SINGLE-FLOAT-BITS f))
|
||||
;; #+allegro (encode-int32 (multiple-value-bind (x y)
|
||||
;; (excl:single-float-to-shorts f)
|
||||
;; (+ (ash x 16) y)))
|
||||
;; #-(or sbcl cmucl openmcl allegro ieee-floats) (error "Can't encode single-floats using this implementation."))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(defun decode-float32 (v)
|
||||
"Convert a vector of 4 bytes in network byte order into an ieee754 float."
|
||||
(ieee-floats:decode-float32 (decode-int32 v)))
|
||||
;; #+sbcl (sb-kernel:make-single-float (decode-int32 v))
|
||||
;; #+cmucl (kernel:make-single-float (decode-int32 v))
|
||||
;; #+openmcl (CCL::HOST-SINGLE-FLOAT-FROM-UNSIGNED-BYTE-32 (decode-uint32 v))
|
||||
;; #+allegro (excl:shorts-to-single-float (ldb (byte 16 16) (decode-int32 v))
|
||||
;; (ldb (byte 16 0) (decode-int32 v)))
|
||||
;; #-(or sbcl cmucl openmcl allegro) (error "Can't decode single-floats using this implementation."))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(defun encode-float64 (d)
|
||||
"Encode an ieee754 float as a 8 byte vector. currently sbcl/cmucl specific."
|
||||
#+sbcl (cat (encode-int32 (sb-kernel:double-float-high-bits d))
|
||||
(encode-int32 (sb-kernel:double-float-low-bits d)))
|
||||
#-(or sbcl ieee-floats) (error "Can't encode double-floats using this implementation."))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC lisp
|
||||
(defun decode-float64 (v)
|
||||
"Convert a vector of 8 bytes in network byte order into an ieee754 float."
|
||||
#+sbcl (sb-kernel:make-double-float
|
||||
(decode-uint32 (subseq v 0 4))
|
||||
(decode-uint32 (subseq v 4 8)))
|
||||
#-(or sbcl ieee-floats) (error "Can't decode single-floats using this implementation."))
|
||||
#+END_SRC
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
(is (equalp
|
||||
(osc::decode-float32 #(254 254 254 254)) -1.6947395e38)))
|
||||
|
||||
;; (osc::decode-float32 #(127 255 255 255))
|
||||
;; #<SINGLE-FLOAT quiet NaN>
|
||||
|
||||
(test osc-string
|
||||
"OSC string encoding tests."
|
||||
(is (equalp
|
||||
|
@ -290,6 +293,28 @@
|
|||
;; v1.1. tests
|
||||
(in-suite protocol-v1.1)
|
||||
|
||||
(test v1.1-required-data-types
|
||||
"OSC data encoding test. All required types for v1.1"
|
||||
(is (equalp
|
||||
#(44 105 104 115 102 100 98 0)
|
||||
(osc::encode-typetags '(3
|
||||
4294967297
|
||||
"test"
|
||||
2.1e2
|
||||
2.1d23
|
||||
#(1 2 3 4)
|
||||
;; (osc::encode-timetag :now)
|
||||
)))))
|
||||
|
||||
(test v1.1-keyword-typetags
|
||||
"OSC typetag encoding test."
|
||||
(is (equalp
|
||||
(osc::encode-typetags '(:true :false :null :impulse))
|
||||
#(44 84 70 78 73 0 0 0))))
|
||||
|
||||
;; (osc::encode-typetags '("s" 1))
|
||||
|
||||
|
||||
;; play nicely with others
|
||||
(in-suite interoperability)
|
||||
|
||||
|
|
74
osc.lisp
74
osc.lisp
|
@ -82,29 +82,43 @@
|
|||
|
||||
(defun encode-typetags (data)
|
||||
"Create a typetag string suitable for the given DATA.
|
||||
valid typetags according to the OSC spec are ,i ,f ,s and ,b
|
||||
non-std extensions include ,{h|t|d|S|c|r|m|T|F|N|I|[|]}
|
||||
see the spec for more details. ..
|
||||
valid typetags according to the OSC 1.0 spec are ,i ,f ,s and ,b
|
||||
the OSC 1.1 spec includes ,h ,t ,d ,S ,T ,F ,N and ,I
|
||||
|
||||
NOTE: currently handles the following tags
|
||||
i => #(105) => int32
|
||||
f => #(102) => float32
|
||||
s => #(115) => string
|
||||
b => #(98) => blob
|
||||
h => #(104) => int64
|
||||
and considers non int/float/string data to be a blob."
|
||||
The following tags are written based on type check
|
||||
integer => i => #(105)
|
||||
=> h => #(104)
|
||||
single-float => f => #(102)
|
||||
double-float => d => #(100)
|
||||
simple-string => s => #(115)
|
||||
* => b => #(98)
|
||||
|
||||
The following tags are written based on :keywords in the data
|
||||
:true (or t) => T => #(84)
|
||||
:false => F => #(70)
|
||||
:null => N => #(78)
|
||||
:impulse => I => #(73)
|
||||
"
|
||||
(let ((lump (make-array 0 :adjustable t
|
||||
:fill-pointer t)))
|
||||
(macrolet ((write-to-vector (char)
|
||||
`(vector-push-extend
|
||||
(char-code ,char) lump)))
|
||||
(write-to-vector #\,)
|
||||
(write-to-vector #\,) ;; #(44)
|
||||
(dolist (x data)
|
||||
(typecase x
|
||||
(integer (if (>= x 4294967296) (write-to-vector #\h) (write-to-vector #\i)))
|
||||
(float (write-to-vector #\f))
|
||||
(single-float (write-to-vector #\f))
|
||||
(double-float (write-to-vector #\d))
|
||||
(simple-string (write-to-vector #\s))
|
||||
;; lisp semantics vs. OSC semantics
|
||||
(keyword (case x
|
||||
(:true (write-to-vector #\T))
|
||||
(:false (write-to-vector #\F))
|
||||
(:null (write-to-vector #\N))
|
||||
(:impulse (write-to-vector #\I))))
|
||||
(null ('false (write-to-vector #\F)))
|
||||
;; anything else is treated as a blob
|
||||
(t (write-to-vector #\b)))))
|
||||
(cat lump
|
||||
(pad (padding-length (length lump))))))
|
||||
|
@ -117,8 +131,10 @@
|
|||
(dolist (x data)
|
||||
(typecase x
|
||||
(integer (if (>= x 4294967296) (enc encode-int64) (enc encode-int32)))
|
||||
(float (enc encode-float32))
|
||||
(single-float (enc encode-float32))
|
||||
(double-float (enc encode-float64))
|
||||
(simple-string (enc encode-string))
|
||||
;; -> timetag
|
||||
(t (enc encode-blob))))
|
||||
lump)))
|
||||
|
||||
|
@ -324,24 +340,41 @@
|
|||
;; floats are encoded using ieee-floats library for brevity and compatibility
|
||||
;; - https://ieee-floats.common-lisp.dev/
|
||||
;;
|
||||
;; implementation specific encoding can be used for sbc, cmucl,
|
||||
;; allegro or ccl if required (see README)
|
||||
;; It should be possible to use 32 and 64 bit floats in most common lisp environments.
|
||||
;; An implementation specific encoder/decoder is used where available.
|
||||
|
||||
(defun encode-float32 (f)
|
||||
"Encode an ieee754 float as a 4 byte vector. currently sbcl/cmucl specific."
|
||||
(encode-int32 (ieee-floats:encode-float32 f)))
|
||||
#+sbcl (encode-int32 (sb-kernel:single-float-bits f))
|
||||
#+cmucl (encode-int32 (kernel:single-float-bits f))
|
||||
#+openmcl (encode-int32 (CCL::SINGLE-FLOAT-BITS f))
|
||||
#+allegro (encode-int32 (multiple-value-bind (x y)
|
||||
(excl:single-float-to-shorts f)
|
||||
(+ (ash x 16) y)))
|
||||
#-(or sbcl cmucl openmcl allegro) (encode-int32 (ieee-floats:encode-float32 f)))
|
||||
|
||||
(defun decode-float32 (v)
|
||||
"Convert a vector of 4 bytes in network byte order into an ieee754 float."
|
||||
(ieee-floats:decode-float32 (decode-uint32 v)))
|
||||
#+sbcl (sb-kernel:make-single-float (decode-uint32 v))
|
||||
#+cmucl (kernel:make-single-float (decode-int32 v))
|
||||
#+openmcl (CCL::HOST-SINGLE-FLOAT-FROM-UNSIGNED-BYTE-32 (decode-uint32 v))
|
||||
#+allegro (excl:shorts-to-single-float (ldb (byte 16 16) (decode-uint32 v))
|
||||
(ldb (byte 16 0) (decode-uint32 v)))
|
||||
#-(or sbcl cmucl openmcl allegro) (ieee-floats:decode-float32 (decode-uint32 v)))
|
||||
|
||||
|
||||
(defun encode-float64 (d)
|
||||
"Encode an ieee754 float as a 8 byte vector."
|
||||
(encode-int64 (ieee-floats:encode-float64 d)))
|
||||
#+sbcl (cat (encode-int32 (sb-kernel:double-float-high-bits d))
|
||||
(encode-int32 (sb-kernel:double-float-low-bits d)))
|
||||
#-sbcl (encode-int64 (ieee-floats:encode-float64 d)))
|
||||
|
||||
(defun decode-float64 (v)
|
||||
"Convert a vector of 8 bytes in network byte order into an ieee754 float."
|
||||
(ieee-floats:decode-float64 (decode-int64 v)))
|
||||
#+sbcl (sb-kernel:make-double-float
|
||||
(decode-uint32 (subseq v 0 4))
|
||||
(decode-uint32 (subseq v 4 8)))
|
||||
#-sbcl (ieee-floats:decode-float64 (decode-uint64 v)))
|
||||
|
||||
;; osc-strings are unsigned bytes, padded to a 4 byte boundary
|
||||
|
||||
|
@ -355,7 +388,7 @@
|
|||
(string-padding string)))
|
||||
|
||||
;; blobs are binary data, consisting of a length (int32) and bytes which are
|
||||
;; osc-padded to a 4 byte boundary.
|
||||
;; padded to a 4 byte boundary.
|
||||
|
||||
(defun decode-blob (blob)
|
||||
"Decode a BLOB as a vector of unsigned bytes."
|
||||
|
@ -371,6 +404,7 @@
|
|||
;; NOTE: cannot use (padding-length bl), as it is not the same algorithm. Blobs of 4, 8, 12 etc bytes should not be padded!
|
||||
|
||||
;; utility functions for osc-string/padding/slonking
|
||||
;; NOTE: string padding is treated differently between v1.0 and v1.1
|
||||
|
||||
(defun cat (&rest catatac)
|
||||
"Concatenate items into a byte vector."
|
||||
|
|
Loading…
Reference in a new issue