node package manager

osc

A JavaScript Open Sound Control (OSC) library that works in Node.js and the browser.

osc.js

osc.js is a library for reading and writing Open Sound Control messages in JavaScript. It works in both Node.js and in a web browser.

There are several other OSC libraries available for JavaScript. However, most depend on Node.js-specific APIs. This means that they can't be run in a browser or on web-only platforms such as Chrome OS. osc.js uses only cross-platform APIs (TypedArrays and DataView), ensuring that it can run in any modern JavaScript environment.

osc.js is fast, comprehensive, fully spec-compliant, tested, modular, and provides a wide variety of optional transports for sending and receiving OSC data.

osc.js reads and writes OSC-formatted binary data into plain JavaScript objects. It provides adaptors for Node.js Buffer objects as well as standard ArrayBuffers.

The core of osc.js is transport agnostic. You can receive OSC data in whatever manner works best for your application: serial port APIs such as node-serialport or chrome.serial, socket APIs such as Node.js dgram or WebRTC data channels, WebSockets or binary XHR messages should all work. Connect osc.js up to your source of incoming/outgoing data, and you're all set. This approach is consistent with the design of Open Sound Control as a content format that is independent from its means of transport.

In addition to the low-level encoder/decoder functions, osc.js also provides a comprehensive set of transport objects, called Ports, for use in standard browsers, Chrome Apps, and Node.js applications. These include:

Transport Supported Platforms
UDP Node.js, Chrome Apps
Serial port Node.js, Chrome Apps
Web Sockets Browsers, Node.js, Chrome Apps
TCP Node.js

For stream-based protocols such as serial and TCP, osc.js will take care of SLIP framing for you.

osc.js supports all OSC 1.0 and 1.1 required and optional types.

osc.js consists of two distinct layers:

  1. The transports, which provide a simple EventEmitter-style API for sending an receiving OSC packets using a variety of transports such as UDP and Web Sockets.
  2. The underlying stateless API that provides functions for reading and writing OSC packets.

All osc.Port objects implement the following supported methods:

Method Description Arguments
send Sends an OSC package (either a message or a bundle) on this Port. packet: the OSC message or bundle to send

All osc.Ports implement the Event Emitter API. The following events are supported:

Event Description Arguments
message Fires whenever an OSC message is received by the Port. message: the OSC message received;
timeTag: the time tag specified by the sender (may be undefined for non-bundle messages);
infoan implementation-specific remote information object
bundle Fires whenever an OSC bundle is received. Subsequent bundle and/or message events will be fired for each sub-packet in the bundle. bundle: the OSC bundle received;
timeTag: the time tag specified by the sender;
infoan implementation-specific remote information object
osc Fires whenever any type of OSC packet is recieved by this Port. packet: the OSC message or bundle received
infoan implementation-specific remote information object
raw Fires whenever any data is recieved by this Port. data: an Uint8Array containing the raw data received
infoan implementation-specific remote information object
error Fires whenever an error occurs. error: the Error object that was raised

In-depth example osc.js applications for the browser, Node.js, and Chrome OS are available in the osc.js examples repository.

The osc.WebSocketPort object supports sending and receiving OSC messages over Web Sockets.

Property Description Default Value
url The Web Socket URL to connect to (required for clients) none
socket A Web Socket instance to bind to (optional); if supplied, it is your job to configure and open it appropriately none

More code examples showing how osc.js can be used in browser-based, Node.js, and Chrome App applications can be found in the osc.js examples repository.

<!DOCTYPE html>
<html>
    <head>
        <title>osc.js Web Sockets</title>
        <meta charset="UTF-8" />
        <script src="bower_components/osc.js/dist/osc-browser.min.js"></script> 
    </head>
    <body></body>
</html>
var oscPort = new osc.WebSocketPort({
    url: "ws://localhost:8081" // URL to your Web Socket server. 
});
oscPort.open();
oscPort.on("message", function (oscMsg) {
    console.log("An OSC message just arrived!", oscMsg);
});
// For most Ports, send() should only be called after the "open" event fires. 
oscPort.send({
    address: "/carrier/frequency",
    args: 440
});
oscPort.send({
    timeTag: osc.timeTag(60), // Schedules this bundle 60 seconds from now. 
    packets: [
        {
            address: "/carrier/frequency",
            args: 440
        },
        {
            address: "/carrier/amplitude"
            args: 0.5
        }
    ]
});
// Define your module paths, including osc.js' dependencies. 
// Note: these paths must resolve to wherever you have placed 
// osc.js, slip.js, and eventEmitter in your project. 
require.config({
    paths: {
        slip: "../bower_components/slip.js/dist/slip.min",
        EventEmitter: "../bower_components/eventEmitter/EventEmitter.min",
        long: "../bower_components/long/dist/Long.min",
        osc: "../bower_components/osc.js/osc-module.min"
    }
});
 
// Load it asynchronously. 
require(["osc"], function (osc) {
    // Do something with osc.js when it has fully loaded. 
});

