Learn RNBO Raspberry Pi OSCQuery Runner

Getting Started

Welcome to RNBO

Quickstart

RNBO Basics

Key Differences

Why We Made RNBO

Coding Resources

Fundamentals

Audio IO

Messages to rnbo~

Using Parameters

MIDI in RNBO

Messages and Ports

Polyphony and Voice Control

Audio Files in RNBO

Using Buffers

Using the FFT

Export Targets

Export Targets Overview

VST/AudioUnit
Max External Target
Raspberry Pi Target
The Web Export Target
The C++ Source Code Target

Code Export

Working with JavaScript
Working with C++

Special Topics

Sample Accurate Patching
Scala and Custom Tuning

RNBO and Max for Live

RNBO Raspberry Pi OSCQuery Runner

Metadata

Export Description

Raspberry Pi GPIO

Updating the RNBO Package

The RNBO Raspberry Pi OSCQuery Runner

The OSCQuery Runner is the simplest method to load exported code onto a Raspberry Pi.

It is setup to provide plug and play access to the pi from the Max application and provides a communication with the running code using OSCQuery. When a RNBO patcher is exported to an rPi the OSC namespace is automatically generated based on the parameters and inport/outport objects in the RNBO patcher code.

You can communicate with the runner via Open Sound Control (OSC) over either websockets or UDP.

Communicating with the runner Via UDP

If you have sucessfully connected to an rPi with an active runner in Max, the associated target sidebar info should show you the UDP and HTTP/WS host port and, for OSC, transport.

By default the HTTP and websocket port are 5678 and OSC is UDP at 1234 so if you know the IP address of your runner, you should be able to load a webpage with the url:

http://<ipoftherunner>:5678 and send OSC messages at osc.udp://<ipoftherunner>:1234

The device hostname followed by port can also be used. i.e., if the hostname is c74rpi, then the addresses are http://c74rpi.local:5678 and osc.udp://c74rpi.local:1234.

The websocket interface is created via an http upgrade from the HTTP host and port.

*NOTE* the websocket interface is used for more than just `OSC`, so you'll want to detect the type of the websocket messages and only try to parse the Binary messages.

OSC Namespace

If you've exported a patch to your Pi, you should be able to investigate the runner's OSCQuery namespace via HTTP, as described above. For instance, if the runner is at the default name c74rpi.local, loading the URL http://c74rpi.local:5678 will reveal a json file exposing the full paths of RNBO code running on the Raspberry Pi.

FULL_PATH entries correspond to OSC addresses. TYPE entries identify the OSC type that those parameters expect, if any.

If the ACCESS value is 2 (set only) or 3 (get set) then you can send OSC messages to that address to alter parameters. ACCESS 1 is reserved for system/read-only data values.

See the OSCQueryProposal for more details on OSCQuery.

Below an example of what the json tree structure will look like will look like using the exported RNBO code from the RNBO OSCQUERY example.

