Port = function (options) { this.options = options || {}; this.on("data", this.decodeOSC.bind(this)); }
n/a
Relay = function (port1, port2, options) { var o = this.options = options || {}; o.raw = false; this.port1 = port1; this.port2 = port2; this.listen(); }
n/a
SLIPPort = function (options) { var that = this; var o = this.options = options || {}; o.useSLIP = o.useSLIP === undefined ? true : o.useSLIP; this.decoder = new slip.Decoder({ onMessage: this.decodeOSC.bind(this), onError: function (err) { that.emit("error", err); } }); var decodeHandler = o.useSLIP ? this.decodeSLIPData : this.decodeOSC; this.on("data", decodeHandler.bind(this)); }
n/a
SerialPort = function (options) { this.on("open", this.listen.bind(this)); osc.SLIPPort.call(this, options); this.options.bitrate = this.options.bitrate || 9600; this.serialPort = options.serialPort; if (this.serialPort) { this.emit("open", this.serialPort); } }
...
}
}
```
#### Connecting to the serial port and listening for OSC messages
```javascript
// 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);
});
...
TCPSocketPort = function (options) { osc.SLIPPort.call(this, options); var o = this.options; o.localAddress = o.localAddress || "127.0.0.1"; o.localPort = o.localPort !== undefined ? o.localPort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
n/a
UDPPort = function (options) { osc.Port.call(this, options); this.options.localAddress = this.options.localAddress || "127.0.0.1"; this.options.localPort = this.options.localPort !== undefined ? this.options.localPort : 57121; this.options.remoteAddress = this.options.remoteAddress || "127.0.0.1"; this.options.remotePort = this.options.remotePort !== undefined ? this.options.remotePort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
...
</tr>
</table>
#### Sample Code
```javascript
// 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);
...
function WebSocket(address, protocols, options) { if (this instanceof WebSocket === false) { return new WebSocket(address, protocols, options); } EventEmitter.call(this); if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) { // accept the "options" Object as the 2nd argument options = protocols; protocols = null; } if ('string' === typeof protocols) { protocols = [ protocols ]; } if (!Array.isArray(protocols)) { protocols = []; } this._socket = null; this._ultron = null; this._closeReceived = false; this.bytesReceived = 0; this.readyState = null; this.supports = {}; this.extensions = {}; this._binaryType = 'nodebuffer'; if (Array.isArray(address)) { initAsServerClient.apply(this, address.concat(options)); } else { initAsClient.apply(this, [address, protocols, options]); } }
...
};
var p = osc.WebSocketPort.prototype = Object.create(osc.Port.prototype);
p.constructor = osc.WebSocketPort;
p.open = function () {
if (!this.socket || this.socket.readyState > 1) {
this.socket = new osc.WebSocket(this.options.url);
}
osc.WebSocketPort.setupSocketForBinary(this.socket);
var that = this;
this.socket.onopen = function () {
that.emit("open", that.socket);
...
function Receiver(extensions, maxPayload) { if (this instanceof Receiver === false) { throw new TypeError("Classes can't be function-called"); } if(typeof extensions==='number'){ maxPayload=extensions; extensions={}; } // memory pool for fragmented messages var fragmentedPoolPrevUsed = -1; this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? Math.ceil((fragmentedPoolPrevUsed + db.used) / 2) : db.used; }); // memory pool for unfragmented messages var unfragmentedPoolPrevUsed = -1; this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? Math.ceil((unfragmentedPoolPrevUsed + db.used) / 2) : db.used; }); this.extensions = extensions || {}; this.maxPayload = maxPayload || 0; this.currentPayloadLength = 0; this.state = { activeFragmentedOperation: null, lastFragment: false, masked: false, opcode: 0, fragmentedOperation: false }; this.overflow = []; this.headerBuffer = new Buffer(10); this.expectOffset = 0; this.expectBuffer = null; this.expectHandler = null; this.currentMessage = []; this.currentMessageLength = 0; this.messageHandlers = []; this.expectHeader(2, this.processPacket); this.dead = false; this.processing = false; this.onerror = function() {}; this.ontext = function() {}; this.onbinary = function() {}; this.onclose = function() {}; this.onping = function() {}; this.onpong = function() {}; }
n/a
function Sender(socket, extensions) { if (this instanceof Sender === false) { throw new TypeError("Classes can't be function-called"); } events.EventEmitter.call(this); this._socket = socket; this.extensions = extensions || {}; this.firstFragment = true; this.compress = false; this.messageHandlers = []; this.processing = false; }
n/a
function WebSocketServer(options, callback) { if (this instanceof WebSocketServer === false) { return new WebSocketServer(options, callback); } events.EventEmitter.call(this); options = new Options({ host: '0.0.0.0', port: null, server: null, verifyClient: null, handleProtocols: null, path: null, noServer: false, disableHixie: false, clientTracking: true, perMessageDeflate: true, maxPayload: 100 * 1024 * 1024 }).merge(options); if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { throw new TypeError('`port` or a `server` must be provided'); } var self = this; if (options.isDefinedAndNonNull('port')) { this._server = http.createServer(function (req, res) { var body = http.STATUS_CODES[426]; res.writeHead(426, { 'Content-Length': body.length, 'Content-Type': 'text/plain' }); res.end(body); }); this._server.allowHalfOpen = false; this._server.listen(options.value.port, options.value.host, callback); this._closeServer = function() { if (self._server) self._server.close(); }; } else if (options.value.server) { this._server = options.value.server; if (options.value.path) { // take note of the path, to avoid collisions when multiple websocket servers are // listening on the same http server if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); } if (typeof this._server._webSocketPaths !== 'object') { this._server._webSocketPaths = {}; } this._server._webSocketPaths[options.value.path] = 1; } } if (this._server) { this._onceServerListening = function() { self.emit('listening'); }; this._server.once('listening', this._onceServerListening); } if (typeof this._server != 'undefined') { this._onServerError = function(error) { self.emit('error', error) }; this._server.on('error', this._onServerError); this._onServerUpgrade = function(req, socket, upgradeHead) { //copy upgradeHead to avoid retention of large slab buffers used in node core var head = new Buffer(upgradeHead.length); upgradeHead.copy(head); self.handleUpgrade(req, socket, head, function(client) { self.emit('connection'+req.url, client); self.emit('connection', client); }); }; this._server.on('upgrade', this._onServerUpgrade); } this.options = options.value; this.path = options.value.path; this.clients = []; }
n/a
WebSocketPort = function (options) { osc.Port.call(this, options); this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { if (this.socket.readyState === 1) { osc.WebSocketPort.setupSocketForBinary(this.socket); this.emit("open", this.socket); } else { this.open(); } } }
...
</head>
<body></body>
</html>
```
##### Creating an OSC Web Socket Port object:
```javascript
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
...
addDataPart = function (dataPart, dataCollection) { dataCollection.parts.push(dataPart); dataCollection.byteLength += dataPart.length; }
...
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
var data = osc[writer](arg.value);
osc.addDataPart(data, dataCollection);
}
return arg.type;
};
// Unsupported, non-API function.
osc.collectArguments = function (args, options, dataCollection) {
...
annotateArguments = function (args) { var annotated = []; for (var i = 0; i < args.length; i++) { var arg = args[i], msgArg; if (typeof (arg) === "object" && arg.type && arg.value !== undefined) { // We've got an explicitly typed argument. msgArg = arg; } else if (osc.isArray(arg)) { // We've got an array of arguments, // so they each need to be inferred and expanded. msgArg = osc.annotateArguments(arg); } else { var oscType = osc.inferTypeForArgument(arg); msgArg = { type: oscType, value: arg }; } annotated.push(msgArg); } return annotated; }
...
dataCollection = dataCollection || {
byteLength: 0,
parts: []
};
if (!options.metadata) {
args = osc.annotateArguments(args);
}
var typeTagString = ",",
currPartIdx = dataCollection.parts.length;
for (var i = 0; i < args.length; i++) {
var arg = args[i];
...
byteArray = function (obj) { if (obj instanceof Uint8Array) { return obj; } var buf = obj.buffer ? obj.buffer : obj; if (!(buf instanceof ArrayBuffer) && (typeof buf.length === "undefined" || typeof buf === "string")) { throw new Error("Can't wrap a non-array-like object as Uint8Array. Object was: " + JSON.stringify(obj, null, 2)); } // TODO gh-39: This is a potentially unsafe algorithm; // if we're getting anything other than a TypedArrayView (such as a DataView), // we really need to determine the range of the view it is viewing. return new Uint8Array(buf); }
...
/**
* Writes a raw collection of bytes to a new ArrayBuffer.
*
* @param {Array-like} data a collection of octets
* @return {ArrayBuffer} a buffer containing the OSC-formatted blob
*/
osc.writeBlob = function (data) {
data = osc.byteArray(data);
var len = data.byteLength,
paddedLen = (len + 3) & ~0x03,
offset = 4, // Extra 4 bytes is for the size.
blobLen = paddedLen + offset,
arr = new Uint8Array(blobLen),
dv = new DataView(arr.buffer);
...
collectArguments = function (args, options, dataCollection) { if (!osc.isArray(args)) { args = typeof args === "undefined" ? [] : [args]; } dataCollection = dataCollection || { byteLength: 0, parts: [] }; if (!options.metadata) { args = osc.annotateArguments(args); } var typeTagString = ",", currPartIdx = dataCollection.parts.length; for (var i = 0; i < args.length; i++) { var arg = args[i]; typeTagString += osc.writeArgument(arg, dataCollection); } var typeData = osc.writeString(typeTagString); dataCollection.byteLength += typeData.byteLength; dataCollection.parts.splice(currPartIdx, 0, typeData); return dataCollection; }
...
* Writes the specified arguments.
*
* @param {Array} args an array of arguments
* @param {Object} options options for writing
* @return {Uint8Array} a buffer containing the OSC-formatted argument type tag and values
*/
osc.writeArguments = function (args, options) {
var argCollection = osc.collectArguments(args, options);
return osc.joinParts(argCollection);
};
// Unsupported, non-API function.
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
...
collectBundlePackets = function (bundle, options, dataCollection) { dataCollection = dataCollection || { byteLength: 0, parts: [] }; osc.addDataPart(osc.writeString("#bundle"), dataCollection); osc.addDataPart(osc.writeTimeTag(bundle.timeTag), dataCollection); for (var i = 0; i < bundle.packets.length; i++) { var packet = bundle.packets[i], collector = packet.address ? osc.collectMessageParts : osc.collectBundlePackets, packetCollection = collector(packet, options); dataCollection.byteLength += packetCollection.byteLength; osc.addDataPart(osc.writeInt32(packetCollection.byteLength), dataCollection); dataCollection.parts = dataCollection.parts.concat(packetCollection.parts); } return dataCollection; }
...
osc.writeBundle = function (bundle, options) {
if (!osc.isValidBundle(bundle)) {
throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " +
"Bundle was: " + JSON.stringify(bundle, null, 2));
}
options = options || osc.defaults;
var bundleCollection = osc.collectBundlePackets(bundle, options);
return osc.joinParts(bundleCollection);
};
osc.isValidBundle = function (bundle) {
return bundle.timeTag !== undefined && bundle.packets !== undefined;
};
...
collectMessageParts = function (msg, options, dataCollection) { dataCollection = dataCollection || { byteLength: 0, parts: [] }; osc.addDataPart(osc.writeString(msg.address), dataCollection); return osc.collectArguments(msg.args, options, dataCollection); }
...
options = options || osc.defaults;
if (!osc.isValidMessage(msg)) {
throw new Error("An OSC message must contain a valid address. Message was: " +
JSON.stringify(msg, null, 2));
}
var msgCollection = osc.collectMessageParts(msg, options);
return osc.joinParts(msgCollection);
};
osc.isValidMessage = function (msg) {
return msg.address && msg.address.indexOf("/") === 0;
};
...
copyByteArray = function (source, target, offset) { if (osc.isTypedArrayView(source) && osc.isTypedArrayView(target)) { target.set(source, offset); } else { var start = offset === undefined ? 0 : offset, len = Math.min(target.length - offset, source.length); for (var i = 0, j = start; i < len; i++, j++) { target[j] = source[i]; } } return target; }
...
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
offset = 0;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
osc.copyByteArray(part, buf, offset);
offset += part.length;
}
return buf;
};
// Unsupported, non-API function.
...
dataView = function (obj, offset, length) { if (obj.buffer) { return new DataView(obj.buffer, offset, length); } if (obj instanceof ArrayBuffer) { return new DataView(obj, offset, length); } return new DataView(new Uint8Array(obj), offset, length); }
...
* @param {Object} [options] read options
* @param {Object} [offsetState] an offsetState object that stores the current offset into dv
* @return {Object} the OSC message, formatted as a JavaScript object containing "address" and "args" properties
*/
osc.readMessage = function (data, options, offsetState) {
options = options || osc.defaults;
var dv = osc.dataView(data, data.byteOffset, data.byteLength);
offsetState = offsetState || {
idx: 0
};
var address = osc.readString(dv, offsetState);
return osc.readMessageContents(address, dv, options, offsetState);
};
...
fireBundleEvents = function (port, bundle, timeTag, packetInfo) { port.emit("bundle", bundle, timeTag, packetInfo); for (var i = 0; i < bundle.packets.length; i++) { var packet = bundle.packets[i]; osc.firePacketEvents(port, packet, bundle.timeTag, packetInfo); } }
...
"use strict";
// Unsupported, non-API function.
osc.firePacketEvents = function (port, packet, timeTag, packetInfo) {
if (packet.address) {
port.emit("message", packet, timeTag, packetInfo);
} else {
osc.fireBundleEvents(port, packet, timeTag, packetInfo);
}
};
// Unsupported, non-API function.
osc.fireBundleEvents = function (port, bundle, timeTag, packetInfo) {
port.emit("bundle", bundle, timeTag, packetInfo);
for (var i = 0; i < bundle.packets.length; i++) {
...
fireClosedPortSendError = function (port, msg) { msg = msg || "Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open()."; port.emit("error", msg); }
...
p.listen = function () {
osc.listenToTransport(this, chrome.serial, "connectionId");
};
p.sendRaw = function (encoded) {
if (!this.connectionId) {
osc.fireClosedPortSendError(this);
return;
}
var that = this;
// TODO gh-39: This is unsafe; we should only access the underlying
// buffer within the range of its view.
...
firePacketEvents = function (port, packet, timeTag, packetInfo) { if (packet.address) { port.emit("message", packet, timeTag, packetInfo); } else { osc.fireBundleEvents(port, packet, timeTag, packetInfo); } }
...
};
// Unsupported, non-API function.
osc.fireBundleEvents = function (port, bundle, timeTag, packetInfo) {
port.emit("bundle", bundle, timeTag, packetInfo);
for (var i = 0; i < bundle.packets.length; i++) {
var packet = bundle.packets[i];
osc.firePacketEvents(port, packet, bundle.timeTag, packetInfo);
}
};
osc.fireClosedPortSendError = function (port, msg) {
msg = msg || "Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open()."
;;
port.emit("error", msg);
...
inferTypeForArgument = function (arg) { var type = typeof arg; // TODO: This is freaking hideous. switch (type) { case "boolean": return arg ? "T" : "F"; case "string": return "s"; case "number": return "f"; case "undefined": return "N"; case "object": if (arg === null) { return "N"; } else if (arg instanceof Uint8Array || arg instanceof ArrayBuffer) { return "b"; } else if (typeof arg.high === "number" && typeof arg.low === "number") { return "h"; } break; } throw new Error("Can't infer OSC argument type for value: " + JSON.stringify(arg, null, 2)); }
...
// We've got an explicitly typed argument.
msgArg = arg;
} else if (osc.isArray(arg)) {
// We've got an array of arguments,
// so they each need to be inferred and expanded.
msgArg = osc.annotateArguments(arg);
} else {
var oscType = osc.inferTypeForArgument(arg);
msgArg = {
type: oscType,
value: arg
};
}
annotated.push(msgArg);
...
isArray = function (obj) { return obj && Object.prototype.toString.call(obj) === "[object Array]"; }
...
typeTag += "]";
return typeTag;
};
osc.writeArgument = function (arg, dataCollection) {
if (osc.isArray(arg)) {
return osc.writeArrayArguments(arg, dataCollection);
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
...
isBuffer = function (obj) { return osc.isBufferEnv && obj instanceof Buffer; }
...
*
* @param {Array-like or Array-wrapping} obj an array-like or array-wrapping object
* @returns {Buffer|Uint8Array} a buffer object
*/
// Unsupported, non-API function.
osc.nativeBuffer = function (obj) {
if (osc.isBufferEnv) {
return osc.isBuffer(obj) ? obj :
new Buffer(obj.buffer ? obj : new Uint8Array(obj));
}
return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj);
};
// Unsupported, non-API function
...
isTypedArrayView = function (obj) { return obj.buffer && obj.buffer instanceof ArrayBuffer; }
...
// Unsupported, non-API function.
osc.nativeBuffer = function (obj) {
if (osc.isBufferEnv) {
return osc.isBuffer(obj) ? obj :
new Buffer(obj.buffer ? obj : new Uint8Array(obj));
}
return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj);
};
// Unsupported, non-API function
osc.copyByteArray = function (source, target, offset) {
if (osc.isTypedArrayView(source) && osc.isTypedArrayView(target)) {
target.set(source, offset);
} else {
...
isValidBundle = function (bundle) { return bundle.timeTag !== undefined && bundle.packets !== undefined; }
...
* Writes an OSC bundle.
*
* @param {Object} a bundle object containing "timeTag" and "packets" properties
* @param {object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writeBundle = function (bundle, options) {
if (!osc.isValidBundle(bundle)) {
throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " +
"Bundle was: " + JSON.stringify(bundle, null, 2));
}
options = options || osc.defaults;
var bundleCollection = osc.collectBundlePackets(bundle, options);
...
isValidMessage = function (msg) { return msg.address && msg.address.indexOf("/") === 0; }
...
* @param {Object} msg a message object containing "address" and "args" properties
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the OSC message
*/
osc.writeMessage = function (msg, options) {
options = options || osc.defaults;
if (!osc.isValidMessage(msg)) {
throw new Error("An OSC message must contain a valid address. Message was: " +
JSON.stringify(msg, null, 2));
}
var msgCollection = osc.collectMessageParts(msg, options);
return osc.joinParts(msgCollection);
};
...
joinParts = function (dataCollection) { var buf = new Uint8Array(dataCollection.byteLength), parts = dataCollection.parts, offset = 0; for (var i = 0; i < parts.length; i++) { var part = parts[i]; osc.copyByteArray(part, buf, offset); offset += part.length; } return buf; }
...
*
* @param {Array} args an array of arguments
* @param {Object} options options for writing
* @return {Uint8Array} a buffer containing the OSC-formatted argument type tag and values
*/
osc.writeArguments = function (args, options) {
var argCollection = osc.collectArguments(args, options);
return osc.joinParts(argCollection);
};
// Unsupported, non-API function.
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
offset = 0;
...
jsToNTPTime = function (jsTime) { var secs = jsTime / 1000, secsWhole = Math.floor(secs), secsFrac = secs - secsWhole, ntpSecs = secsWhole + osc.SECS_70YRS, ntpFracs = Math.round(osc.TWO_32 * secsFrac); return [ntpSecs, ntpFracs]; }
...
* values. The first represents the number of seconds since January 1, 1900; the second, fractions of a second.
* "Native" JavaScript timestamps are specified as a Number representing milliseconds since January 1, 1970.
*
* @param {Object} timeTag time tag object containing either a native JS timestamp (in ms) or a NTP timestamp pair
* @return {Uint8Array} raw bytes for the written time tag
*/
osc.writeTimeTag = function (timeTag) {
var raw = timeTag.raw ? timeTag.raw : osc.jsToNTPTime(timeTag.native),
arr = new Uint8Array(8), // Two Unit32s.
dv = new DataView(arr.buffer);
osc.writeInt32(raw[0], dv, 0);
osc.writeInt32(raw[1], dv, 4);
return arr;
...
nativeBuffer = function (obj) { if (osc.isBufferEnv) { return osc.isBuffer(obj) ? obj : new Buffer(obj.buffer ? obj : new Uint8Array(obj)); } return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj); }
...
var p = osc.Port.prototype = Object.create(EventEmitter.prototype);
p.constructor = osc.Port;
p.send = function (oscPacket) {
var args = Array.prototype.slice.call(arguments),
encoded = this.encodeOSC(oscPacket),
buf = osc.nativeBuffer(encoded);
args[0] = buf;
this.sendRaw.apply(this, args);
};
p.encodeOSC = function (packet) {
// TODO gh-39: This is unsafe; we should only access the underlying
...
ntpToJSTime = function (secs1900, frac) { var secs1970 = secs1900 - osc.SECS_70YRS, decimals = frac / osc.TWO_32, msTime = (secs1970 + decimals) * 1000; return msTime; }
...
* @param {DataView} dv the DataView instance to read from
* @param {Object} offsetState an offset state object containing the current index into dv
* @param {Object} a time tag object containing both the raw NTP as well as the converted native (i.e. JS/UNIX) time
*/
osc.readTimeTag = function (dv, offsetState) {
var secs1900 = osc.readPrimitive(dv, "getUint32", 4, offsetState),
frac = osc.readPrimitive(dv, "getUint32", 4, offsetState),
native = (secs1900 === 0 && frac === 1) ? Date.now() : osc.ntpToJSTime(secs1900, frac);
return {
raw: [secs1900, frac],
native: native
};
};
...
readArgument = function (argType, typeTagString, dv, options, offsetState) { var typeSpec = osc.argumentTypes[argType]; if (!typeSpec) { throw new Error("'" + argType + "' is not a valid OSC type tag. Type tag string was: " + typeTagString); } var argReader = typeSpec.reader, arg = osc[argReader](dv, offsetState); if (options.metadata) { arg = { type: argType, value: arg }; } return arg; }
...
"without a matching close array tag ('[]'). Type tag was: " + typeTagString);
}
var typesInArray = fromArrayOpen.slice(0, endArrayIdx);
arg = osc.readArgumentsIntoArray([], typesInArray, typeTagString, dv, options, offsetState);
i += endArrayIdx + 2;
} else {
arg = osc.readArgument(argType, typeTagString, dv, options, offsetState);
i++;
}
arr.push(arg);
}
return arr;
...
readArguments = function (dv, options, offsetState) { var typeTagString = osc.readString(dv, offsetState); if (typeTagString.indexOf(",") !== 0) { // Despite what the OSC 1.0 spec says, // it just doesn't make sense to handle messages without type tags. // scsynth appears to read such messages as if they have a single // Uint8 argument. sclang throws an error if the type tag is omitted. throw new Error("A malformed type tag string was found while reading " + "the arguments of an OSC message. String was: " + typeTagString, " at offset: " + offsetState.idx); } var argTypes = typeTagString.substring(1).split(""), args = []; osc.readArgumentsIntoArray(args, argTypes, typeTagString, dv, options, offsetState); return args; }
...
// Unsupported, non-API function.
osc.readMessageContents = function (address, dv, options, offsetState) {
if (address.indexOf("/") !== 0) {
throw new Error("A malformed OSC address was found while reading " +
"an OSC message. String was: " + address);
}
var args = osc.readArguments(dv, options, offsetState);
return {
address: address,
args: args.length === 1 && options.unpackSingleArgs ? args[0] : args
};
};
...
readArgumentsIntoArray = function (arr, argTypes, typeTagString, dv, options, offsetState) { var i = 0; while (i < argTypes.length) { var argType = argTypes[i], arg; if (argType === "[") { var fromArrayOpen = argTypes.slice(i + 1), endArrayIdx = fromArrayOpen.indexOf("]"); if (endArrayIdx < 0) { throw new Error("Invalid argument type tag: an open array type tag ('[') was found " + "without a matching close array tag ('[]'). Type tag was: " + typeTagString); } var typesInArray = fromArrayOpen.slice(0, endArrayIdx); arg = osc.readArgumentsIntoArray([], typesInArray, typeTagString, dv, options, offsetState); i += endArrayIdx + 2; } else { arg = osc.readArgument(argType, typeTagString, dv, options, offsetState); i++; } arr.push(arg); } return arr; }
...
"the arguments of an OSC message. String was: " +
typeTagString, " at offset: " + offsetState.idx);
}
var argTypes = typeTagString.substring(1).split(""),
args = [];
osc.readArgumentsIntoArray(args, argTypes, typeTagString, dv, options, offsetState
);
return args;
};
// Unsupported, non-API function.
osc.readArgument = function (argType, typeTagString, dv, options, offsetState) {
var typeSpec = osc.argumentTypes[argType];
...
readBlob = function (dv, offsetState) { var len = osc.readInt32(dv, offsetState), paddedLen = (len + 3) & ~0x03, blob = new Uint8Array(dv.buffer, offsetState.idx, len); offsetState.idx += paddedLen; return blob; }
n/a
readBundle = function (dv, options, offsetState) { return osc.readPacket(dv, options, offsetState); }
n/a
readBundleContents = function (dv, options, offsetState, len) { var timeTag = osc.readTimeTag(dv, offsetState), packets = []; while (offsetState.idx < len) { var packetSize = osc.readInt32(dv, offsetState), packetLen = offsetState.idx + packetSize, packet = osc.readPacket(dv, options, offsetState, packetLen); packets.push(packet); } return { timeTag: timeTag, packets: packets }; }
...
idx: 0
};
var header = osc.readString(dv, offsetState),
firstChar = header[0];
if (firstChar === "#") {
return osc.readBundleContents(dv, options, offsetState, len);
} else if (firstChar === "/") {
return osc.readMessageContents(header, dv, options, offsetState);
}
throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string." +
" Header was: " + header);
};
...
readChar32 = function (dv, offsetState) { var charCode = osc.readPrimitive(dv, "getUint32", 4, offsetState); return String.fromCharCode(charCode); }
n/a
readColor = function (dv, offsetState) { var bytes = new Uint8Array(dv.buffer, offsetState.idx, 4), alpha = bytes[3] / 255; offsetState.idx += 4; return { r: bytes[0], g: bytes[1], b: bytes[2], a: alpha }; }
n/a
readFalse = function () { return false; }
n/a
readFloat32 = function (dv, offsetState) { return osc.readPrimitive(dv, "getFloat32", 4, offsetState); }
n/a
readFloat64 = function (dv, offsetState) { return osc.readPrimitive(dv, "getFloat64", 8, offsetState); }
n/a
readImpulse = function () { return 1.0; }
n/a
readInt32 = function (dv, offsetState) { return osc.readPrimitive(dv, "getInt32", 4, offsetState); }
...
* Reads an OSC blob ("b") (i.e. a Uint8Array).
*
* @param {DataView} dv a DataView instance to read from
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
* @return {Uint8Array} the data that was read
*/
osc.readBlob = function (dv, offsetState) {
var len = osc.readInt32(dv, offsetState),
paddedLen = (len + 3) & ~0x03,
blob = new Uint8Array(dv.buffer, offsetState.idx, len);
offsetState.idx += paddedLen;
return blob;
};
...
readInt64 = function (dv, offsetState) { var high = osc.readPrimitive(dv, "getInt32", 4, offsetState), low = osc.readPrimitive(dv, "getInt32", 4, offsetState); if (Long) { return new Long(low, high); } else { return { high: high, low: low, unsigned: false }; } }
n/a
readMIDIBytes = function (dv, offsetState) { var midi = new Uint8Array(dv.buffer, offsetState.idx, 4); offsetState.idx += 4; return midi; }
n/a
readMessage = function (data, options, offsetState) { options = options || osc.defaults; var dv = osc.dataView(data, data.byteOffset, data.byteLength); offsetState = offsetState || { idx: 0 }; var address = osc.readString(dv, offsetState); return osc.readMessageContents(address, dv, options, offsetState); }
n/a
readMessageContents = function (address, dv, options, offsetState) { if (address.indexOf("/") !== 0) { throw new Error("A malformed OSC address was found while reading " + "an OSC message. String was: " + address); } var args = osc.readArguments(dv, options, offsetState); return { address: address, args: args.length === 1 && options.unpackSingleArgs ? args[0] : args }; }
...
var dv = osc.dataView(data, data.byteOffset, data.byteLength);
offsetState = offsetState || {
idx: 0
};
var address = osc.readString(dv, offsetState);
return osc.readMessageContents(address, dv, options, offsetState);
};
// Unsupported, non-API function.
osc.readMessageContents = function (address, dv, options, offsetState) {
if (address.indexOf("/") !== 0) {
throw new Error("A malformed OSC address was found while reading " +
"an OSC message. String was: " + address);
...
readNull = function () { return null; }
n/a
readPacket = function (data, options, offsetState, len) { var dv = osc.dataView(data, data.byteOffset, data.byteLength); len = len === undefined ? dv.byteLength : len; offsetState = offsetState || { idx: 0 }; var header = osc.readString(dv, offsetState), firstChar = header[0]; if (firstChar === "#") { return osc.readBundleContents(dv, options, offsetState, len); } else if (firstChar === "/") { return osc.readMessageContents(header, dv, options, offsetState); } throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string." + " Header was: " + header); }
...
they should be caught and handled using
<code>try</code>/<code>catch</code>.
```javascript
var msg;
try {
msg = osc.readPacket(rawPacket);
} catch (error) {
console.log("An error occurred: ", error.message);
}
```
The osc.js Low-Level API
------------------------
...
readPrimitive = function (dv, readerName, numBytes, offsetState) { var val = dv[readerName](offsetState.idx, false); offsetState.idx += numBytes; return val; }
...
* Reads an OSC int32 ("i") value.
*
* @param {DataView} dv a DataView containing the raw bytes
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
* @return {Number} the number that was read
*/
osc.readInt32 = function (dv, offsetState) {
return osc.readPrimitive(dv, "getInt32", 4, offsetState);
};
/**
* Writes an OSC int32 ("i") value.
*
* @param {Number} val the number to write
* @param {DataView} [dv] a DataView instance to write the number into
...
readString = function (dv, offsetState) { var charCodes = [], idx = offsetState.idx; for (; idx < dv.byteLength; idx++) { var charCode = dv.getUint8(idx); if (charCode !== 0) { charCodes.push(charCode); } else { idx++; break; } } // Round to the nearest 4-byte block. idx = (idx + 3) & ~0x03; offsetState.idx = idx; return String.fromCharCode.apply(null, charCodes); }
...
*
* @param {DataView} dv a DataView instance to read from
* @param {Object} offsetState the offsetState object that stores the current offset into dv
* @param {Oobject} [options] read options
* @return {Array} an array of the OSC arguments that were read
*/
osc.readArguments = function (dv, options, offsetState) {
var typeTagString = osc.readString(dv, offsetState);
if (typeTagString.indexOf(",") !== 0) {
// Despite what the OSC 1.0 spec says,
// it just doesn't make sense to handle messages without type tags.
// scsynth appears to read such messages as if they have a single
// Uint8 argument. sclang throws an error if the type tag is omitted.
throw new Error("A malformed type tag string was found while reading " +
"the arguments of an OSC message. String was: " +
...
readTimeTag = function (dv, offsetState) { var secs1900 = osc.readPrimitive(dv, "getUint32", 4, offsetState), frac = osc.readPrimitive(dv, "getUint32", 4, offsetState), native = (secs1900 === 0 && frac === 1) ? Date.now() : osc.ntpToJSTime(secs1900, frac); return { raw: [secs1900, frac], native: native }; }
...
osc.isValidBundle = function (bundle) {
return bundle.timeTag !== undefined && bundle.packets !== undefined;
};
// Unsupported, non-API function.
osc.readBundleContents = function (dv, options, offsetState, len) {
var timeTag = osc.readTimeTag(dv, offsetState),
packets = [];
while (offsetState.idx < len) {
var packetSize = osc.readInt32(dv, offsetState),
packetLen = offsetState.idx + packetSize,
packet = osc.readPacket(dv, options, offsetState, packetLen);
...
readTrue = function () { return true; }
n/a
relay = function (from, to, eventName, sendFnName, transformFn, sendArgs) { eventName = eventName || "message"; sendFnName = sendFnName || "send"; transformFn = transformFn || function () {}; sendArgs = sendArgs ? [null].concat(sendArgs) : []; var listener = function (data) { sendArgs[0] = data; data = transformFn(data); to[sendFnName].apply(to, sendArgs); }; from.on(eventName, listener); return { eventName: eventName, listener: listener }; }
...
};
// Unsupported, non-API function.
osc.relayPorts = function (from, to, o) {
var eventName = o.raw ? "raw" : "osc",
sendFnName = o.raw ? "sendRaw" : "send";
return osc.relay(from, to, eventName, sendFnName, o.transform);
};
// Unsupported, non-API function.
osc.stopRelaying = function (from, relaySpec) {
from.removeListener(relaySpec.eventName, relaySpec.listener);
};
...
relayPorts = function (from, to, o) { var eventName = o.raw ? "raw" : "osc", sendFnName = o.raw ? "sendRaw" : "send"; return osc.relay(from, to, eventName, sendFnName, o.transform); }
...
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
// Users are still responsible for closing the underlying ports
// if necessary.
var closeListener = this.close.bind(this);
...
stopRelaying = function (from, relaySpec) { from.removeListener(relaySpec.eventName, relaySpec.listener); }
...
// if necessary.
var closeListener = this.close.bind(this);
this.port1.on("close", closeListener);
this.port2.on("close", closeListener);
};
p.close = function () {
osc.stopRelaying(this.port1, this.port1Spec);
osc.stopRelaying(this.port2, this.port2Spec);
this.emit("close", this.port1, this.port2);
};
// If we're in a require-compatible environment, export ourselves.
if (typeof module !== "undefined" && module.exports) {
...
timeTag = function (secs, now) { secs = secs || 0; now = now || Date.now(); var nowSecs = now / 1000, nowWhole = Math.floor(nowSecs), nowFracs = nowSecs - nowWhole, secsWhole = Math.floor(secs), secsFracs = secs - secsWhole, fracs = nowFracs + secsFracs; if (fracs > 1) { var fracsWhole = Math.floor(fracs), fracsFracs = fracs - fracsWhole; secsWhole += fracsWhole; fracs = fracsFracs; } var ntpSecs = nowWhole + secsWhole + osc.SECS_70YRS, ntpFracs = Math.round(osc.TWO_32 * fracs); return { raw: [ntpSecs, ntpFracs] }; }
...
});
```
##### Sending OSC bundles:
```javascript
oscPort.on("ready", function () {
oscPort.send({
timeTag: osc.timeTag(60), // Schedules this bundle 60 seconds from now.
packets: [
{
address: "/carrier/frequency",
args: 440
},
{
address: "/carrier/amplitude"
...
writeArgument = function (arg, dataCollection) { if (osc.isArray(arg)) { return osc.writeArrayArguments(arg, dataCollection); } var type = arg.type, writer = osc.argumentTypes[type].writer; if (writer) { var data = osc[writer](arg.value); osc.addDataPart(data, dataCollection); } return arg.type; }
...
};
osc.writeArrayArguments = function (args, dataCollection) {
var typeTag = "[";
for (var i = 0; i < args.length; i++) {
var arg = args[i];
typeTag += osc.writeArgument(arg, dataCollection);
}
typeTag += "]";
return typeTag;
};
...
writeArguments = function (args, options) { var argCollection = osc.collectArguments(args, options); return osc.joinParts(argCollection); }
n/a
writeArrayArguments = function (args, dataCollection) { var typeTag = "["; for (var i = 0; i < args.length; i++) { var arg = args[i]; typeTag += osc.writeArgument(arg, dataCollection); } typeTag += "]"; return typeTag; }
...
typeTag += "]";
return typeTag;
};
osc.writeArgument = function (arg, dataCollection) {
if (osc.isArray(arg)) {
return osc.writeArrayArguments(arg, dataCollection);
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
var data = osc[writer](arg.value);
...
writeBlob = function (data) { data = osc.byteArray(data); var len = data.byteLength, paddedLen = (len + 3) & ~0x03, offset = 4, // Extra 4 bytes is for the size. blobLen = paddedLen + offset, arr = new Uint8Array(blobLen), dv = new DataView(arr.buffer); // Write the size. osc.writeInt32(len, dv); // Since we're writing to a real ArrayBuffer, // we don't need to pad the remaining bytes. arr.set(data, offset); return arr; }
n/a
writeBundle = function (bundle, options) { if (!osc.isValidBundle(bundle)) { throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " + "Bundle was: " + JSON.stringify(bundle, null, 2)); } options = options || osc.defaults; var bundleCollection = osc.collectBundlePackets(bundle, options); return osc.joinParts(bundleCollection); }
...
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writePacket = function (packet, options) {
if (osc.isValidMessage(packet)) {
return osc.writeMessage(packet, options);
} else if (osc.isValidBundle(packet)) {
return osc.writeBundle(packet, options);
} else {
throw new Error("The specified packet was not recognized as a valid OSC message or bundle." +
" Packet was: " + JSON.stringify(packet, null, 2));
}
};
// Unsupported, non-API.
...
writeChar32 = function (str, dv, offset) { var charCode = str.charCodeAt(0); if (charCode === undefined || charCode < -1) { return undefined; } return osc.writePrimitive(charCode, dv, "setUint32", 4, offset); }
n/a
writeColor = function (color) { var alpha = Math.round(color.a * 255), arr = new Uint8Array([color.r, color.g, color.b, alpha]); return arr; }
n/a
writeFloat32 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setFloat32", 4, offset); }
n/a
writeFloat64 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setFloat64", 8, offset); }
n/a
writeInt32 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setInt32", 4, offset); }
...
paddedLen = (len + 3) & ~0x03,
offset = 4, // Extra 4 bytes is for the size.
blobLen = paddedLen + offset,
arr = new Uint8Array(blobLen),
dv = new DataView(arr.buffer);
// Write the size.
osc.writeInt32(len, dv);
// Since we're writing to a real ArrayBuffer,
// we don't need to pad the remaining bytes.
arr.set(data, offset);
return arr;
};
...
writeInt64 = function (val, dv, offset) { var arr = new Uint8Array(8); arr.set(osc.writePrimitive(val.high, dv, "setInt32", 4, offset), 0); arr.set(osc.writePrimitive(val.low, dv, "setInt32", 4, offset + 4), 4); return arr; }
n/a
writeMIDIBytes = function (bytes) { bytes = osc.byteArray(bytes); var arr = new Uint8Array(4); arr.set(bytes); return arr; }
n/a
writeMessage = function (msg, options) { options = options || osc.defaults; if (!osc.isValidMessage(msg)) { throw new Error("An OSC message must contain a valid address. Message was: " + JSON.stringify(msg, null, 2)); } var msgCollection = osc.collectMessageParts(msg, options); return osc.joinParts(msgCollection); }
...
*
* @param {Object} a bundle or message object
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writePacket = function (packet, options) {
if (osc.isValidMessage(packet)) {
return osc.writeMessage(packet, options);
} else if (osc.isValidBundle(packet)) {
return osc.writeBundle(packet, options);
} else {
throw new Error("The specified packet was not recognized as a valid OSC message or bundle." +
" Packet was: " + JSON.stringify(packet, null, 2));
}
};
...
writePacket = function (packet, options) { if (osc.isValidMessage(packet)) { return osc.writeMessage(packet, options); } else if (osc.isValidBundle(packet)) { return osc.writeBundle(packet, options); } else { throw new Error("The specified packet was not recognized as a valid OSC message or bundle." + " Packet was: " + JSON.stringify(packet, null, 2)); } }
...
<code>options</code>: (optional) An options object, described below; <br />
<code>offsetState</code>: (optional) an offset state object containing an <code>idx</
code> property that specifies the offset index into <code>data</code>; <br />
<code>length</code> the length (in bytes) to read from <code>data</code>
</td>
<td>An osc.js message or bundle object</td>
</tr>
<tr>
<td><code>osc.writePacket()</code></td>
<td>Writes an OSC message or bundle object to a binary array.</td>
<td>
<code>packate</code>: An osc.js message or bundle object;<br />
<code>options</code>: (optional) An options object, described below<br />
</td>
<td>A <code>Uint8Array</code></td>
</tr>
...
writePrimitive = function (val, dv, writerName, numBytes, offset) { offset = offset === undefined ? 0 : offset; var arr; if (!dv) { arr = new Uint8Array(numBytes); dv = new DataView(arr.buffer); } else { arr = new Uint8Array(dv.buffer); } dv[writerName](offset, val, false); return arr; }
...
* Writes an OSC int32 ("i") value.
*
* @param {Number} val the number to write
* @param {DataView} [dv] a DataView instance to write the number into
* @param {Number} [offset] an offset into dv
*/
osc.writeInt32 = function (val, dv, offset) {
return osc.writePrimitive(val, dv, "setInt32", 4, offset);
};
/**
* Reads an OSC int64 ("h") value.
*
* @param {DataView} dv a DataView containing the raw bytes
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
...
writeString = function (str) { var terminated = str + "\u0000", len = terminated.length, paddedLen = (len + 3) & ~0x03, arr = new Uint8Array(paddedLen); for (var i = 0; i < terminated.length; i++) { var charCode = terminated.charCodeAt(i); arr[i] = charCode; } return arr; }
...
currPartIdx = dataCollection.parts.length;
for (var i = 0; i < args.length; i++) {
var arg = args[i];
typeTagString += osc.writeArgument(arg, dataCollection);
}
var typeData = osc.writeString(typeTagString);
dataCollection.byteLength += typeData.byteLength;
dataCollection.parts.splice(currPartIdx, 0, typeData);
return dataCollection;
};
/**
...
writeTimeTag = function (timeTag) { var raw = timeTag.raw ? timeTag.raw : osc.jsToNTPTime(timeTag.native), arr = new Uint8Array(8), // Two Unit32s. dv = new DataView(arr.buffer); osc.writeInt32(raw[0], dv, 0); osc.writeInt32(raw[1], dv, 4); return arr; }
...
osc.collectBundlePackets = function (bundle, options, dataCollection) {
dataCollection = dataCollection || {
byteLength: 0,
parts: []
};
osc.addDataPart(osc.writeString("#bundle"), dataCollection);
osc.addDataPart(osc.writeTimeTag(bundle.timeTag), dataCollection);
for (var i = 0; i < bundle.packets.length; i++) {
var packet = bundle.packets[i],
collector = packet.address ? osc.collectMessageParts : osc.collectBundlePackets,
packetCollection = collector(packet, options);
dataCollection.byteLength += packetCollection.byteLength;
...
Port = function (options) { this.options = options || {}; this.on("data", this.decodeOSC.bind(this)); }
n/a
constructor = function (options) { this.options = options || {}; this.on("data", this.decodeOSC.bind(this)); }
n/a
decodeOSC = function (data, packetInfo) { data = osc.byteArray(data); this.emit("raw", data, packetInfo); try { var packet = osc.readPacket(data, this.options); this.emit("osc", packet, packetInfo); osc.firePacketEvents(this, packet, undefined, packetInfo); } catch (err) { this.emit("error", err); } }
n/a
encodeOSC = function (packet) { // TODO gh-39: This is unsafe; we should only access the underlying // buffer within the range of its view. packet = packet.buffer ? packet.buffer : packet; var encoded; try { encoded = osc.writePacket(packet, this.options); } catch (err) { this.emit("error", err); } return encoded; }
...
};
var p = osc.Port.prototype = Object.create(EventEmitter.prototype);
p.constructor = osc.Port;
p.send = function (oscPacket) {
var args = Array.prototype.slice.call(arguments),
encoded = this.encodeOSC(oscPacket),
buf = osc.nativeBuffer(encoded);
args[0] = buf;
this.sendRaw.apply(this, args);
};
p.encodeOSC = function (packet) {
...
send = function (oscPacket) { var args = Array.prototype.slice.call(arguments), encoded = this.encodeOSC(oscPacket), buf = osc.nativeBuffer(encoded); args[0] = buf; this.sendRaw.apply(this, args); }
...
});
```
##### Sending OSC messages:
```javascript
// For most Ports, send() should only be called after the "ready" event fires.
oscPort.on("ready", function () {
oscPort.send({
address: "/carrier/frequency",
args: 440
});
});
```
##### Sending OSC bundles:
...
Relay = function (port1, port2, options) { var o = this.options = options || {}; o.raw = false; this.port1 = port1; this.port2 = port2; this.listen(); }
n/a
close = function () { osc.stopRelaying(this.port1, this.port1Spec); osc.stopRelaying(this.port2, this.port2Spec); this.emit("close", this.port1, this.port2); }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
constructor = function (port1, port2, options) { var o = this.options = options || {}; o.raw = false; this.port1 = port1; this.port2 = port2; this.listen(); }
n/a
listen = function () { if (this.port1Spec && this.port2Spec) { this.close(); } this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options); this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options); // Bind port close listeners to ensure that the relay // will stop forwarding messages if one of its ports close. // Users are still responsible for closing the underlying ports // if necessary. var closeListener = this.close.bind(this); this.port1.on("close", closeListener); this.port2.on("close", closeListener); }
...
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
});
...
open = function () { this.port1.open(); this.port2.open(); }
...
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
```
##### Listening for incoming OSC messages:
```javascript
oscPort.on("message", function (oscMsg) {
console.log("An OSC message just arrived!", oscMsg);
});
...
SLIPPort = function (options) { var that = this; var o = this.options = options || {}; o.useSLIP = o.useSLIP === undefined ? true : o.useSLIP; this.decoder = new slip.Decoder({ onMessage: this.decodeOSC.bind(this), onError: function (err) { that.emit("error", err); } }); var decodeHandler = o.useSLIP ? this.decodeSLIPData : this.decodeOSC; this.on("data", decodeHandler.bind(this)); }
n/a
constructor = function (options) { var that = this; var o = this.options = options || {}; o.useSLIP = o.useSLIP === undefined ? true : o.useSLIP; this.decoder = new slip.Decoder({ onMessage: this.decodeOSC.bind(this), onError: function (err) { that.emit("error", err); } }); var decodeHandler = o.useSLIP ? this.decodeSLIPData : this.decodeOSC; this.on("data", decodeHandler.bind(this)); }
n/a
decodeSLIPData = function (data, packetInfo) { // TODO: Get packetInfo through SLIP decoder. this.decoder.decode(data, packetInfo); }
n/a
encodeOSC = function (packet) { // TODO gh-39: This is unsafe; we should only access the underlying // buffer within the range of its view. packet = packet.buffer ? packet.buffer : packet; var framed; try { var encoded = osc.writePacket(packet, this.options); framed = slip.encode(encoded); } catch (err) { this.emit("error", err); } return framed; }
...
};
var p = osc.Port.prototype = Object.create(EventEmitter.prototype);
p.constructor = osc.Port;
p.send = function (oscPacket) {
var args = Array.prototype.slice.call(arguments),
encoded = this.encodeOSC(oscPacket),
buf = osc.nativeBuffer(encoded);
args[0] = buf;
this.sendRaw.apply(this, args);
};
p.encodeOSC = function (packet) {
...
SerialPort = function (options) { this.on("open", this.listen.bind(this)); osc.SLIPPort.call(this, options); this.options.bitrate = this.options.bitrate || 9600; this.serialPort = options.serialPort; if (this.serialPort) { this.emit("open", this.serialPort); } }
...
}
}
```
#### Connecting to the serial port and listening for OSC messages
```javascript
// 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);
});
...
close = function () { if (this.serialPort) { this.serialPort.close(); } }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
constructor = function (options) { this.on("open", this.listen.bind(this)); osc.SLIPPort.call(this, options); this.options.bitrate = this.options.bitrate || 9600; this.serialPort = options.serialPort; if (this.serialPort) { this.emit("open", this.serialPort); } }
n/a
listen = function () { var that = this; this.serialPort.on("data", function (data) { that.emit("data", data, undefined); }); this.serialPort.on("error", function (err) { that.emit("error", err); }); this.serialPort.on("close", function (err) { if (err) { that.emit("error", err); } else { that.emit("close"); } }); that.emit("ready"); }
...
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
});
...
open = function () { if (this.serialPort) { // If we already have a serial port, close it and open a new one. this.once("close", this.open.bind(this)); this.close(); return; } var that = this; this.serialPort = new SerialPort(this.options.devicePath, { baudrate: this.options.bitrate, autoOpen: false }); this.serialPort.open(function() { that.emit("open", that.serialPort); }); }
...
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
```
##### Listening for incoming OSC messages:
```javascript
oscPort.on("message", function (oscMsg) {
console.log("An OSC message just arrived!", oscMsg);
});
...
sendRaw = function (encoded) { if (!this.serialPort || !this.serialPort.isOpen()) { osc.fireClosedPortSendError(this); return; } var that = this; this.serialPort.write(encoded, function (err) { if (err) { that.emit("error", err); } }); }
n/a
TCPSocketPort = function (options) { osc.SLIPPort.call(this, options); var o = this.options; o.localAddress = o.localAddress || "127.0.0.1"; o.localPort = o.localPort !== undefined ? o.localPort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
n/a
close = function () { this.socket.end(); }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
constructor = function (options) { osc.SLIPPort.call(this, options); var o = this.options; o.localAddress = o.localAddress || "127.0.0.1"; o.localPort = o.localPort !== undefined ? o.localPort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
n/a
listen = function () { var that = this; this.socket.on("data", function (msg) { that.emit("data", msg, undefined); }); this.socket.on("error", function (err) { that.emit("error", err); }); this.socket.on("close", function (err) { if (err) { that.emit("error", err); } else { that.emit("close"); } }); this.socket.on("connect", function () { that.emit("ready"); }); }
...
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
});
...
open = function (address, port) { var o = this.options; address = address || o.address; port = port !== undefined ? port : o.port; if (!this.socket) { this.socket = net.connect({ port: port, host: address }); } else { this.socket.connect(port, address); } this.emit("open", this.socket); }
...
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
```
##### Listening for incoming OSC messages:
```javascript
oscPort.on("message", function (oscMsg) {
console.log("An OSC message just arrived!", oscMsg);
});
...
sendRaw = function (encoded) { if (!this.socket) { return; } encoded = new Buffer(encoded); try { this.socket.write(encoded); } catch (err) { this.emit("error", err); } }
n/a
UDPPort = function (options) { osc.Port.call(this, options); this.options.localAddress = this.options.localAddress || "127.0.0.1"; this.options.localPort = this.options.localPort !== undefined ? this.options.localPort : 57121; this.options.remoteAddress = this.options.remoteAddress || "127.0.0.1"; this.options.remotePort = this.options.remotePort !== undefined ? this.options.remotePort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
...
</tr>
</table>
#### Sample Code
```javascript
// 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);
...
setupMulticast = function (that) { if (that.options.multicastTTL !== undefined) { that.socket.setMulticastTTL(that.options.multicastTTL); } if (that.options.multicastMembership) { if (typeof that.options.multicastMembership === "string") { that.options.multicastMembership = [that.options.multicastMembership]; } that.options.multicastMembership.forEach(function (addr) { if (typeof addr === "string") { that.socket.addMembership(addr); } else { that.socket.addMembership(addr.address, addr.interface); } }); } }
n/a
close = function () { if (this.socket) { this.socket.close(); } }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
constructor = function (options) { osc.Port.call(this, options); this.options.localAddress = this.options.localAddress || "127.0.0.1"; this.options.localPort = this.options.localPort !== undefined ? this.options.localPort : 57121; this.options.remoteAddress = this.options.remoteAddress || "127.0.0.1"; this.options.remotePort = this.options.remotePort !== undefined ? this.options.remotePort : 57121; this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { this.emit("open", this.socket); } }
n/a
listen = function () { if (!this.socket) { return; } var that = this; this.socket.on("message", function (msg, rinfo) { that.emit("data", msg, rinfo); }); this.socket.on("error", function (error) { that.emit("error", error); }); this.socket.on("close", function () { that.emit("close"); }); that.emit("ready"); }
...
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
});
...
open = function () { var that = this; if (this.socket) { return; } this.socket = dgram.createSocket("udp4"); function onBound() { osc.UDPPort.setupMulticast(that); if (that.options.broadcast) { that.socket.setBroadcast(that.options.broadcast); } that.emit("open", that.socket); } this.socket.bind(this.options.localPort, this.options.localAddress, onBound); }
...
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
```
##### Listening for incoming OSC messages:
```javascript
oscPort.on("message", function (oscMsg) {
console.log("An OSC message just arrived!", oscMsg);
});
...
sendRaw = function (encoded, address, port) { if (!this.socket) { osc.fireClosedPortSendError(this); return; } var length = encoded.byteLength !== undefined ? encoded.byteLength : encoded.length, that = this; address = address || this.options.remoteAddress; port = port !== undefined ? port : this.options.remotePort; this.socket.send(encoded, 0, length, port, address, function (err) { if (err) { that.emit("error", err); } }); }
n/a
function WebSocket(address, protocols, options) { if (this instanceof WebSocket === false) { return new WebSocket(address, protocols, options); } EventEmitter.call(this); if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) { // accept the "options" Object as the 2nd argument options = protocols; protocols = null; } if ('string' === typeof protocols) { protocols = [ protocols ]; } if (!Array.isArray(protocols)) { protocols = []; } this._socket = null; this._ultron = null; this._closeReceived = false; this.bytesReceived = 0; this.readyState = null; this.supports = {}; this.extensions = {}; this._binaryType = 'nodebuffer'; if (Array.isArray(address)) { initAsServerClient.apply(this, address.concat(options)); } else { initAsClient.apply(this, [address, protocols, options]); } }
...
};
var p = osc.WebSocketPort.prototype = Object.create(osc.Port.prototype);
p.constructor = osc.WebSocketPort;
p.open = function () {
if (!this.socket || this.socket.readyState > 1) {
this.socket = new osc.WebSocket(this.options.url);
}
osc.WebSocketPort.setupSocketForBinary(this.socket);
var that = this;
this.socket.onopen = function () {
that.emit("open", that.socket);
...
function Receiver(extensions, maxPayload) { if (this instanceof Receiver === false) { throw new TypeError("Classes can't be function-called"); } if(typeof extensions==='number'){ maxPayload=extensions; extensions={}; } // memory pool for fragmented messages var fragmentedPoolPrevUsed = -1; this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? Math.ceil((fragmentedPoolPrevUsed + db.used) / 2) : db.used; }); // memory pool for unfragmented messages var unfragmentedPoolPrevUsed = -1; this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? Math.ceil((unfragmentedPoolPrevUsed + db.used) / 2) : db.used; }); this.extensions = extensions || {}; this.maxPayload = maxPayload || 0; this.currentPayloadLength = 0; this.state = { activeFragmentedOperation: null, lastFragment: false, masked: false, opcode: 0, fragmentedOperation: false }; this.overflow = []; this.headerBuffer = new Buffer(10); this.expectOffset = 0; this.expectBuffer = null; this.expectHandler = null; this.currentMessage = []; this.currentMessageLength = 0; this.messageHandlers = []; this.expectHeader(2, this.processPacket); this.dead = false; this.processing = false; this.onerror = function() {}; this.ontext = function() {}; this.onbinary = function() {}; this.onclose = function() {}; this.onping = function() {}; this.onpong = function() {}; }
n/a
function Sender(socket, extensions) { if (this instanceof Sender === false) { throw new TypeError("Classes can't be function-called"); } events.EventEmitter.call(this); this._socket = socket; this.extensions = extensions || {}; this.firstFragment = true; this.compress = false; this.messageHandlers = []; this.processing = false; }
n/a
function WebSocketServer(options, callback) { if (this instanceof WebSocketServer === false) { return new WebSocketServer(options, callback); } events.EventEmitter.call(this); options = new Options({ host: '0.0.0.0', port: null, server: null, verifyClient: null, handleProtocols: null, path: null, noServer: false, disableHixie: false, clientTracking: true, perMessageDeflate: true, maxPayload: 100 * 1024 * 1024 }).merge(options); if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { throw new TypeError('`port` or a `server` must be provided'); } var self = this; if (options.isDefinedAndNonNull('port')) { this._server = http.createServer(function (req, res) { var body = http.STATUS_CODES[426]; res.writeHead(426, { 'Content-Length': body.length, 'Content-Type': 'text/plain' }); res.end(body); }); this._server.allowHalfOpen = false; this._server.listen(options.value.port, options.value.host, callback); this._closeServer = function() { if (self._server) self._server.close(); }; } else if (options.value.server) { this._server = options.value.server; if (options.value.path) { // take note of the path, to avoid collisions when multiple websocket servers are // listening on the same http server if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); } if (typeof this._server._webSocketPaths !== 'object') { this._server._webSocketPaths = {}; } this._server._webSocketPaths[options.value.path] = 1; } } if (this._server) { this._onceServerListening = function() { self.emit('listening'); }; this._server.once('listening', this._onceServerListening); } if (typeof this._server != 'undefined') { this._onServerError = function(error) { self.emit('error', error) }; this._server.on('error', this._onServerError); this._onServerUpgrade = function(req, socket, upgradeHead) { //copy upgradeHead to avoid retention of large slab buffers used in node core var head = new Buffer(upgradeHead.length); upgradeHead.copy(head); self.handleUpgrade(req, socket, head, function(client) { self.emit('connection'+req.url, client); self.emit('connection', client); }); }; this._server.on('upgrade', this._onServerUpgrade); } this.options = options.value; this.path = options.value.path; this.clients = []; }
...
// 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
...
function buildHostHeader(isSecure, hostname, port) { var headerHost = hostname; if (hostname) { if ((isSecure && (port != 443)) || (!isSecure && (port != 80))){ headerHost = headerHost + ':' + port; } } return headerHost; }
n/a
function connect(address, fn) { var client = new WS(address); if (typeof fn === 'function') { client.on('open', fn); } return client; }
...
p.open = function () {
var that = this,
connectionOpts = {
bitrate: that.options.bitrate
};
chrome.serial.connect(this.options.devicePath, connectionOpts, function (info) {
that.connectionId = info.connectionId;
that.emit("open", info);
});
};
p.listen = function () {
osc.listenToTransport(this, chrome.serial, "connectionId");
...
function connect(address, fn) { var client = new WS(address); if (typeof fn === 'function') { client.on('open', fn); } return client; }
n/a
function createServer(options, fn) { var server = new WS.Server(options); if (typeof fn === 'function') { server.on('connection', fn); } return server; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Receiver(extensions, maxPayload) { if (this instanceof Receiver === false) { throw new TypeError("Classes can't be function-called"); } if(typeof extensions==='number'){ maxPayload=extensions; extensions={}; } // memory pool for fragmented messages var fragmentedPoolPrevUsed = -1; this.fragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return fragmentedPoolPrevUsed = fragmentedPoolPrevUsed >= 0 ? Math.ceil((fragmentedPoolPrevUsed + db.used) / 2) : db.used; }); // memory pool for unfragmented messages var unfragmentedPoolPrevUsed = -1; this.unfragmentedBufferPool = new BufferPool(1024, function(db, length) { return db.used + length; }, function(db) { return unfragmentedPoolPrevUsed = unfragmentedPoolPrevUsed >= 0 ? Math.ceil((unfragmentedPoolPrevUsed + db.used) / 2) : db.used; }); this.extensions = extensions || {}; this.maxPayload = maxPayload || 0; this.currentPayloadLength = 0; this.state = { activeFragmentedOperation: null, lastFragment: false, masked: false, opcode: 0, fragmentedOperation: false }; this.overflow = []; this.headerBuffer = new Buffer(10); this.expectOffset = 0; this.expectBuffer = null; this.expectHandler = null; this.currentMessage = []; this.currentMessageLength = 0; this.messageHandlers = []; this.expectHeader(2, this.processPacket); this.dead = false; this.processing = false; this.onerror = function() {}; this.ontext = function() {}; this.onbinary = function() {}; this.onclose = function() {}; this.onping = function() {}; this.onpong = function() {}; }
n/a
add = function (data) { if (this.dead) return; var dataLength = data.length; if (dataLength == 0) return; if (this.expectBuffer == null) { this.overflow.push(data); return; } var toRead = Math.min(dataLength, this.expectBuffer.length - this.expectOffset); fastCopy(toRead, data, this.expectBuffer, this.expectOffset); this.expectOffset += toRead; if (toRead < dataLength) { this.overflow.push(data.slice(toRead)); } while (this.expectBuffer && this.expectOffset == this.expectBuffer.length) { var bufferForHandler = this.expectBuffer; this.expectBuffer = null; this.expectOffset = 0; this.expectHandler.call(this, bufferForHandler); } }
n/a
allocateFromPool = function (length, isFragmented) { return (isFragmented ? this.fragmentedBufferPool : this.unfragmentedBufferPool).get(length); }
n/a
applyExtensions = function (messageBuffer, fin, compressed, callback) { var self = this; if (compressed) { this.extensions[PerMessageDeflate.extensionName].decompress(messageBuffer, fin, function(err, buffer) { if (self.dead) return; if (err) { callback(new Error('invalid compressed data')); return; } callback(null, buffer); }); } else { callback(null, messageBuffer); } }
n/a
cleanup = function () { this.dead = true; this.overflow = null; this.headerBuffer = null; this.expectBuffer = null; this.expectHandler = null; this.unfragmentedBufferPool = null; this.fragmentedBufferPool = null; this.state = null; this.currentMessage = null; this.onerror = null; this.ontext = null; this.onbinary = null; this.onclose = null; this.onping = null; this.onpong = null; }
n/a
endPacket = function () { if (this.dead) return; if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true); else if (this.state.lastFragment) this.fragmentedBufferPool.reset(true); this.expectOffset = 0; this.expectBuffer = null; this.expectHandler = null; if (this.state.lastFragment && this.state.opcode === this.state.activeFragmentedOperation) { // end current fragmented operation this.state.activeFragmentedOperation = null; } this.currentPayloadLength = 0; this.state.lastFragment = false; this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0; this.state.masked = false; this.expectHeader(2, this.processPacket); }
n/a
error = function (reason, protocolErrorCode) { if (this.dead) return; this.reset(); if(typeof reason == 'string'){ this.onerror(new Error(reason), protocolErrorCode); } else if(reason.constructor == Error){ this.onerror(reason, protocolErrorCode); } else{ this.onerror(new Error("An error occured"),protocolErrorCode); } return this; }
n/a
expectData = function (length, handler) { if (length == 0) { handler(null); return; } this.expectBuffer = this.allocateFromPool(length, this.state.fragmentedOperation); this.expectHandler = handler; var toRead = length; while (toRead > 0 && this.overflow.length > 0) { var fromOverflow = this.overflow.pop(); if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); var read = Math.min(fromOverflow.length, toRead); fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); this.expectOffset += read; toRead -= read; } }
n/a
expectHeader = function (length, handler) { if (length == 0) { handler(null); return; } this.expectBuffer = this.headerBuffer.slice(this.expectOffset, this.expectOffset + length); this.expectHandler = handler; var toRead = length; while (toRead > 0 && this.overflow.length > 0) { var fromOverflow = this.overflow.pop(); if (toRead < fromOverflow.length) this.overflow.push(fromOverflow.slice(toRead)); var read = Math.min(fromOverflow.length, toRead); fastCopy(read, fromOverflow, this.expectBuffer, this.expectOffset); this.expectOffset += read; toRead -= read; } }
n/a
flush = function () { if (this.processing || this.dead) return; var handler = this.messageHandlers.shift(); if (!handler) return; this.processing = true; var self = this; handler(function() { self.processing = false; self.flush(); }); }
n/a
maxPayloadExceeded = function (length) { if (this.maxPayload=== undefined || this.maxPayload === null || this.maxPayload < 1) { return false; } var fullLength = this.currentPayloadLength + length; if (fullLength < this.maxPayload) { this.currentPayloadLength = fullLength; return false; } this.error('payload cannot exceed ' + this.maxPayload + ' bytes', 1009); this.messageBuffer=[]; this.cleanup(); return true; }
n/a
processPacket = function (data) { if (this.extensions[PerMessageDeflate.extensionName]) { if ((data[0] & 0x30) != 0) { this.error('reserved fields (2, 3) must be empty', 1002); return; } } else { if ((data[0] & 0x70) != 0) { this.error('reserved fields must be empty', 1002); return; } } this.state.lastFragment = (data[0] & 0x80) == 0x80; this.state.masked = (data[1] & 0x80) == 0x80; var compressed = (data[0] & 0x40) == 0x40; var opcode = data[0] & 0xf; if (opcode === 0) { if (compressed) { this.error('continuation frame cannot have the Per-message Compressed bits', 1002); return; } // continuation frame this.state.fragmentedOperation = true; this.state.opcode = this.state.activeFragmentedOperation; if (!(this.state.opcode == 1 || this.state.opcode == 2)) { this.error('continuation frame cannot follow current opcode', 1002); return; } } else { if (opcode < 3 && this.state.activeFragmentedOperation != null) { this.error('data frames after the initial data frame must have opcode 0', 1002); return; } if (opcode >= 8 && compressed) { this.error('control frames cannot have the Per-message Compressed bits', 1002); return; } this.state.compressed = compressed; this.state.opcode = opcode; if (this.state.lastFragment === false) { this.state.fragmentedOperation = true; this.state.activeFragmentedOperation = opcode; } else this.state.fragmentedOperation = false; } var handler = opcodes[this.state.opcode]; if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode, 1002); else { handler.start.call(this, data); } }
n/a
reset = function () { if (this.dead) return; this.state = { activeFragmentedOperation: null, lastFragment: false, masked: false, opcode: 0, fragmentedOperation: false }; this.fragmentedBufferPool.reset(true); this.unfragmentedBufferPool.reset(true); this.expectOffset = 0; this.expectBuffer = null; this.expectHandler = null; this.overflow = []; this.currentMessage = []; this.currentMessageLength = 0; this.messageHandlers = []; this.currentPayloadLength = 0; }
n/a
unmask = function (mask, buf, binary) { if (mask != null && buf != null) bufferUtil.unmask(buf, mask); if (binary) return buf; return buf != null ? buf.toString('utf8') : ''; }
n/a
function Sender(socket, extensions) { if (this instanceof Sender === false) { throw new TypeError("Classes can't be function-called"); } events.EventEmitter.call(this); this._socket = socket; this.extensions = extensions || {}; this.firstFragment = true; this.compress = false; this.messageHandlers = []; this.processing = false; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
applyExtensions = function (data, fin, compress, callback) { if (compress && data) { if ((data.buffer || data) instanceof ArrayBuffer) { data = getArrayBuffer(data); } this.extensions[PerMessageDeflate.extensionName].compress(data, fin, callback); } else { callback(null, data); } }
n/a
close = function (code, data, mask, cb) { if (typeof code !== 'undefined') { if (typeof code !== 'number' || !ErrorCodes.isValidErrorCode(code)) throw new Error('first argument must be a valid error code number'); } code = code || 1000; var dataBuffer = new Buffer(2 + (data ? Buffer.byteLength(data) : 0)); writeUInt16BE.call(dataBuffer, code, 0); if (dataBuffer.length > 2) dataBuffer.write(data, 2); var self = this; this.messageHandlers.push(function(callback) { self.frameAndSend(0x8, dataBuffer, true, mask); callback(); if (typeof cb == 'function') cb(); }); this.flush(); }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
flush = function () { if (this.processing) return; var handler = this.messageHandlers.shift(); if (!handler) return; this.processing = true; var self = this; handler(function() { self.processing = false; self.flush(); }); }
n/a
frameAndSend = function (opcode, data, finalFragment, maskData, compressed, cb) { var canModifyData = false; if (!data) { try { this._socket.write(new Buffer([opcode | (finalFragment ? 0x80 : 0), 0 | (maskData ? 0x80 : 0)].concat(maskData ? [0, 0, 0, 0] : [])), 'binary', cb); } catch (e) { if (typeof cb == 'function') cb(e); else this.emit('error', e); } return; } if (!Buffer.isBuffer(data)) { canModifyData = true; if (data && (typeof data.byteLength !== 'undefined' || typeof data.buffer !== 'undefined')) { data = getArrayBuffer(data); } else { // // If people want to send a number, this would allocate the number in // bytes as memory size instead of storing the number as buffer value. So // we need to transform it to string in order to prevent possible // vulnerabilities / memory attacks. // if (typeof data === 'number') data = data.toString(); data = new Buffer(data); } } var dataLength = data.length , dataOffset = maskData ? 6 : 2 , secondByte = dataLength; if (dataLength >= 65536) { dataOffset += 8; secondByte = 127; } else if (dataLength > 125) { dataOffset += 2; secondByte = 126; } var mergeBuffers = dataLength < 32768 || (maskData && !canModifyData); var totalLength = mergeBuffers ? dataLength + dataOffset : dataOffset; var outputBuffer = new Buffer(totalLength); outputBuffer[0] = finalFragment ? opcode | 0x80 : opcode; if (compressed) outputBuffer[0] |= 0x40; switch (secondByte) { case 126: writeUInt16BE.call(outputBuffer, dataLength, 2); break; case 127: writeUInt32BE.call(outputBuffer, 0, 2); writeUInt32BE.call(outputBuffer, dataLength, 6); } if (maskData) { outputBuffer[1] = secondByte | 0x80; var mask = getRandomMask(); outputBuffer[dataOffset - 4] = mask[0]; outputBuffer[dataOffset - 3] = mask[1]; outputBuffer[dataOffset - 2] = mask[2]; outputBuffer[dataOffset - 1] = mask[3]; if (mergeBuffers) { bufferUtil.mask(data, mask, outputBuffer, dataOffset, dataLength); try { this._socket.write(outputBuffer, 'binary', cb); } catch (e) { if (typeof cb == 'function') cb(e); else this.emit('error', e); } } else { bufferUtil.mask(data, mask, data, 0, dataLength); try { this._socket.write(outputBuffer, 'binary'); this._socket.write(data, 'binary', cb); } catch (e) { if (typeof cb == 'function') cb(e); else this.emit('error', e); } } } else { outputBuffer[1] = secondByte; if (mergeBuffers) { data.copy(outputBuffer, dataOffset); try { this._socket.write(outputBuffer, 'binary', cb); } catch (e) { if (typeof cb == 'function') cb(e); else this.emit('error', e); } } else { try { this._socket.write(outputBuffer, 'binary'); this._socket.write(data, 'binary', cb); } catch (e) { if (typeof cb == 'function') cb(e); else this.emit('error', e); } } } }
n/a
ping = function (data, options) { var mask = options && options.mask; var self = this; this.messageHandlers.push(function(callback) { self.frameAndSend(0x9, data || '', true, mask); callback(); }); this.flush(); }
n/a
pong = function (data, options) { var mask = options && options.mask; var self = this; this.messageHandlers.push(function(callback) { self.frameAndSend(0xa, data || '', true, mask); callback(); }); this.flush(); }
n/a
send = function (data, options, cb) { var finalFragment = options && options.fin === false ? false : true; var mask = options && options.mask; var compress = options && options.compress; var opcode = options && options.binary ? 2 : 1; if (this.firstFragment === false) { opcode = 0; compress = false; } else { this.firstFragment = false; this.compress = compress; } if (finalFragment) this.firstFragment = true var compressFragment = this.compress; var self = this; this.messageHandlers.push(function(callback) { self.applyExtensions(data, finalFragment, compressFragment, function(err, data) { if (err) { if (typeof cb == 'function') cb(err); else self.emit('error', err); return; } self.frameAndSend(opcode, data, finalFragment, mask, compress, cb); callback(); }); }); this.flush(); }
...
});
```
##### Sending OSC messages:
```javascript
// For most Ports, send() should only be called after the "ready" event fires.
oscPort.on("ready", function () {
oscPort.send({
address: "/carrier/frequency",
args: 440
});
});
```
##### Sending OSC bundles:
...
function WebSocketServer(options, callback) { if (this instanceof WebSocketServer === false) { return new WebSocketServer(options, callback); } events.EventEmitter.call(this); options = new Options({ host: '0.0.0.0', port: null, server: null, verifyClient: null, handleProtocols: null, path: null, noServer: false, disableHixie: false, clientTracking: true, perMessageDeflate: true, maxPayload: 100 * 1024 * 1024 }).merge(options); if (!options.isDefinedAndNonNull('port') && !options.isDefinedAndNonNull('server') && !options.value.noServer) { throw new TypeError('`port` or a `server` must be provided'); } var self = this; if (options.isDefinedAndNonNull('port')) { this._server = http.createServer(function (req, res) { var body = http.STATUS_CODES[426]; res.writeHead(426, { 'Content-Length': body.length, 'Content-Type': 'text/plain' }); res.end(body); }); this._server.allowHalfOpen = false; this._server.listen(options.value.port, options.value.host, callback); this._closeServer = function() { if (self._server) self._server.close(); }; } else if (options.value.server) { this._server = options.value.server; if (options.value.path) { // take note of the path, to avoid collisions when multiple websocket servers are // listening on the same http server if (this._server._webSocketPaths && options.value.server._webSocketPaths[options.value.path]) { throw new Error('two instances of WebSocketServer cannot listen on the same http server path'); } if (typeof this._server._webSocketPaths !== 'object') { this._server._webSocketPaths = {}; } this._server._webSocketPaths[options.value.path] = 1; } } if (this._server) { this._onceServerListening = function() { self.emit('listening'); }; this._server.once('listening', this._onceServerListening); } if (typeof this._server != 'undefined') { this._onServerError = function(error) { self.emit('error', error) }; this._server.on('error', this._onServerError); this._onServerUpgrade = function(req, socket, upgradeHead) { //copy upgradeHead to avoid retention of large slab buffers used in node core var head = new Buffer(upgradeHead.length); upgradeHead.copy(head); self.handleUpgrade(req, socket, head, function(client) { self.emit('connection'+req.url, client); self.emit('connection', client); }); }; this._server.on('upgrade', this._onServerUpgrade); } this.options = options.value; this.path = options.value.path; this.clients = []; }
...
// 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
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
close = function (callback) { // terminate all associated clients var error = null; try { for (var i = 0, l = this.clients.length; i < l; ++i) { this.clients[i].terminate(); } } catch (e) { error = e; } // remove path descriptor, if any if (this.path && this._server._webSocketPaths) { delete this._server._webSocketPaths[this.path]; if (Object.keys(this._server._webSocketPaths).length == 0) { delete this._server._webSocketPaths; } } // close the http server if it was internally created try { if (typeof this._closeServer !== 'undefined') { this._closeServer(); } } finally { if (this._server) { this._server.removeListener('listening', this._onceServerListening); this._server.removeListener('error', this._onServerError); this._server.removeListener('upgrade', this._onServerUpgrade); } delete this._server; } if(callback) callback(error); else if(error) throw error; }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
handleUpgrade = function (req, socket, upgradeHead, cb) { // check for wrong path if (this.options.path) { var u = url.parse(req.url); if (u && u.pathname !== this.options.path) return; } if (typeof req.headers.upgrade === 'undefined' || req.headers.upgrade.toLowerCase() !== 'websocket') { abortConnection(socket, 400, 'Bad Request'); return; } if (req.headers['sec-websocket-key1']) handleHixieUpgrade.apply(this, arguments); else handleHybiUpgrade.apply(this, arguments); }
n/a
addEventListener = function (method, listener) { var target = this; function onMessage (data, flags) { if (flags.binary && this.binaryType === 'arraybuffer') data = new Uint8Array(data).buffer; listener.call(target, new MessageEvent(data, !!flags.binary, target)); } function onClose (code, message) { listener.call(target, new CloseEvent(code, message, target)); } function onError (event) { event.type = 'error'; event.target = target; listener.call(target, event); } function onOpen () { listener.call(target, new OpenEvent(target)); } if (typeof listener === 'function') { if (method === 'message') { // store a reference so we can return the original function from the // addEventListener hook onMessage._listener = listener; this.on(method, onMessage); } else if (method === 'close') { // store a reference so we can return the original function from the // addEventListener hook onClose._listener = listener; this.on(method, onClose); } else if (method === 'error') { // store a reference so we can return the original function from the // addEventListener hook onError._listener = listener; this.on(method, onError); } else if (method === 'open') { // store a reference so we can return the original function from the // addEventListener hook onOpen._listener = listener; this.on(method, onOpen); } else { this.on(method, listener); } } }
n/a
function close(code, data) { if (this.readyState === WebSocket.CLOSED) return; if (this.readyState === WebSocket.CONNECTING) { this.readyState = WebSocket.CLOSED; return; } if (this.readyState === WebSocket.CLOSING) { if (this._closeReceived && this._isServer) { this.terminate(); } return; } var self = this; try { this.readyState = WebSocket.CLOSING; this._closeCode = code; this._closeMessage = data; var mask = !this._isServer; this._sender.close(code, data, mask, function(err) { if (err) self.emit('error', err); if (self._closeReceived && self._isServer) { self.terminate(); } else { // ensure that the connection is cleaned up even when no response of closing handshake. clearTimeout(self._closeTimer); self._closeTimer = setTimeout(cleanupWebsocketResources.bind(self, true), closeTimeout); } }); } catch (e) { this.emit('error', e); } }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
function pauser() { if (this.readyState !== WebSocket.OPEN) throw new Error('not opened'); return this._socket.pause(); }
n/a
function ping(data, options, dontFailWhenClosed) { if (this.readyState !== WebSocket.OPEN) { if (dontFailWhenClosed === true) return; throw new Error('not opened'); } options = options || {}; if (typeof options.mask === 'undefined') options.mask = !this._isServer; this._sender.ping(data, options); }
n/a
pong = function (data, options, dontFailWhenClosed) { if (this.readyState !== WebSocket.OPEN) { if (dontFailWhenClosed === true) return; throw new Error('not opened'); } options = options || {}; if (typeof options.mask === 'undefined') options.mask = !this._isServer; this._sender.pong(data, options); }
n/a
function resume() { if (this.readyState !== WebSocket.OPEN) throw new Error('not opened'); return this._socket.resume(); }
n/a
function send(data, options, cb) { if (typeof options === 'function') { cb = options; options = {}; } if (this.readyState !== WebSocket.OPEN) { if (typeof cb === 'function') cb(new Error('not opened')); else throw new Error('not opened'); return; } if (!data) data = ''; if (this._queue) { var self = this; this._queue.push(function() { self.send(data, options, cb); }); return; } options = options || {}; options.fin = true; if (typeof options.binary === 'undefined') { options.binary = (data instanceof ArrayBuffer || data instanceof Buffer || data instanceof Uint8Array || data instanceof Uint16Array || data instanceof Uint32Array || data instanceof Int8Array || data instanceof Int16Array || data instanceof Int32Array || data instanceof Float32Array || data instanceof Float64Array); } if (typeof options.mask === 'undefined') options.mask = !this._isServer; if (typeof options.compress === 'undefined') options.compress = true; if (!this.extensions[PerMessageDeflate.extensionName]) { options.compress = false; } var readable = typeof stream.Readable === 'function' ? stream.Readable : stream.Stream; if (data instanceof readable) { startQueue(this); var self = this; sendStream(this, data, options, function send(error) { process.nextTick(function tock() { executeQueueSends(self); }); if (typeof cb === 'function') cb(error); }); } else { this._sender.send(data, options, cb); } }
...
});
```
##### Sending OSC messages:
```javascript
// For most Ports, send() should only be called after the "ready" event fires.
oscPort.on("ready", function () {
oscPort.send({
address: "/carrier/frequency",
args: 440
});
});
```
##### Sending OSC bundles:
...
function stream(options, cb) { if (typeof options === 'function') { cb = options; options = {}; } var self = this; if (typeof cb !== 'function') throw new Error('callback must be provided'); if (this.readyState !== WebSocket.OPEN) { if (typeof cb === 'function') cb(new Error('not opened')); else throw new Error('not opened'); return; } if (this._queue) { this._queue.push(function () { self.stream(options, cb); }); return; } options = options || {}; if (typeof options.mask === 'undefined') options.mask = !this._isServer; if (typeof options.compress === 'undefined') options.compress = true; if (!this.extensions[PerMessageDeflate.extensionName]) { options.compress = false; } startQueue(this); function send(data, final) { try { if (self.readyState !== WebSocket.OPEN) throw new Error('not opened'); options.fin = final === true; self._sender.send(data, options); if (!final) process.nextTick(cb.bind(null, null, send)); else executeQueueSends(self); } catch (e) { if (typeof cb === 'function') cb(e); else { delete self._queue; self.emit('error', e); } } } process.nextTick(cb.bind(null, null, send)); }
n/a
function terminate() { if (this.readyState === WebSocket.CLOSED) return; if (this._socket) { this.readyState = WebSocket.CLOSING; // End the connection try { this._socket.end(); } catch (e) { // Socket error during end() call, so just destroy it right now cleanupWebsocketResources.call(this, true); return; } // Add a timeout to ensure that the connection is completely // cleaned up within 30 seconds, even if the clean close procedure // fails for whatever reason // First cleanup any pre-existing timeout from an earlier "terminate" call, // if one exists. Otherwise terminate calls in quick succession will leak timeouts // and hold the program open for `closeTimout` time. if (this._closeTimer) { clearTimeout(this._closeTimer); } this._closeTimer = setTimeout(cleanupWebsocketResources.bind(this, true), closeTimeout); } else if (this.readyState === WebSocket.CONNECTING) { cleanupWebsocketResources.call(this, true); } }
n/a
WebSocketPort = function (options) { osc.Port.call(this, options); this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { if (this.socket.readyState === 1) { osc.WebSocketPort.setupSocketForBinary(this.socket); this.emit("open", this.socket); } else { this.open(); } } }
...
</head>
<body></body>
</html>
```
##### Creating an OSC Web Socket Port object:
```javascript
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
...
setupSocketForBinary = function (socket) { socket.binaryType = osc.isNode ? "nodebuffer" : "arraybuffer"; }
...
osc.WebSocketPort = function (options) {
osc.Port.call(this, options);
this.on("open", this.listen.bind(this));
this.socket = options.socket;
if (this.socket) {
if (this.socket.readyState === 1) {
osc.WebSocketPort.setupSocketForBinary(this.socket);
this.emit("open", this.socket);
} else {
this.open();
}
}
};
...
close = function (code, reason) { this.socket.close(code, reason); }
...
p.open = function () {
this.port1.open();
this.port2.open();
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
...
constructor = function (options) { osc.Port.call(this, options); this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { if (this.socket.readyState === 1) { osc.WebSocketPort.setupSocketForBinary(this.socket); this.emit("open", this.socket); } else { this.open(); } } }
n/a
listen = function () { var that = this; this.socket.onmessage = function (e) { that.emit("data", e.data, e); }; this.socket.onerror = function (err) { that.emit("error", err); }; this.socket.onclose = function (e) { that.emit("close", e); }; that.emit("ready"); }
...
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
});
...
open = function () { if (!this.socket || this.socket.readyState > 1) { this.socket = new osc.WebSocket(this.options.url); } osc.WebSocketPort.setupSocketForBinary(this.socket); var that = this; this.socket.onopen = function () { that.emit("open", that.socket); }; }
...
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
```
##### Listening for incoming OSC messages:
```javascript
oscPort.on("message", function (oscMsg) {
console.log("An OSC message just arrived!", oscMsg);
});
...
sendRaw = function (encoded) { if (!this.socket || this.socket.readyState !== 1) { osc.fireClosedPortSendError(this); return; } this.socket.send(encoded); }
n/a
Port = function (options) { this.options = options || {}; this.on("data", this.decodeOSC.bind(this)); }
n/a
Relay = function (port1, port2, options) { var o = this.options = options || {}; o.raw = false; this.port1 = port1; this.port2 = port2; this.listen(); }
n/a
SLIPPort = function (options) { var that = this; var o = this.options = options || {}; o.useSLIP = o.useSLIP === undefined ? true : o.useSLIP; this.decoder = new slip.Decoder({ onMessage: this.decodeOSC.bind(this), onError: function (err) { that.emit("error", err); } }); var decodeHandler = o.useSLIP ? this.decodeSLIPData : this.decodeOSC; this.on("data", decodeHandler.bind(this)); }
n/a
function WebSocket(address, protocols, options) { if (this instanceof WebSocket === false) { return new WebSocket(address, protocols, options); } EventEmitter.call(this); if (protocols && !Array.isArray(protocols) && 'object' === typeof protocols) { // accept the "options" Object as the 2nd argument options = protocols; protocols = null; } if ('string' === typeof protocols) { protocols = [ protocols ]; } if (!Array.isArray(protocols)) { protocols = []; } this._socket = null; this._ultron = null; this._closeReceived = false; this.bytesReceived = 0; this.readyState = null; this.supports = {}; this.extensions = {}; this._binaryType = 'nodebuffer'; if (Array.isArray(address)) { initAsServerClient.apply(this, address.concat(options)); } else { initAsClient.apply(this, [address, protocols, options]); } }
...
};
var p = osc.WebSocketPort.prototype = Object.create(osc.Port.prototype);
p.constructor = osc.WebSocketPort;
p.open = function () {
if (!this.socket || this.socket.readyState > 1) {
this.socket = new osc.WebSocket(this.options.url);
}
osc.WebSocketPort.setupSocketForBinary(this.socket);
var that = this;
this.socket.onopen = function () {
that.emit("open", that.socket);
...
WebSocketPort = function (options) { osc.Port.call(this, options); this.on("open", this.listen.bind(this)); this.socket = options.socket; if (this.socket) { if (this.socket.readyState === 1) { osc.WebSocketPort.setupSocketForBinary(this.socket); this.emit("open", this.socket); } else { this.open(); } } }
...
</head>
<body></body>
</html>
```
##### Creating an OSC Web Socket Port object:
```javascript
var oscPort = new osc.WebSocketPort({
url: "ws://localhost:8081" // URL to your Web Socket server.
});
```
##### Opening the Port:
```javascript
oscPort.open();
...
addDataPart = function (dataPart, dataCollection) { dataCollection.parts.push(dataPart); dataCollection.byteLength += dataPart.length; }
...
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
var data = osc[writer](arg.value);
osc.addDataPart(data, dataCollection);
}
return arg.type;
};
// Unsupported, non-API function.
osc.collectArguments = function (args, options, dataCollection) {
...
annotateArguments = function (args) { var annotated = []; for (var i = 0; i < args.length; i++) { var arg = args[i], msgArg; if (typeof (arg) === "object" && arg.type && arg.value !== undefined) { // We've got an explicitly typed argument. msgArg = arg; } else if (osc.isArray(arg)) { // We've got an array of arguments, // so they each need to be inferred and expanded. msgArg = osc.annotateArguments(arg); } else { var oscType = osc.inferTypeForArgument(arg); msgArg = { type: oscType, value: arg }; } annotated.push(msgArg); } return annotated; }
...
dataCollection = dataCollection || {
byteLength: 0,
parts: []
};
if (!options.metadata) {
args = osc.annotateArguments(args);
}
var typeTagString = ",",
currPartIdx = dataCollection.parts.length;
for (var i = 0; i < args.length; i++) {
var arg = args[i];
...
byteArray = function (obj) { if (obj instanceof Uint8Array) { return obj; } var buf = obj.buffer ? obj.buffer : obj; if (!(buf instanceof ArrayBuffer) && (typeof buf.length === "undefined" || typeof buf === "string")) { throw new Error("Can't wrap a non-array-like object as Uint8Array. Object was: " + JSON.stringify(obj, null, 2)); } // TODO gh-39: This is a potentially unsafe algorithm; // if we're getting anything other than a TypedArrayView (such as a DataView), // we really need to determine the range of the view it is viewing. return new Uint8Array(buf); }
...
/**
* Writes a raw collection of bytes to a new ArrayBuffer.
*
* @param {Array-like} data a collection of octets
* @return {ArrayBuffer} a buffer containing the OSC-formatted blob
*/
osc.writeBlob = function (data) {
data = osc.byteArray(data);
var len = data.byteLength,
paddedLen = (len + 3) & ~0x03,
offset = 4, // Extra 4 bytes is for the size.
blobLen = paddedLen + offset,
arr = new Uint8Array(blobLen),
dv = new DataView(arr.buffer);
...
collectArguments = function (args, options, dataCollection) { if (!osc.isArray(args)) { args = typeof args === "undefined" ? [] : [args]; } dataCollection = dataCollection || { byteLength: 0, parts: [] }; if (!options.metadata) { args = osc.annotateArguments(args); } var typeTagString = ",", currPartIdx = dataCollection.parts.length; for (var i = 0; i < args.length; i++) { var arg = args[i]; typeTagString += osc.writeArgument(arg, dataCollection); } var typeData = osc.writeString(typeTagString); dataCollection.byteLength += typeData.byteLength; dataCollection.parts.splice(currPartIdx, 0, typeData); return dataCollection; }
...
* Writes the specified arguments.
*
* @param {Array} args an array of arguments
* @param {Object} options options for writing
* @return {Uint8Array} a buffer containing the OSC-formatted argument type tag and values
*/
osc.writeArguments = function (args, options) {
var argCollection = osc.collectArguments(args, options);
return osc.joinParts(argCollection);
};
// Unsupported, non-API function.
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
...
collectBundlePackets = function (bundle, options, dataCollection) { dataCollection = dataCollection || { byteLength: 0, parts: [] }; osc.addDataPart(osc.writeString("#bundle"), dataCollection); osc.addDataPart(osc.writeTimeTag(bundle.timeTag), dataCollection); for (var i = 0; i < bundle.packets.length; i++) { var packet = bundle.packets[i], collector = packet.address ? osc.collectMessageParts : osc.collectBundlePackets, packetCollection = collector(packet, options); dataCollection.byteLength += packetCollection.byteLength; osc.addDataPart(osc.writeInt32(packetCollection.byteLength), dataCollection); dataCollection.parts = dataCollection.parts.concat(packetCollection.parts); } return dataCollection; }
...
osc.writeBundle = function (bundle, options) {
if (!osc.isValidBundle(bundle)) {
throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " +
"Bundle was: " + JSON.stringify(bundle, null, 2));
}
options = options || osc.defaults;
var bundleCollection = osc.collectBundlePackets(bundle, options);
return osc.joinParts(bundleCollection);
};
osc.isValidBundle = function (bundle) {
return bundle.timeTag !== undefined && bundle.packets !== undefined;
};
...
collectMessageParts = function (msg, options, dataCollection) { dataCollection = dataCollection || { byteLength: 0, parts: [] }; osc.addDataPart(osc.writeString(msg.address), dataCollection); return osc.collectArguments(msg.args, options, dataCollection); }
...
options = options || osc.defaults;
if (!osc.isValidMessage(msg)) {
throw new Error("An OSC message must contain a valid address. Message was: " +
JSON.stringify(msg, null, 2));
}
var msgCollection = osc.collectMessageParts(msg, options);
return osc.joinParts(msgCollection);
};
osc.isValidMessage = function (msg) {
return msg.address && msg.address.indexOf("/") === 0;
};
...
copyByteArray = function (source, target, offset) { if (osc.isTypedArrayView(source) && osc.isTypedArrayView(target)) { target.set(source, offset); } else { var start = offset === undefined ? 0 : offset, len = Math.min(target.length - offset, source.length); for (var i = 0, j = start; i < len; i++, j++) { target[j] = source[i]; } } return target; }
...
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
offset = 0;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
osc.copyByteArray(part, buf, offset);
offset += part.length;
}
return buf;
};
// Unsupported, non-API function.
...
dataView = function (obj, offset, length) { if (obj.buffer) { return new DataView(obj.buffer, offset, length); } if (obj instanceof ArrayBuffer) { return new DataView(obj, offset, length); } return new DataView(new Uint8Array(obj), offset, length); }
...
* @param {Object} [options] read options
* @param {Object} [offsetState] an offsetState object that stores the current offset into dv
* @return {Object} the OSC message, formatted as a JavaScript object containing "address" and "args" properties
*/
osc.readMessage = function (data, options, offsetState) {
options = options || osc.defaults;
var dv = osc.dataView(data, data.byteOffset, data.byteLength);
offsetState = offsetState || {
idx: 0
};
var address = osc.readString(dv, offsetState);
return osc.readMessageContents(address, dv, options, offsetState);
};
...
fireBundleEvents = function (port, bundle, timeTag, packetInfo) { port.emit("bundle", bundle, timeTag, packetInfo); for (var i = 0; i < bundle.packets.length; i++) { var packet = bundle.packets[i]; osc.firePacketEvents(port, packet, bundle.timeTag, packetInfo); } }
...
"use strict";
// Unsupported, non-API function.
osc.firePacketEvents = function (port, packet, timeTag, packetInfo) {
if (packet.address) {
port.emit("message", packet, timeTag, packetInfo);
} else {
osc.fireBundleEvents(port, packet, timeTag, packetInfo);
}
};
// Unsupported, non-API function.
osc.fireBundleEvents = function (port, bundle, timeTag, packetInfo) {
port.emit("bundle", bundle, timeTag, packetInfo);
for (var i = 0; i < bundle.packets.length; i++) {
...
fireClosedPortSendError = function (port, msg) { msg = msg || "Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open()."; port.emit("error", msg); }
...
p.listen = function () {
osc.listenToTransport(this, chrome.serial, "connectionId");
};
p.sendRaw = function (encoded) {
if (!this.connectionId) {
osc.fireClosedPortSendError(this);
return;
}
var that = this;
// TODO gh-39: This is unsafe; we should only access the underlying
// buffer within the range of its view.
...
firePacketEvents = function (port, packet, timeTag, packetInfo) { if (packet.address) { port.emit("message", packet, timeTag, packetInfo); } else { osc.fireBundleEvents(port, packet, timeTag, packetInfo); } }
...
};
// Unsupported, non-API function.
osc.fireBundleEvents = function (port, bundle, timeTag, packetInfo) {
port.emit("bundle", bundle, timeTag, packetInfo);
for (var i = 0; i < bundle.packets.length; i++) {
var packet = bundle.packets[i];
osc.firePacketEvents(port, packet, bundle.timeTag, packetInfo);
}
};
osc.fireClosedPortSendError = function (port, msg) {
msg = msg || "Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open()."
;;
port.emit("error", msg);
...
inferTypeForArgument = function (arg) { var type = typeof arg; // TODO: This is freaking hideous. switch (type) { case "boolean": return arg ? "T" : "F"; case "string": return "s"; case "number": return "f"; case "undefined": return "N"; case "object": if (arg === null) { return "N"; } else if (arg instanceof Uint8Array || arg instanceof ArrayBuffer) { return "b"; } else if (typeof arg.high === "number" && typeof arg.low === "number") { return "h"; } break; } throw new Error("Can't infer OSC argument type for value: " + JSON.stringify(arg, null, 2)); }
...
// We've got an explicitly typed argument.
msgArg = arg;
} else if (osc.isArray(arg)) {
// We've got an array of arguments,
// so they each need to be inferred and expanded.
msgArg = osc.annotateArguments(arg);
} else {
var oscType = osc.inferTypeForArgument(arg);
msgArg = {
type: oscType,
value: arg
};
}
annotated.push(msgArg);
...
isArray = function (obj) { return obj && Object.prototype.toString.call(obj) === "[object Array]"; }
...
typeTag += "]";
return typeTag;
};
osc.writeArgument = function (arg, dataCollection) {
if (osc.isArray(arg)) {
return osc.writeArrayArguments(arg, dataCollection);
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
...
isBuffer = function (obj) { return osc.isBufferEnv && obj instanceof Buffer; }
...
*
* @param {Array-like or Array-wrapping} obj an array-like or array-wrapping object
* @returns {Buffer|Uint8Array} a buffer object
*/
// Unsupported, non-API function.
osc.nativeBuffer = function (obj) {
if (osc.isBufferEnv) {
return osc.isBuffer(obj) ? obj :
new Buffer(obj.buffer ? obj : new Uint8Array(obj));
}
return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj);
};
// Unsupported, non-API function
...
isTypedArrayView = function (obj) { return obj.buffer && obj.buffer instanceof ArrayBuffer; }
...
// Unsupported, non-API function.
osc.nativeBuffer = function (obj) {
if (osc.isBufferEnv) {
return osc.isBuffer(obj) ? obj :
new Buffer(obj.buffer ? obj : new Uint8Array(obj));
}
return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj);
};
// Unsupported, non-API function
osc.copyByteArray = function (source, target, offset) {
if (osc.isTypedArrayView(source) && osc.isTypedArrayView(target)) {
target.set(source, offset);
} else {
...
isValidBundle = function (bundle) { return bundle.timeTag !== undefined && bundle.packets !== undefined; }
...
* Writes an OSC bundle.
*
* @param {Object} a bundle object containing "timeTag" and "packets" properties
* @param {object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writeBundle = function (bundle, options) {
if (!osc.isValidBundle(bundle)) {
throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " +
"Bundle was: " + JSON.stringify(bundle, null, 2));
}
options = options || osc.defaults;
var bundleCollection = osc.collectBundlePackets(bundle, options);
...
isValidMessage = function (msg) { return msg.address && msg.address.indexOf("/") === 0; }
...
* @param {Object} msg a message object containing "address" and "args" properties
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the OSC message
*/
osc.writeMessage = function (msg, options) {
options = options || osc.defaults;
if (!osc.isValidMessage(msg)) {
throw new Error("An OSC message must contain a valid address. Message was: " +
JSON.stringify(msg, null, 2));
}
var msgCollection = osc.collectMessageParts(msg, options);
return osc.joinParts(msgCollection);
};
...
joinParts = function (dataCollection) { var buf = new Uint8Array(dataCollection.byteLength), parts = dataCollection.parts, offset = 0; for (var i = 0; i < parts.length; i++) { var part = parts[i]; osc.copyByteArray(part, buf, offset); offset += part.length; } return buf; }
...
*
* @param {Array} args an array of arguments
* @param {Object} options options for writing
* @return {Uint8Array} a buffer containing the OSC-formatted argument type tag and values
*/
osc.writeArguments = function (args, options) {
var argCollection = osc.collectArguments(args, options);
return osc.joinParts(argCollection);
};
// Unsupported, non-API function.
osc.joinParts = function (dataCollection) {
var buf = new Uint8Array(dataCollection.byteLength),
parts = dataCollection.parts,
offset = 0;
...
jsToNTPTime = function (jsTime) { var secs = jsTime / 1000, secsWhole = Math.floor(secs), secsFrac = secs - secsWhole, ntpSecs = secsWhole + osc.SECS_70YRS, ntpFracs = Math.round(osc.TWO_32 * secsFrac); return [ntpSecs, ntpFracs]; }
...
* values. The first represents the number of seconds since January 1, 1900; the second, fractions of a second.
* "Native" JavaScript timestamps are specified as a Number representing milliseconds since January 1, 1970.
*
* @param {Object} timeTag time tag object containing either a native JS timestamp (in ms) or a NTP timestamp pair
* @return {Uint8Array} raw bytes for the written time tag
*/
osc.writeTimeTag = function (timeTag) {
var raw = timeTag.raw ? timeTag.raw : osc.jsToNTPTime(timeTag.native),
arr = new Uint8Array(8), // Two Unit32s.
dv = new DataView(arr.buffer);
osc.writeInt32(raw[0], dv, 0);
osc.writeInt32(raw[1], dv, 4);
return arr;
...
nativeBuffer = function (obj) { if (osc.isBufferEnv) { return osc.isBuffer(obj) ? obj : new Buffer(obj.buffer ? obj : new Uint8Array(obj)); } return osc.isTypedArrayView(obj) ? obj : new Uint8Array(obj); }
...
var p = osc.Port.prototype = Object.create(EventEmitter.prototype);
p.constructor = osc.Port;
p.send = function (oscPacket) {
var args = Array.prototype.slice.call(arguments),
encoded = this.encodeOSC(oscPacket),
buf = osc.nativeBuffer(encoded);
args[0] = buf;
this.sendRaw.apply(this, args);
};
p.encodeOSC = function (packet) {
// TODO gh-39: This is unsafe; we should only access the underlying
...
ntpToJSTime = function (secs1900, frac) { var secs1970 = secs1900 - osc.SECS_70YRS, decimals = frac / osc.TWO_32, msTime = (secs1970 + decimals) * 1000; return msTime; }
...
* @param {DataView} dv the DataView instance to read from
* @param {Object} offsetState an offset state object containing the current index into dv
* @param {Object} a time tag object containing both the raw NTP as well as the converted native (i.e. JS/UNIX) time
*/
osc.readTimeTag = function (dv, offsetState) {
var secs1900 = osc.readPrimitive(dv, "getUint32", 4, offsetState),
frac = osc.readPrimitive(dv, "getUint32", 4, offsetState),
native = (secs1900 === 0 && frac === 1) ? Date.now() : osc.ntpToJSTime(secs1900, frac);
return {
raw: [secs1900, frac],
native: native
};
};
...
readArgument = function (argType, typeTagString, dv, options, offsetState) { var typeSpec = osc.argumentTypes[argType]; if (!typeSpec) { throw new Error("'" + argType + "' is not a valid OSC type tag. Type tag string was: " + typeTagString); } var argReader = typeSpec.reader, arg = osc[argReader](dv, offsetState); if (options.metadata) { arg = { type: argType, value: arg }; } return arg; }
...
"without a matching close array tag ('[]'). Type tag was: " + typeTagString);
}
var typesInArray = fromArrayOpen.slice(0, endArrayIdx);
arg = osc.readArgumentsIntoArray([], typesInArray, typeTagString, dv, options, offsetState);
i += endArrayIdx + 2;
} else {
arg = osc.readArgument(argType, typeTagString, dv, options, offsetState);
i++;
}
arr.push(arg);
}
return arr;
...
readArguments = function (dv, options, offsetState) { var typeTagString = osc.readString(dv, offsetState); if (typeTagString.indexOf(",") !== 0) { // Despite what the OSC 1.0 spec says, // it just doesn't make sense to handle messages without type tags. // scsynth appears to read such messages as if they have a single // Uint8 argument. sclang throws an error if the type tag is omitted. throw new Error("A malformed type tag string was found while reading " + "the arguments of an OSC message. String was: " + typeTagString, " at offset: " + offsetState.idx); } var argTypes = typeTagString.substring(1).split(""), args = []; osc.readArgumentsIntoArray(args, argTypes, typeTagString, dv, options, offsetState); return args; }
...
// Unsupported, non-API function.
osc.readMessageContents = function (address, dv, options, offsetState) {
if (address.indexOf("/") !== 0) {
throw new Error("A malformed OSC address was found while reading " +
"an OSC message. String was: " + address);
}
var args = osc.readArguments(dv, options, offsetState);
return {
address: address,
args: args.length === 1 && options.unpackSingleArgs ? args[0] : args
};
};
...
readArgumentsIntoArray = function (arr, argTypes, typeTagString, dv, options, offsetState) { var i = 0; while (i < argTypes.length) { var argType = argTypes[i], arg; if (argType === "[") { var fromArrayOpen = argTypes.slice(i + 1), endArrayIdx = fromArrayOpen.indexOf("]"); if (endArrayIdx < 0) { throw new Error("Invalid argument type tag: an open array type tag ('[') was found " + "without a matching close array tag ('[]'). Type tag was: " + typeTagString); } var typesInArray = fromArrayOpen.slice(0, endArrayIdx); arg = osc.readArgumentsIntoArray([], typesInArray, typeTagString, dv, options, offsetState); i += endArrayIdx + 2; } else { arg = osc.readArgument(argType, typeTagString, dv, options, offsetState); i++; } arr.push(arg); } return arr; }
...
"the arguments of an OSC message. String was: " +
typeTagString, " at offset: " + offsetState.idx);
}
var argTypes = typeTagString.substring(1).split(""),
args = [];
osc.readArgumentsIntoArray(args, argTypes, typeTagString, dv, options, offsetState
);
return args;
};
// Unsupported, non-API function.
osc.readArgument = function (argType, typeTagString, dv, options, offsetState) {
var typeSpec = osc.argumentTypes[argType];
...
readBlob = function (dv, offsetState) { var len = osc.readInt32(dv, offsetState), paddedLen = (len + 3) & ~0x03, blob = new Uint8Array(dv.buffer, offsetState.idx, len); offsetState.idx += paddedLen; return blob; }
n/a
readBundle = function (dv, options, offsetState) { return osc.readPacket(dv, options, offsetState); }
n/a
readBundleContents = function (dv, options, offsetState, len) { var timeTag = osc.readTimeTag(dv, offsetState), packets = []; while (offsetState.idx < len) { var packetSize = osc.readInt32(dv, offsetState), packetLen = offsetState.idx + packetSize, packet = osc.readPacket(dv, options, offsetState, packetLen); packets.push(packet); } return { timeTag: timeTag, packets: packets }; }
...
idx: 0
};
var header = osc.readString(dv, offsetState),
firstChar = header[0];
if (firstChar === "#") {
return osc.readBundleContents(dv, options, offsetState, len);
} else if (firstChar === "/") {
return osc.readMessageContents(header, dv, options, offsetState);
}
throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string." +
" Header was: " + header);
};
...
readChar32 = function (dv, offsetState) { var charCode = osc.readPrimitive(dv, "getUint32", 4, offsetState); return String.fromCharCode(charCode); }
n/a
readColor = function (dv, offsetState) { var bytes = new Uint8Array(dv.buffer, offsetState.idx, 4), alpha = bytes[3] / 255; offsetState.idx += 4; return { r: bytes[0], g: bytes[1], b: bytes[2], a: alpha }; }
n/a
readFalse = function () { return false; }
n/a
readFloat32 = function (dv, offsetState) { return osc.readPrimitive(dv, "getFloat32", 4, offsetState); }
n/a
readFloat64 = function (dv, offsetState) { return osc.readPrimitive(dv, "getFloat64", 8, offsetState); }
n/a
readImpulse = function () { return 1.0; }
n/a
readInt32 = function (dv, offsetState) { return osc.readPrimitive(dv, "getInt32", 4, offsetState); }
...
* Reads an OSC blob ("b") (i.e. a Uint8Array).
*
* @param {DataView} dv a DataView instance to read from
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
* @return {Uint8Array} the data that was read
*/
osc.readBlob = function (dv, offsetState) {
var len = osc.readInt32(dv, offsetState),
paddedLen = (len + 3) & ~0x03,
blob = new Uint8Array(dv.buffer, offsetState.idx, len);
offsetState.idx += paddedLen;
return blob;
};
...
readInt64 = function (dv, offsetState) { var high = osc.readPrimitive(dv, "getInt32", 4, offsetState), low = osc.readPrimitive(dv, "getInt32", 4, offsetState); if (Long) { return new Long(low, high); } else { return { high: high, low: low, unsigned: false }; } }
n/a
readMIDIBytes = function (dv, offsetState) { var midi = new Uint8Array(dv.buffer, offsetState.idx, 4); offsetState.idx += 4; return midi; }
n/a
readMessage = function (data, options, offsetState) { options = options || osc.defaults; var dv = osc.dataView(data, data.byteOffset, data.byteLength); offsetState = offsetState || { idx: 0 }; var address = osc.readString(dv, offsetState); return osc.readMessageContents(address, dv, options, offsetState); }
n/a
readMessageContents = function (address, dv, options, offsetState) { if (address.indexOf("/") !== 0) { throw new Error("A malformed OSC address was found while reading " + "an OSC message. String was: " + address); } var args = osc.readArguments(dv, options, offsetState); return { address: address, args: args.length === 1 && options.unpackSingleArgs ? args[0] : args }; }
...
var dv = osc.dataView(data, data.byteOffset, data.byteLength);
offsetState = offsetState || {
idx: 0
};
var address = osc.readString(dv, offsetState);
return osc.readMessageContents(address, dv, options, offsetState);
};
// Unsupported, non-API function.
osc.readMessageContents = function (address, dv, options, offsetState) {
if (address.indexOf("/") !== 0) {
throw new Error("A malformed OSC address was found while reading " +
"an OSC message. String was: " + address);
...
readNull = function () { return null; }
n/a
readPacket = function (data, options, offsetState, len) { var dv = osc.dataView(data, data.byteOffset, data.byteLength); len = len === undefined ? dv.byteLength : len; offsetState = offsetState || { idx: 0 }; var header = osc.readString(dv, offsetState), firstChar = header[0]; if (firstChar === "#") { return osc.readBundleContents(dv, options, offsetState, len); } else if (firstChar === "/") { return osc.readMessageContents(header, dv, options, offsetState); } throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string." + " Header was: " + header); }
...
they should be caught and handled using
<code>try</code>/<code>catch</code>.
```javascript
var msg;
try {
msg = osc.readPacket(rawPacket);
} catch (error) {
console.log("An error occurred: ", error.message);
}
```
The osc.js Low-Level API
------------------------
...
readPrimitive = function (dv, readerName, numBytes, offsetState) { var val = dv[readerName](offsetState.idx, false); offsetState.idx += numBytes; return val; }
...
* Reads an OSC int32 ("i") value.
*
* @param {DataView} dv a DataView containing the raw bytes
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
* @return {Number} the number that was read
*/
osc.readInt32 = function (dv, offsetState) {
return osc.readPrimitive(dv, "getInt32", 4, offsetState);
};
/**
* Writes an OSC int32 ("i") value.
*
* @param {Number} val the number to write
* @param {DataView} [dv] a DataView instance to write the number into
...
readString = function (dv, offsetState) { var charCodes = [], idx = offsetState.idx; for (; idx < dv.byteLength; idx++) { var charCode = dv.getUint8(idx); if (charCode !== 0) { charCodes.push(charCode); } else { idx++; break; } } // Round to the nearest 4-byte block. idx = (idx + 3) & ~0x03; offsetState.idx = idx; return String.fromCharCode.apply(null, charCodes); }
...
*
* @param {DataView} dv a DataView instance to read from
* @param {Object} offsetState the offsetState object that stores the current offset into dv
* @param {Oobject} [options] read options
* @return {Array} an array of the OSC arguments that were read
*/
osc.readArguments = function (dv, options, offsetState) {
var typeTagString = osc.readString(dv, offsetState);
if (typeTagString.indexOf(",") !== 0) {
// Despite what the OSC 1.0 spec says,
// it just doesn't make sense to handle messages without type tags.
// scsynth appears to read such messages as if they have a single
// Uint8 argument. sclang throws an error if the type tag is omitted.
throw new Error("A malformed type tag string was found while reading " +
"the arguments of an OSC message. String was: " +
...
readTimeTag = function (dv, offsetState) { var secs1900 = osc.readPrimitive(dv, "getUint32", 4, offsetState), frac = osc.readPrimitive(dv, "getUint32", 4, offsetState), native = (secs1900 === 0 && frac === 1) ? Date.now() : osc.ntpToJSTime(secs1900, frac); return { raw: [secs1900, frac], native: native }; }
...
osc.isValidBundle = function (bundle) {
return bundle.timeTag !== undefined && bundle.packets !== undefined;
};
// Unsupported, non-API function.
osc.readBundleContents = function (dv, options, offsetState, len) {
var timeTag = osc.readTimeTag(dv, offsetState),
packets = [];
while (offsetState.idx < len) {
var packetSize = osc.readInt32(dv, offsetState),
packetLen = offsetState.idx + packetSize,
packet = osc.readPacket(dv, options, offsetState, packetLen);
...
readTrue = function () { return true; }
n/a
relay = function (from, to, eventName, sendFnName, transformFn, sendArgs) { eventName = eventName || "message"; sendFnName = sendFnName || "send"; transformFn = transformFn || function () {}; sendArgs = sendArgs ? [null].concat(sendArgs) : []; var listener = function (data) { sendArgs[0] = data; data = transformFn(data); to[sendFnName].apply(to, sendArgs); }; from.on(eventName, listener); return { eventName: eventName, listener: listener }; }
...
};
// Unsupported, non-API function.
osc.relayPorts = function (from, to, o) {
var eventName = o.raw ? "raw" : "osc",
sendFnName = o.raw ? "sendRaw" : "send";
return osc.relay(from, to, eventName, sendFnName, o.transform);
};
// Unsupported, non-API function.
osc.stopRelaying = function (from, relaySpec) {
from.removeListener(relaySpec.eventName, relaySpec.listener);
};
...
relayPorts = function (from, to, o) { var eventName = o.raw ? "raw" : "osc", sendFnName = o.raw ? "sendRaw" : "send"; return osc.relay(from, to, eventName, sendFnName, o.transform); }
...
};
p.listen = function () {
if (this.port1Spec && this.port2Spec) {
this.close();
}
this.port1Spec = osc.relayPorts(this.port1, this.port2, this.options);
this.port2Spec = osc.relayPorts(this.port2, this.port1, this.options);
// Bind port close listeners to ensure that the relay
// will stop forwarding messages if one of its ports close.
// Users are still responsible for closing the underlying ports
// if necessary.
var closeListener = this.close.bind(this);
...
stopRelaying = function (from, relaySpec) { from.removeListener(relaySpec.eventName, relaySpec.listener); }
...
// if necessary.
var closeListener = this.close.bind(this);
this.port1.on("close", closeListener);
this.port2.on("close", closeListener);
};
p.close = function () {
osc.stopRelaying(this.port1, this.port1Spec);
osc.stopRelaying(this.port2, this.port2Spec);
this.emit("close", this.port1, this.port2);
};
// If we're in a require-compatible environment, export ourselves.
if (typeof module !== "undefined" && module.exports) {
...
timeTag = function (secs, now) { secs = secs || 0; now = now || Date.now(); var nowSecs = now / 1000, nowWhole = Math.floor(nowSecs), nowFracs = nowSecs - nowWhole, secsWhole = Math.floor(secs), secsFracs = secs - secsWhole, fracs = nowFracs + secsFracs; if (fracs > 1) { var fracsWhole = Math.floor(fracs), fracsFracs = fracs - fracsWhole; secsWhole += fracsWhole; fracs = fracsFracs; } var ntpSecs = nowWhole + secsWhole + osc.SECS_70YRS, ntpFracs = Math.round(osc.TWO_32 * fracs); return { raw: [ntpSecs, ntpFracs] }; }
...
});
```
##### Sending OSC bundles:
```javascript
oscPort.on("ready", function () {
oscPort.send({
timeTag: osc.timeTag(60), // Schedules this bundle 60 seconds from now.
packets: [
{
address: "/carrier/frequency",
args: 440
},
{
address: "/carrier/amplitude"
...
writeArgument = function (arg, dataCollection) { if (osc.isArray(arg)) { return osc.writeArrayArguments(arg, dataCollection); } var type = arg.type, writer = osc.argumentTypes[type].writer; if (writer) { var data = osc[writer](arg.value); osc.addDataPart(data, dataCollection); } return arg.type; }
...
};
osc.writeArrayArguments = function (args, dataCollection) {
var typeTag = "[";
for (var i = 0; i < args.length; i++) {
var arg = args[i];
typeTag += osc.writeArgument(arg, dataCollection);
}
typeTag += "]";
return typeTag;
};
...
writeArguments = function (args, options) { var argCollection = osc.collectArguments(args, options); return osc.joinParts(argCollection); }
n/a
writeArrayArguments = function (args, dataCollection) { var typeTag = "["; for (var i = 0; i < args.length; i++) { var arg = args[i]; typeTag += osc.writeArgument(arg, dataCollection); } typeTag += "]"; return typeTag; }
...
typeTag += "]";
return typeTag;
};
osc.writeArgument = function (arg, dataCollection) {
if (osc.isArray(arg)) {
return osc.writeArrayArguments(arg, dataCollection);
}
var type = arg.type,
writer = osc.argumentTypes[type].writer;
if (writer) {
var data = osc[writer](arg.value);
...
writeBlob = function (data) { data = osc.byteArray(data); var len = data.byteLength, paddedLen = (len + 3) & ~0x03, offset = 4, // Extra 4 bytes is for the size. blobLen = paddedLen + offset, arr = new Uint8Array(blobLen), dv = new DataView(arr.buffer); // Write the size. osc.writeInt32(len, dv); // Since we're writing to a real ArrayBuffer, // we don't need to pad the remaining bytes. arr.set(data, offset); return arr; }
n/a
writeBundle = function (bundle, options) { if (!osc.isValidBundle(bundle)) { throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. " + "Bundle was: " + JSON.stringify(bundle, null, 2)); } options = options || osc.defaults; var bundleCollection = osc.collectBundlePackets(bundle, options); return osc.joinParts(bundleCollection); }
...
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writePacket = function (packet, options) {
if (osc.isValidMessage(packet)) {
return osc.writeMessage(packet, options);
} else if (osc.isValidBundle(packet)) {
return osc.writeBundle(packet, options);
} else {
throw new Error("The specified packet was not recognized as a valid OSC message or bundle." +
" Packet was: " + JSON.stringify(packet, null, 2));
}
};
// Unsupported, non-API.
...
writeChar32 = function (str, dv, offset) { var charCode = str.charCodeAt(0); if (charCode === undefined || charCode < -1) { return undefined; } return osc.writePrimitive(charCode, dv, "setUint32", 4, offset); }
n/a
writeColor = function (color) { var alpha = Math.round(color.a * 255), arr = new Uint8Array([color.r, color.g, color.b, alpha]); return arr; }
n/a
writeFloat32 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setFloat32", 4, offset); }
n/a
writeFloat64 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setFloat64", 8, offset); }
n/a
writeInt32 = function (val, dv, offset) { return osc.writePrimitive(val, dv, "setInt32", 4, offset); }
...
paddedLen = (len + 3) & ~0x03,
offset = 4, // Extra 4 bytes is for the size.
blobLen = paddedLen + offset,
arr = new Uint8Array(blobLen),
dv = new DataView(arr.buffer);
// Write the size.
osc.writeInt32(len, dv);
// Since we're writing to a real ArrayBuffer,
// we don't need to pad the remaining bytes.
arr.set(data, offset);
return arr;
};
...
writeInt64 = function (val, dv, offset) { var arr = new Uint8Array(8); arr.set(osc.writePrimitive(val.high, dv, "setInt32", 4, offset), 0); arr.set(osc.writePrimitive(val.low, dv, "setInt32", 4, offset + 4), 4); return arr; }
n/a
writeMIDIBytes = function (bytes) { bytes = osc.byteArray(bytes); var arr = new Uint8Array(4); arr.set(bytes); return arr; }
n/a
writeMessage = function (msg, options) { options = options || osc.defaults; if (!osc.isValidMessage(msg)) { throw new Error("An OSC message must contain a valid address. Message was: " + JSON.stringify(msg, null, 2)); } var msgCollection = osc.collectMessageParts(msg, options); return osc.joinParts(msgCollection); }
...
*
* @param {Object} a bundle or message object
* @param {Object} [options] write options
* @return {Uint8Array} an array of bytes containing the message
*/
osc.writePacket = function (packet, options) {
if (osc.isValidMessage(packet)) {
return osc.writeMessage(packet, options);
} else if (osc.isValidBundle(packet)) {
return osc.writeBundle(packet, options);
} else {
throw new Error("The specified packet was not recognized as a valid OSC message or bundle." +
" Packet was: " + JSON.stringify(packet, null, 2));
}
};
...
writePacket = function (packet, options) { if (osc.isValidMessage(packet)) { return osc.writeMessage(packet, options); } else if (osc.isValidBundle(packet)) { return osc.writeBundle(packet, options); } else { throw new Error("The specified packet was not recognized as a valid OSC message or bundle." + " Packet was: " + JSON.stringify(packet, null, 2)); } }
...
<code>options</code>: (optional) An options object, described below; <br />
<code>offsetState</code>: (optional) an offset state object containing an <code>idx</
code> property that specifies the offset index into <code>data</code>; <br />
<code>length</code> the length (in bytes) to read from <code>data</code>
</td>
<td>An osc.js message or bundle object</td>
</tr>
<tr>
<td><code>osc.writePacket()</code></td>
<td>Writes an OSC message or bundle object to a binary array.</td>
<td>
<code>packate</code>: An osc.js message or bundle object;<br />
<code>options</code>: (optional) An options object, described below<br />
</td>
<td>A <code>Uint8Array</code></td>
</tr>
...
writePrimitive = function (val, dv, writerName, numBytes, offset) { offset = offset === undefined ? 0 : offset; var arr; if (!dv) { arr = new Uint8Array(numBytes); dv = new DataView(arr.buffer); } else { arr = new Uint8Array(dv.buffer); } dv[writerName](offset, val, false); return arr; }
...
* Writes an OSC int32 ("i") value.
*
* @param {Number} val the number to write
* @param {DataView} [dv] a DataView instance to write the number into
* @param {Number} [offset] an offset into dv
*/
osc.writeInt32 = function (val, dv, offset) {
return osc.writePrimitive(val, dv, "setInt32", 4, offset);
};
/**
* Reads an OSC int64 ("h") value.
*
* @param {DataView} dv a DataView containing the raw bytes
* @param {Object} offsetState an offsetState object used to store the current offset index into dv
...
writeString = function (str) { var terminated = str + "\u0000", len = terminated.length, paddedLen = (len + 3) & ~0x03, arr = new Uint8Array(paddedLen); for (var i = 0; i < terminated.length; i++) { var charCode = terminated.charCodeAt(i); arr[i] = charCode; } return arr; }
...
currPartIdx = dataCollection.parts.length;
for (var i = 0; i < args.length; i++) {
var arg = args[i];
typeTagString += osc.writeArgument(arg, dataCollection);
}
var typeData = osc.writeString(typeTagString);
dataCollection.byteLength += typeData.byteLength;
dataCollection.parts.splice(currPartIdx, 0, typeData);
return dataCollection;
};
/**
...
writeTimeTag = function (timeTag) { var raw = timeTag.raw ? timeTag.raw : osc.jsToNTPTime(timeTag.native), arr = new Uint8Array(8), // Two Unit32s. dv = new DataView(arr.buffer); osc.writeInt32(raw[0], dv, 0); osc.writeInt32(raw[1], dv, 4); return arr; }
...
osc.collectBundlePackets = function (bundle, options, dataCollection) {
dataCollection = dataCollection || {
byteLength: 0,
parts: []
};
osc.addDataPart(osc.writeString("#bundle"), dataCollection);
osc.addDataPart(osc.writeTimeTag(bundle.timeTag), dataCollection);
for (var i = 0; i < bundle.packets.length; i++) {
var packet = bundle.packets[i],
collector = packet.address ? osc.collectMessageParts : osc.collectBundlePackets,
packetCollection = collector(packet, options);
dataCollection.byteLength += packetCollection.byteLength;
...