The osc.WebSocketPort object supports sending and receiving OSC messages over Web Sockets.

Property Description Default Value
url The Web Socket URL to connect to (required for clients) none
socket A Web Socket instance to bind to (required for servers, optional for clients); if supplied, it is your job to configure and open it appropriately none
var osc = require("osc"),
    http = require("http"),
    WebSocket = require("ws");
 
// Create an Express server app 
// and serve up a directory of static files. 
var app = require("express").express(),
    server = app.listen(8081);
 
app.use("/", express.static(__dirname + "/static"));
 
// Listen for Web Socket requests. 
var wss = new WebSocket.Server({
    server: server
});
 
// Listen for Web Socket connections. 
wss.on("connection", function (socket) {
    var socketPort = new osc.WebSocketPort({
        socket: socket
    });
 
    socketPort.on("message", function (oscMsg) {
        console.log("An OSC Message was received!", oscMsg);
    });
});

The osc.UDPPort object supports the sending and receiving of OSC messages over Node.js's UDP sockets. It also supports broadcast and multicast UDP.

Property Description Default Value
localPort The port to listen on 57121
localAddress The local address to bind to "127.0.0.1"
remotePort The remote port to send messages to (optional) none
remoteAddress The remote address to send messages to (optional) none
broadcast A flag specifying if messages should be sent via UDP broadcast false
multicastTTL The time to live (number of hops) for a multicast connection (optional) none
multicastMembership An array of multicast addresses to join when listening for multicast messages (optional) none
socket A raw dgram.Socket to use instead of osc.js creating one for you; if supplied, it is your job to configure and bind it appropriately none
// Create an osc.js UDP Port listening on port 57121. 
var udpPort = new osc.UDPPort({
    localAddress: "0.0.0.0",
    localPort: 57121
});
 
// Listen for incoming OSC bundles. 
udpPort.on("bundle", function (oscBundle, timeTag, info) {
    console.log("An OSC bundle just arrived for time tag", timeTag, ":" oscBundle);
    console.log("Remote info is: ", info);
});
 
// Open the socket. 
udpPort.open();
 
// Send an OSC message to, say, SuperCollider 
udpPort.send({
    address: "/s_new",
    args: ["default", 100]
}, "127.0.0.1", 57110);
<script src="../bower_components/osc.js/dist/osc-chromeapp.min.js"></script>
{
    "name": "OSC.js Chrome App Demo",
    "version": "1",
    "manifest_version": 2,
    "permissions": [
        "serial"
    ],
    "app": {
        "background": {
            "scripts": ["js/launch.js"],
            "transient": true
        }
    }
}
// Instantiate a new OSC Serial Port. 
var serialPort = new osc.SerialPort({
    devicePath: "/dev/cu.usbmodem22131"
});
 
// Listen for the message event and map the OSC message to the synth. 
serialPort.on("message", function (oscMsg) {
    console.log("An OSC message was received!", oscMsg);
});
 
// Open the port. 
serialPort.open();

The osc.UDPPort object supports the sending and receiving of OSC messages over a chrome.sockets.udp socket. It also supports broadcast and multicast UDP.

Property Description Default Value
localPort The port to listen on 57121
localAddress The local address to bind to "127.0.0.1"
remotePort The remote port to send messages to (optional) none
remoteAddress The remote address to send messages to (optional) none
broadcast A flag specifying if messages should be sent via UDP broadcast false
multicastTTL The time to live (number of hops) for a multicast connection (optional) none
multicastMembership An array of multicast addresses to join when listening for multicast messages (optional) none
socketId The id of an existing socket to use instead of osc.js creating one for you; if supplied, it is your job to configure and bind it appropriately none

All osc.js Transport objects emit "error" messages whenever an error occurs, such as when a malformed message is received. You should always listen for errors and handle them in an appropriate manner for your application.

var port = osc.UDPPort();
port.on("error", function (error) {
    console.log("An error occurred: ", error.message);
});

The low-level osc.js API, described below, will throw JavaScript Error objects whenever an error occurs; they should be caught and handled using try/catch.

var msg;
 
try {
    msg = osc.readPacket(rawPacket);
} catch (error) {
    console.log("An error occurred: ", error.message);
}

osc.js represents bundles and messages as (mostly) JSON-compatible objects. Here's how they are structured:

OSC Message objects consist of two properties, address, which contains the URL-style address path and args which is an array of either raw argument values or type-annotated Argument objects (depending on the value of the metadata option used when reading the message).

{
    address: "/an/osc/address",
    args: [
        {} // Raw or type-annotated OSC arguments 
    ]
}

OSC bundle objects consist of a time tag and an array of packets. Packets can be a mix of OSC bundle objects and message objects.

{
    timeTag: {
        // OSC Time Tag object 
    },
    packets: [
        {} // Nested OSC bundle and message objects> 
    ]
}

Type-annotated argument objects contain two properties: type, which contains the OSC type tag character (e.g. "i", "f", "t", etc.) and the raw value.

{
    type: "f", // OSC type tag string 
    value: 444.4
}