{
  "FULL_PATH": "/rnbo",
  "CONTENTS": {
    "info": {
      "FULL_PATH": "/rnbo/info",
      "DESCRIPTION": "information about RNBO and the running system",
      "CONTENTS": {
        "version": {
          "FULL_PATH": "/rnbo/info/version",
          "TYPE": "s",
          "VALUE": "0.14.0-dev.12",
          "ACCESS": 1,
          "CLIPMODE": "none"
        },
        "system_name": {
          "FULL_PATH": "/rnbo/info/system_name",
          "TYPE": "s",
          "VALUE": "Linux",
          "ACCESS": 1,
          "CLIPMODE": "none"
        },
        "system_processor": {
          "FULL_PATH": "/rnbo/info/system_processor",
          "TYPE": "s",
          "VALUE": "armv7",
          "ACCESS": 1,
          "CLIPMODE": "none"
        },
        "system_id": {
          "FULL_PATH": "/rnbo/info/system_id",
          "TYPE": "s",
          "VALUE": "e76c9ab1-efbf-404b-87ef-30ba0021fab9",
          "ACCESS": 1,
          "CLIPMODE": "none",
          "DESCRIPTION": "a unique, one time generated id for this system"
        },
        "disk_bytes_available": {
          "FULL_PATH": "/rnbo/info/disk_bytes_available",
          "TYPE": "s",
          "VALUE": "26440867840",
          "ACCESS": 1,
          "CLIPMODE": "none"
        },
        "update": {
          "FULL_PATH": "/rnbo/info/update",
          "DESCRIPTION": "Self upgrade/downgrade",
          "CONTENTS": {
            "state": {
              "FULL_PATH": "/rnbo/info/update/state",
              "TYPE": "s",
              "VALUE": "idle",
              "RANGE": [
                {
                  "VALS": [
                    "idle",
                    "active",
                    "failed"
                  ]
                }
              ],
              "ACCESS": 1,
              "CLIPMODE": "both",
              "DESCRIPTION": "Update state"
            },
            "status": {
              "FULL_PATH": "/rnbo/info/update/status",
              "TYPE": "s",
              "VALUE": "waiting",
              "ACCESS": 1,
              "CLIPMODE": "none",
              "DESCRIPTION": "Latest update status"
            },
            "outdated": {
              "FULL_PATH": "/rnbo/info/update/outdated",
              "TYPE": "i",
              "VALUE": -1,
              "ACCESS": 1,
              "CLIPMODE": "none",
              "DESCRIPTION": "Number of outdated packages detected on the system"
            },
            "supported": {
              "FULL_PATH": "/rnbo/info/update/supported",
              "TYPE": "T",
              "VALUE": null,
              "ACCESS": 1,
              "CLIPMODE": "none",
              "DESCRIPTION": "Does this runner support remote upgrade/downgrade"
            }
          }
        }
      }
    },
    "cmd": {
      "FULL_PATH": "/rnbo/cmd",
      "TYPE": "s",
      "VALUE": "",
      "ACCESS": 2,
      "CLIPMODE": "none",
      "DESCRIPTION": "command handler"
    },
    "resp": {
      "FULL_PATH": "/rnbo/resp",
      "TYPE": "s",
      "VALUE": "{\"id\":\"40b2464b-0692-4ca7-86e9-4e8b080cf401\",\"jsonrpc\":\"2.0\",\"result\":{\"code\":2,\"message\":\"loaded\",\"progress\":100}}",
      "ACCESS": 1,
      "CLIPMODE": "none",
      "DESCRIPTION": "command response"
    },
    "listeners": {
      "FULL_PATH": "/rnbo/listeners",
      "CONTENTS": {
        "entries": {
          "FULL_PATH": "/rnbo/listeners/entries",
          "TYPE": "",
          "VALUE": [],
          "ACCESS": 1,
          "CLIPMODE": "none",
          "EXTENDED_TYPE": "list",
          "DESCRIPTION": "list of OSC listeners"
        },
        "add": {
          "FULL_PATH": "/rnbo/listeners/add",
          "TYPE": "s",
          "VALUE": "",
          "ACCESS": 2,
          "CLIPMODE": "none",
          "DESCRIPTION": "add OSC UDP listener: \"ip:port\""
        },
        "del": {
          "FULL_PATH": "/rnbo/listeners/del",
          "TYPE": "s",
          "VALUE": "",
          "ACCESS": 2,
          "CLIPMODE": "none",
          "DESCRIPTION": "delete OSC UDP listener: \"ip:port\""
        },
        "clear": {
          "FULL_PATH": "/rnbo/listeners/clear",
          "TYPE": "I",
          "VALUE": null,
          "ACCESS": 2,
          "CLIPMODE": "none",
          "DESCRIPTION": "clear all OSC UDP listeners"
        }
      }
    },
    "jack": {
      "FULL_PATH": "/rnbo/jack",
      "CONTENTS": {
        "info": {
          "FULL_PATH": "/rnbo/jack/info",
          "CONTENTS": {
            "alsa_cards": {
              "FULL_PATH": "/rnbo/jack/info/alsa_cards",
              "CONTENTS": {
                "hw:pisound": {
                  "FULL_PATH": "/rnbo/jack/info/alsa_cards/hw:pisound",
                  "TYPE": "s",
                  "VALUE": "pisound - pisound\npisound",
                  "ACCESS": 1,
                  "CLIPMODE": "none"
                },
                "hw:1": {
                  "FULL_PATH": "/rnbo/jack/info/alsa_cards/hw:1",
                  "TYPE": "s",
                  "VALUE": "pisound - pisound\npisound",
                  "ACCESS": 1,
                  "CLIPMODE": "none"
                }
              }
            },
            "is_realtime": {
              "FULL_PATH": "/rnbo/jack/info/is_realtime",
              "TYPE": "T",
              "VALUE": null,
              "ACCESS": 1,
              "CLIPMODE": "none",
              "DESCRIPTION": "indicates if jack is running in realtime mode or not"
            }
          }
        },
        "config": {
          "FULL_PATH": "/rnbo/jack/config",
          "DESCRIPTION": "Jack configuration parameters",
          "CONTENTS": {
            "card": {
              "FULL_PATH": "/rnbo/jack/config/card",
              "TYPE": "s",
              "VALUE": "hw:1",
              "RANGE": [
                {
                  "VALS": [
                    "hw:pisound",
                    "hw:1"
                  ]
                }
              ],
              "ACCESS": 3,
              "CLIPMODE": "both",
              "DESCRIPTION": "ALSA device name"
            },
            "num_periods": {
              "FULL_PATH": "/rnbo/jack/config/num_periods",
              "TYPE": "i",
              "VALUE": 2,
              "RANGE": [
                {
                  "VALS": [
                    1,
                    2,
                    3,
                    4
                  ]
                }
              ],
              "ACCESS": 3,
              "CLIPMODE": "both",
              "DESCRIPTION": "Number of periods of playback latency"
            },
            "period_frames": {
              "FULL_PATH": "/rnbo/jack/config/period_frames",
              "TYPE": "i",
              "VALUE": 256,
              "RANGE": [
                {
                  "VALS": [
                    32,
                    64,
                    128,
                    256,
                    512,
                    1024
                  ]
                }
              ],
              "ACCESS": 3,
              "CLIPMODE": "both",
              "DESCRIPTION": "Frames per period"
            },
            "sample_rate": {
              "FULL_PATH": "/rnbo/jack/config/sample_rate",
              "TYPE": "f",
              "VALUE": 48000,
              "RANGE": [
                {
                  "MIN": 22050
                }
              ],
              "ACCESS": 3,
              "CLIPMODE": "both",
              "DESCRIPTION": "Sample rate"
            }
          }
        },
        "active": {
          "FULL_PATH": "/rnbo/jack/active",
          "TYPE": "T",
          "VALUE": null,
          "ACCESS": 3,
          "CLIPMODE": "none"
        },
        "transport": {
          "FULL_PATH": "/rnbo/jack/transport",
          "CONTENTS": {
            "bpm": {
              "FULL_PATH": "/rnbo/jack/transport/bpm",
              "TYPE": "f",
              "VALUE": 100,
              "ACCESS": 3,
              "CLIPMODE": "none"
            },
            "rolling": {
              "FULL_PATH": "/rnbo/jack/transport/rolling",
              "TYPE": "F",
              "VALUE": null,
              "ACCESS": 3,
              "CLIPMODE": "none"
            }
          }
        }
      }
    },
    "inst": {
      "FULL_PATH": "/rnbo/inst",
      "DESCRIPTION": "code export instances",
      "CONTENTS": {
        "0": {
          "FULL_PATH": "/rnbo/inst/0",
          "CONTENTS": {
            "jack": {
              "FULL_PATH": "/rnbo/inst/0/jack",
              "CONTENTS": {
                "audio_ins": {
                  "FULL_PATH": "/rnbo/inst/0/jack/audio_ins",
                  "TYPE": "",
                  "VALUE": [],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list"
                },
                "audio_outs": {
                  "FULL_PATH": "/rnbo/inst/0/jack/audio_outs",
                  "TYPE": "ss",
                  "VALUE": [
                    "rnbo0:out1",
                    "rnbo0:out2"
                  ],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list"
                },
                "midi_ins": {
                  "FULL_PATH": "/rnbo/inst/0/jack/midi_ins",
                  "TYPE": "s",
                  "VALUE": [
                    "rnbo0:midiin1"
                  ],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list"
                },
                "midi_outs": {
                  "FULL_PATH": "/rnbo/inst/0/jack/midi_outs",
                  "TYPE": "s",
                  "VALUE": [
                    "rnbo0:midiout1"
                  ],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list"
                }
              }
            },
            "params": {
              "FULL_PATH": "/rnbo/inst/0/params",
              "DESCRIPTION": "Parameter get/set",
              "CONTENTS": {
                "frequency": {
                  "FULL_PATH": "/rnbo/inst/0/params/frequency",
                  "TYPE": "f",
                  "VALUE": 120,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 1200
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/frequency/normalized",
                      "TYPE": "f",
                      "VALUE": 0.10000000149011612,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                },
                "cyclegain": {
                  "FULL_PATH": "/rnbo/inst/0/params/cyclegain",
                  "TYPE": "f",
                  "VALUE": 0.10000000149011612,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 1
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/cyclegain/normalized",
                      "TYPE": "f",
                      "VALUE": 0.10000000149011612,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                },
                "sahgainin": {
                  "FULL_PATH": "/rnbo/inst/0/params/sahgainin",
                  "TYPE": "f",
                  "VALUE": 0,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 1
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/sahgainin/normalized",
                      "TYPE": "f",
                      "VALUE": 0,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                },
                "groovegain": {
                  "FULL_PATH": "/rnbo/inst/0/params/groovegain",
                  "TYPE": "f",
                  "VALUE": 0.10000000149011612,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 1
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/groovegain/normalized",
                      "TYPE": "f",
                      "VALUE": 0.10000000149011612,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                },
                "phasorfreq": {
                  "FULL_PATH": "/rnbo/inst/0/params/phasorfreq",
                  "TYPE": "f",
                  "VALUE": 0,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 100
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/phasorfreq/normalized",
                      "TYPE": "f",
                      "VALUE": 0,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                },
                "phasorgain": {
                  "FULL_PATH": "/rnbo/inst/0/params/phasorgain",
                  "TYPE": "f",
                  "VALUE": 0,
                  "RANGE": [
                    {
                      "MIN": 0,
                      "MAX": 1
                    }
                  ],
                  "ACCESS": 3,
                  "CLIPMODE": "both",
                  "CONTENTS": {
                    "normalized": {
                      "FULL_PATH": "/rnbo/inst/0/params/phasorgain/normalized",
                      "TYPE": "f",
                      "VALUE": 0,
                      "RANGE": [
                        {
                          "MIN": 0,
                          "MAX": 1
                        }
                      ],
                      "ACCESS": 3,
                      "CLIPMODE": "both"
                    }
                  }
                }
              }
            },
            "data_refs": {
              "FULL_PATH": "/rnbo/inst/0/data_refs",
              "CONTENTS": {
                "bufferone": {
                  "FULL_PATH": "/rnbo/inst/0/data_refs/bufferone",
                  "TYPE": "s",
                  "VALUE": "drumLoop.aif",
                  "ACCESS": 3,
                  "CLIPMODE": "none"
                }
              }
            },
            "presets": {
              "FULL_PATH": "/rnbo/inst/0/presets",
              "CONTENTS": {
                "entries": {
                  "FULL_PATH": "/rnbo/inst/0/presets/entries",
                  "TYPE": "sss",
                  "VALUE": [
                    "60 freq",
                    "120 freq",
                    "440 freq"
                  ],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list",
                  "DESCRIPTION": "A list of presets that can be loaded"
                },
                "save": {
                  "FULL_PATH": "/rnbo/inst/0/presets/save",
                  "TYPE": "s",
                  "VALUE": "",
                  "ACCESS": 2,
                  "CLIPMODE": "none",
                  "DESCRIPTION": "Save the current settings as a preset with the given name"
                },
                "load": {
                  "FULL_PATH": "/rnbo/inst/0/presets/load",
                  "TYPE": "s",
                  "VALUE": "",
                  "ACCESS": 2,
                  "CLIPMODE": "none",
                  "DESCRIPTION": "Load a preset with the given name"
                },
                "delete": {
                  "FULL_PATH": "/rnbo/inst/0/presets/delete",
                  "TYPE": "s",
                  "VALUE": "",
                  "ACCESS": 2,
                  "CLIPMODE": "none",
                  "DESCRIPTION": "Delete a preset with the given name"
                },
                "del": {
                  "FULL_PATH": "/rnbo/inst/0/presets/del",
                  "TYPE": "s",
                  "VALUE": "",
                  "ACCESS": 2,
                  "CLIPMODE": "none",
                  "DESCRIPTION": "Delete a preset with the given name"
                },
                "initial": {
                  "FULL_PATH": "/rnbo/inst/0/presets/initial",
                  "TYPE": "s",
                  "VALUE": "",
                  "ACCESS": 3,
                  "CLIPMODE": "none",
                  "DESCRIPTION": "Indicate a preset, by name, that should be loaded every time this patch is reloaded. Set to an empty string to load the last loaded preset instead"
                }
              }
            },
            "messages": {
              "FULL_PATH": "/rnbo/inst/0/messages",
              "CONTENTS": {
                "in": {
                  "FULL_PATH": "/rnbo/inst/0/messages/in",
                  "CONTENTS": {
                    "phasorinput": {
                      "FULL_PATH": "/rnbo/inst/0/messages/in/phasorinput",
                      "TYPE": "",
                      "VALUE": [],
                      "ACCESS": 2,
                      "CLIPMODE": "none",
                      "EXTENDED_TYPE": "list"
                    },
                    "trigger": {
                      "FULL_PATH": "/rnbo/inst/0/messages/in/trigger",
                      "TYPE": "",
                      "VALUE": [],
                      "ACCESS": 2,
                      "CLIPMODE": "none",
                      "EXTENDED_TYPE": "list"
                    },
                    "threshold": {
                      "FULL_PATH": "/rnbo/inst/0/messages/in/threshold",
                      "TYPE": "",
                      "VALUE": [],
                      "ACCESS": 2,
                      "CLIPMODE": "none",
                      "EXTENDED_TYPE": "list"
                    }
                  }
                },
                "out": {
                  "FULL_PATH": "/rnbo/inst/0/messages/out",
                  "CONTENTS": {
                    "sahgainout": {
                      "FULL_PATH": "/rnbo/inst/0/messages/out/sahgainout",
                      "TYPE": "f",
                      "VALUE": [
                        0
                      ],
                      "ACCESS": 1,
                      "CLIPMODE": "none",
                      "EXTENDED_TYPE": "list"
                    }
                  }
                }
              }
            },
            "midi": {
              "FULL_PATH": "/rnbo/inst/0/midi",
              "CONTENTS": {
                "in": {
                  "FULL_PATH": "/rnbo/inst/0/midi/in",
                  "TYPE": "",
                  "VALUE": [],
                  "ACCESS": 2,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list",
                  "DESCRIPTION": "midi events in to your RNBO patch"
                },
                "out": {
                  "FULL_PATH": "/rnbo/inst/0/midi/out",
                  "TYPE": "",
                  "VALUE": [],
                  "ACCESS": 1,
                  "CLIPMODE": "none",
                  "EXTENDED_TYPE": "list",
                  "DESCRIPTION": "midi events out of your RNBO patch"
                }
              }
            }
          }
        }
      }
    }
  }
}
```

Inst

RNBO code export instances are listed at /rnbo/inst and describe the state of the running patcher on the target. This path contains paths to set and/or get params, data_refs, presets, midi events and messages to and from inports and outports. The jack sub-path containst read-only access to the jack port name mappings for audio and midi io.

Listener Ports

Listener ports can be created on the runner to enable parameter changes to be communicated via UDP to other devices, looped back to scripts and applications on the same device, or both. To add a listener port, send a message via UDP to /rnbo/listeners/add followed by the ipv4 address:port number. This will add the numbered port to the runner on the Pi where changes can be observed in real time, without needing to poll the runner.

To delete a listener port, send a message via UDP to /rnbo/listeners/del followed by the ipv4 address:port number of the active listener port to remove.

A list of active listener ports can be queried via the address /rnbo/listeners/entries and all listener ports can be cleared at once via /rnbo/listeners/clear.

Audio Configuration

The audio settings of the runner such as the audio device, samplerate, number of periods of latency and number of frames per period can be queried and set via /rnbo/jack/config. To apply the changes after setting any of these values, send a 0 message to /rnbo/jack/active shortly before sending a 1 to the same address.

Commandline OSC message to the Raspberry Pi

OSC messages can be sent to parameters from a commandline on the Raspberry Pi running rnbo code.

On Mac, to send a normalized parameter update to the Pi named c74rpi.local we use oscsend, which can be installed via homebrew.

Commands can be sent to control any parameter in the namespace:

oscsend osc.udp://c74rpi.local:1234 /rnbo/inst/0/params/foo/normalized f 0.2

In the case above, if foo is a valid parameter in your loaded patch, and you send the above message, then load http://c74rpi.local:5678/rnbo/inst/0/params/ in a webbrowser, you should see that both foo and foo/normalized have been updated.

Commandline OSC Example for Windows

On Windows, you will need to install from the zip file which can be found at https://github.com/yoggy/sendosc/blob/master/README.md.

On windows, the command structure is like this:

cd <path to exe>/sendosc c74rpi.local 1234 /rnbo/inst/0/params/foo/normalized f .2

Again, ff foo is a valid parameter in your loaded patch, and you send the above message, then load http://c74rpi.local:5678/rnbo/inst/0/params/ in a webbrowser, you should see that both foo and foo/normalized have been updated.

Communicating with the Runner via UDP in Max

The udpsend and udpreceive objects in Max can also be used to communicate with the runner in the same way.

See the Raspberry Pi OSCQuery Max example to learn more.

Communicating with the Runner Via Websocket

To run the Websocket example, the ws package is required. to install, we can run `npm install ws` from a commandline.

Basic Javascript Websocket Example

const OSC = require("osc");

{
	let ws = new WebSocket(YOUR_RUNNER_URL);

	ws.on('message', (d) => {
		//must be a buffer because there are other non OSC websocket messages as well
		if (Buffer.isBuffer(d)) {
			try {
				const msg = OSC.readPacket(d, {metadata: true});
				//process
			} catch (e) {
			}
		}
	});

	ws.on('open', () => {
		//send OSC
		const array = OSC.writePacket({
			address: "/rnbo/inst/0/params/foo",
			args: [
				{
					type: "f",
					value: 1.0
				}
			]
		},
		{ metadata: true });
		ws.send(array);
	});
}

Commands

The OSCQuery runner uses a modified jsonRPC for command communication.

modifications:

* id is a uuid.

* method calls may have multiple responces indicating progress.

* libossia thread safety

* osc.js