JSONlib - A JSON de- and encoder for SuperCollider

A JSON de- and encoder for SuperCollider

The JSON implementation of the SuperCollider standard library lacks certain features such as

  • a JSON encoder (the conversion of an dictionary to a JSON string)
  • parsing JSON values into their respective type (.parseJSON converts everything to a string)

which this Quark implements, building on top of the existing implementation.

There also exists a json Quark which also adds a wrapper for sccode.org but lacks a recursive encoding of objects.
The goal of JSONlib is to simply provide a full implementation of the JSON standard in sclang and nothing beyond it.

Quickstart

Installation

// install the quark
Quarks.install("https://github.com/musikinformatik/JSONlib.git");

// restart the interpreter so the new classes are available
thisProcess.recompile;

// open documention
HelpBrowser.openHelpFor("Classes/JSONlib");

Basic usage

Parse a JSON

Let’s say we have a JSON with an integer as a value

{
    "hello": 42
}

which we want to parse in sclang.

// use Symbol instead of String to get rid of escaping quotation marks
j = '{"hello": 42}';

// turn this into an Event
d = JSONlib.convertToSC(j);
// -> ( 'hello': 42 )

// an integer gets parsed as an actual integer
d[\hello].class
// -> Integer

// compare to the built-in method of sclang
// it uses a Dictionary instead of an Event
d = j.parseJSON()
// -> Dictionary[ (hello -> 42) ]

// but the Integer 42 is a String here
d["hello"].class
// -> String

Encode an Event as JSON

// create an event
e = (\foo: "bar", \baz: (\nested: true));

e.asJSON
// -> { "baz": { "nested": true }, "foo": "bar" }

// or use the class JSONlib
JSONlib.convertToJSON(e);
// -> { "baz": { "nested": true }, "foo": "bar" }

Use custom en/decoders to store functions

// create event with function
x = (\myFunc: {|x| x**2}, \data: 42);

// encode it to JSON
(
a = JSONlib.convertToJSON(x, customEncoder: {|x|
    if(x.class==Function, {
        "--func%".format(x.asCompileString).quote;
    });
});
)
// -> { "data": 42, "myFunc": --func{|x| x**2} }

// decode JSON to SC with our custom decoder
// which re-constructs the function
(
b = JSONlib.convertToSC(a,     customDecoder: {|x|
    if(x.class==String) {
        if(x.beginsWith("--func")) {
            x["--func".size()..].compile().();
        }
    }
});
)
// -> ( 'myFunc': a Function, 'data': 42 )

b[\myFunc].(4)
// -> 16.0

Transfer nested objects via OSC

JSON allows to distribute and receive nested objects via OSC by distributing it as a String in an OSC message.

// create event
e = (\hello: (\foo: 42));

// create local listener which converts a JSON string to an SC object
(
OSCdef(\myJSONparser, func: {|m|
    // received strings are symbols, so we need to cast them to strings
    "Received %".format(JSONlib.convertToSC(m[1].asString)).postln;
}, path: "/myAddress", recvPort: 57120);
)

// send nested event as JSON
(
NetAddr(hostname: "127.0.0.1", port: 57120).sendMsg(
    "/myAddress",
    JSONlib.convertToJSON(e),
);
)

// Received ( 'hello': ( 'foo': 42 ) )

// clear OSC listener
OSCdef.clear;

More is described in the SCdoc documentation.


Developed by @julian and me @ IMM Düsseldorf

Enjoy!

5 Likes

thanks! This would have saved me a lot of trouble!