If you are using type-annotated arguments, you should also set the metadata option to true when you instantiate your OSCPort instance (or in the options argument to osc.writeMessage if you're using the low-level API).

Time tag objects contain two different representations: the raw NTP time and the equivalent (though less precise) native JavaScript timestamp. NTP times consist of a pair of values in an array. The first value represents the number of seconds since January 1, 1900. The second value is a Uint32 value (i.e. between 0 and 4294967296) that represents fractions of a second.

JavaScript timestamps are represented as milliseconds since January 1, 1970, which is the same unit as is returned by calls to Date.now().

{
    raw: [
        3608146800, // seconds since January 1, 1900. 
        2147483648  // fractions of a second 
    ],
    native: Number // Milliseconds since January 1, 1970 
}

Colours are automatically normalized to CSS 3 rgba values (i.e. the alpha channel is represented as a float from 0.0 to 1.0).

{
    r: 255,
    g: 255,
    b: 255,
    a: 1.0
}

There are two primary functions in osc.js used to read and write OSC data:

Function Description Arguments Return value
osc.readPacket() Decodes binary OSC message into a tree of JavaScript objects containing the messages or bundles that were read. data: A Uint8Array containing the raw data of the OSC packet;
options: (optional) An options object, described below;
offsetState: (optional) an offset state object containing an idx property that specifies the offset index into data;
length the length (in bytes) to read from data
An osc.js message or bundle object
osc.writePacket() Writes an OSC message or bundle object to a binary array. packate: An osc.js message or bundle object;
options: (optional) An options object, described below
A Uint8Array

Many osc.js functions take an options object that can be used to customize its behaviour. These options are also supported by all osc.Port objects, and can be included as a parameter in the options arguments passed to any Port constructor. The supported fields in an options object are:

  • metadata: specifies if the OSC type metadata should be included. By default, type metadata isn't included when reading packets, and is inferred automatically when writing packets. If you need greater precision in regards to the arguments in an OSC message, set the metadata argument to true. Defaults to false.
  • unpackSingleArgs: specifies if osc.js should automatically unpack single-argument messages so that their args property isn't wrapped in an array. Defaults to true.

Here are a few examples showing how OSC packets are mapped to plain JavaScript objects by osc.js.

Message Objects
"/carrier/freq" ",f" 440.4
{
  address: "/carrier/freq",
  args: [440.4]
}
"/float/andArray" ",f[ff]" 440.4 42 47
{
  address: "/carrier/freq",
  args: [
    440.4, [42.0, 47.0]
  ]
}
"/aTimeTag" ",t" 3608146800 2147483648
{
  address: "/scheduleAt",
  args: [
    {
      raw: [3608146800, 2147483648],
      jsTime: 1399158000500
    }
  ]
}
"/blob" ",b" 0x63 0x61 0x74 0x21

{
  address: "/blob",
  args: [
    Uint8Aray([0x63, 0x61, 0x74, 0x21])
  ]
}
    
"/colour" ",r" "255 255 255 255"
{
  address: "/colour",
  args: [{
      r: 255,
      g: 255,
      b: 255,
      a: 1.0
    }
  ]
}
"/midiMessage" ",m" 0x00 0x90 0x45 0x65
{
  address: "/midiMessage",
  args: [
    // Port ID, Status, Data 1, Data 2
    Uint8Array([0, 144, 69, 101])
  ]
}

osc.js is maintained by Colin Clark and distributed under the MIT and GPL 3 licenses.

osc.js releases are tested in Chrome, Firefox, Safari, and Microsoft Edge on Mac OS X and Windows, and in Node.js 4.2.0 (LTS) and 0.10.40 on Mac OS X and Linux.

Contributions and pull requests to osc.js are hugely appreciated. Wherever possible, all fixes and new features should be accompanied by unit tests to help verify that they work and avoid regressions. When new features are introduced, a pull request to the osc.js-examples repository with an example of how to use it is also appreciated.

Code should follow the style conventions of the project (such as they are), which can be automatically validated using JSHint by running grunt jshint.

Currently, the project is maintained by one person; sometimes it will take a bit of time to respond, review, and merge contributions. Help with bug triage, code reviews, testing, and examples is also welcome.

osc.js depends on npm and Grunt. Make sure you have these installed, and then run the following commands to fetch all necessary dependencies:

npm install
npm run dedupe-infusion

To lint and generate builds from new source code:

grunt

Running the unit tests:

  1. To run the Node.js unit tests, run npm run clean-test
  2. In the browser, open tests/all-tests.html
  3. To run the tests in a Vagrant VM under Node.js 0.10.40, run vagrant up
  • @colinbdclark wrote osc.js.
  • @jacoscaz and @xseignard fixed bugs.
  • @drart made and helped test some examples.
  • @egasimus added support for 64-bit integers.
  • @heisters contributed fixes for broadcast and multicast UDP on Node.js and improved time tag support.
  • @tambien fixed error handling bugs in the transports layer.
  • @janslow added support for passing remote information to all Port data events.