rob@77: var min = require('osc-min'); rob@77: var dgram = require('dgram'); rob@77: var util = require('util'); rob@77: var events = require('events'); rob@77: var jspack = require('jspack').jspack; rob@77: rob@77: //////////////////// rob@77: // OSC Message rob@77: //////////////////// rob@77: rob@77: rob@77: function Message(address) { rob@77: this.oscType = "message"; rob@77: this.address = address; rob@77: this.args = []; rob@77: rob@77: for (var i = 1; i < arguments.length; i++) { rob@77: this.append(arguments[i]); rob@77: } rob@77: } rob@77: rob@77: Message.prototype = { rob@77: append: function (arg) { rob@77: switch (typeof arg) { rob@77: case 'object': rob@77: if (arg.type) { rob@77: this.args.push(arg); rob@77: } else { rob@77: throw new Error("don't know how to encode object " + arg) rob@77: } rob@77: break; rob@77: case 'number': rob@77: if (Math.floor(arg) == arg) { rob@77: var argOut = new Argument('integer', arg); rob@77: this.args.push(argOut); rob@77: } else { rob@77: var argOut = new Argument('float', arg); rob@77: this.args.push(argOut); rob@77: } rob@77: break; rob@77: case 'string': rob@77: var argOut = new Argument('string', arg); rob@77: this.args.push(argOut); rob@77: break; rob@77: default: rob@77: throw new Error("don't know how to encode " + arg); rob@77: } rob@77: } rob@77: } rob@77: rob@77: exports.Message = Message; rob@77: rob@77: function Argument(type, value){ rob@77: this.type = type; rob@77: this.value = value; rob@77: } rob@77: rob@77: //////////////////// rob@77: // OSC Client rob@77: //////////////////// rob@77: rob@77: var Client = function (host, port) { rob@77: this.host = host; rob@77: this.port = port; rob@77: this._sock = dgram.createSocket('udp4'); rob@77: } rob@77: rob@77: Client.prototype = { rob@77: send: function (message) { rob@77: switch (typeof message) { rob@77: case 'object': rob@77: var buf = min.toBuffer(message); rob@77: this._sock.send(buf, 0, buf.length, this.port, this.host); rob@77: break; rob@77: case 'string': rob@77: mes = new Message(arguments[0]); rob@77: for (var i = 1; i < arguments.length; i++) { rob@77: mes.append(arguments[i]); rob@77: } rob@77: var buf = min.toBuffer(mes); rob@77: this._sock.send(buf, 0, buf.length, this.port, this.host); rob@77: break; rob@77: default: rob@77: throw new Error("That Message Just Doesn't Seem Right"); rob@77: } rob@77: } rob@77: } rob@77: rob@77: exports.Client = Client; rob@77: rob@77: //////////////////// rob@77: // OSC Message encoding and decoding functions rob@77: //////////////////// rob@77: rob@77: function ShortBuffer(type, buf, requiredLength) rob@77: { rob@77: this.type = "ShortBuffer"; rob@77: var message = "buffer ["; rob@77: for (var i = 0; i < buf.length; i++) { rob@77: if (i) { rob@77: message += ", "; rob@77: } rob@77: message += buf.charCodeAt(i); rob@77: } rob@77: message += "] too short for " + type + ", " + requiredLength + " bytes required"; rob@77: this.message = message; rob@77: } rob@77: rob@77: function TString (value) { this.value = value; } rob@77: TString.prototype = { rob@77: typetag: 's', rob@77: decode: function (data) { rob@77: var end = 0; rob@77: while (data[end] && end < data.length) { rob@77: end++; rob@77: } rob@77: if (end == data.length) { rob@77: throw Error("OSC string not null terminated"); rob@77: } rob@77: this.value = data.toString('ascii', 0, end); rob@77: var nextData = parseInt(Math.ceil((end + 1) / 4.0) * 4); rob@77: return data.slice(nextData); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: var len = Math.ceil((this.value.length + 1) / 4.0) * 4; rob@77: return jspack.PackTo('>' + len + 's', buf, pos, [ this.value ]); rob@77: } rob@77: } rob@77: exports.TString = TString; rob@77: rob@77: function TInt (value) { this.value = value; } rob@77: TInt.prototype = { rob@77: typetag: 'i', rob@77: decode: function (data) { rob@77: if (data.length < 4) { rob@77: throw new ShortBuffer('int', data, 4); rob@77: } rob@77: rob@77: this.value = jspack.Unpack('>i', data.slice(0, 4))[0]; rob@77: return data.slice(4); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: return jspack.PackTo('>i', buf, pos, [ this.value ]); rob@77: } rob@77: } rob@77: exports.TInt = TInt; rob@77: rob@77: function TTime (value) { this.value = value; } rob@77: TTime.prototype = { rob@77: typetag: 't', rob@77: decode: function (data) { rob@77: if (data.length < 8) { rob@77: throw new ShortBuffer('time', data, 8); rob@77: } rob@77: var raw = jspack.Unpack('>LL', data.slice(0, 8)); rob@77: var secs = raw[0]; rob@77: var fracs = raw[1]; rob@77: this.value = secs + fracs / 4294967296; rob@77: return data.slice(8); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: return jspack.PackTo('>LL', buf, pos, this.value); rob@77: } rob@77: } rob@77: exports.TTime = TTime; rob@77: rob@77: function TFloat (value) { this.value = value; } rob@77: TFloat.prototype = { rob@77: typetag: 'f', rob@77: decode: function (data) { rob@77: if (data.length < 4) { rob@77: throw new ShortBuffer('float', data, 4); rob@77: } rob@77: rob@77: this.value = jspack.Unpack('>f', data.slice(0, 4))[0]; rob@77: return data.slice(4); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: return jspack.PackTo('>f', buf, pos, [ this.value ]); rob@77: } rob@77: } rob@77: exports.TFloat = TFloat; rob@77: rob@77: function TBlob (value) { this.value = value; } rob@77: TBlob.prototype = { rob@77: typetag: 'b', rob@77: decode: function (data) { rob@77: var length = jspack.Unpack('>i', data.slice(0, 4))[0]; rob@77: var nextData = parseInt(Math.ceil((length) / 4.0) * 4) + 4; rob@77: this.value = data.slice(4, length + 4); rob@77: return data.slice(nextData); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: var len = Math.ceil((this.value.length) / 4.0) * 4; rob@77: return jspack.PackTo('>i' + len + 's', buf, pos, [len, this.value]); rob@77: } rob@77: } rob@77: exports.TBlob = TBlob; rob@77: rob@77: function TDouble (value) { this.value = value; } rob@77: TDouble.prototype = { rob@77: typetag: 'd', rob@77: decode: function (data) { rob@77: if (data.length < 8) { rob@77: throw new ShortBuffer('double', data, 8); rob@77: } rob@77: this.value = jspack.Unpack('>d', data.slice(0, 8))[0]; rob@77: return data.slice(8); rob@77: }, rob@77: encode: function (buf, pos) { rob@77: return jspack.PackTo('>d', buf, pos, [ this.value ]); rob@77: } rob@77: } rob@77: exports.TDouble = TDouble; rob@77: rob@77: // for each OSC type tag we use a specific constructor function to decode its respective data rob@77: var tagToConstructor = { 'i': function () { return new TInt }, rob@77: 'f': function () { return new TFloat }, rob@77: 's': function () { return new TString }, rob@77: 'b': function () { return new TBlob }, rob@77: 'd': function () { return new TDouble } }; rob@77: rob@77: function decode (data) { rob@77: // this stores the decoded data as an array rob@77: var message = []; rob@77: rob@77: // we start getting the
and