├── .gitignore ├── LICENCE ├── README.md ├── examples ├── before-after.js ├── before-after.js~ ├── run.js ├── run.js~ ├── set.js ├── set.js~ └── sine.sc ├── node_modules └── node-osc │ ├── README.rst │ ├── index.js │ └── lib │ ├── node-jspack │ ├── LICENSE │ ├── README │ └── jspack.js │ └── osc.js └── supercollider.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Konstantinos Patsourakis, George Stagakis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Nodejs client for supercollider still in the very begining trying to implement some more of the basic sc messages... -------------------------------------------------------------------------------- /examples/before-after.js: -------------------------------------------------------------------------------- 1 | var sc = require('../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create synths 9 | lfo = sc.Synth('RingMod', [1,1,'freq',10]) 10 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 11 | 12 | 13 | //apply lfo 14 | setTimeout(function(){ 15 | sine.before(lfo.node) 16 | },1000) 17 | 18 | //move out lfo 19 | setTimeout(function(){ 20 | sine.after(lfo.node) 21 | },2000) 22 | 23 | 24 | 25 | // free 26 | setTimeout(function() { 27 | sine.free() 28 | lfo.free() 29 | process.exit(0) 30 | }, 3000) 31 | 32 | -------------------------------------------------------------------------------- /examples/before-after.js~: -------------------------------------------------------------------------------- 1 | var sc = require('../../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create synths 9 | lfo = sc.Synth('RingMod', [1,1,'freq',10]) 10 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 11 | 12 | 13 | //apply lfo 14 | setTimeout(function(){ 15 | sine.before(lfo.node) 16 | },1000) 17 | 18 | //move out lfo 19 | setTimeout(function(){ 20 | sine.after(lfo.node) 21 | },2000) 22 | 23 | 24 | 25 | // free 26 | setTimeout(function() { 27 | sine.free() 28 | lfo.free() 29 | process.exit(0) 30 | }, 3000) 31 | 32 | -------------------------------------------------------------------------------- /examples/run.js: -------------------------------------------------------------------------------- 1 | var sc = require('../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create a synth 9 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 10 | 11 | // change amp after 500 ms 12 | setTimeout(function() { 13 | sine.run(0) 14 | }, 500) 15 | 16 | // change amp after 500 ms 17 | setTimeout(function() { 18 | sine.run(1) 19 | }, 1000) 20 | 21 | // free after 3000 ms 22 | setTimeout(function() { 23 | sine.free() 24 | process.exit(0) 25 | }, 3000) -------------------------------------------------------------------------------- /examples/run.js~: -------------------------------------------------------------------------------- 1 | var sc = require('../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create a synth 9 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 10 | 11 | // change amp after 500 ms 12 | setTimeout(function() { 13 | sine.set('amp', 0.6) 14 | }, 500) 15 | 16 | // free after 3000 ms 17 | setTimeout(function() { 18 | sine.free() 19 | process.exit(0) 20 | }, 3000) -------------------------------------------------------------------------------- /examples/set.js: -------------------------------------------------------------------------------- 1 | var sc = require('../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create a synth 9 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 10 | 11 | // change amp after 500 ms 12 | setTimeout(function() { 13 | sine.set('freq', 200) 14 | }, 500) 15 | 16 | // free after 3000 ms 17 | setTimeout(function() { 18 | sine.free() 19 | process.exit(0) 20 | }, 3000) -------------------------------------------------------------------------------- /examples/set.js~: -------------------------------------------------------------------------------- 1 | var sc = require('../supercollider')() 2 | 3 | // listen on all messages 4 | sc.on('message', function(message, address) { 5 | console.log('message:', message, address) 6 | }) 7 | 8 | // create a synth 9 | sine = sc.Synth('sine', [1, 1, 'freq', 440, 'amp', 0.2]) 10 | 11 | // change amp after 500 ms 12 | setTimeout(function() { 13 | sine.set('amp', 0.6) 14 | }, 500) 15 | 16 | // free after 3000 ms 17 | setTimeout(function() { 18 | sine.free() 19 | process.exit(0) 20 | }, 3000) -------------------------------------------------------------------------------- /examples/sine.sc: -------------------------------------------------------------------------------- 1 | s = Server.local; 2 | s.boot; 3 | 4 | ( 5 | SynthDef("sine", { 6 | |freq=440, amp=0.1| 7 | var osc; 8 | osc = SinOsc.ar(freq, 0, amp); 9 | Out.ar(0, osc); 10 | }).send(s); 11 | ) 12 | 13 | 14 | ( 15 | SynthDef(\RingMod,{ 16 | |freq = 1000| 17 | var in = [0,1]; 18 | var out = [0,1]; 19 | var ring = SinOsc.kr(freq); 20 | 21 | var sound = In.ar(in); 22 | Out.ar(out, sound*ring); 23 | }).send(s); 24 | ) 25 | -------------------------------------------------------------------------------- /node_modules/node-osc/README.rst: -------------------------------------------------------------------------------- 1 | -------- 2 | node-osc 3 | -------- 4 | 5 | A very basic OSC client (so far) implementation based heavily on pyOSC_. 6 | 7 | 8 | Relies on current trunk of node.js for the dgram library. 9 | 10 | .. _pyOSC: https://trac.v2.nl/wiki/pyOSC 11 | 12 | Example 13 | ------- 14 | 15 | :: 16 | 17 | var osc = require('osc'); 18 | 19 | var client = osc.Client(10000, '127.0.0.1'); 20 | client.sendSimple('/oscAddress', [200]); 21 | 22 | // slightly more complex 23 | var msg = osc.Message('/oscAddress'); 24 | msg.append(200); 25 | msg.append(10); 26 | 27 | client.send(msg); 28 | 29 | You can also create a OSC server: 30 | 31 | :: 32 | 33 | var osc = require('osc'); 34 | 35 | var server = osc.Server(10001, '127.0.0.1'); 36 | 37 | server.addMsgHandler('/bang', function (args) { 38 | console.log('I got a bang!') 39 | }); 40 | 41 | Licensing 42 | --------- 43 | 44 | pyOSC looks to be GPL so I guess this is too. More formalities later on. 45 | -------------------------------------------------------------------------------- /node_modules/node-osc/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/osc.js') -------------------------------------------------------------------------------- /node_modules/node-osc/lib/node-jspack/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Fair Oaks Labs, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list 8 | of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or other 12 | materials provided with the distribution. 13 | 14 | * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors may be 15 | used to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 | THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /node_modules/node-osc/lib/node-jspack/README: -------------------------------------------------------------------------------- 1 | Disclaimer: The jspack module and documentation are essentially ports of the 2 | Python struct module and documentation, with such changes as were necessary. 3 | If any Python people are miffed that I've ripped off their docs, let me know, 4 | and I'll gladly revise them. 5 | 6 | This module performs conversions between JavaScript values and C structs 7 | represented as octet arrays (i.e. JavaScript arrays of integral numbers 8 | between 0 and 255, inclusive). It uses format strings (explained below) as 9 | compact descriptions of the layout of the C structs and the intended conversion 10 | to/from JavaScript values. This can be used to handle binary data stored in 11 | files, or received from network connections or other sources. 12 | 13 | 14 | The module defines the following functions: 15 | 16 | Unpack(fmt, a, p) 17 | Return an array containing values unpacked from the octet array a, 18 | beginning at position p, according to the supplied format string. If there 19 | are more octets in a than required by the format string, the excess is 20 | ignored. If there are fewer octets than required, Unpack() will return 21 | undefined. If no value is supplied for the p argument, zero is assumed. 22 | 23 | PackTo(fmt, a, p, values) 24 | Pack and store the values array into the supplied octet array a, beginning 25 | at position p. If there are more values supplied than are specified in the 26 | format string, the excess is ignored. If there are fewer values supplied, 27 | PackTo() will return false. If there is insufficient space in a to store 28 | the packed values, PackTo() will return false. On success, PackTo() returns 29 | the a argument. If any value is of an inappropriate type, the results are 30 | undefined. 31 | 32 | Pack(fmt, values) 33 | Return an octet array containing the packed values array. If there are 34 | more values supplied than are specified in the format string, the excess is 35 | ignored. If there are fewer values supplied, Pack() will return false. If 36 | any value is of an inappropriate type, the results are undefined. 37 | 38 | CalcLength(fmt) 39 | Return the number of octets required to store the given format string. 40 | 41 | 42 | Format characters have the following meanings; the conversion between C and 43 | JavaScript values should be obvious given their types: 44 | 45 | Format | C Type | JavaScript Type | Size (octets) | Notes 46 | ------------------------------------------------------------------- 47 | A | char[] | Array | Length | (1) 48 | x | pad byte | N/A | 1 | 49 | c | char | string (length 1) | 1 | (2) 50 | b | signed char | number | 1 | (3) 51 | B | unsigned char | number | 1 | (3) 52 | h | signed short | number | 2 | (3) 53 | H | unsigned short | number | 2 | (3) 54 | i | signed long | number | 4 | (3) 55 | I | unsigned long | number | 4 | (3) 56 | l | signed long | number | 4 | (3) 57 | L | unsigned long | number | 4 | (3) 58 | s | char[] | string | Length | (2) 59 | f | float | number | 4 | (4) 60 | d | double | number | 8 | (5) 61 | 62 | Notes: 63 | 64 | (1) The "A" code simply returns a slice of the source octet array. This is 65 | primarily useful when a data structure contains bytes which are subject to 66 | multiple intepretations (e.g. unions), and the data structure is being 67 | decoded in multiple passes. 68 | 69 | (2) The "c" and "s" codes handle strings with codepoints between 0 and 255, 70 | inclusive. The data are not bounds-checked, so strings containing characters 71 | with codepoints outside this range will encode to "octet" arrays that contain 72 | values outside the range of an octet. Furthermore, since these codes decode 73 | octet arrays by assuming the octets represent UNICODE codepoints, they may 74 | not "correctly" decode bytes in the range 128-255, since that range is subject 75 | to multiple interpretations. Caveat coder! 76 | 77 | (3) The 8 "integer" codes clip their encoded values to the minima and maxmima 78 | of their respective types: If you invoke Struct.Pack('b', [-129]), for 79 | instance, the result will be [128], which is the octet encoding of -128, 80 | which is the minima of a signed char. Similarly, Struct.Pack('h', [-32769]) 81 | returns [128, 0]. Fractions are truncated. 82 | 83 | (4) Since JavaScript doesn't natively support 32-bit floats, whenever a float 84 | is stored, the source JavaScript number must be rounded. This module applies 85 | correct rounding during this process. Numbers with magnitude greater than or 86 | equal to 2**128-2**103 round to either positive or negative Infinity. The 87 | rounding algorithm assumes that JavsScript is using exactly 64 bits of 88 | floating point precision; 128-bit floating point will result in subtle errors. 89 | 90 | (5) This module assumes that JavaScript is using 64 bits of floating point 91 | precision, so the "d" code performs no rounding. 128-bit floating point will 92 | cause the "d" code to simply truncate significands to 52 bits. 93 | 94 | A format character may be preceded by an integral repeat count. For example, 95 | the format string "4h" means exactly the same thing as "hhhh". 96 | 97 | Whitespace characters between formats are ignored; a count and its format must 98 | not be separated by whitespace, however. 99 | 100 | For the "A" format character, the count is interpreted as the size of the 101 | array, not a repeat count as for the other format characters; for example, "10A" 102 | means a single 10-octet array. When packing, the Array is truncated or padded 103 | with 0 bytes as appropriate to make it conform to the specified length. When 104 | unpacking, the resulting Array always has exactly the specified number of bytes. 105 | As a special case, "0A" means a single, empty Array. 106 | 107 | For the "s" format character, the count is interpreted as the size of the 108 | string, not a repeat count as for the other format characters; for example, 109 | "10s" means a single 10-byte string, while "10c" means 10 characters. When 110 | packing, the string is truncated or padded with 0 bytes as appropriate to make 111 | it conform to the specified length. When unpacking, the resulting string always 112 | has exactly the specified number of bytes. As a special case, "0s" means a 113 | single, empty string (while "0c" means 0 characters). 114 | 115 | 116 | By default, C numbers are represented in network (or big-endian) byte order. 117 | Alternatively, the first character of the format string can be used to indicate 118 | byte order of the packed data, according to the following table: 119 | 120 | Character | Byte Order 121 | ---------------------------------- 122 | < | little-endian 123 | > | big-endian 124 | ! | network (= big-endian) 125 | 126 | If the first character is not one of these, "!" is assumed. 127 | -------------------------------------------------------------------------------- /node_modules/node-osc/lib/node-jspack/jspack.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stagas/node-supercollider/a18411368377bf57d48df6dad07128edfecce7fa/node_modules/node-osc/lib/node-jspack/jspack.js -------------------------------------------------------------------------------- /node_modules/node-osc/lib/osc.js: -------------------------------------------------------------------------------- 1 | require.paths.unshift(__dirname + '/node-jspack'); 2 | var buffer = require('buffer'); 3 | var dgram = require('dgram'); 4 | var sys = require('sys'); 5 | 6 | var jspack = require('jspack').jspack; 7 | 8 | //////////////////// 9 | // OSC Message 10 | //////////////////// 11 | 12 | var Message = function (address) { 13 | this.address = address; 14 | this.typetags = ','; 15 | this.message = []; 16 | } 17 | 18 | Message.prototype = { 19 | append: function (arg, typehint) { 20 | if (arg instanceof Array) { 21 | for (var i in arg) { 22 | this.append(arg[i], typehint); 23 | } 24 | return null; 25 | } 26 | if (typeof(arg) == 'object') { 27 | for (var k in arg) { 28 | this.append([k, arg[k]]); 29 | } 30 | return null; 31 | } 32 | 33 | if (typehint == 'b') { 34 | binary = OSCBlob(arg); 35 | tag = 'b'; 36 | } else if (typehint == 't') { 37 | binary = OSCTimeTag(arg); 38 | tag = 't'; 39 | } else { 40 | rv = OSCArgument(arg, typehint); 41 | tag = rv[0]; 42 | binary = rv[1]; 43 | } 44 | 45 | this.typetags += tag; 46 | this.message = this.message.concat(binary); 47 | }, 48 | toBinary: function () { 49 | var binary = OSCString(this.address); 50 | binary = binary.concat(OSCString(this.typetags)); 51 | binary = binary.concat(this.message); 52 | return binary; 53 | }, 54 | } 55 | exports.Message = Message; 56 | 57 | var Bundle = function (address, time) { 58 | Message.call(this, address); 59 | this.timetag = time || 0; 60 | } 61 | 62 | sys.inherits(Bundle, Message); 63 | 64 | Bundle.prototype.append = function (arg, typehint) { 65 | var binary; 66 | if (arg instanceof Message) { 67 | binary = OSCBlob(arg.toBinary()); 68 | } else { 69 | var msg = Message(this.address); 70 | if (typeof(arg) == 'Object') { 71 | if (arg.addr) { 72 | msg.address = arg.addr; 73 | } 74 | if (arg.args) { 75 | msg.append(arg.args, typehint); 76 | } 77 | } else { 78 | msg.append(arg, typehint); 79 | } 80 | binary = OSCBlob(msg.toBinary()); 81 | } 82 | this.message += binary; 83 | this.typetags += 'b'; 84 | }; 85 | 86 | Bundle.prototype.toBinary = function () { 87 | var binary = OSCString('#bundle'); 88 | binary = binary.concat(OSCTimeTag(this.timetag)); 89 | binary = binary.concat(this.message); 90 | return binary; 91 | }; 92 | 93 | exports.Bundle = Bundle; 94 | 95 | //////////////////// 96 | // OSC Message Encoding Functions 97 | //////////////////// 98 | 99 | var OSCString = function (next) { 100 | var len = Math.ceil((next.length + 1) / 4.0) * 4; 101 | var foo = jspack.Pack('>' + len + 's', [next]); 102 | return foo 103 | } 104 | 105 | var OSCBlob = function (next) { 106 | var binary; 107 | if (typeof(next) == 'String') { 108 | var len = Math.ceil((next.length) / 4.0) * 4; 109 | binary = jspack.Pack('>i' + len + 's', [len, next]); 110 | } else { 111 | binary = ''; 112 | } 113 | return binary; 114 | } 115 | 116 | var OSCArgument = function (next, typehint) { 117 | var binary, tag; 118 | if (!typehint) { 119 | if (typeof(next) == 'number') { 120 | if (next.toString().indexOf('.') != -1) { 121 | binary = jspack.Pack('>f', [next]); 122 | tag = 'f'; 123 | } else { 124 | binary = jspack.Pack('>i', [next]); 125 | tag = 'i'; 126 | } 127 | } else { 128 | binary = OSCString(next); 129 | tag = 's'; 130 | } 131 | } else if (typehint == 'd') { 132 | try { 133 | binary = jspack.Pack('>f', [parseFloat(next)]); 134 | tag = 'f'; 135 | } catch (e) { 136 | binary = OSCString(next); 137 | tag = 's'; 138 | } 139 | } else if (typehint == 'i') { 140 | try { 141 | binary = jspack.Pack('>i', [parseInt(next)]); 142 | tag = 'i'; 143 | } catch (e) { 144 | binary = OSCString(next); 145 | tag = 's'; 146 | } 147 | } else { 148 | binary = OSCString(next); 149 | tag = 's'; 150 | } 151 | return [tag, binary]; 152 | } 153 | 154 | var OSCTimeTag = function (time) { 155 | // Not Implemented Yet 156 | return jspack.Pack('>LL', 0, 1); 157 | } 158 | 159 | //////////////////// 160 | // OSC Client 161 | //////////////////// 162 | 163 | var Client = function (port, bindPort, host, debug) { 164 | var self = this; 165 | this.debug = debug; 166 | this._callbacks = []; 167 | this.port = port; 168 | this.host = host; 169 | this._sock = dgram.createSocket('udp4'); 170 | this._sock.bind(bindPort); 171 | this._sock.on('message', function (msg, rinfo) { 172 | // on every message sent through the UDP socket... 173 | // we decode the message getting a beautiful array with the form: 174 | // [
, , *] 175 | var decoded = decodeOSC(msg); 176 | //console.log('decoded:', decoded, rinfo) 177 | // and we run along the callbacks list 178 | for (var c=0; c of the message 183 | self._callbacks[c].callback(decoded[0], decoded.slice(2)); 184 | } 185 | } 186 | }); 187 | } 188 | 189 | Client.prototype = { 190 | msg: function (msg) { 191 | var binary = msg.toBinary(); 192 | var b = new buffer.Buffer(binary, 'binary'); 193 | this._sock.send(b, 0, b.length, this.port, this.host); 194 | }, 195 | send: function () { 196 | var args = [].slice.call(arguments) 197 | , address = args.shift(); 198 | 199 | if (this.debug) console.log('sending:', address, args.toString()); 200 | var msg = new Message(address); 201 | var data; 202 | while(data = args.shift()) { 203 | if ('undefined' !== typeof data) msg.append(data); 204 | } 205 | this.msg(msg); 206 | }, 207 | on: function(address, callback) { 208 | // if not regex do some replacement 209 | if (typeof(address) == 'string') { 210 | address = '/' + address.replace('/', ''); 211 | } 212 | this._callbacks.push({'address': address, 'callback': callback}); 213 | }, 214 | removeListener: function(address) { 215 | for (var c=0; ci', new Buffer(data.substring(0,4))); 244 | if (value == undefined) { 245 | value = 0; 246 | } 247 | rest = data.substr(4); 248 | } 249 | return [value, rest]; 250 | }; 251 | 252 | var _readFloat = function (data) { 253 | if (data.length < 4) { 254 | console.log('Error: too few bytes for float ' + data + data.length); 255 | rest = data; 256 | value = 0; 257 | } else { 258 | value = jspack.Unpack('>f', new Buffer(data.substring(0,4))); 259 | if (value == undefined) { 260 | value = 0; 261 | } 262 | rest = data.substr(4); 263 | } 264 | return [value, rest]; 265 | }; 266 | 267 | var _readBlob = function (data) { 268 | var length = fdpack.Unpack('>i', new Buffer(data.substring(0,4))); 269 | var nextData = parseInt(Math.ceil((length) / 4.0) * 4) + 4; 270 | return [data.substring(4, length + 4), data.substr(nextData)] 271 | }; 272 | 273 | var _readDouble = function (data) { 274 | if (data.length < 8) { 275 | console.log(data) 276 | console.log('Error: too few bytes for double ' + data + data.length); 277 | rest = data; 278 | value = 0; 279 | } else { 280 | value = jspack.Unpack('>d', new Buffer(data.substring(0,8))); 281 | if (value == undefined) { 282 | value = 0; 283 | } 284 | rest = data.substr(8); 285 | } 286 | return [value, rest]; 287 | }; 288 | 289 | var decodeOSC = function (data) { 290 | // for each tag we use a specific function to decode it's respective data 291 | var table = {'i':_readInt, 'f':_readFloat, 's':_readString, 'b':_readBlob, 'd':_readDouble}; 292 | 293 | // this stores the decoded data as an array 294 | var decoded = []; 295 | 296 | // we start getting the
and of OSC msg /
\0\0\0 297 | var pair = _readString(data); 298 | var address = pair[0]; 299 | var rest = pair[1]; 300 | 301 | // if we have rest, maybe we have some typetags... let see... 302 | if (rest.length > 0) { 303 | // now we advance on the old rest, getting 304 | var pair = _readString(rest); 305 | var typetags = pair[0]; 306 | var rest = pair[1]; 307 | 308 | // so we start building our decoded list 309 | decoded.push(address); 310 | decoded.push(typetags.substr(1)); 311 | console.log(decoded) 312 | // typetag-string need to start with the magic , 313 | if (typetags[0] == ',') { 314 | // for each tag... 315 | for (var t=0; t, , *] 359 | var decoded = decodeOSC(msg); 360 | // and we run along the callbacks list 361 | for (var c=0; c<_callbacks.length; c++) { 362 | // if the msg address equals to one of callbacks adresses... 363 | if (_callbacks[c] && address_matches(decoded[0], _callbacks[c].address)) { 364 | // we call the respective callback function, passing 365 | // the list of of the message 366 | _callbacks[c].callback(decoded[0], decoded[2]); 367 | } 368 | } 369 | }); 370 | 371 | this.on = function(address, callback) { 372 | // if not regex do some replacement 373 | if (typeof(address) == 'string') { 374 | address = '/' + address.replace('/', ''); 375 | } 376 | _callbacks.push({'address': address, 377 | 'callback': callback}); 378 | }; 379 | 380 | this.removeListener = function(address) { 381 | for (var c=0; c<_callbacks.length; c++) { 382 | // if they're matching strings or matching regex 383 | if (_callbacks[c] && address_matches(address, _callbacks[c].address)) { 384 | delete _callbacks[c]; 385 | } 386 | } 387 | }; 388 | 389 | } 390 | 391 | exports.Server = Server; -------------------------------------------------------------------------------- /supercollider.js: -------------------------------------------------------------------------------- 1 | var util = require('util') 2 | , path = require('path') 3 | , osc = require('node-osc') 4 | , EventEmitter = require('events').EventEmitter 5 | 6 | var SuperCollider = module.exports = function(port, host) { 7 | if (!(this instanceof SuperCollider)) return new SuperCollider(port, host) 8 | var self = this 9 | 10 | EventEmitter.call(this) 11 | 12 | this.port = port || 57110 13 | this.clientPort = this.clientOriginalPort = this.port + 30 14 | this.host = host || '127.0.0.1' 15 | this._nextId = 1000 16 | } 17 | 18 | util.inherits(SuperCollider, EventEmitter) 19 | 20 | SuperCollider.prototype._createClient = function(port, rr, host) { 21 | console.log(port, rr, host) 22 | return new osc.Client(port, rr, host, true) 23 | } 24 | 25 | SuperCollider.prototype.roundRobinPort = function() { 26 | if (this.clientPort > this.clientOriginalPort + 50) this.clientPort = this.clientOriginalPort 27 | return this.clientPort++ 28 | } 29 | 30 | SuperCollider.prototype.send = function() { 31 | var self = this 32 | , args = [].slice.call(arguments) 33 | , cb 34 | if ('function' === typeof args[args.length - 1]) { 35 | cb = args.pop() 36 | } 37 | var scc = this._createClient(this.port, this.roundRobinPort(), this.host) 38 | cb && scc._sock.once('message', function(message, address) { 39 | var messageString = message.toString() 40 | self.emit('message', messageString, address) 41 | cb(null, messageString, address) 42 | }) 43 | scc.send.apply(scc, args) 44 | return scc 45 | } 46 | 47 | // Get next node id 48 | SuperCollider.prototype.nextNodeId = function() { 49 | return this._nextId++ 50 | } 51 | 52 | SuperCollider.prototype.Synth = function(synthName, args) { 53 | var synth = new Synth(this, synthName, args) 54 | return synth 55 | } 56 | 57 | var Synth = function(sc, synthName, args) { 58 | this.sc = sc 59 | this.node = sc.nextNodeId() 60 | this.sc.send.apply(this.sc, ['/s_new', synthName, this.node].concat(args)) 61 | return this 62 | } 63 | 64 | Synth.prototype.set = function() { 65 | this.sc.send.apply(this.sc, ['/n_set', this.node].concat([].slice.call(arguments))) 66 | return this 67 | } 68 | 69 | Synth.prototype.free = function() { 70 | this.sc.send.call(this.sc, '/n_free', this.node) 71 | return this 72 | } 73 | 74 | Synth.prototype.run = function(flag){ 75 | this.sc.send.apply(this.sc, ['/n_run',this.node, flag, this.node].concat([].slice.call(arguments))) 76 | return this 77 | } 78 | 79 | Synth.prototype.after = function(id){ 80 | this.sc.send.apply(this.sc, ['/n_after',this.node, id, this.node].concat([].slice.call(arguments))) 81 | return this 82 | } 83 | 84 | Synth.prototype.before = function(id){ 85 | this.sc.send.apply(this.sc, ['/n_before',this.node, id, this.node].concat([].slice.call(arguments))) 86 | return this 87 | } --------------------------------------------------------------------------------