From 0be0347f8bd9fe60df720f140f74d2e48f1fc1a1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 28 Mar 2022 21:22:24 +0200 Subject: [PATCH 01/37] basic communication with superdirt --- packages/osc/README.md | 33 +++++++++ packages/osc/index.html | 22 ++++++ packages/osc/package-lock.json | 76 +++++++++++++++++++ packages/osc/package.json | 32 ++++++++ packages/osc/server.js | 129 +++++++++++++++++++++++++++++++++ packages/osc/tidal-sniffer.js | 125 ++++++++++++++++++++++++++++++++ 6 files changed, 417 insertions(+) create mode 100644 packages/osc/README.md create mode 100644 packages/osc/index.html create mode 100644 packages/osc/package-lock.json create mode 100644 packages/osc/package.json create mode 100644 packages/osc/server.js create mode 100644 packages/osc/tidal-sniffer.js diff --git a/packages/osc/README.md b/packages/osc/README.md new file mode 100644 index 00000000..e8f5069b --- /dev/null +++ b/packages/osc/README.md @@ -0,0 +1,33 @@ +# @strudel.cycles/osc + +OSC messaging between strudel and super collider? + +## Sniffing Tidal Messages + +```sh +npm run tidal-sniffer +``` + +Now open a .tidal file and play something. There should be logs like: + +```log +received: /dirt/play [ + '_id_', '1', + 'cps', 0.5625, + 'cutoff', 100, + 'cycle', 724.1875, + 'delta', 0.11111068725585938, + 'orbit', 0, + 's', 'arpy' +] +``` + +## Web Client + Server (WIP) + +```sh +npm run client +npm run server # another terminal +``` + +Then go to [http://localhost:4321](localhost:4321) and push the button. +In your server terminal, there should be a log. diff --git a/packages/osc/index.html b/packages/osc/index.html new file mode 100644 index 00000000..0890caa1 --- /dev/null +++ b/packages/osc/index.html @@ -0,0 +1,22 @@ + + + diff --git a/packages/osc/package-lock.json b/packages/osc/package-lock.json new file mode 100644 index 00000000..33516920 --- /dev/null +++ b/packages/osc/package-lock.json @@ -0,0 +1,76 @@ +{ + "name": "@strudel.cycles/osc", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@strudel.cycles/osc", + "version": "0.0.1", + "license": "GPL-3.0-or-later", + "dependencies": { + "osc-js": "^2.3.0" + } + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/osc-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", + "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", + "dependencies": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "requires": {} + }, + "osc-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", + "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", + "requires": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} + } + } +} diff --git a/packages/osc/package.json b/packages/osc/package.json new file mode 100644 index 00000000..67a0cc76 --- /dev/null +++ b/packages/osc/package.json @@ -0,0 +1,32 @@ +{ + "name": "@strudel.cycles/osc", + "version": "0.0.1", + "description": "OSC messaging for strudel", + "main": "osc.mjs", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "server": "node server.js", + "tidal-sniffer": "node tidal-sniffer.js", + "client": "npx serve -p 4321" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/tidalcycles/strudel.git" + }, + "keywords": [ + "tidalcycles", + "strudel", + "pattern", + "livecoding", + "algorave" + ], + "author": "Felix Roos ", + "license": "GPL-3.0-or-later", + "bugs": { + "url": "https://github.com/tidalcycles/strudel/issues" + }, + "homepage": "https://github.com/tidalcycles/strudel#readme", + "dependencies": { + "osc-js": "^2.3.0" + } +} diff --git a/packages/osc/server.js b/packages/osc/server.js new file mode 100644 index 00000000..0d5c6986 --- /dev/null +++ b/packages/osc/server.js @@ -0,0 +1,129 @@ +const OSC = require('osc-js'); + +const config = { + receiver: 'ws', // @param {string} Where messages sent via 'send' method will be delivered to, 'ws' for Websocket clients, 'udp' for udp client + udpServer: { + host: 'localhost', // @param {string} Hostname of udp server to bind to + port: 57121, // @param {number} Port of udp client for messaging + // enabling the following line will receive tidal messages: + // port: 57120, // @param {number} Port of udp client for messaging + exclusive: false, // @param {boolean} Exclusive flag + }, + udpClient: { + host: 'localhost', // @param {string} Hostname of udp client for messaging + port: 57120, // @param {number} Port of udp client for messaging + }, + wsServer: { + host: 'localhost', // @param {string} Hostname of WebSocket server + port: 8080, // @param {number} Port of WebSocket server + }, +}; +const osc = new OSC({ plugin: new OSC.BridgePlugin(config) }); + +osc.open(); // start a WebSocket server on port 8080 + +console.log('osc client running on port', config.udpClient.port); +console.log('osc server running on port', config.udpServer.port); +console.log('websocket server running on port', config.wsServer.port); + +// listen for messages from the client +osc.on('*', (m) => { + // forward message to supercollider?? + const message = new OSC.Message(m.address, ...m.args); + osc.send(message); // will it even be received?? + console.log('forward:', m.address, m.args); +}); + +/* +example tidal messages: + +/* + +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 503.5, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', '1', + 'cps', 0.5625, + 'cycle', 503.6666564941406, + 'delta', 0.592592716217041, + 'orbit', 0, + 's', 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504, + 'delta', + 0.592592716217041, + 'orbit', + 0, + 's', + 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504.3333435058594, + 'delta', + 0.5925922393798828, + 'orbit', + 0, + 's', + 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504.5, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', '1', + 'cps', 0.5625, + 'cycle', 504.6666564941406, + 'delta', 0.592592716217041, + 'orbit', 0, + 's', 'hh' +] + +*/ diff --git a/packages/osc/tidal-sniffer.js b/packages/osc/tidal-sniffer.js new file mode 100644 index 00000000..a1bdd659 --- /dev/null +++ b/packages/osc/tidal-sniffer.js @@ -0,0 +1,125 @@ +const OSC = require('osc-js'); + +const config = { + receiver: 'ws', // @param {string} Where messages sent via 'send' method will be delivered to, 'ws' for Websocket clients, 'udp' for udp client + udpServer: { + host: 'localhost', // @param {string} Hostname of udp server to bind to + port: 57120, // @param {number} Port of udp client for messaging + exclusive: false, // @param {boolean} Exclusive flag + }, + udpClient: { + host: 'localhost', // @param {string} Hostname of udp client for messaging + // port: 57120, // @param {number} Port of udp client for messaging + port: 41235, // @param {number} Port of udp client for messaging + }, + wsServer: { + host: 'localhost', // @param {string} Hostname of WebSocket server + port: 8080, // @param {number} Port of WebSocket server + }, +}; +const osc = new OSC({ plugin: new OSC.BridgePlugin(config) }); + +osc.open(); // start a WebSocket server on port 8080 + +console.log('osc client running on port', config.udpClient.port); +console.log('osc server running on port', config.udpServer.port); +console.log('websocket server running on port', config.wsServer.port); + +// listen for messages from the client +osc.on('*', (m) => { + console.log('received:', m.address, m.args); +}); + +/* +example tidal messages: + +/* + +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 503.5, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', '1', + 'cps', 0.5625, + 'cycle', 503.6666564941406, + 'delta', 0.592592716217041, + 'orbit', 0, + 's', 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504, + 'delta', + 0.592592716217041, + 'orbit', + 0, + 's', + 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504.3333435058594, + 'delta', + 0.5925922393798828, + 'orbit', + 0, + 's', + 'hh' +] +received: /dirt/play [ + '_id_', + '1', + 'cps', + 0.5625, + 'cycle', + 504.5, + 'delta', + 0.8888888359069824, + 'orbit', + 0, + 's', + 'bd' +] +received: /dirt/play [ + '_id_', '1', + 'cps', 0.5625, + 'cycle', 504.6666564941406, + 'delta', 0.592592716217041, + 'orbit', 0, + 's', 'hh' +] + +*/ From ed6cf2ecf1925a6a8ffd3ef78d930c3f9b3b626b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 28 Mar 2022 21:24:44 +0200 Subject: [PATCH 02/37] enlarge button --- packages/osc/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/osc/index.html b/packages/osc/index.html index 0890caa1..e7630904 100644 --- a/packages/osc/index.html +++ b/packages/osc/index.html @@ -1,4 +1,4 @@ - + +

+ This page shows how skypack can be used to import strudel core directly into a simple html page.
+ No server, no bundler and no build setup is needed to run this! +

diff --git a/packages/core/examples/canvas.html b/packages/core/examples/canvas.html new file mode 100644 index 00000000..685cc56e --- /dev/null +++ b/packages/core/examples/canvas.html @@ -0,0 +1,34 @@ + + + + + From ac01a621beb6be0e739ae7d14078c577ee6b23c4 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Apr 2022 15:37:50 +0100 Subject: [PATCH 11/37] workaround for osc-js timestamp bug, reduce latency --- packages/osc/osc.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 33586d29..34169ed0 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -3,17 +3,18 @@ import { Pattern, isPattern } from '@strudel.cycles/core/strudel.mjs'; const comm = new OSC(); comm.open(); +// TODO - get startTime from scheduler const startTime = Date.now(); -const latency = 0.2; +const latency = 0.1; Pattern.prototype.osc = function () { return this._withEvent((event) => { const onTrigger = (time, event) => { - console.log(time); const keyvals = Object.entries(event.value).flat(); - const ts = startTime + ((time+latency)*1000); + const ts = Math.floor(startTime + ((time + latency) * 1000)); const message = new OSC.Message('/dirt/play',...keyvals); - const bundle = new OSC.Bundle([message], ts) + const bundle = new OSC.Bundle([message], ts); + bundle.timestamp(ts); // workaround for https://github.com/adzialocha/osc-js/issues/60 comm.send(bundle); }; return event.setContext({ ...event.context, onTrigger }); From bf7c8cebc4468ac825f93cf7776ea00bf1c54c6a Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Apr 2022 15:38:06 +0100 Subject: [PATCH 12/37] tidy --- packages/osc/server.js | 106 ----------------------------------------- 1 file changed, 106 deletions(-) diff --git a/packages/osc/server.js b/packages/osc/server.js index dd697d8c..f765b284 100644 --- a/packages/osc/server.js +++ b/packages/osc/server.js @@ -1,4 +1,3 @@ -const dgram = require('dgram') const OSC = require('osc-js'); const config = { @@ -29,108 +28,3 @@ osc.open(); // start a WebSocket server on port 8080 console.log('osc client running on port', config.udpClient.port); console.log('osc server running on port', config.udpServer.port); console.log('websocket server running on port', config.wsServer.port); - -// listen for messages from the client -// osc.on('*', (m) => { -// console.log("hmm!"); -// const ts = m.args.shift(); -// const message = new OSC.Message(m.address, ...m.args); -// console.log(m.args); -// const bundle = new OSC.Bundle([message], new Date(ts)) -// osc.send(bundle); -// console.log('forward:', bundle); -// }); - -/* -example tidal messages: - -/* - -received: /dirt/play [ - '_id_', - '1', - 'cps', - 0.5625, - 'cycle', - 503.5, - 'delta', - 0.8888888359069824, - 'orbit', - 0, - 's', - 'bd' -] -received: /dirt/play [ - '_id_', '1', - 'cps', 0.5625, - 'cycle', 503.6666564941406, - 'delta', 0.592592716217041, - 'orbit', 0, - 's', 'hh' -] -received: /dirt/play [ - '_id_', - '1', - 'cps', - 0.5625, - 'cycle', - 504, - 'delta', - 0.8888888359069824, - 'orbit', - 0, - 's', - 'bd' -] -received: /dirt/play [ - '_id_', - '1', - 'cps', - 0.5625, - 'cycle', - 504, - 'delta', - 0.592592716217041, - 'orbit', - 0, - 's', - 'hh' -] -received: /dirt/play [ - '_id_', - '1', - 'cps', - 0.5625, - 'cycle', - 504.3333435058594, - 'delta', - 0.5925922393798828, - 'orbit', - 0, - 's', - 'hh' -] -received: /dirt/play [ - '_id_', - '1', - 'cps', - 0.5625, - 'cycle', - 504.5, - 'delta', - 0.8888888359069824, - 'orbit', - 0, - 's', - 'bd' -] -received: /dirt/play [ - '_id_', '1', - 'cps', 0.5625, - 'cycle', 504.6666564941406, - 'delta', 0.592592716217041, - 'orbit', 0, - 's', 'hh' -] - -*/ From 723b239fda4cfae0d89df9fa7b9bfc3083545ab6 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Apr 2022 23:15:39 +0100 Subject: [PATCH 13/37] formatting --- packages/osc/osc.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 34169ed0..bfa3cf96 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -12,7 +12,7 @@ Pattern.prototype.osc = function () { const onTrigger = (time, event) => { const keyvals = Object.entries(event.value).flat(); const ts = Math.floor(startTime + ((time + latency) * 1000)); - const message = new OSC.Message('/dirt/play',...keyvals); + const message = new OSC.Message('/dirt/play', ...keyvals); const bundle = new OSC.Bundle([message], ts); bundle.timestamp(ts); // workaround for https://github.com/adzialocha/osc-js/issues/60 comm.send(bundle); From 46b2e82b4301831c35375a6fe9c39abbf172c4ff Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Apr 2022 23:15:54 +0100 Subject: [PATCH 14/37] formatting --- packages/core/strudel.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strudel.mjs b/packages/core/strudel.mjs index d285fe76..f6c4f7f9 100644 --- a/packages/core/strudel.mjs +++ b/packages/core/strudel.mjs @@ -780,7 +780,7 @@ class Pattern { // known as iter' in tidalcycles iterBack(times) { - return this.iter(times,true) + return this.iter(times, true) } _chunk(n, func, back = false) { From 89a7bd4e7d04622e18c192a206802758ca0b7025 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 1 Apr 2022 23:17:52 +0100 Subject: [PATCH 15/37] superdirt parameters --- packages/osc/superdirt.mjs | 23 +++++++++++++++++++++++ repl/src/App.js | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 packages/osc/superdirt.mjs diff --git a/packages/osc/superdirt.mjs b/packages/osc/superdirt.mjs new file mode 100644 index 00000000..95615781 --- /dev/null +++ b/packages/osc/superdirt.mjs @@ -0,0 +1,23 @@ +import { Pattern } from '@strudel.cycles/core/strudel.mjs'; + +const _name = (name, pat) => pat.withValue(x => ({ [name]: x })); + +export const s = pat => _name("s", pat); +Pattern.prototype.s = function (pat) { return (this.union(s(pat))) }; +export const snd = s; +Pattern.prototype.snd = Pattern.prototype.s; +export const sound = s; +Pattern.prototype.sound = Pattern.prototype.s; +export const n = pat => _name("n", pat); +Pattern.prototype.n = function (pat) { return (this.union(n(pat))) }; +export const num = n; +Pattern.prototype.num = Pattern.prototype.n; +export const number = n; +Pattern.prototype.number = Pattern.prototype.n; +export const room = pat => _name("room", pat); +Pattern.prototype.room = function (pat) { return (this.union(room(pat))) }; +export const size = pat => _name("size", pat); +Pattern.prototype.size = function (pat) { return (this.union(size(pat))) }; +export const speed = pat => _name("speed", pat); +Pattern.prototype.speed = function (pat) { return (this.union(speed(pat))) }; + diff --git a/repl/src/App.js b/repl/src/App.js index 4f522aea..7f37b75f 100644 --- a/repl/src/App.js +++ b/repl/src/App.js @@ -29,8 +29,9 @@ import '@strudel.cycles/core/euclid.mjs'; import '@strudel.cycles/tone/pianoroll.mjs'; import '@strudel.cycles/tone/draw.mjs'; import '@strudel.cycles/osc/osc.mjs'; +import * as superdirt from '@strudel.cycles/osc/superdirt.mjs'; -extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { +extend(Tone, strudel, superdirt, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { gist, euclid, mini, From e28a411408100a1e102b2ed2681ee1cd23a09dff Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 16:03:50 +0100 Subject: [PATCH 16/37] Make param args a sequence, remove some redundancy --- packages/osc/superdirt.mjs | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/packages/osc/superdirt.mjs b/packages/osc/superdirt.mjs index 95615781..5f9c6efd 100644 --- a/packages/osc/superdirt.mjs +++ b/packages/osc/superdirt.mjs @@ -1,23 +1,37 @@ -import { Pattern } from '@strudel.cycles/core/strudel.mjs'; +import { Pattern, sequence } from '@strudel.cycles/core/strudel.mjs'; -const _name = (name, pat) => pat.withValue(x => ({ [name]: x })); +const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x })); -export const s = pat => _name("s", pat); -Pattern.prototype.s = function (pat) { return (this.union(s(pat))) }; -export const snd = s; -Pattern.prototype.snd = Pattern.prototype.s; +const _unionise = (func) => + function (...pats) { + return this.union(func(...pats)); + }; + +export const s = (...pats) => _name('s', ...pats); +Pattern.prototype.s = _unionise(s); export const sound = s; Pattern.prototype.sound = Pattern.prototype.s; -export const n = pat => _name("n", pat); -Pattern.prototype.n = function (pat) { return (this.union(n(pat))) }; -export const num = n; -Pattern.prototype.num = Pattern.prototype.n; + +export const n = (pat) => _name('n', pat); +Pattern.prototype.n = _unionise(n); export const number = n; Pattern.prototype.number = Pattern.prototype.n; -export const room = pat => _name("room", pat); -Pattern.prototype.room = function (pat) { return (this.union(room(pat))) }; -export const size = pat => _name("size", pat); -Pattern.prototype.size = function (pat) { return (this.union(size(pat))) }; -export const speed = pat => _name("speed", pat); -Pattern.prototype.speed = function (pat) { return (this.union(speed(pat))) }; +export const room = (pat) => _name('room', pat); +Pattern.prototype.room = _unionise(room); + +export const size = (pat) => _name('size', pat); +Pattern.prototype.size = _unionise(size); + +export const speed = (pat) => _name('speed', pat); +Pattern.prototype.speed = _unionise(speed); + +export const squiz = (pat) => _name('squiz', pat); +Pattern.prototype.squiz = _unionise(squiz); + +// currently overwritten by tone package +export const gain = (pat) => _name('gain', pat); +Pattern.prototype.gain = _unionise(gain); + +export const vowel = (pat) => _name('vowel', pat); +Pattern.prototype.vowel = _unionise(vowel); \ No newline at end of file From acca363a4eae462c3606e335cb7891e85b1ff12b Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 16:06:42 +0100 Subject: [PATCH 17/37] move osc/superdirt to core/controls --- packages/osc/superdirt.mjs | 37 ------------------------------------- repl/src/App.js | 4 ++-- 2 files changed, 2 insertions(+), 39 deletions(-) delete mode 100644 packages/osc/superdirt.mjs diff --git a/packages/osc/superdirt.mjs b/packages/osc/superdirt.mjs deleted file mode 100644 index 5f9c6efd..00000000 --- a/packages/osc/superdirt.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import { Pattern, sequence } from '@strudel.cycles/core/strudel.mjs'; - -const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x })); - -const _unionise = (func) => - function (...pats) { - return this.union(func(...pats)); - }; - -export const s = (...pats) => _name('s', ...pats); -Pattern.prototype.s = _unionise(s); -export const sound = s; -Pattern.prototype.sound = Pattern.prototype.s; - -export const n = (pat) => _name('n', pat); -Pattern.prototype.n = _unionise(n); -export const number = n; -Pattern.prototype.number = Pattern.prototype.n; - -export const room = (pat) => _name('room', pat); -Pattern.prototype.room = _unionise(room); - -export const size = (pat) => _name('size', pat); -Pattern.prototype.size = _unionise(size); - -export const speed = (pat) => _name('speed', pat); -Pattern.prototype.speed = _unionise(speed); - -export const squiz = (pat) => _name('squiz', pat); -Pattern.prototype.squiz = _unionise(squiz); - -// currently overwritten by tone package -export const gain = (pat) => _name('gain', pat); -Pattern.prototype.gain = _unionise(gain); - -export const vowel = (pat) => _name('vowel', pat); -Pattern.prototype.vowel = _unionise(vowel); \ No newline at end of file diff --git a/repl/src/App.js b/repl/src/App.js index 7f37b75f..df74aed5 100644 --- a/repl/src/App.js +++ b/repl/src/App.js @@ -29,9 +29,9 @@ import '@strudel.cycles/core/euclid.mjs'; import '@strudel.cycles/tone/pianoroll.mjs'; import '@strudel.cycles/tone/draw.mjs'; import '@strudel.cycles/osc/osc.mjs'; -import * as superdirt from '@strudel.cycles/osc/superdirt.mjs'; +import * as controls from '@strudel.cycles/core/controls.mjs'; -extend(Tone, strudel, superdirt, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { +extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), controls, toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { gist, euclid, mini, From 64ea9b7c8ba1d3dbf626e90db7ab3eb8ac68de3e Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 17:32:36 +0100 Subject: [PATCH 18/37] controls (renamed from packages/osc/superdirt.mjs --- packages/core/controls.mjs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/core/controls.mjs diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs new file mode 100644 index 00000000..5f9c6efd --- /dev/null +++ b/packages/core/controls.mjs @@ -0,0 +1,37 @@ +import { Pattern, sequence } from '@strudel.cycles/core/strudel.mjs'; + +const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x })); + +const _unionise = (func) => + function (...pats) { + return this.union(func(...pats)); + }; + +export const s = (...pats) => _name('s', ...pats); +Pattern.prototype.s = _unionise(s); +export const sound = s; +Pattern.prototype.sound = Pattern.prototype.s; + +export const n = (pat) => _name('n', pat); +Pattern.prototype.n = _unionise(n); +export const number = n; +Pattern.prototype.number = Pattern.prototype.n; + +export const room = (pat) => _name('room', pat); +Pattern.prototype.room = _unionise(room); + +export const size = (pat) => _name('size', pat); +Pattern.prototype.size = _unionise(size); + +export const speed = (pat) => _name('speed', pat); +Pattern.prototype.speed = _unionise(speed); + +export const squiz = (pat) => _name('squiz', pat); +Pattern.prototype.squiz = _unionise(squiz); + +// currently overwritten by tone package +export const gain = (pat) => _name('gain', pat); +Pattern.prototype.gain = _unionise(gain); + +export const vowel = (pat) => _name('vowel', pat); +Pattern.prototype.vowel = _unionise(vowel); \ No newline at end of file From 1fb1d15d4c14e6397a34684c703a9e1e15d602d7 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 18:38:20 +0100 Subject: [PATCH 19/37] add all the superdirt controls --- packages/core/controls.mjs | 557 +++++++++++++++++++++++++++++++++++-- 1 file changed, 532 insertions(+), 25 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 5f9c6efd..a4587f0b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -1,5 +1,278 @@ import { Pattern, sequence } from '@strudel.cycles/core/strudel.mjs'; +const controls = {}; +const generic_params = [ + ['s', 's', 'sound'], + //['s', 'toArg', 'for internal sound routing'], + // ["f", "from", "for internal sound routing"), + //['f', 'to', 'for internal sound routing'], + ['f', 'accelerate', 'a pattern of numbers that speed up (or slow down) samples while they play.'], + ['f', 'amp', 'like @gain@, but linear.'], + [ + 'f', + 'attack', + 'a pattern of numbers to specify the attack time (in seconds) of an envelope applied to each sample.', + ], + ['f', 'bandf', 'a pattern of numbers from 0 to 1. Sets the center frequency of the band-pass filter.'], + ['f', 'bandq', 'a pattern of anumbers from 0 to 1. Sets the q-factor of the band-pass filter.'], + [ + 'f', + 'begin', + 'a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.', + ], + ['f', 'legato', 'controls the amount of overlap between two adjacent sounds'], + // ['f', 'clhatdecay', ''], + [ + 'f', + 'crush', + 'bit crushing, a pattern of numbers from 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).', + ], + [ + 'f', + 'coarse', + 'fake-resampling, a pattern of numbers for lowering the sample rate, i.e. 1 for original 2 for half, 3 for a third and so on.', + ], + ['i', 'channel', 'choose the channel the pattern is sent to in superdirt'], + [ + 'i', + 'cut', + 'In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open.', + ], + ['f', 'cutoff', 'a pattern of numbers from 0 to 1. Applies the cutoff frequency of the low-pass filter.'], + // ['f', 'cutoffegint', ''], + ['f', 'decay', ''], + ['f', 'delay', 'a pattern of numbers from 0 to 1. Sets the level of the delay signal.'], + ['f', 'delayfeedback', 'a pattern of numbers from 0 to 1. Sets the amount of delay feedback.'], + ['f', 'delaytime', 'a pattern of numbers from 0 to 1. Sets the length of the delay.'], + ['f', 'detune', ''], + ['f', 'djf', 'DJ filter, below 0.5 is low pass filter, above is high pass filter.'], + [ + 'f', + 'dry', + 'when set to `1` will disable all reverb for this pattern. See `room` and `size` for more information about reverb.', + ], + [ + 'f', + 'end', + 'the same as `begin`, but cuts the end off samples, shortening them; e.g. `0.75` to cut off the last quarter of each sample.', + ], + [ + 'f', + 'fadeTime', + "Used when using begin/end or chop/striate and friends, to change the fade out time of the 'grain' envelope.", + ], + [ + 'f', + 'fadeInTime', + 'As with fadeTime, but controls the fade in time of the grain envelope. Not used if the grain begins at position 0 in the sample.', + ], + ['f', 'freq', ''], + [ + 'f', + 'gain', + 'a pattern of numbers that specify volume. Values less than 1 make the sound quieter. Values greater than 1 make the sound louder. For the linear equivalent, see @amp@.', + ], + ['f', 'gate', ''], + // ['f', 'hatgrain', ''], + [ + 'f', + 'hcutoff', + 'a pattern of numbers from 0 to 1. Applies the cutoff frequency of the high-pass filter. Also has alias @hpf@', + ], + [ + 'f', + 'hold', + 'a pattern of numbers to specify the hold time (in seconds) of an envelope applied to each sample. Only takes effect if `attack` and `release` are also specified.', + ], + [ + 'f', + 'hresonance', + 'a pattern of numbers from 0 to 1. Applies the resonance of the high-pass filter. Has alias @hpq@', + ], + // ['f', 'lagogo', ''], + // ['f', 'lclap', ''], + // ['f', 'lclaves', ''], + // ['f', 'lclhat', ''], + // ['f', 'lcrash', ''], + ['f', 'leslie', ''], + ['f', 'lrate', ''], + ['f', 'lsize', ''], + // ['f', 'lfo', ''], + // ['f', 'lfocutoffint', ''], + // ['f', 'lfodelay', ''], + // ['f', 'lfoint', ''], + // ['f', 'lfopitchint', ''], + // ['f', 'lfoshape', ''], + // ['f', 'lfosync', ''], + // ['f', 'lhitom', ''], + // ['f', 'lkick', ''], + // ['f', 'llotom', ''], + [ + 'f', + 'lock', + 'A pattern of numbers. Specifies whether delaytime is calculated relative to cps. When set to 1, delaytime is a direct multiple of a cycle.', + ], + ['f', 'loop', 'loops the sample (from `begin` to `end`) the specified number of times.'], + // ['f', 'lophat', ''], + // ['f', 'lsnare', ''], + ['f', 'n', 'The note or sample number to choose for a synth or sampleset'], + ['f', 'note', 'The note or pitch to play a sound or synth with'], + ['f', 'degree', ''], + ['f', 'mtranspose', ''], + ['f', 'ctranspose', ''], + ['f', 'harmonic', ''], + ['f', 'stepsPerOctave', ''], + ['f', 'octaveR', ''], + [ + 'f', + 'nudge', + 'Nudges events into the future by the specified number of seconds. Negative numbers work up to a point as well (due to internal latency)', + ], + ['i', 'octave', ''], + ['f', 'offset', ''], + // ['f', 'ophatdecay', ''], + [ + 'i', + 'orbit', + 'a pattern of numbers. An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share hardware output bus offset and global effects, e.g. reverb and delay. The maximum number of orbits is specified in the superdirt startup, numbers higher than maximum will wrap around.', + ], + ['f', 'overgain', ''], + ['f', 'overshape', ''], + [ + 'f', + 'pan', + 'a pattern of numbers between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)', + ], + [ + 'f', + 'panspan', + 'a pattern of numbers between -inf and inf, which controls how much multichannel output is fanned out (negative is backwards ordering)', + ], + [ + 'f', + 'pansplay', + 'a pattern of numbers between 0.0 and 1.0, which controls the multichannel spread range (multichannel only)', + ], + [ + 'f', + 'panwidth', + 'a pattern of numbers between 0.0 and inf, which controls how much each channel is distributed over neighbours (multichannel only)', + ], + [ + 'f', + 'panorient', + 'a pattern of numbers between -1.0 and 1.0, which controls the relative position of the centre pan in a pair of adjacent speakers (multichannel only)', + ], + // ['f', 'pitch1', ''], + // ['f', 'pitch2', ''], + // ['f', 'pitch3', ''], + // ['f', 'portamento', ''], + ['f', 'rate', "used in SuperDirt softsynths as a control rate or 'speed'"], + [ + 'f', + 'release', + 'a pattern of numbers to specify the release time (in seconds) of an envelope applied to each sample.', + ], + ['f', 'resonance', 'a pattern of numbers from 0 to 1. Specifies the resonance of the low-pass filter.'], + ['f', 'room', 'a pattern of numbers from 0 to 1. Sets the level of reverb.'], + // ['f', 'sagogo', ''], + // ['f', 'sclap', ''], + // ['f', 'sclaves', ''], + // ['f', 'scrash', ''], + ['f', 'semitone', ''], + [ + 'f', + 'shape', + 'wave shaping distortion, a pattern of numbers from 0 for no distortion up to 1 for loads of distortion.', + ], + [ + 'f', + 'size', + 'a pattern of numbers from 0 to 1. Sets the perceptual size (reverb time) of the `room` to be used in reverb.', + ], + ['f', 'slide', ''], + [ + 'f', + 'speed', + 'a pattern of numbers which changes the speed of sample playback, i.e. a cheap way of changing pitch. Negative values will play the sample backwards!', + ], + ['f', 'squiz', ''], + ['f', 'stutterdepth', ''], + ['f', 'stuttertime', ''], + ['f', 'sustain', ''], + ['f', 'timescale', ''], + ['f', 'timescalewin', ''], + // ['f', 'tomdecay', ''], + [ + 's', + 'unit', + 'used in conjunction with `speed`, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.', + ], + ['f', 'velocity', ''], + // ['f', 'vcfegint', ''], + // ['f', 'vcoegint', ''], + ['f', 'voice', ''], + [ + 's', + 'vowel', + 'formant filter to make things sound like vowels, a pattern of either `a`, `e`, `i`, `o` or `u`. Use a rest (`~`) for no effect.', + ], + ['f', 'waveloss', ''], + ['f', 'dur', ''], + // ['f', 'modwheel', ''], + ['f', 'expression', ''], + ['f', 'sustainpedal', ''], + ['f', 'tremolodepth', "Tremolo Audio DSP effect | params are 'tremolorate' and 'tremolodepth'"], + ['f', 'tremolorate', "Tremolo Audio DSP effect | params are 'tremolorate' and 'tremolodepth'"], + ['f', 'phaserdepth', "Phaser Audio DSP effect | params are 'phaserrate' and 'phaserdepth'"], + ['f', 'phaserrate', "Phaser Audio DSP effect | params are 'phaserrate' and 'phaserdepth'"], + ['f', 'fshift', 'frequency shifter'], + ['f', 'fshiftnote', 'frequency shifter'], + ['f', 'fshiftphase', 'frequency shifter'], + ['f', 'triode', 'tube distortion'], + ['f', 'krush', 'shape/bass enhancer'], + ['f', 'kcutoff', ''], + ['f', 'octer', 'octaver effect'], + ['f', 'octersub', 'octaver effect'], + ['f', 'octersubsub', 'octaver effect'], + ['f', 'ring', 'ring modulation'], + ['f', 'ringf', 'ring modulation'], + ['f', 'ringdf', 'ring modulation'], + ['f', 'distort', 'noisy fuzzy distortion'], + ['f', 'freeze', 'Spectral freeze'], + ['f', 'xsdelay', ''], + ['f', 'tsdelay', ''], + ['f', 'real', 'Spectral conform'], + ['f', 'imag', ''], + ['f', 'enhance', 'Spectral enhance'], + ['f', 'partials', ''], + ['f', 'comb', 'Spectral comb'], + ['f', 'smear', 'Spectral smear'], + ['f', 'scram', 'Spectral scramble'], + ['f', 'binshift', 'Spectral binshift'], + ['f', 'hbrick', 'High pass sort of spectral filter'], + ['f', 'lbrick', 'Low pass sort of spectral filter'], + ['f', 'midichan', ''], + ['f', 'control', ''], + ['f', 'ccn', ''], + ['f', 'ccv', ''], + ['f', 'polyTouch', ''], + ['f', 'midibend', ''], + ['f', 'miditouch', ''], + ['f', 'ctlNum', ''], + ['f', 'frameRate', ''], + ['f', 'frames', ''], + ['f', 'hours', ''], + ['s', 'midicmd', ''], + ['f', 'minutes', ''], + ['f', 'progNum', ''], + ['f', 'seconds', ''], + ['f', 'songPtr', ''], + ['f', 'uid', ''], + ['f', 'val', ''], + ['f', 'cps', ''], +]; + const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x })); const _unionise = (func) => @@ -7,31 +280,265 @@ const _unionise = (func) => return this.union(func(...pats)); }; -export const s = (...pats) => _name('s', ...pats); -Pattern.prototype.s = _unionise(s); -export const sound = s; -Pattern.prototype.sound = Pattern.prototype.s; +generic_params.forEach(([type, name, description]) => { + controls[name] = (...pats) => _name(name, ...pats); + Pattern.prototype[name] = _unionise(controls[name]); +}); -export const n = (pat) => _name('n', pat); -Pattern.prototype.n = _unionise(n); -export const number = n; -Pattern.prototype.number = Pattern.prototype.n; +console.log(Object.keys(controls).sort().join(', ')); -export const room = (pat) => _name('room', pat); -Pattern.prototype.room = _unionise(room); +const { + accelerate, + amp, + attack, + bandf, + bandq, + begin, + binshift, + ccn, + ccv, + channel, + coarse, + comb, + control, + cps, + crush, + ctlNum, + ctranspose, + cut, + cutoff, + decay, + degree, + delay, + delayfeedback, + delaytime, + detune, + distort, + djf, + dry, + dur, + end, + enhance, + expression, + fadeInTime, + fadeTime, + frameRate, + frames, + freeze, + freq, + fshift, + fshiftnote, + fshiftphase, + gain, + gate, + harmonic, + hbrick, + hcutoff, + hold, + hours, + hresonance, + imag, + kcutoff, + krush, + lbrick, + legato, + leslie, + lock, + loop, + lrate, + lsize, + midibend, + midichan, + midicmd, + miditouch, + minutes, + mtranspose, + n, + note, + nudge, + octave, + octaveR, + octer, + octersub, + octersubsub, + offset, + orbit, + overgain, + overshape, + pan, + panorient, + panspan, + pansplay, + panwidth, + partials, + phaserdepth, + phaserrate, + polyTouch, + progNum, + rate, + real, + release, + resonance, + ring, + ringdf, + ringf, + room, + s, + scram, + seconds, + semitone, + shape, + size, + slide, + smear, + songPtr, + speed, + squiz, + stepsPerOctave, + stutterdepth, + stuttertime, + sustain, + sustainpedal, + timescale, + timescalewin, + tremolodepth, + tremolorate, + triode, + tsdelay, + uid, + unit, + val, + velocity, + voice, + vowel, + waveloss, + xsdelay, +} = controls; -export const size = (pat) => _name('size', pat); -Pattern.prototype.size = _unionise(size); - -export const speed = (pat) => _name('speed', pat); -Pattern.prototype.speed = _unionise(speed); - -export const squiz = (pat) => _name('squiz', pat); -Pattern.prototype.squiz = _unionise(squiz); - -// currently overwritten by tone package -export const gain = (pat) => _name('gain', pat); -Pattern.prototype.gain = _unionise(gain); - -export const vowel = (pat) => _name('vowel', pat); -Pattern.prototype.vowel = _unionise(vowel); \ No newline at end of file +export { + accelerate, + amp, + attack, + bandf, + bandq, + begin, + binshift, + ccn, + ccv, + channel, + coarse, + comb, + control, + cps, + crush, + ctlNum, + ctranspose, + cut, + cutoff, + decay, + degree, + delay, + delayfeedback, + delaytime, + detune, + distort, + djf, + dry, + dur, + end, + enhance, + expression, + fadeInTime, + fadeTime, + frameRate, + frames, + freeze, + freq, + fshift, + fshiftnote, + fshiftphase, + gain, + gate, + harmonic, + hbrick, + hcutoff, + hold, + hours, + hresonance, + imag, + kcutoff, + krush, + lbrick, + legato, + leslie, + lock, + loop, + lrate, + lsize, + midibend, + midichan, + midicmd, + miditouch, + minutes, + mtranspose, + n, + note, + nudge, + octave, + octaveR, + octer, + octersub, + octersubsub, + offset, + orbit, + overgain, + overshape, + pan, + panorient, + panspan, + pansplay, + panwidth, + partials, + phaserdepth, + phaserrate, + polyTouch, + progNum, + rate, + real, + release, + resonance, + ring, + ringdf, + ringf, + room, + s, + scram, + seconds, + semitone, + shape, + size, + slide, + smear, + songPtr, + speed, + squiz, + stepsPerOctave, + stutterdepth, + stuttertime, + sustain, + sustainpedal, + timescale, + timescalewin, + tremolodepth, + tremolorate, + triode, + tsdelay, + uid, + unit, + val, + velocity, + voice, + vowel, + waveloss, + xsdelay, +}; \ No newline at end of file From 7bbac0ed23887c8c8671e224349a1a7f6cad60ee Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 18:40:27 +0100 Subject: [PATCH 20/37] newline --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a4587f0b..093fcf0f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -541,4 +541,4 @@ export { vowel, waveloss, xsdelay, -}; \ No newline at end of file +}; From c3b15fffa4bc560a26b0169a0ab2a69cd277ea6f Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 2 Apr 2022 18:48:30 +0100 Subject: [PATCH 21/37] remove duplication --- packages/core/controls.mjs | 258 +------------------------------------ repl/src/App.js | 2 +- 2 files changed, 2 insertions(+), 258 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 093fcf0f..5ae19da6 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -285,260 +285,4 @@ generic_params.forEach(([type, name, description]) => { Pattern.prototype[name] = _unionise(controls[name]); }); -console.log(Object.keys(controls).sort().join(', ')); - -const { - accelerate, - amp, - attack, - bandf, - bandq, - begin, - binshift, - ccn, - ccv, - channel, - coarse, - comb, - control, - cps, - crush, - ctlNum, - ctranspose, - cut, - cutoff, - decay, - degree, - delay, - delayfeedback, - delaytime, - detune, - distort, - djf, - dry, - dur, - end, - enhance, - expression, - fadeInTime, - fadeTime, - frameRate, - frames, - freeze, - freq, - fshift, - fshiftnote, - fshiftphase, - gain, - gate, - harmonic, - hbrick, - hcutoff, - hold, - hours, - hresonance, - imag, - kcutoff, - krush, - lbrick, - legato, - leslie, - lock, - loop, - lrate, - lsize, - midibend, - midichan, - midicmd, - miditouch, - minutes, - mtranspose, - n, - note, - nudge, - octave, - octaveR, - octer, - octersub, - octersubsub, - offset, - orbit, - overgain, - overshape, - pan, - panorient, - panspan, - pansplay, - panwidth, - partials, - phaserdepth, - phaserrate, - polyTouch, - progNum, - rate, - real, - release, - resonance, - ring, - ringdf, - ringf, - room, - s, - scram, - seconds, - semitone, - shape, - size, - slide, - smear, - songPtr, - speed, - squiz, - stepsPerOctave, - stutterdepth, - stuttertime, - sustain, - sustainpedal, - timescale, - timescalewin, - tremolodepth, - tremolorate, - triode, - tsdelay, - uid, - unit, - val, - velocity, - voice, - vowel, - waveloss, - xsdelay, -} = controls; - -export { - accelerate, - amp, - attack, - bandf, - bandq, - begin, - binshift, - ccn, - ccv, - channel, - coarse, - comb, - control, - cps, - crush, - ctlNum, - ctranspose, - cut, - cutoff, - decay, - degree, - delay, - delayfeedback, - delaytime, - detune, - distort, - djf, - dry, - dur, - end, - enhance, - expression, - fadeInTime, - fadeTime, - frameRate, - frames, - freeze, - freq, - fshift, - fshiftnote, - fshiftphase, - gain, - gate, - harmonic, - hbrick, - hcutoff, - hold, - hours, - hresonance, - imag, - kcutoff, - krush, - lbrick, - legato, - leslie, - lock, - loop, - lrate, - lsize, - midibend, - midichan, - midicmd, - miditouch, - minutes, - mtranspose, - n, - note, - nudge, - octave, - octaveR, - octer, - octersub, - octersubsub, - offset, - orbit, - overgain, - overshape, - pan, - panorient, - panspan, - pansplay, - panwidth, - partials, - phaserdepth, - phaserrate, - polyTouch, - progNum, - rate, - real, - release, - resonance, - ring, - ringdf, - ringf, - room, - s, - scram, - seconds, - semitone, - shape, - size, - slide, - smear, - songPtr, - speed, - squiz, - stepsPerOctave, - stutterdepth, - stuttertime, - sustain, - sustainpedal, - timescale, - timescalewin, - tremolodepth, - tremolorate, - triode, - tsdelay, - uid, - unit, - val, - velocity, - voice, - vowel, - waveloss, - xsdelay, -}; +export default controls; diff --git a/repl/src/App.js b/repl/src/App.js index df74aed5..e3fe8f70 100644 --- a/repl/src/App.js +++ b/repl/src/App.js @@ -29,7 +29,7 @@ import '@strudel.cycles/core/euclid.mjs'; import '@strudel.cycles/tone/pianoroll.mjs'; import '@strudel.cycles/tone/draw.mjs'; import '@strudel.cycles/osc/osc.mjs'; -import * as controls from '@strudel.cycles/core/controls.mjs'; +import controls from '@strudel.cycles/core/controls.mjs'; extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), controls, toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { gist, From 86b1e992a158a56d8fa03aef0f6c2407c803015b Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 2 Apr 2022 21:46:56 +0200 Subject: [PATCH 22/37] fix absolute time --- packages/osc/osc.mjs | 8 +++----- repl/src/useCycle.mjs | 9 +++++++-- repl/src/useRepl.mjs | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index bfa3cf96..3baefb0f 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -1,17 +1,15 @@ import OSC from './node_modules/osc-js/lib/osc.js'; -import { Pattern, isPattern } from '@strudel.cycles/core/strudel.mjs'; +import { Pattern } from '@strudel.cycles/core/strudel.mjs'; const comm = new OSC(); comm.open(); -// TODO - get startTime from scheduler -const startTime = Date.now(); const latency = 0.1; Pattern.prototype.osc = function () { return this._withEvent((event) => { - const onTrigger = (time, event) => { + const onTrigger = (time, event, startedAt) => { const keyvals = Object.entries(event.value).flat(); - const ts = Math.floor(startTime + ((time + latency) * 1000)); + const ts = Math.floor(startedAt + (time + latency) * 1000); const message = new OSC.Message('/dirt/play', ...keyvals); const bundle = new OSC.Bundle([message], ts); bundle.timestamp(ts); // workaround for https://github.com/adzialocha/osc-js/issues/60 diff --git a/repl/src/useCycle.mjs b/repl/src/useCycle.mjs index 199ffb59..9c5f16c4 100644 --- a/repl/src/useCycle.mjs +++ b/repl/src/useCycle.mjs @@ -10,6 +10,8 @@ import { State, TimeSpan } from '@strudel.cycles/core'; ready?: boolean; // if false, query will not be called on change props } */ +export let startedAt; + // function useCycle(props: UseCycleProps) { function useCycle(props) { // onX must use useCallback! @@ -42,7 +44,7 @@ function useCycle(props) { ?.filter((event) => event.part.begin.equals(event.whole.begin)) .forEach((event) => { Tone.getTransport().schedule((time) => { - onEvent(time, event); + onEvent(time, event, startedAt); Tone.Draw.schedule(() => { // do drawing or DOM manipulation here onDraw?.(time, event); @@ -57,7 +59,10 @@ function useCycle(props) { const start = async () => { setStarted(true); - await Tone.start(); + if (!startedAt) { + await Tone.start(); + startedAt = Date.now() - Tone.getContext().currentTime * 1000; + } Tone.getTransport().start('+0.1'); }; const stop = () => { diff --git a/repl/src/useRepl.mjs b/repl/src/useRepl.mjs index f1a3dcde..ce823f9b 100644 --- a/repl/src/useRepl.mjs +++ b/repl/src/useRepl.mjs @@ -27,7 +27,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { const cycle = useCycle({ onDraw, onEvent: useCallback( - (time, event) => { + (time, event, startedAt) => { try { onEvent?.(event); const { onTrigger, velocity } = event.context; @@ -41,7 +41,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { /* console.warn('no instrument chosen', event); throw new Error(`no instrument chosen for ${JSON.stringify(event)}`); */ } else { - onTrigger(time, event); + onTrigger(time, event, startedAt); } } catch (err) { console.warn(err); From 0c726d835df70fcbaf71ffca07a3c0cf816050a3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 2 Apr 2022 22:40:35 +0200 Subject: [PATCH 23/37] fix keybindings on safari --- repl/src/App.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/repl/src/App.js b/repl/src/App.js index e3fe8f70..0a928ce0 100644 --- a/repl/src/App.js +++ b/repl/src/App.js @@ -77,8 +77,10 @@ function App() { if (e.ctrlKey || e.altKey) { if (e.code === 'Enter') { await activateCode(); + e.preventDefault(); } else if (e.code === 'Period') { cycle.stop(); + e.preventDefault(); } } }; From c8e9fe519f5c22a83b89cba49cb7cee4b8cd02b0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 2 Apr 2022 22:41:04 +0200 Subject: [PATCH 24/37] osc timing now hopefully works everywhere --- packages/osc/osc.mjs | 7 +++++-- repl/src/useCycle.mjs | 9 ++------- repl/src/useRepl.mjs | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 3baefb0f..932e803d 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -7,9 +7,12 @@ const latency = 0.1; Pattern.prototype.osc = function () { return this._withEvent((event) => { - const onTrigger = (time, event, startedAt) => { + const onTrigger = (time, event, currentTime) => { + // time should be audio time of onset + // currentTime should be current time of audio context (slightly before time) const keyvals = Object.entries(event.value).flat(); - const ts = Math.floor(startedAt + (time + latency) * 1000); + const offset = (time - currentTime + latency) * 1000; + const ts = Math.floor(Date.now() + offset); const message = new OSC.Message('/dirt/play', ...keyvals); const bundle = new OSC.Bundle([message], ts); bundle.timestamp(ts); // workaround for https://github.com/adzialocha/osc-js/issues/60 diff --git a/repl/src/useCycle.mjs b/repl/src/useCycle.mjs index 9c5f16c4..908193f9 100644 --- a/repl/src/useCycle.mjs +++ b/repl/src/useCycle.mjs @@ -10,8 +10,6 @@ import { State, TimeSpan } from '@strudel.cycles/core'; ready?: boolean; // if false, query will not be called on change props } */ -export let startedAt; - // function useCycle(props: UseCycleProps) { function useCycle(props) { // onX must use useCallback! @@ -44,7 +42,7 @@ function useCycle(props) { ?.filter((event) => event.part.begin.equals(event.whole.begin)) .forEach((event) => { Tone.getTransport().schedule((time) => { - onEvent(time, event, startedAt); + onEvent(time, event, Tone.getContext().currentTime); Tone.Draw.schedule(() => { // do drawing or DOM manipulation here onDraw?.(time, event); @@ -59,10 +57,7 @@ function useCycle(props) { const start = async () => { setStarted(true); - if (!startedAt) { - await Tone.start(); - startedAt = Date.now() - Tone.getContext().currentTime * 1000; - } + await Tone.start(); Tone.getTransport().start('+0.1'); }; const stop = () => { diff --git a/repl/src/useRepl.mjs b/repl/src/useRepl.mjs index ce823f9b..061cd2f3 100644 --- a/repl/src/useRepl.mjs +++ b/repl/src/useRepl.mjs @@ -27,7 +27,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { const cycle = useCycle({ onDraw, onEvent: useCallback( - (time, event, startedAt) => { + (time, event, currentTime) => { try { onEvent?.(event); const { onTrigger, velocity } = event.context; @@ -41,7 +41,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { /* console.warn('no instrument chosen', event); throw new Error(`no instrument chosen for ${JSON.stringify(event)}`); */ } else { - onTrigger(time, event, startedAt); + onTrigger(time, event, currentTime); } } catch (err) { console.warn(err); From f8cbd6755780571b8aa3b1579b89a003b18b606f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 20:14:08 +0200 Subject: [PATCH 25/37] fix: disable highlighting --- repl/src/useRepl.mjs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/repl/src/useRepl.mjs b/repl/src/useRepl.mjs index 061cd2f3..c20a9cba 100644 --- a/repl/src/useRepl.mjs +++ b/repl/src/useRepl.mjs @@ -23,6 +23,13 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { const dirty = useMemo(() => code !== activeCode || error, [code, activeCode, error]); const pushLog = useCallback((message) => setLog((log) => log + `${log ? '\n\n' : ''}${message}`), []); + // below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment) + onDraw = useMemo(() => { + if (activeCode && !activeCode.includes('strudel disable-highlighting')) { + return onDraw; + } + }, [activeCode, onDraw]); + // cycle hook to control scheduling const cycle = useCycle({ onDraw, @@ -111,13 +118,6 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }) { } }; - // below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment) - onDraw = useMemo(() => { - if (activeCode && !activeCode.includes('strudel disable-highlighting')) { - return onDraw; - } - }, [activeCode, onDraw]); - const togglePlay = () => { if (!cycle.started) { activateCode(); From c604f920a061b603e1ccba533ec2920f40d8690f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 20:14:48 +0200 Subject: [PATCH 26/37] add root scripts --- package-lock.json | 75 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 ++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 299d7e7d..2fefcea2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1885,6 +1885,10 @@ "resolved": "packages/mini", "link": true }, + "node_modules/@strudel.cycles/osc": { + "resolved": "packages/osc", + "link": true + }, "node_modules/@strudel.cycles/tonal": { "resolved": "packages/tonal", "link": true @@ -5131,6 +5135,14 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -6703,6 +6715,15 @@ "node": ">=0.10.0" } }, + "node_modules/osc-js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.1.tgz", + "integrity": "sha512-DjpfUcyTsMmD7uLdyjqsT9zwuNkUOG8yJMc56H9spTCRqTls5vLt5QnlVploVqSRwQ2stvcc+CsY18ouxab9mg==", + "dependencies": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, "node_modules/osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", @@ -9085,6 +9106,26 @@ "node": ">=6" } }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", @@ -9266,6 +9307,13 @@ "@strudel.cycles/tone": "^0.0.4" } }, + "packages/osc": { + "version": "0.0.1", + "license": "GPL-3.0-or-later", + "dependencies": { + "osc-js": "^2.3.0" + } + }, "packages/tonal": { "name": "@strudel.cycles/tonal", "version": "0.0.3", @@ -10847,6 +10895,12 @@ "@strudel.cycles/tone": "^0.0.4" } }, + "@strudel.cycles/osc": { + "version": "file:packages/osc", + "requires": { + "osc-js": "^2.3.0" + } + }, "@strudel.cycles/tonal": { "version": "file:packages/tonal", "requires": { @@ -13407,6 +13461,12 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "requires": {} + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -14632,6 +14692,15 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osc-js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.1.tgz", + "integrity": "sha512-DjpfUcyTsMmD7uLdyjqsT9zwuNkUOG8yJMc56H9spTCRqTls5vLt5QnlVploVqSRwQ2stvcc+CsY18ouxab9mg==", + "requires": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", @@ -16490,6 +16559,12 @@ } } }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} + }, "xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", diff --git a/package.json b/package.json index d78b901a..4702ff10 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "main": "strudel.mjs", "scripts": { "test": "npm run test --workspaces --if-present", - "bootstrap": "lerna bootstrap" + "bootstrap": "lerna bootstrap", + "repl": "cd repl && npm run start", + "osc": "cd packages/osc && npm run server" }, "workspaces": [ "packages/*" From 324dcd7ef8a9ce4e27cd6e60a3b20ea02803fae1 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 12 Apr 2022 21:48:11 +0100 Subject: [PATCH 27/37] use local osc.js --- packages/osc/osc.mjs | 2 +- packages/osc/server.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 932e803d..2965fa30 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -1,4 +1,4 @@ -import OSC from './node_modules/osc-js/lib/osc.js'; +import OSC from './osc-js/osc.js'; import { Pattern } from '@strudel.cycles/core/strudel.mjs'; const comm = new OSC(); diff --git a/packages/osc/server.js b/packages/osc/server.js index f765b284..febe2d90 100644 --- a/packages/osc/server.js +++ b/packages/osc/server.js @@ -1,4 +1,4 @@ -const OSC = require('osc-js'); +const OSC = require('./osc-js/osc.js'); const config = { receiver: 'ws', // @param {string} Where messages sent via 'send' method will be delivered to, 'ws' for Websocket clients, 'udp' for udp client From 57c1c4e016a495bb456aaf1601a42017787a3a7f Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 12 Apr 2022 21:48:29 +0100 Subject: [PATCH 28/37] more info --- packages/osc/osc-js/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/osc/osc-js/README.md diff --git a/packages/osc/osc-js/README.md b/packages/osc/osc-js/README.md new file mode 100644 index 00000000..323d870c --- /dev/null +++ b/packages/osc/osc-js/README.md @@ -0,0 +1,5 @@ +Adapted from https://github.com/adzialocha/osc-js/ , with small fix. + +We'll return to using upstream version when this bug is resolved: + https://github.com/adzialocha/osc-js/issues/50 + From 4111a12cbfafa709055a624a4fb4fcc0aa7fb15b Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 12 Apr 2022 21:48:48 +0100 Subject: [PATCH 29/37] hard temporary fork of osc-js --- packages/osc/osc-js/LICENSE | 22 + packages/osc/osc-js/osc.js | 1747 +++++++++++++++++++++++++++++++++++ 2 files changed, 1769 insertions(+) create mode 100644 packages/osc/osc-js/LICENSE create mode 100644 packages/osc/osc-js/osc.js diff --git a/packages/osc/osc-js/LICENSE b/packages/osc/osc-js/LICENSE new file mode 100644 index 00000000..5a99e00b --- /dev/null +++ b/packages/osc/osc-js/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2016 adzialocha (Andreas Dzialocha) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/osc/osc-js/osc.js b/packages/osc/osc-js/osc.js new file mode 100644 index 00000000..976f250c --- /dev/null +++ b/packages/osc/osc-js/osc.js @@ -0,0 +1,1747 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.OSC = factory()); +})(this, (function () { 'use strict'; + + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + + return keys; + } + + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + + return target; + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + Object.defineProperty(subClass, "prototype", { + writable: false + }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); + } + + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + + return _setPrototypeOf(o, p); + } + + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); + return true; + } catch (e) { + return false; + } + } + + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return self; + } + + function _possibleConstructorReturn(self, call) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + + return _assertThisInitialized(self); + } + + function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), + result; + + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + + return _possibleConstructorReturn(this, result); + }; + } + + function _superPropBase(object, property) { + while (!Object.prototype.hasOwnProperty.call(object, property)) { + object = _getPrototypeOf(object); + if (object === null) break; + } + + return object; + } + + function _get() { + if (typeof Reflect !== "undefined" && Reflect.get) { + _get = Reflect.get; + } else { + _get = function _get(target, property, receiver) { + var base = _superPropBase(target, property); + + if (!base) return; + var desc = Object.getOwnPropertyDescriptor(base, property); + + if (desc.get) { + return desc.get.call(arguments.length < 3 ? target : receiver); + } + + return desc.value; + }; + } + + return _get.apply(this, arguments); + } + + function isInt(n) { + return Number(n) === n && n % 1 === 0; + } + function isFloat(n) { + return Number(n) === n && n % 1 !== 0; + } + function isNumber(n) { + return Number(n) === n; + } + function isString(n) { + return typeof n === 'string'; + } + function isBoolean(n) { + return typeof n === 'boolean'; + } + function isInfinity(n) { + return n === Infinity; + } + function isArray(n) { + return Object.prototype.toString.call(n) === '[object Array]'; + } + function isObject(n) { + return Object.prototype.toString.call(n) === '[object Object]'; + } + function isFunction(n) { + return typeof n === 'function'; + } + function isBlob(n) { + return n instanceof Uint8Array; + } + function isDate(n) { + return n instanceof Date; + } + function isUndefined(n) { + return typeof n === 'undefined'; + } + function isNull(n) { + return n === null; + } + function pad(n) { + return n + 3 & ~0x03; + } + function hasProperty(name) { + return Object.prototype.hasOwnProperty.call(typeof global !== 'undefined' ? global : window, + name); + } + function dataView(obj) { + if (obj.buffer) { + return new DataView(obj.buffer); + } else if (obj instanceof ArrayBuffer) { + return new DataView(obj); + } + return new DataView(new Uint8Array(obj)); + } + + function typeTag(item) { + if (isInt(item)) { + return 'i'; + } else if (isFloat(item)) { + return 'f'; + } else if (isString(item)) { + return 's'; + } else if (isBlob(item)) { + return 'b'; + } else if (isBoolean(item)) { + return item ? 'T' : 'F'; + } else if (isNull(item)) { + return 'N'; + } else if (isInfinity(item)) { + return 'I'; + } + throw new Error('OSC typeTag() found unknown value type'); + } + function prepareAddress(obj) { + var address = ''; + if (isArray(obj)) { + return "/".concat(obj.join('/')); + } else if (isString(obj)) { + address = obj; + if (address.length > 1 && address[address.length - 1] === '/') { + address = address.slice(0, address.length - 1); + } + if (address.length > 1 && address[0] !== '/') { + address = "/".concat(address); + } + return address; + } + throw new Error('OSC prepareAddress() needs addresses of type array or string'); + } + function prepareRegExPattern(str) { + var pattern; + if (!isString(str)) { + throw new Error('OSC prepareRegExPattern() needs strings'); + } + pattern = str.replace(/\./g, '\\.'); + pattern = pattern.replace(/\(/g, '\\('); + pattern = pattern.replace(/\)/g, '\\)'); + pattern = pattern.replace(/\{/g, '('); + pattern = pattern.replace(/\}/g, ')'); + pattern = pattern.replace(/,/g, '|'); + pattern = pattern.replace(/\[!/g, '[^'); + pattern = pattern.replace(/\?/g, '.'); + pattern = pattern.replace(/\*/g, '.*'); + return pattern; + } + var EncodeHelper = function () { + function EncodeHelper() { + _classCallCheck(this, EncodeHelper); + this.data = []; + this.byteLength = 0; + } + _createClass(EncodeHelper, [{ + key: "add", + value: function add(item) { + if (isBoolean(item) || isInfinity(item) || isNull(item)) { + return this; + } + var buffer = item.pack(); + this.byteLength += buffer.byteLength; + this.data.push(buffer); + return this; + } + }, { + key: "merge", + value: function merge() { + var result = new Uint8Array(this.byteLength); + var offset = 0; + this.data.forEach(function (data) { + result.set(data, offset); + offset += data.byteLength; + }); + return result; + } + }]); + return EncodeHelper; + }(); + + var Atomic = function () { + function Atomic(value) { + _classCallCheck(this, Atomic); + this.value = value; + this.offset = 0; + } + _createClass(Atomic, [{ + key: "pack", + value: function pack(method, byteLength) { + if (!(method && byteLength)) { + throw new Error('OSC Atomic cant\'t be packed without given method or byteLength'); + } + var data = new Uint8Array(byteLength); + var dataView = new DataView(data.buffer); + if (isUndefined(this.value)) { + throw new Error('OSC Atomic cant\'t be encoded with empty value'); + } + dataView[method](this.offset, this.value, false); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView, method, byteLength) { + var initialOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + if (!(dataView && method && byteLength)) { + throw new Error('OSC Atomic cant\'t be unpacked without given dataView, method or byteLength'); + } + if (!(dataView instanceof DataView)) { + throw new Error('OSC Atomic expects an instance of type DataView'); + } + this.value = dataView[method](initialOffset, false); + this.offset = initialOffset + byteLength; + return this.offset; + } + }]); + return Atomic; + }(); + + var AtomicInt32 = function (_Atomic) { + _inherits(AtomicInt32, _Atomic); + var _super = _createSuper(AtomicInt32); + function AtomicInt32(value) { + _classCallCheck(this, AtomicInt32); + if (value && !isInt(value)) { + throw new Error('OSC AtomicInt32 constructor expects value of type number'); + } + return _super.call(this, value); + } + _createClass(AtomicInt32, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicInt32.prototype), "pack", this).call(this, 'setInt32', 4); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicInt32.prototype), "unpack", this).call(this, dataView, 'getInt32', 4, initialOffset); + } + }]); + return AtomicInt32; + }(Atomic); + + var STR_SLICE_SIZE = 65537; + var STR_ENCODING = 'utf-8'; + function charCodesToString(charCodes) { + if (hasProperty('Buffer')) { + return Buffer.from(charCodes).toString(STR_ENCODING); + } else if (hasProperty('TextDecoder')) { + return new TextDecoder(STR_ENCODING) + .decode(new Int8Array(charCodes)); + } + var str = ''; + for (var i = 0; i < charCodes.length; i += STR_SLICE_SIZE) { + str += String.fromCharCode.apply(null, charCodes.slice(i, i + STR_SLICE_SIZE)); + } + return str; + } + var AtomicString = function (_Atomic) { + _inherits(AtomicString, _Atomic); + var _super = _createSuper(AtomicString); + function AtomicString(value) { + _classCallCheck(this, AtomicString); + if (value && !isString(value)) { + throw new Error('OSC AtomicString constructor expects value of type string'); + } + return _super.call(this, value); + } + _createClass(AtomicString, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicString can not be encoded with empty value'); + } + var terminated = "".concat(this.value, "\0"); + var byteLength = pad(terminated.length); + var buffer = new Uint8Array(byteLength); + for (var i = 0; i < terminated.length; i += 1) { + buffer[i] = terminated.charCodeAt(i); + } + return buffer; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicString expects an instance of type DataView'); + } + var offset = initialOffset; + var charcode; + var charCodes = []; + for (; offset < dataView.byteLength; offset += 1) { + charcode = dataView.getUint8(offset); + if (charcode !== 0) { + charCodes.push(charcode); + } else { + offset += 1; + break; + } + } + if (offset === dataView.length) { + throw new Error('OSC AtomicString found a malformed OSC string'); + } + this.offset = pad(offset); + this.value = charCodesToString(charCodes); + return this.offset; + } + }]); + return AtomicString; + }(Atomic); + + var SECONDS_70_YEARS = 2208988800; + var TWO_POWER_32 = 4294967296; + var Timetag = function () { + function Timetag() { + var seconds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var fractions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + _classCallCheck(this, Timetag); + if (!(isInt(seconds) && isInt(fractions))) { + throw new Error('OSC Timetag constructor expects values of type integer number'); + } + this.seconds = seconds; + this.fractions = fractions; + } + _createClass(Timetag, [{ + key: "timestamp", + value: function timestamp(milliseconds) { + var seconds; + if (typeof milliseconds === 'number') { + seconds = milliseconds / 1000; + var rounded = Math.floor(seconds); + this.seconds = rounded + SECONDS_70_YEARS; + this.fractions = Math.round(TWO_POWER_32 * (seconds - rounded)); + return milliseconds; + } + seconds = this.seconds - SECONDS_70_YEARS; + return (seconds + Math.round(this.fractions / TWO_POWER_32)) * 1000; + } + }]); + return Timetag; + }(); + var AtomicTimetag = function (_Atomic) { + _inherits(AtomicTimetag, _Atomic); + var _super = _createSuper(AtomicTimetag); + function AtomicTimetag() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Date.now(); + _classCallCheck(this, AtomicTimetag); + var timetag = new Timetag(); + if (value instanceof Timetag) { + timetag = value; + } else if (isInt(value)) { + timetag.timestamp(value); + } else if (isDate(value)) { + timetag.timestamp(value.getTime()); + } + return _super.call(this, timetag); + } + _createClass(AtomicTimetag, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicTimetag can not be encoded with empty value'); + } + var _this$value = this.value, + seconds = _this$value.seconds, + fractions = _this$value.fractions; + var data = new Uint8Array(8); + var dataView = new DataView(data.buffer); + dataView.setInt32(0, seconds, false); + dataView.setInt32(4, fractions, false); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicTimetag expects an instance of type DataView'); + } + var seconds = dataView.getUint32(initialOffset, false); + var fractions = dataView.getUint32(initialOffset + 4, false); + this.value = new Timetag(seconds, fractions); + this.offset = initialOffset + 8; + return this.offset; + } + }]); + return AtomicTimetag; + }(Atomic); + + var AtomicBlob = function (_Atomic) { + _inherits(AtomicBlob, _Atomic); + var _super = _createSuper(AtomicBlob); + function AtomicBlob(value) { + _classCallCheck(this, AtomicBlob); + if (value && !isBlob(value)) { + throw new Error('OSC AtomicBlob constructor expects value of type Uint8Array'); + } + return _super.call(this, value); + } + _createClass(AtomicBlob, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicBlob can not be encoded with empty value'); + } + var byteLength = pad(this.value.byteLength); + var data = new Uint8Array(byteLength + 4); + var dataView = new DataView(data.buffer); + dataView.setInt32(0, this.value.byteLength, false); + data.set(this.value, 4); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicBlob expects an instance of type DataView'); + } + var byteLength = dataView.getInt32(initialOffset, false); + this.value = new Uint8Array(dataView.buffer, initialOffset + 4, byteLength); + this.offset = pad(initialOffset + 4 + byteLength); + return this.offset; + } + }]); + return AtomicBlob; + }(Atomic); + + var AtomicFloat32 = function (_Atomic) { + _inherits(AtomicFloat32, _Atomic); + var _super = _createSuper(AtomicFloat32); + function AtomicFloat32(value) { + _classCallCheck(this, AtomicFloat32); + if (value && !isNumber(value)) { + throw new Error('OSC AtomicFloat32 constructor expects value of type float'); + } + return _super.call(this, value); + } + _createClass(AtomicFloat32, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicFloat32.prototype), "pack", this).call(this, 'setFloat32', 4); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicFloat32.prototype), "unpack", this).call(this, dataView, 'getFloat32', 4, initialOffset); + } + }]); + return AtomicFloat32; + }(Atomic); + + var AtomicFloat64 = function (_Atomic) { + _inherits(AtomicFloat64, _Atomic); + var _super = _createSuper(AtomicFloat64); + function AtomicFloat64(value) { + _classCallCheck(this, AtomicFloat64); + if (value && !isNumber(value)) { + throw new Error('OSC AtomicFloat64 constructor expects value of type float'); + } + return _super.call(this, value); + } + _createClass(AtomicFloat64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicFloat64.prototype), "pack", this).call(this, 'setFloat64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicFloat64.prototype), "unpack", this).call(this, dataView, 'getFloat64', 8, initialOffset); + } + }]); + return AtomicFloat64; + }(Atomic); + + var MAX_INT64 = BigInt('9223372036854775807'); + var MIN_INT64 = BigInt('-9223372036854775808'); + var AtomicInt64 = function (_Atomic) { + _inherits(AtomicInt64, _Atomic); + var _super = _createSuper(AtomicInt64); + function AtomicInt64(value) { + _classCallCheck(this, AtomicInt64); + if (value && typeof value !== 'bigint') { + throw new Error('OSC AtomicInt64 constructor expects value of type BigInt'); + } + if (value && (value < MIN_INT64 || value > MAX_INT64)) { + throw new Error('OSC AtomicInt64 value is out of bounds'); + } + var tmp; + if (value) { + tmp = BigInt.asIntN(64, value); + } + return _super.call(this, tmp); + } + _createClass(AtomicInt64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicInt64.prototype), "pack", this).call(this, 'setBigInt64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicInt64.prototype), "unpack", this).call(this, dataView, 'getBigInt64', 8, initialOffset); + } + }]); + return AtomicInt64; + }(Atomic); + + var MAX_UINT64 = BigInt('18446744073709551615'); + var AtomicUInt64 = function (_Atomic) { + _inherits(AtomicUInt64, _Atomic); + var _super = _createSuper(AtomicUInt64); + function AtomicUInt64(value) { + _classCallCheck(this, AtomicUInt64); + if (value && typeof value !== 'bigint') { + throw new Error('OSC AtomicUInt64 constructor expects value of type BigInt'); + } + if (value && (value < 0 || value > MAX_UINT64)) { + throw new Error('OSC AtomicUInt64 value is out of bounds'); + } + var tmp; + if (value) { + tmp = BigInt.asUintN(64, value); + } + return _super.call(this, tmp); + } + _createClass(AtomicUInt64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicUInt64.prototype), "pack", this).call(this, 'setBigUint64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicUInt64.prototype), "unpack", this).call(this, dataView, 'getBigUint64', 8, initialOffset); + } + }]); + return AtomicUInt64; + }(Atomic); + + var VALUE_TRUE = true; + var VALUE_FALSE = false; + var VALUE_NONE = null; + var VALUE_INFINITY = Infinity; + + var TypedMessage = function () { + function TypedMessage(address, args) { + var _this = this; + _classCallCheck(this, TypedMessage); + this.offset = 0; + this.address = ''; + this.types = ''; + this.args = []; + if (!isUndefined(address)) { + if (!(isString(address) || isArray(address))) { + throw new Error('OSC Message constructor first argument (address) must be a string or array'); + } + this.address = prepareAddress(address); + } + if (!isUndefined(args)) { + if (!isArray(args)) { + throw new Error('OSC Message constructor second argument (args) must be an array'); + } + args.forEach(function (item) { + return _this.add(item.type, item.value); + }); + } + } + _createClass(TypedMessage, [{ + key: "add", + value: function add(type, item) { + if (isUndefined(type)) { + throw new Error('OSC Message needs a valid OSC Atomic Data Type'); + } + if (type === 'N') { + this.args.push(VALUE_NONE); + } else if (type === 'T') { + this.args.push(VALUE_TRUE); + } else if (type === 'F') { + this.args.push(VALUE_FALSE); + } else if (type === 'I') { + this.args.push(VALUE_INFINITY); + } else { + this.args.push(item); + } + this.types += type; + } + }, { + key: "pack", + value: function pack() { + var _this2 = this; + if (this.address.length === 0 || this.address[0] !== '/') { + throw new Error('OSC Message has an invalid address'); + } + var encoder = new EncodeHelper(); + encoder.add(new AtomicString(this.address)); + encoder.add(new AtomicString(",".concat(this.types))); + if (this.args.length > 0) { + var argument; + if (this.args.length > this.types.length) { + throw new Error('OSC Message argument and type tag mismatch'); + } + this.args.forEach(function (value, index) { + var type = _this2.types[index]; + if (type === 'i') { + argument = new AtomicInt32(value); + } else if (type === 'h') { + argument = new AtomicInt64(value); + } else if (type === 't') { + argument = new AtomicUInt64(value); + } else if (type === 'f') { + argument = new AtomicFloat32(value); + } else if (type === 'd') { + argument = new AtomicFloat64(value); + } else if (type === 's') { + argument = new AtomicString(value); + } else if (type === 'b') { + argument = new AtomicBlob(value); + } else if (type === 'T') { + argument = VALUE_TRUE; + } else if (type === 'F') { + argument = VALUE_FALSE; + } else if (type === 'N') { + argument = VALUE_NONE; + } else if (type === 'I') { + argument = VALUE_INFINITY; + } else { + throw new Error('OSC Message found unknown argument type'); + } + encoder.add(argument); + }); + } + return encoder.merge(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Message expects an instance of type DataView.'); + } + var address = new AtomicString(); + address.unpack(dataView, initialOffset); + var types = new AtomicString(); + types.unpack(dataView, address.offset); + if (address.value.length === 0 || address.value[0] !== '/') { + throw new Error('OSC Message found malformed or missing address string'); + } + if (types.value.length === 0 && types.value[0] !== ',') { + throw new Error('OSC Message found malformed or missing type string'); + } + var offset = types.offset; + var next; + var type; + var args = []; + for (var i = 1; i < types.value.length; i += 1) { + type = types.value[i]; + next = null; + if (type === 'i') { + next = new AtomicInt32(); + } else if (type === 'h') { + next = new AtomicInt64(); + } else if (type === 't') { + next = new AtomicUInt64(); + } else if (type === 'f') { + next = new AtomicFloat32(); + } else if (type === 'd') { + next = new AtomicFloat64(); + } else if (type === 's') { + next = new AtomicString(); + } else if (type === 'b') { + next = new AtomicBlob(); + } else if (type === 'T') { + args.push(VALUE_TRUE); + } else if (type === 'F') { + args.push(VALUE_FALSE); + } else if (type === 'N') { + args.push(VALUE_NONE); + } else if (type === 'I') { + args.push(VALUE_INFINITY); + } else { + throw new Error('OSC Message found unsupported argument type'); + } + if (next) { + offset = next.unpack(dataView, offset); + args.push(next.value); + } + } + this.offset = offset; + this.address = address.value; + this.types = types.value; + this.args = args; + return this.offset; + } + }]); + return TypedMessage; + }(); + var Message = function (_TypedMessage) { + _inherits(Message, _TypedMessage); + var _super = _createSuper(Message); + function Message() { + var _this3; + _classCallCheck(this, Message); + var address; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length > 0) { + address = args.shift(); + } + var oscArgs; + if (args.length > 0) { + if (args[0] instanceof Array) { + oscArgs = args.shift(); + } + } + _this3 = _super.call(this, address, oscArgs); + if (args.length > 0) { + _this3.types = args.map(function (item) { + return typeTag(item); + }).join(''); + _this3.args = args; + } + return _this3; + } + _createClass(Message, [{ + key: "add", + value: function add(item) { + _get(_getPrototypeOf(Message.prototype), "add", this).call(this, typeTag(item), item); + } + }]); + return Message; + }(TypedMessage); + + var BUNDLE_TAG = '#bundle'; + var Bundle = function () { + function Bundle() { + var _this = this; + _classCallCheck(this, Bundle); + this.offset = 0; + this.timetag = new AtomicTimetag(); + this.bundleElements = []; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length > 0) { + if (args[0] instanceof Date || isInt(args[0])) { + this.timetag = new AtomicTimetag(args[0]); + } else if (isArray(args[0])) { + args[0].forEach(function (item) { + _this.add(item); + }); + if (args.length > 1 && (args[1] instanceof Date || isInt(args[1]))) { + this.timetag = new AtomicTimetag(args[1]); + } + } else { + args.forEach(function (item) { + _this.add(item); + }); + } + } + } + _createClass(Bundle, [{ + key: "timestamp", + value: function timestamp(ms) { + if (!isInt(ms)) { + throw new Error('OSC Bundle needs an integer for setting the timestamp'); + } + this.timetag = new AtomicTimetag(ms); + } + }, { + key: "add", + value: function add(item) { + if (!(item instanceof Message || item instanceof Bundle)) { + throw new Error('OSC Bundle contains only Messages and Bundles'); + } + this.bundleElements.push(item); + } + }, { + key: "pack", + value: function pack() { + var encoder = new EncodeHelper(); + encoder.add(new AtomicString(BUNDLE_TAG)); + if (!this.timetag) { + this.timetag = new AtomicTimetag(); + } + encoder.add(this.timetag); + this.bundleElements.forEach(function (item) { + encoder.add(new AtomicInt32(item.pack().byteLength)); + encoder.add(item); + }); + return encoder.merge(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Bundle expects an instance of type DataView'); + } + var parentHead = new AtomicString(); + parentHead.unpack(dataView, initialOffset); + if (parentHead.value !== BUNDLE_TAG) { + throw new Error('OSC Bundle does not contain a valid #bundle head'); + } + var timetag = new AtomicTimetag(); + var offset = timetag.unpack(dataView, parentHead.offset); + this.bundleElements = []; + while (offset < dataView.byteLength) { + var head = new AtomicString(); + var size = new AtomicInt32(); + offset = size.unpack(dataView, offset); + var item = void 0; + head.unpack(dataView, offset); + if (head.value === BUNDLE_TAG) { + item = new Bundle(); + } else { + item = new Message(); + } + offset = item.unpack(dataView, offset); + this.bundleElements.push(item); + } + this.offset = offset; + this.timetag = timetag; + return this.offset; + } + }]); + return Bundle; + }(); + + var Packet = function () { + function Packet(value) { + _classCallCheck(this, Packet); + if (value && !(value instanceof Message || value instanceof Bundle)) { + throw new Error('OSC Packet value has to be Message or Bundle'); + } + this.value = value; + this.offset = 0; + } + _createClass(Packet, [{ + key: "pack", + value: function pack() { + if (!this.value) { + throw new Error('OSC Packet can not be encoded with empty body'); + } + return this.value.pack(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Packet expects an instance of type DataView'); + } + if (dataView.byteLength % 4 !== 0) { + throw new Error('OSC Packet byteLength has to be a multiple of four'); + } + var head = new AtomicString(); + head.unpack(dataView, initialOffset); + var item; + if (head.value === BUNDLE_TAG) { + item = new Bundle(); + } else { + item = new Message(); + } + item.unpack(dataView, initialOffset); + this.offset = item.offset; + this.value = item; + return this.offset; + } + }]); + return Packet; + }(); + + var defaultOptions$5 = { + discardLateMessages: false + }; + var EventHandler = function () { + function EventHandler(options) { + _classCallCheck(this, EventHandler); + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$5), options); + this.addressHandlers = []; + this.eventHandlers = { + open: [], + error: [], + close: [] + }; + this.uuid = 0; + } + _createClass(EventHandler, [{ + key: "dispatch", + value: function dispatch(packet, rinfo) { + var _this = this; + if (!(packet instanceof Packet)) { + throw new Error('OSC EventHander dispatch() accepts only arguments of type Packet'); + } + if (!packet.value) { + throw new Error('OSC EventHander dispatch() can\'t read empty Packets'); + } + if (packet.value instanceof Bundle) { + var bundle = packet.value; + return bundle.bundleElements.forEach(function (bundleItem) { + if (bundleItem instanceof Bundle) { + if (bundle.timetag.value.timestamp() < bundleItem.timetag.value.timestamp()) { + throw new Error('OSC Bundle timestamp is older than the timestamp of enclosed Bundles'); + } + return _this.dispatch(bundleItem); + } else if (bundleItem instanceof Message) { + var message = bundleItem; + return _this.notify(message.address, message, bundle.timetag.value.timestamp(), rinfo); + } + throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); + }); + } else if (packet.value instanceof Message) { + var message = packet.value; + return this.notify(message.address, message, 0, rinfo); + } + throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); + } + }, { + key: "call", + value: function call(name, data, rinfo) { + var success = false; + if (isString(name) && name in this.eventHandlers) { + this.eventHandlers[name].forEach(function (handler) { + handler.callback(data, rinfo); + success = true; + }); + return success; + } + var handlerKeys = Object.keys(this.addressHandlers); + var handlers = this.addressHandlers; + handlerKeys.forEach(function (key) { + var foundMatch = false; + var regex = new RegExp(prepareRegExPattern(prepareAddress(name)), 'g'); + var test = regex.test(key); + if (test && key.length === regex.lastIndex) { + foundMatch = true; + } + if (!foundMatch) { + var reverseRegex = new RegExp(prepareRegExPattern(prepareAddress(key)), 'g'); + var reverseTest = reverseRegex.test(name); + if (reverseTest && name.length === reverseRegex.lastIndex) { + foundMatch = true; + } + } + if (foundMatch) { + handlers[key].forEach(function (handler) { + handler.callback(data, rinfo); + success = true; + }); + } + }); + return success; + } + }, { + key: "notify", + value: function notify() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length === 0) { + throw new Error('OSC EventHandler can not be called without any argument'); + } + if (args[0] instanceof Packet) { + return this.dispatch(args[0], args[1]); + } else if (args[0] instanceof Bundle || args[0] instanceof Message) { + return this.dispatch(new Packet(args[0]), args[1]); + } else if (!isString(args[0])) { + var packet = new Packet(); + packet.unpack(dataView(args[0])); + return this.dispatch(packet, args[1]); + } + var name = args[0]; + var data = null; + if (args.length > 1) { + data = args[1]; + } + var timestamp = null; + if (args.length > 2) { + if (isInt(args[2])) { + timestamp = args[2]; + } else if (args[2] instanceof Date) { + timestamp = args[2].getTime(); + } else { + throw new Error('OSC EventHandler timestamp has to be a number or Date'); + } + } + var rinfo = null; + if (args.length >= 3) { + rinfo = args[3]; + } + if (timestamp) { + var now = Date.now(); + if (now > timestamp) { + if (!this.options.discardLateMessages) { + return this.call(name, data, rinfo); + } + } + var that = this; + setTimeout(function () { + that.call(name, data, rinfo); + }, timestamp - now); + return true; + } + return this.call(name, data, rinfo); + } + }, { + key: "on", + value: function on(name, callback) { + if (!(isString(name) || isArray(name))) { + throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); + } + if (!isFunction(callback)) { + throw new Error('OSC EventHandler callback has to be a function'); + } + this.uuid += 1; + var handler = { + id: this.uuid, + callback: callback + }; + if (isString(name) && name in this.eventHandlers) { + this.eventHandlers[name].push(handler); + return this.uuid; + } + var address = prepareAddress(name); + if (!(address in this.addressHandlers)) { + this.addressHandlers[address] = []; + } + this.addressHandlers[address].push(handler); + return this.uuid; + } + }, { + key: "off", + value: function off(name, subscriptionId) { + if (!(isString(name) || isArray(name))) { + throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); + } + if (!isInt(subscriptionId)) { + throw new Error('OSC EventHandler subscription id has to be a number'); + } + var key; + var haystack; + if (isString(name) && name in this.eventHandlers) { + key = name; + haystack = this.eventHandlers; + } else { + key = prepareAddress(name); + haystack = this.addressHandlers; + } + if (key in haystack) { + return haystack[key].some(function (item, index) { + if (item.id === subscriptionId) { + haystack[key].splice(index, 1); + return true; + } + return false; + }); + } + return false; + } + }]); + return EventHandler; + }(); + + var dgram$1; + try { + dgram$1 = require('dgram'); + } catch(error) { + if (typeof window === 'undefined') { + throw(error); + } + } + var STATUS$4 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOpenOptions = { + host: 'localhost', + port: 41234, + exclusive: false + }; + var defaultSendOptions = { + host: 'localhost', + port: 41235 + }; + var defaultOptions$4 = { + type: 'udp4', + open: defaultOpenOptions, + send: defaultSendOptions + }; + function mergeOptions$1(base, custom) { + return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4), base), custom), {}, { + open: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.open), base.open), custom.open), + send: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.send), base.send), custom.send) + }); + } + var DatagramPlugin = function () { + function DatagramPlugin() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, DatagramPlugin); + if (!dgram$1) { + throw new Error('DatagramPlugin can not be used in browser context'); + } + this.options = mergeOptions$1({}, customOptions); + this.socket = dgram$1.createSocket(this.options.type); + this.socketStatus = STATUS$4.IS_NOT_INITIALIZED; + this.socket.on('message', function (message, rinfo) { + _this.notify(message, rinfo); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.notify = function () {}; + } + _createClass(DatagramPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this2 = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options.open), customOptions); + var port = options.port, + exclusive = options.exclusive; + this.socketStatus = STATUS$4.IS_CONNECTING; + this.socket.bind({ + address: options.host, + port: port, + exclusive: exclusive + }, function () { + _this2.socketStatus = STATUS$4.IS_OPEN; + _this2.notify('open'); + }); + } + }, { + key: "close", + value: function close() { + var _this3 = this; + this.socketStatus = STATUS$4.IS_CLOSING; + this.socket.close(function () { + _this3.socketStatus = STATUS$4.IS_CLOSED; + _this3.notify('close'); + }); + } + }, { + key: "send", + value: function send(binary) { + var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options.send), customOptions); + var port = options.port, + host = options.host; + this.socket.send(Buffer.from(binary), 0, binary.byteLength, port, host); + } + }]); + return DatagramPlugin; + }(); + + var dgram; + try { + dgram = require('dgram'); + } catch(error) { + if (typeof window === 'undefined') { + throw(error); + } + } + var WebSocketServer$1 = typeof window === 'undefined' ? require('isomorphic-ws').Server : undefined; + var STATUS$3 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$3 = { + udpServer: { + host: 'localhost', + port: 41234, + exclusive: false + }, + udpClient: { + host: 'localhost', + port: 41235 + }, + wsServer: { + host: 'localhost', + port: 8080 + }, + receiver: 'ws' + }; + function mergeOptions(base, custom) { + return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3), base), custom), {}, { + udpServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpServer), base.udpServer), custom.udpServer), + udpClient: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpClient), base.udpClient), custom.udpClient), + wsServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.wsServer), base.wsServer), custom.wsServer) + }); + } + var BridgePlugin = function () { + function BridgePlugin() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, BridgePlugin); + if (!dgram || !WebSocketServer$1) { + throw new Error('BridgePlugin can not be used in browser context'); + } + this.options = mergeOptions({}, customOptions); + this.websocket = null; + this.socket = dgram.createSocket('udp4'); + this.socketStatus = STATUS$3.IS_NOT_INITIALIZED; + this.socket.on('message', function (message) { + _this.send(message, { + receiver: 'ws' + }); + _this.notify(message.buffer); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.notify = function () {}; + } + _createClass(BridgePlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this2 = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = mergeOptions(this.options, customOptions); + this.socketStatus = STATUS$3.IS_CONNECTING; + this.socket.bind({ + address: options.udpServer.host, + port: options.udpServer.port, + exclusive: options.udpServer.exclusive + }, function () { + var wsServerOptions = {}; + if (options.wsServer.server) wsServerOptions.server = options.wsServer.server;else wsServerOptions = options.wsServer; + _this2.websocket = new WebSocketServer$1(wsServerOptions); + _this2.websocket.binaryType = 'arraybuffer'; + _this2.websocket.on('listening', function () { + _this2.socketStatus = STATUS$3.IS_OPEN; + _this2.notify('open'); + }); + _this2.websocket.on('error', function (error) { + _this2.notify('error', error); + }); + _this2.websocket.on('connection', function (client) { + client.on('message', function (message, rinfo) { + _this2.send(message, { + receiver: 'udp' + }); + _this2.notify(new Uint8Array(message), rinfo); + }); + }); + }); + } + }, { + key: "close", + value: function close() { + var _this3 = this; + this.socketStatus = STATUS$3.IS_CLOSING; + this.socket.close(function () { + _this3.websocket.close(function () { + _this3.socketStatus = STATUS$3.IS_CLOSED; + _this3.notify('close'); + }); + }); + } + }, { + key: "send", + value: function send(binary) { + var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var options = mergeOptions(this.options, customOptions); + var receiver = options.receiver; + if (receiver === 'udp') { + var data = binary instanceof Buffer ? binary : Buffer.from(binary); + this.socket.send(data, 0, data.byteLength, options.udpClient.port, options.udpClient.host); + } else if (receiver === 'ws') { + this.websocket.clients.forEach(function (client) { + client.send(binary, { + binary: true + }); + }); + } else { + throw new Error('BridgePlugin can not send message to unknown receiver'); + } + } + }]); + return BridgePlugin; + }(); + + var scope = typeof global === 'undefined' ? window : global; + var WebSocket = typeof __dirname === 'undefined' ? scope.WebSocket : require('isomorphic-ws'); + var STATUS$2 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$2 = { + host: 'localhost', + port: 8080, + secure: false, + protocol: [] + }; + var WebsocketClientPlugin = function () { + function WebsocketClientPlugin(customOptions) { + _classCallCheck(this, WebsocketClientPlugin); + if (!WebSocket) { + throw new Error('WebsocketClientPlugin can\'t find a WebSocket class'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$2), customOptions); + this.socket = null; + this.socketStatus = STATUS$2.IS_NOT_INITIALIZED; + this.notify = function () {}; + } + _createClass(WebsocketClientPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); + var port = options.port, + host = options.host, + secure = options.secure, + protocol = options.protocol; + if (this.socket) { + this.close(); + } + var scheme = secure ? 'wss' : 'ws'; + var rinfo = { + address: host, + family: scheme, + port: port, + size: 0 + }; + this.socket = new WebSocket("".concat(scheme, "://").concat(host, ":").concat(port), protocol); + this.socket.binaryType = 'arraybuffer'; + this.socketStatus = STATUS$2.IS_CONNECTING; + this.socket.onopen = function () { + _this.socketStatus = STATUS$2.IS_OPEN; + _this.notify('open'); + }; + this.socket.onclose = function () { + _this.socketStatus = STATUS$2.IS_CLOSED; + _this.notify('close'); + }; + this.socket.onerror = function (error) { + _this.notify('error', error); + }; + this.socket.onmessage = function (message) { + _this.notify(message.data, rinfo); + }; + } + }, { + key: "close", + value: function close() { + this.socketStatus = STATUS$2.IS_CLOSING; + this.socket.close(); + } + }, { + key: "send", + value: function send(binary) { + this.socket.send(binary); + } + }]); + return WebsocketClientPlugin; + }(); + + var WebSocketServer = typeof __dirname !== 'undefined' ? require('isomorphic-ws').Server : undefined; + var STATUS$1 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$1 = { + host: 'localhost', + port: 8080 + }; + var WebsocketServerPlugin = function () { + function WebsocketServerPlugin(customOptions) { + _classCallCheck(this, WebsocketServerPlugin); + if (!WebSocketServer) { + throw new Error('WebsocketServerPlugin can not be used in browser context'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$1), customOptions); + this.socket = null; + this.socketStatus = STATUS$1.IS_NOT_INITIALIZED; + this.notify = function () {}; + } + _createClass(WebsocketServerPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); + var port = options.port, + host = options.host; + var rinfo = { + address: host, + family: 'wsserver', + port: port, + size: 0 + }; + if (this.socket) { + this.close(); + } + if (options.server) { + this.socket = new WebSocketServer({ + server: options.server + }); + } else { + this.socket = new WebSocketServer({ + host: host, + port: port + }); + } + this.socket.binaryType = 'arraybuffer'; + this.socketStatus = STATUS$1.IS_CONNECTING; + this.socket.on('listening', function () { + _this.socketStatus = STATUS$1.IS_OPEN; + _this.notify('open'); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.socket.on('connection', function (client) { + client.on('message', function (message) { + _this.notify(new Uint8Array(message), rinfo); + }); + }); + } + }, { + key: "close", + value: function close() { + var _this2 = this; + this.socketStatus = STATUS$1.IS_CLOSING; + this.socket.close(function () { + _this2.socketStatus = STATUS$1.IS_CLOSED; + _this2.notify('close'); + }); + } + }, { + key: "send", + value: function send(binary) { + this.socket.clients.forEach(function (client) { + client.send(binary, { + binary: true + }); + }); + } + }]); + return WebsocketServerPlugin; + }(); + + var defaultOptions = { + discardLateMessages: false, + plugin: new WebsocketClientPlugin() + }; + var STATUS = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var OSC = function () { + function OSC(options) { + _classCallCheck(this, OSC); + if (options && !isObject(options)) { + throw new Error('OSC options argument has to be an object.'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions), options); + this.eventHandler = new EventHandler({ + discardLateMessages: this.options.discardLateMessages + }); + var eventHandler = this.eventHandler; + if (this.options.plugin && this.options.plugin.registerNotify) { + this.options.plugin.registerNotify(function () { + return eventHandler.notify.apply(eventHandler, arguments); + }); + } + } + _createClass(OSC, [{ + key: "on", + value: function on(eventName, callback) { + if (!(isString(eventName) && isFunction(callback))) { + throw new Error('OSC on() needs event- or address string and callback function'); + } + return this.eventHandler.on(eventName, callback); + } + }, { + key: "off", + value: function off(eventName, subscriptionId) { + if (!(isString(eventName) && isInt(subscriptionId))) { + throw new Error('OSC off() needs string and number (subscriptionId) to unsubscribe'); + } + return this.eventHandler.off(eventName, subscriptionId); + } + }, { + key: "open", + value: function open(options) { + if (options && !isObject(options)) { + throw new Error('OSC open() options argument needs to be an object'); + } + if (!(this.options.plugin && isFunction(this.options.plugin.open))) { + throw new Error('OSC Plugin API #open is not implemented!'); + } + return this.options.plugin.open(options); + } + }, { + key: "status", + value: function status() { + if (!(this.options.plugin && isFunction(this.options.plugin.status))) { + throw new Error('OSC Plugin API #status is not implemented!'); + } + return this.options.plugin.status(); + } + }, { + key: "close", + value: function close() { + if (!(this.options.plugin && isFunction(this.options.plugin.close))) { + throw new Error('OSC Plugin API #close is not implemented!'); + } + return this.options.plugin.close(); + } + }, { + key: "send", + value: function send(packet, options) { + if (!(this.options.plugin && isFunction(this.options.plugin.send))) { + throw new Error('OSC Plugin API #send is not implemented!'); + } + if (!(packet instanceof TypedMessage || packet instanceof Message || packet instanceof Bundle || packet instanceof Packet)) { + throw new Error('OSC send() needs Messages, Bundles or Packets'); + } + if (options && !isObject(options)) { + throw new Error('OSC send() options argument has to be an object'); + } + return this.options.plugin.send(packet.pack(), options); + } + }]); + return OSC; + }(); + OSC.STATUS = STATUS; + OSC.Packet = Packet; + OSC.Bundle = Bundle; + OSC.Message = Message; + OSC.TypedMessage = TypedMessage; + OSC.DatagramPlugin = DatagramPlugin; + OSC.WebsocketClientPlugin = WebsocketClientPlugin; + OSC.WebsocketServerPlugin = WebsocketServerPlugin; + OSC.BridgePlugin = BridgePlugin; + + return OSC; + +})); From c9d7a2f313f241b521ddd6ee182143471fe636d9 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 22:58:13 +0200 Subject: [PATCH 30/37] osc instructions --- packages/osc/README.md | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/osc/README.md b/packages/osc/README.md index e8f5069b..cb48090d 100644 --- a/packages/osc/README.md +++ b/packages/osc/README.md @@ -1,33 +1,37 @@ # @strudel.cycles/osc -OSC messaging between strudel and super collider? +OSC output for strudel patterns! Currently only tested with super collider / super dirt. -## Sniffing Tidal Messages +## Usage -```sh -npm run tidal-sniffer +OSC will only work if you run the REPL locally + the OSC server besides it: + +From the project root: + +```js +npm run repl ``` -Now open a .tidal file and play something. There should be logs like: +and in a seperate shell: + +```js +npm run osc +``` + +This should give you ```log -received: /dirt/play [ - '_id_', '1', - 'cps', 0.5625, - 'cutoff', 100, - 'cycle', 724.1875, - 'delta', 0.11111068725585938, - 'orbit', 0, - 's', 'arpy' -] +osc client running on port 57120 +osc server running on port 57121 +websocket server running on port 8080 ``` -## Web Client + Server (WIP) +Now open Supercollider (with the super dirt startup file) -```sh -npm run client -npm run server # another terminal +Now open the REPL and type: + +```js +s(" hh").osc() ``` -Then go to [http://localhost:4321](localhost:4321) and push the button. -In your server terminal, there should be a log. +or just [click here](http://localhost:3000/#cygiPGJkIHNkPiBoaCIpLm9zYygp)... From e069e66952fffa4fbf218c7bf3ef13a43f479748 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 23:42:46 +0200 Subject: [PATCH 31/37] patch osc for client --- packages/osc/osc.js | 1733 ++++++++++++++++++++++++++++++++ packages/osc/osc.mjs | 2 +- packages/osc/package-lock.json | 148 +-- 3 files changed, 1808 insertions(+), 75 deletions(-) create mode 100644 packages/osc/osc.js diff --git a/packages/osc/osc.js b/packages/osc/osc.js new file mode 100644 index 00000000..7446c0e5 --- /dev/null +++ b/packages/osc/osc.js @@ -0,0 +1,1733 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.OSC = factory()); +})(this, (function () { 'use strict'; + + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + + return keys; + } + + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + + return target; + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function"); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + writable: true, + configurable: true + } + }); + Object.defineProperty(subClass, "prototype", { + writable: false + }); + if (superClass) _setPrototypeOf(subClass, superClass); + } + + function _getPrototypeOf(o) { + _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { + return o.__proto__ || Object.getPrototypeOf(o); + }; + return _getPrototypeOf(o); + } + + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + + return _setPrototypeOf(o, p); + } + + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); + return true; + } catch (e) { + return false; + } + } + + function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return self; + } + + function _possibleConstructorReturn(self, call) { + if (call && (typeof call === "object" || typeof call === "function")) { + return call; + } else if (call !== void 0) { + throw new TypeError("Derived constructors may only return object or undefined"); + } + + return _assertThisInitialized(self); + } + + function _createSuper(Derived) { + var hasNativeReflectConstruct = _isNativeReflectConstruct(); + + return function _createSuperInternal() { + var Super = _getPrototypeOf(Derived), + result; + + if (hasNativeReflectConstruct) { + var NewTarget = _getPrototypeOf(this).constructor; + + result = Reflect.construct(Super, arguments, NewTarget); + } else { + result = Super.apply(this, arguments); + } + + return _possibleConstructorReturn(this, result); + }; + } + + function _superPropBase(object, property) { + while (!Object.prototype.hasOwnProperty.call(object, property)) { + object = _getPrototypeOf(object); + if (object === null) break; + } + + return object; + } + + function _get() { + if (typeof Reflect !== "undefined" && Reflect.get) { + _get = Reflect.get; + } else { + _get = function _get(target, property, receiver) { + var base = _superPropBase(target, property); + + if (!base) return; + var desc = Object.getOwnPropertyDescriptor(base, property); + + if (desc.get) { + return desc.get.call(arguments.length < 3 ? target : receiver); + } + + return desc.value; + }; + } + + return _get.apply(this, arguments); + } + + function isInt(n) { + return Number(n) === n && n % 1 === 0; + } + function isFloat(n) { + return Number(n) === n && n % 1 !== 0; + } + function isNumber(n) { + return Number(n) === n; + } + function isString(n) { + return typeof n === 'string'; + } + function isBoolean(n) { + return typeof n === 'boolean'; + } + function isInfinity(n) { + return n === Infinity; + } + function isArray(n) { + return Object.prototype.toString.call(n) === '[object Array]'; + } + function isObject(n) { + return Object.prototype.toString.call(n) === '[object Object]'; + } + function isFunction(n) { + return typeof n === 'function'; + } + function isBlob(n) { + return n instanceof Uint8Array; + } + function isDate(n) { + return n instanceof Date; + } + function isUndefined(n) { + return typeof n === 'undefined'; + } + function isNull(n) { + return n === null; + } + function pad(n) { + return n + 3 & ~0x03; + } + function hasProperty(name) { + return Object.prototype.hasOwnProperty.call(typeof global !== 'undefined' ? global : window, + name); + } + function dataView(obj) { + if (obj.buffer) { + return new DataView(obj.buffer); + } else if (obj instanceof ArrayBuffer) { + return new DataView(obj); + } + return new DataView(new Uint8Array(obj)); + } + + function typeTag(item) { + if (isInt(item)) { + return 'i'; + } else if (isFloat(item)) { + return 'f'; + } else if (isString(item)) { + return 's'; + } else if (isBlob(item)) { + return 'b'; + } else if (isBoolean(item)) { + return item ? 'T' : 'F'; + } else if (isNull(item)) { + return 'N'; + } else if (isInfinity(item)) { + return 'I'; + } + throw new Error('OSC typeTag() found unknown value type'); + } + function prepareAddress(obj) { + var address = ''; + if (isArray(obj)) { + return "/".concat(obj.join('/')); + } else if (isString(obj)) { + address = obj; + if (address.length > 1 && address[address.length - 1] === '/') { + address = address.slice(0, address.length - 1); + } + if (address.length > 1 && address[0] !== '/') { + address = "/".concat(address); + } + return address; + } + throw new Error('OSC prepareAddress() needs addresses of type array or string'); + } + function prepareRegExPattern(str) { + var pattern; + if (!isString(str)) { + throw new Error('OSC prepareRegExPattern() needs strings'); + } + pattern = str.replace(/\./g, '\\.'); + pattern = pattern.replace(/\(/g, '\\('); + pattern = pattern.replace(/\)/g, '\\)'); + pattern = pattern.replace(/\{/g, '('); + pattern = pattern.replace(/\}/g, ')'); + pattern = pattern.replace(/,/g, '|'); + pattern = pattern.replace(/\[!/g, '[^'); + pattern = pattern.replace(/\?/g, '.'); + pattern = pattern.replace(/\*/g, '.*'); + return pattern; + } + var EncodeHelper = function () { + function EncodeHelper() { + _classCallCheck(this, EncodeHelper); + this.data = []; + this.byteLength = 0; + } + _createClass(EncodeHelper, [{ + key: "add", + value: function add(item) { + if (isBoolean(item) || isInfinity(item) || isNull(item)) { + return this; + } + var buffer = item.pack(); + this.byteLength += buffer.byteLength; + this.data.push(buffer); + return this; + } + }, { + key: "merge", + value: function merge() { + var result = new Uint8Array(this.byteLength); + var offset = 0; + this.data.forEach(function (data) { + result.set(data, offset); + offset += data.byteLength; + }); + return result; + } + }]); + return EncodeHelper; + }(); + + var Atomic = function () { + function Atomic(value) { + _classCallCheck(this, Atomic); + this.value = value; + this.offset = 0; + } + _createClass(Atomic, [{ + key: "pack", + value: function pack(method, byteLength) { + if (!(method && byteLength)) { + throw new Error('OSC Atomic cant\'t be packed without given method or byteLength'); + } + var data = new Uint8Array(byteLength); + var dataView = new DataView(data.buffer); + if (isUndefined(this.value)) { + throw new Error('OSC Atomic cant\'t be encoded with empty value'); + } + dataView[method](this.offset, this.value, false); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView, method, byteLength) { + var initialOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + if (!(dataView && method && byteLength)) { + throw new Error('OSC Atomic cant\'t be unpacked without given dataView, method or byteLength'); + } + if (!(dataView instanceof DataView)) { + throw new Error('OSC Atomic expects an instance of type DataView'); + } + this.value = dataView[method](initialOffset, false); + this.offset = initialOffset + byteLength; + return this.offset; + } + }]); + return Atomic; + }(); + + var AtomicInt32 = function (_Atomic) { + _inherits(AtomicInt32, _Atomic); + var _super = _createSuper(AtomicInt32); + function AtomicInt32(value) { + _classCallCheck(this, AtomicInt32); + if (value && !isInt(value)) { + throw new Error('OSC AtomicInt32 constructor expects value of type number'); + } + return _super.call(this, value); + } + _createClass(AtomicInt32, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicInt32.prototype), "pack", this).call(this, 'setInt32', 4); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicInt32.prototype), "unpack", this).call(this, dataView, 'getInt32', 4, initialOffset); + } + }]); + return AtomicInt32; + }(Atomic); + + var STR_SLICE_SIZE = 65537; + var STR_ENCODING = 'utf-8'; + function charCodesToString(charCodes) { + if (hasProperty('Buffer')) { + return Buffer.from(charCodes).toString(STR_ENCODING); + } else if (hasProperty('TextDecoder')) { + return new TextDecoder(STR_ENCODING) + .decode(new Int8Array(charCodes)); + } + var str = ''; + for (var i = 0; i < charCodes.length; i += STR_SLICE_SIZE) { + str += String.fromCharCode.apply(null, charCodes.slice(i, i + STR_SLICE_SIZE)); + } + return str; + } + var AtomicString = function (_Atomic) { + _inherits(AtomicString, _Atomic); + var _super = _createSuper(AtomicString); + function AtomicString(value) { + _classCallCheck(this, AtomicString); + if (value && !isString(value)) { + throw new Error('OSC AtomicString constructor expects value of type string'); + } + return _super.call(this, value); + } + _createClass(AtomicString, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicString can not be encoded with empty value'); + } + var terminated = "".concat(this.value, "\0"); + var byteLength = pad(terminated.length); + var buffer = new Uint8Array(byteLength); + for (var i = 0; i < terminated.length; i += 1) { + buffer[i] = terminated.charCodeAt(i); + } + return buffer; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicString expects an instance of type DataView'); + } + var offset = initialOffset; + var charcode; + var charCodes = []; + for (; offset < dataView.byteLength; offset += 1) { + charcode = dataView.getUint8(offset); + if (charcode !== 0) { + charCodes.push(charcode); + } else { + offset += 1; + break; + } + } + if (offset === dataView.length) { + throw new Error('OSC AtomicString found a malformed OSC string'); + } + this.offset = pad(offset); + this.value = charCodesToString(charCodes); + return this.offset; + } + }]); + return AtomicString; + }(Atomic); + + var SECONDS_70_YEARS = 2208988800; + var TWO_POWER_32 = 4294967296; + var Timetag = function () { + function Timetag() { + var seconds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var fractions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + _classCallCheck(this, Timetag); + if (!(isInt(seconds) && isInt(fractions))) { + throw new Error('OSC Timetag constructor expects values of type integer number'); + } + this.seconds = seconds; + this.fractions = fractions; + } + _createClass(Timetag, [{ + key: "timestamp", + value: function timestamp(milliseconds) { + var seconds; + if (typeof milliseconds === 'number') { + seconds = milliseconds / 1000; + var rounded = Math.floor(seconds); + this.seconds = rounded + SECONDS_70_YEARS; + this.fractions = Math.round(TWO_POWER_32 * (seconds - rounded)); + return milliseconds; + } + seconds = this.seconds - SECONDS_70_YEARS; + return (seconds + Math.round(this.fractions / TWO_POWER_32)) * 1000; + } + }]); + return Timetag; + }(); + var AtomicTimetag = function (_Atomic) { + _inherits(AtomicTimetag, _Atomic); + var _super = _createSuper(AtomicTimetag); + function AtomicTimetag() { + var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Date.now(); + _classCallCheck(this, AtomicTimetag); + var timetag = new Timetag(); + if (value instanceof Timetag) { + timetag = value; + } else if (isInt(value)) { + timetag.timestamp(value); + } else if (isDate(value)) { + timetag.timestamp(value.getTime()); + } + return _super.call(this, timetag); + } + _createClass(AtomicTimetag, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicTimetag can not be encoded with empty value'); + } + var _this$value = this.value, + seconds = _this$value.seconds, + fractions = _this$value.fractions; + var data = new Uint8Array(8); + var dataView = new DataView(data.buffer); + dataView.setInt32(0, seconds, false); + dataView.setInt32(4, fractions, false); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicTimetag expects an instance of type DataView'); + } + var seconds = dataView.getUint32(initialOffset, false); + var fractions = dataView.getUint32(initialOffset + 4, false); + this.value = new Timetag(seconds, fractions); + this.offset = initialOffset + 8; + return this.offset; + } + }]); + return AtomicTimetag; + }(Atomic); + + var AtomicBlob = function (_Atomic) { + _inherits(AtomicBlob, _Atomic); + var _super = _createSuper(AtomicBlob); + function AtomicBlob(value) { + _classCallCheck(this, AtomicBlob); + if (value && !isBlob(value)) { + throw new Error('OSC AtomicBlob constructor expects value of type Uint8Array'); + } + return _super.call(this, value); + } + _createClass(AtomicBlob, [{ + key: "pack", + value: function pack() { + if (isUndefined(this.value)) { + throw new Error('OSC AtomicBlob can not be encoded with empty value'); + } + var byteLength = pad(this.value.byteLength); + var data = new Uint8Array(byteLength + 4); + var dataView = new DataView(data.buffer); + dataView.setInt32(0, this.value.byteLength, false); + data.set(this.value, 4); + return data; + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC AtomicBlob expects an instance of type DataView'); + } + var byteLength = dataView.getInt32(initialOffset, false); + this.value = new Uint8Array(dataView.buffer, initialOffset + 4, byteLength); + this.offset = pad(initialOffset + 4 + byteLength); + return this.offset; + } + }]); + return AtomicBlob; + }(Atomic); + + var AtomicFloat32 = function (_Atomic) { + _inherits(AtomicFloat32, _Atomic); + var _super = _createSuper(AtomicFloat32); + function AtomicFloat32(value) { + _classCallCheck(this, AtomicFloat32); + if (value && !isNumber(value)) { + throw new Error('OSC AtomicFloat32 constructor expects value of type float'); + } + return _super.call(this, value); + } + _createClass(AtomicFloat32, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicFloat32.prototype), "pack", this).call(this, 'setFloat32', 4); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicFloat32.prototype), "unpack", this).call(this, dataView, 'getFloat32', 4, initialOffset); + } + }]); + return AtomicFloat32; + }(Atomic); + + var AtomicFloat64 = function (_Atomic) { + _inherits(AtomicFloat64, _Atomic); + var _super = _createSuper(AtomicFloat64); + function AtomicFloat64(value) { + _classCallCheck(this, AtomicFloat64); + if (value && !isNumber(value)) { + throw new Error('OSC AtomicFloat64 constructor expects value of type float'); + } + return _super.call(this, value); + } + _createClass(AtomicFloat64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicFloat64.prototype), "pack", this).call(this, 'setFloat64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicFloat64.prototype), "unpack", this).call(this, dataView, 'getFloat64', 8, initialOffset); + } + }]); + return AtomicFloat64; + }(Atomic); + + var MAX_INT64 = BigInt('9223372036854775807'); + var MIN_INT64 = BigInt('-9223372036854775808'); + var AtomicInt64 = function (_Atomic) { + _inherits(AtomicInt64, _Atomic); + var _super = _createSuper(AtomicInt64); + function AtomicInt64(value) { + _classCallCheck(this, AtomicInt64); + if (value && typeof value !== 'bigint') { + throw new Error('OSC AtomicInt64 constructor expects value of type BigInt'); + } + if (value && (value < MIN_INT64 || value > MAX_INT64)) { + throw new Error('OSC AtomicInt64 value is out of bounds'); + } + var tmp; + if (value) { + tmp = BigInt.asIntN(64, value); + } + return _super.call(this, tmp); + } + _createClass(AtomicInt64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicInt64.prototype), "pack", this).call(this, 'setBigInt64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicInt64.prototype), "unpack", this).call(this, dataView, 'getBigInt64', 8, initialOffset); + } + }]); + return AtomicInt64; + }(Atomic); + + var MAX_UINT64 = BigInt('18446744073709551615'); + var AtomicUInt64 = function (_Atomic) { + _inherits(AtomicUInt64, _Atomic); + var _super = _createSuper(AtomicUInt64); + function AtomicUInt64(value) { + _classCallCheck(this, AtomicUInt64); + if (value && typeof value !== 'bigint') { + throw new Error('OSC AtomicUInt64 constructor expects value of type BigInt'); + } + if (value && (value < 0 || value > MAX_UINT64)) { + throw new Error('OSC AtomicUInt64 value is out of bounds'); + } + var tmp; + if (value) { + tmp = BigInt.asUintN(64, value); + } + return _super.call(this, tmp); + } + _createClass(AtomicUInt64, [{ + key: "pack", + value: function pack() { + return _get(_getPrototypeOf(AtomicUInt64.prototype), "pack", this).call(this, 'setBigUint64', 8); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + return _get(_getPrototypeOf(AtomicUInt64.prototype), "unpack", this).call(this, dataView, 'getBigUint64', 8, initialOffset); + } + }]); + return AtomicUInt64; + }(Atomic); + + var VALUE_TRUE = true; + var VALUE_FALSE = false; + var VALUE_NONE = null; + var VALUE_INFINITY = Infinity; + + var TypedMessage = function () { + function TypedMessage(address, args) { + var _this = this; + _classCallCheck(this, TypedMessage); + this.offset = 0; + this.address = ''; + this.types = ''; + this.args = []; + if (!isUndefined(address)) { + if (!(isString(address) || isArray(address))) { + throw new Error('OSC Message constructor first argument (address) must be a string or array'); + } + this.address = prepareAddress(address); + } + if (!isUndefined(args)) { + if (!isArray(args)) { + throw new Error('OSC Message constructor second argument (args) must be an array'); + } + args.forEach(function (item) { + return _this.add(item.type, item.value); + }); + } + } + _createClass(TypedMessage, [{ + key: "add", + value: function add(type, item) { + if (isUndefined(type)) { + throw new Error('OSC Message needs a valid OSC Atomic Data Type'); + } + if (type === 'N') { + this.args.push(VALUE_NONE); + } else if (type === 'T') { + this.args.push(VALUE_TRUE); + } else if (type === 'F') { + this.args.push(VALUE_FALSE); + } else if (type === 'I') { + this.args.push(VALUE_INFINITY); + } else { + this.args.push(item); + } + this.types += type; + } + }, { + key: "pack", + value: function pack() { + var _this2 = this; + if (this.address.length === 0 || this.address[0] !== '/') { + throw new Error('OSC Message has an invalid address'); + } + var encoder = new EncodeHelper(); + encoder.add(new AtomicString(this.address)); + encoder.add(new AtomicString(",".concat(this.types))); + if (this.args.length > 0) { + var argument; + if (this.args.length > this.types.length) { + throw new Error('OSC Message argument and type tag mismatch'); + } + this.args.forEach(function (value, index) { + var type = _this2.types[index]; + if (type === 'i') { + argument = new AtomicInt32(value); + } else if (type === 'h') { + argument = new AtomicInt64(value); + } else if (type === 't') { + argument = new AtomicUInt64(value); + } else if (type === 'f') { + argument = new AtomicFloat32(value); + } else if (type === 'd') { + argument = new AtomicFloat64(value); + } else if (type === 's') { + argument = new AtomicString(value); + } else if (type === 'b') { + argument = new AtomicBlob(value); + } else if (type === 'T') { + argument = VALUE_TRUE; + } else if (type === 'F') { + argument = VALUE_FALSE; + } else if (type === 'N') { + argument = VALUE_NONE; + } else if (type === 'I') { + argument = VALUE_INFINITY; + } else { + throw new Error('OSC Message found unknown argument type'); + } + encoder.add(argument); + }); + } + return encoder.merge(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Message expects an instance of type DataView.'); + } + var address = new AtomicString(); + address.unpack(dataView, initialOffset); + var types = new AtomicString(); + types.unpack(dataView, address.offset); + if (address.value.length === 0 || address.value[0] !== '/') { + throw new Error('OSC Message found malformed or missing address string'); + } + if (types.value.length === 0 && types.value[0] !== ',') { + throw new Error('OSC Message found malformed or missing type string'); + } + var offset = types.offset; + var next; + var type; + var args = []; + for (var i = 1; i < types.value.length; i += 1) { + type = types.value[i]; + next = null; + if (type === 'i') { + next = new AtomicInt32(); + } else if (type === 'h') { + next = new AtomicInt64(); + } else if (type === 't') { + next = new AtomicUInt64(); + } else if (type === 'f') { + next = new AtomicFloat32(); + } else if (type === 'd') { + next = new AtomicFloat64(); + } else if (type === 's') { + next = new AtomicString(); + } else if (type === 'b') { + next = new AtomicBlob(); + } else if (type === 'T') { + args.push(VALUE_TRUE); + } else if (type === 'F') { + args.push(VALUE_FALSE); + } else if (type === 'N') { + args.push(VALUE_NONE); + } else if (type === 'I') { + args.push(VALUE_INFINITY); + } else { + throw new Error('OSC Message found unsupported argument type'); + } + if (next) { + offset = next.unpack(dataView, offset); + args.push(next.value); + } + } + this.offset = offset; + this.address = address.value; + this.types = types.value; + this.args = args; + return this.offset; + } + }]); + return TypedMessage; + }(); + var Message = function (_TypedMessage) { + _inherits(Message, _TypedMessage); + var _super = _createSuper(Message); + function Message() { + var _this3; + _classCallCheck(this, Message); + var address; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length > 0) { + address = args.shift(); + } + var oscArgs; + if (args.length > 0) { + if (args[0] instanceof Array) { + oscArgs = args.shift(); + } + } + _this3 = _super.call(this, address, oscArgs); + if (args.length > 0) { + _this3.types = args.map(function (item) { + return typeTag(item); + }).join(''); + _this3.args = args; + } + return _this3; + } + _createClass(Message, [{ + key: "add", + value: function add(item) { + _get(_getPrototypeOf(Message.prototype), "add", this).call(this, typeTag(item), item); + } + }]); + return Message; + }(TypedMessage); + + var BUNDLE_TAG = '#bundle'; + var Bundle = function () { + function Bundle() { + var _this = this; + _classCallCheck(this, Bundle); + this.offset = 0; + this.timetag = new AtomicTimetag(); + this.bundleElements = []; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length > 0) { + if (args[0] instanceof Date || isInt(args[0])) { + this.timetag = new AtomicTimetag(args[0]); + } else if (isArray(args[0])) { + args[0].forEach(function (item) { + _this.add(item); + }); + if (args.length > 1 && (args[1] instanceof Date || isInt(args[0]))) { + this.timetag = new AtomicTimetag(args[1]); + } + } else { + args.forEach(function (item) { + _this.add(item); + }); + } + } + } + _createClass(Bundle, [{ + key: "timestamp", + value: function timestamp(ms) { + if (!isInt(ms)) { + throw new Error('OSC Bundle needs an integer for setting the timestamp'); + } + this.timetag = new AtomicTimetag(ms); + } + }, { + key: "add", + value: function add(item) { + if (!(item instanceof Message || item instanceof Bundle)) { + throw new Error('OSC Bundle contains only Messages and Bundles'); + } + this.bundleElements.push(item); + } + }, { + key: "pack", + value: function pack() { + var encoder = new EncodeHelper(); + encoder.add(new AtomicString(BUNDLE_TAG)); + if (!this.timetag) { + this.timetag = new AtomicTimetag(); + } + encoder.add(this.timetag); + this.bundleElements.forEach(function (item) { + encoder.add(new AtomicInt32(item.pack().byteLength)); + encoder.add(item); + }); + return encoder.merge(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Bundle expects an instance of type DataView'); + } + var parentHead = new AtomicString(); + parentHead.unpack(dataView, initialOffset); + if (parentHead.value !== BUNDLE_TAG) { + throw new Error('OSC Bundle does not contain a valid #bundle head'); + } + var timetag = new AtomicTimetag(); + var offset = timetag.unpack(dataView, parentHead.offset); + this.bundleElements = []; + while (offset < dataView.byteLength) { + var head = new AtomicString(); + var size = new AtomicInt32(); + offset = size.unpack(dataView, offset); + var item = void 0; + head.unpack(dataView, offset); + if (head.value === BUNDLE_TAG) { + item = new Bundle(); + } else { + item = new Message(); + } + offset = item.unpack(dataView, offset); + this.bundleElements.push(item); + } + this.offset = offset; + this.timetag = timetag; + return this.offset; + } + }]); + return Bundle; + }(); + + var Packet = function () { + function Packet(value) { + _classCallCheck(this, Packet); + if (value && !(value instanceof Message || value instanceof Bundle)) { + throw new Error('OSC Packet value has to be Message or Bundle'); + } + this.value = value; + this.offset = 0; + } + _createClass(Packet, [{ + key: "pack", + value: function pack() { + if (!this.value) { + throw new Error('OSC Packet can not be encoded with empty body'); + } + return this.value.pack(); + } + }, { + key: "unpack", + value: function unpack(dataView) { + var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (!(dataView instanceof DataView)) { + throw new Error('OSC Packet expects an instance of type DataView'); + } + if (dataView.byteLength % 4 !== 0) { + throw new Error('OSC Packet byteLength has to be a multiple of four'); + } + var head = new AtomicString(); + head.unpack(dataView, initialOffset); + var item; + if (head.value === BUNDLE_TAG) { + item = new Bundle(); + } else { + item = new Message(); + } + item.unpack(dataView, initialOffset); + this.offset = item.offset; + this.value = item; + return this.offset; + } + }]); + return Packet; + }(); + + var defaultOptions$5 = { + discardLateMessages: false + }; + var EventHandler = function () { + function EventHandler(options) { + _classCallCheck(this, EventHandler); + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$5), options); + this.addressHandlers = []; + this.eventHandlers = { + open: [], + error: [], + close: [] + }; + this.uuid = 0; + } + _createClass(EventHandler, [{ + key: "dispatch", + value: function dispatch(packet, rinfo) { + var _this = this; + if (!(packet instanceof Packet)) { + throw new Error('OSC EventHander dispatch() accepts only arguments of type Packet'); + } + if (!packet.value) { + throw new Error('OSC EventHander dispatch() can\'t read empty Packets'); + } + if (packet.value instanceof Bundle) { + var bundle = packet.value; + return bundle.bundleElements.forEach(function (bundleItem) { + if (bundleItem instanceof Bundle) { + if (bundle.timetag.value.timestamp() < bundleItem.timetag.value.timestamp()) { + throw new Error('OSC Bundle timestamp is older than the timestamp of enclosed Bundles'); + } + return _this.dispatch(bundleItem); + } else if (bundleItem instanceof Message) { + var message = bundleItem; + return _this.notify(message.address, message, bundle.timetag.value.timestamp(), rinfo); + } + throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); + }); + } else if (packet.value instanceof Message) { + var message = packet.value; + return this.notify(message.address, message, 0, rinfo); + } + throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); + } + }, { + key: "call", + value: function call(name, data, rinfo) { + var success = false; + if (isString(name) && name in this.eventHandlers) { + this.eventHandlers[name].forEach(function (handler) { + handler.callback(data, rinfo); + success = true; + }); + return success; + } + var handlerKeys = Object.keys(this.addressHandlers); + var handlers = this.addressHandlers; + handlerKeys.forEach(function (key) { + var foundMatch = false; + var regex = new RegExp(prepareRegExPattern(prepareAddress(name)), 'g'); + var test = regex.test(key); + if (test && key.length === regex.lastIndex) { + foundMatch = true; + } + if (!foundMatch) { + var reverseRegex = new RegExp(prepareRegExPattern(prepareAddress(key)), 'g'); + var reverseTest = reverseRegex.test(name); + if (reverseTest && name.length === reverseRegex.lastIndex) { + foundMatch = true; + } + } + if (foundMatch) { + handlers[key].forEach(function (handler) { + handler.callback(data, rinfo); + success = true; + }); + } + }); + return success; + } + }, { + key: "notify", + value: function notify() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (args.length === 0) { + throw new Error('OSC EventHandler can not be called without any argument'); + } + if (args[0] instanceof Packet) { + return this.dispatch(args[0], args[1]); + } else if (args[0] instanceof Bundle || args[0] instanceof Message) { + return this.dispatch(new Packet(args[0]), args[1]); + } else if (!isString(args[0])) { + var packet = new Packet(); + packet.unpack(dataView(args[0])); + return this.dispatch(packet, args[1]); + } + var name = args[0]; + var data = null; + if (args.length > 1) { + data = args[1]; + } + var timestamp = null; + if (args.length > 2) { + if (isInt(args[2])) { + timestamp = args[2]; + } else if (args[2] instanceof Date) { + timestamp = args[2].getTime(); + } else { + throw new Error('OSC EventHandler timestamp has to be a number or Date'); + } + } + var rinfo = null; + if (args.length >= 3) { + rinfo = args[3]; + } + if (timestamp) { + var now = Date.now(); + if (now > timestamp) { + if (!this.options.discardLateMessages) { + return this.call(name, data, rinfo); + } + } + var that = this; + setTimeout(function () { + that.call(name, data, rinfo); + }, timestamp - now); + return true; + } + return this.call(name, data, rinfo); + } + }, { + key: "on", + value: function on(name, callback) { + if (!(isString(name) || isArray(name))) { + throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); + } + if (!isFunction(callback)) { + throw new Error('OSC EventHandler callback has to be a function'); + } + this.uuid += 1; + var handler = { + id: this.uuid, + callback: callback + }; + if (isString(name) && name in this.eventHandlers) { + this.eventHandlers[name].push(handler); + return this.uuid; + } + var address = prepareAddress(name); + if (!(address in this.addressHandlers)) { + this.addressHandlers[address] = []; + } + this.addressHandlers[address].push(handler); + return this.uuid; + } + }, { + key: "off", + value: function off(name, subscriptionId) { + if (!(isString(name) || isArray(name))) { + throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); + } + if (!isInt(subscriptionId)) { + throw new Error('OSC EventHandler subscription id has to be a number'); + } + var key; + var haystack; + if (isString(name) && name in this.eventHandlers) { + key = name; + haystack = this.eventHandlers; + } else { + key = prepareAddress(name); + haystack = this.addressHandlers; + } + if (key in haystack) { + return haystack[key].some(function (item, index) { + if (item.id === subscriptionId) { + haystack[key].splice(index, 1); + return true; + } + return false; + }); + } + return false; + } + }]); + return EventHandler; + }(); + + var dgram$1 = /* typeof window !== 'undefined' ? require('dgram') : */ undefined; + var STATUS$4 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOpenOptions = { + host: 'localhost', + port: 41234, + exclusive: false + }; + var defaultSendOptions = { + host: 'localhost', + port: 41235 + }; + var defaultOptions$4 = { + type: 'udp4', + open: defaultOpenOptions, + send: defaultSendOptions + }; + function mergeOptions$1(base, custom) { + return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4), base), custom), {}, { + open: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.open), base.open), custom.open), + send: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.send), base.send), custom.send) + }); + } + var DatagramPlugin = function () { + function DatagramPlugin() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, DatagramPlugin); + if (!dgram$1) { + throw new Error('DatagramPlugin can not be used in browser context'); + } + this.options = mergeOptions$1({}, customOptions); + this.socket = dgram$1.createSocket(this.options.type); + this.socketStatus = STATUS$4.IS_NOT_INITIALIZED; + this.socket.on('message', function (message, rinfo) { + _this.notify(message, rinfo); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.notify = function () {}; + } + _createClass(DatagramPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this2 = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options.open), customOptions); + var port = options.port, + exclusive = options.exclusive; + this.socketStatus = STATUS$4.IS_CONNECTING; + this.socket.bind({ + address: options.host, + port: port, + exclusive: exclusive + }, function () { + _this2.socketStatus = STATUS$4.IS_OPEN; + _this2.notify('open'); + }); + } + }, { + key: "close", + value: function close() { + var _this3 = this; + this.socketStatus = STATUS$4.IS_CLOSING; + this.socket.close(function () { + _this3.socketStatus = STATUS$4.IS_CLOSED; + _this3.notify('close'); + }); + } + }, { + key: "send", + value: function send(binary) { + var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options.send), customOptions); + var port = options.port, + host = options.host; + this.socket.send(Buffer.from(binary), 0, binary.byteLength, port, host); + } + }]); + return DatagramPlugin; + }(); + + var dgram = /* typeof window !== 'undefined' ? require('dgram') : */ undefined; + var WebSocketServer$1 = /* typeof window !== 'undefined' ? require('isomorphic-ws').Server : */ undefined; + var STATUS$3 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$3 = { + udpServer: { + host: 'localhost', + port: 41234, + exclusive: false + }, + udpClient: { + host: 'localhost', + port: 41235 + }, + wsServer: { + host: 'localhost', + port: 8080 + }, + receiver: 'ws' + }; + function mergeOptions(base, custom) { + return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3), base), custom), {}, { + udpServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpServer), base.udpServer), custom.udpServer), + udpClient: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpClient), base.udpClient), custom.udpClient), + wsServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.wsServer), base.wsServer), custom.wsServer) + }); + } + var BridgePlugin = function () { + function BridgePlugin() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + _classCallCheck(this, BridgePlugin); + if (!dgram || !WebSocketServer$1) { + throw new Error('BridgePlugin can not be used in browser context'); + } + this.options = mergeOptions({}, customOptions); + this.websocket = null; + this.socket = dgram.createSocket('udp4'); + this.socketStatus = STATUS$3.IS_NOT_INITIALIZED; + this.socket.on('message', function (message) { + _this.send(message, { + receiver: 'ws' + }); + _this.notify(message.buffer); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.notify = function () {}; + } + _createClass(BridgePlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this2 = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = mergeOptions(this.options, customOptions); + this.socketStatus = STATUS$3.IS_CONNECTING; + this.socket.bind({ + address: options.udpServer.host, + port: options.udpServer.port, + exclusive: options.udpServer.exclusive + }, function () { + var wsServerOptions = {}; + if (options.wsServer.server) wsServerOptions.server = options.wsServer.server;else wsServerOptions = options.wsServer; + _this2.websocket = new WebSocketServer$1(wsServerOptions); + _this2.websocket.binaryType = 'arraybuffer'; + _this2.websocket.on('listening', function () { + _this2.socketStatus = STATUS$3.IS_OPEN; + _this2.notify('open'); + }); + _this2.websocket.on('error', function (error) { + _this2.notify('error', error); + }); + _this2.websocket.on('connection', function (client) { + client.on('message', function (message, rinfo) { + _this2.send(message, { + receiver: 'udp' + }); + _this2.notify(new Uint8Array(message), rinfo); + }); + }); + }); + } + }, { + key: "close", + value: function close() { + var _this3 = this; + this.socketStatus = STATUS$3.IS_CLOSING; + this.socket.close(function () { + _this3.websocket.close(function () { + _this3.socketStatus = STATUS$3.IS_CLOSED; + _this3.notify('close'); + }); + }); + } + }, { + key: "send", + value: function send(binary) { + var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var options = mergeOptions(this.options, customOptions); + var receiver = options.receiver; + if (receiver === 'udp') { + var data = binary instanceof Buffer ? binary : Buffer.from(binary); + this.socket.send(data, 0, data.byteLength, options.udpClient.port, options.udpClient.host); + } else if (receiver === 'ws') { + this.websocket.clients.forEach(function (client) { + client.send(binary, { + binary: true + }); + }); + } else { + throw new Error('BridgePlugin can not send message to unknown receiver'); + } + } + }]); + return BridgePlugin; + }(); + + var scope = typeof global === 'undefined' ? window : global; + var WebSocket = typeof __dirname === 'undefined' ? scope.WebSocket : require('isomorphic-ws'); + var STATUS$2 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$2 = { + host: 'localhost', + port: 8080, + secure: false, + protocol: [] + }; + var WebsocketClientPlugin = function () { + function WebsocketClientPlugin(customOptions) { + _classCallCheck(this, WebsocketClientPlugin); + if (!WebSocket) { + throw new Error('WebsocketClientPlugin can\'t find a WebSocket class'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$2), customOptions); + this.socket = null; + this.socketStatus = STATUS$2.IS_NOT_INITIALIZED; + this.notify = function () {}; + } + _createClass(WebsocketClientPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); + var port = options.port, + host = options.host, + secure = options.secure, + protocol = options.protocol; + if (this.socket) { + this.close(); + } + var scheme = secure ? 'wss' : 'ws'; + var rinfo = { + address: host, + family: scheme, + port: port, + size: 0 + }; + this.socket = new WebSocket("".concat(scheme, "://").concat(host, ":").concat(port), protocol); + this.socket.binaryType = 'arraybuffer'; + this.socketStatus = STATUS$2.IS_CONNECTING; + this.socket.onopen = function () { + _this.socketStatus = STATUS$2.IS_OPEN; + _this.notify('open'); + }; + this.socket.onclose = function () { + _this.socketStatus = STATUS$2.IS_CLOSED; + _this.notify('close'); + }; + this.socket.onerror = function (error) { + _this.notify('error', error); + }; + this.socket.onmessage = function (message) { + _this.notify(message.data, rinfo); + }; + } + }, { + key: "close", + value: function close() { + this.socketStatus = STATUS$2.IS_CLOSING; + this.socket.close(); + } + }, { + key: "send", + value: function send(binary) { + this.socket.send(binary); + } + }]); + return WebsocketClientPlugin; + }(); + + var WebSocketServer = typeof __dirname !== 'undefined' ? require('isomorphic-ws').Server : undefined; + var STATUS$1 = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var defaultOptions$1 = { + host: 'localhost', + port: 8080 + }; + var WebsocketServerPlugin = function () { + function WebsocketServerPlugin(customOptions) { + _classCallCheck(this, WebsocketServerPlugin); + if (!WebSocketServer) { + throw new Error('WebsocketServerPlugin can not be used in browser context'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions$1), customOptions); + this.socket = null; + this.socketStatus = STATUS$1.IS_NOT_INITIALIZED; + this.notify = function () {}; + } + _createClass(WebsocketServerPlugin, [{ + key: "registerNotify", + value: function registerNotify(fn) { + this.notify = fn; + } + }, { + key: "status", + value: function status() { + return this.socketStatus; + } + }, { + key: "open", + value: function open() { + var _this = this; + var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); + var port = options.port, + host = options.host; + var rinfo = { + address: host, + family: 'wsserver', + port: port, + size: 0 + }; + if (this.socket) { + this.close(); + } + if (options.server) { + this.socket = new WebSocketServer({ + server: options.server + }); + } else { + this.socket = new WebSocketServer({ + host: host, + port: port + }); + } + this.socket.binaryType = 'arraybuffer'; + this.socketStatus = STATUS$1.IS_CONNECTING; + this.socket.on('listening', function () { + _this.socketStatus = STATUS$1.IS_OPEN; + _this.notify('open'); + }); + this.socket.on('error', function (error) { + _this.notify('error', error); + }); + this.socket.on('connection', function (client) { + client.on('message', function (message) { + _this.notify(new Uint8Array(message), rinfo); + }); + }); + } + }, { + key: "close", + value: function close() { + var _this2 = this; + this.socketStatus = STATUS$1.IS_CLOSING; + this.socket.close(function () { + _this2.socketStatus = STATUS$1.IS_CLOSED; + _this2.notify('close'); + }); + } + }, { + key: "send", + value: function send(binary) { + this.socket.clients.forEach(function (client) { + client.send(binary, { + binary: true + }); + }); + } + }]); + return WebsocketServerPlugin; + }(); + + var defaultOptions = { + discardLateMessages: false, + plugin: new WebsocketClientPlugin() + }; + var STATUS = { + IS_NOT_INITIALIZED: -1, + IS_CONNECTING: 0, + IS_OPEN: 1, + IS_CLOSING: 2, + IS_CLOSED: 3 + }; + var OSC = function () { + function OSC(options) { + _classCallCheck(this, OSC); + if (options && !isObject(options)) { + throw new Error('OSC options argument has to be an object.'); + } + this.options = _objectSpread2(_objectSpread2({}, defaultOptions), options); + this.eventHandler = new EventHandler({ + discardLateMessages: this.options.discardLateMessages + }); + var eventHandler = this.eventHandler; + if (this.options.plugin && this.options.plugin.registerNotify) { + this.options.plugin.registerNotify(function () { + return eventHandler.notify.apply(eventHandler, arguments); + }); + } + } + _createClass(OSC, [{ + key: "on", + value: function on(eventName, callback) { + if (!(isString(eventName) && isFunction(callback))) { + throw new Error('OSC on() needs event- or address string and callback function'); + } + return this.eventHandler.on(eventName, callback); + } + }, { + key: "off", + value: function off(eventName, subscriptionId) { + if (!(isString(eventName) && isInt(subscriptionId))) { + throw new Error('OSC off() needs string and number (subscriptionId) to unsubscribe'); + } + return this.eventHandler.off(eventName, subscriptionId); + } + }, { + key: "open", + value: function open(options) { + if (options && !isObject(options)) { + throw new Error('OSC open() options argument needs to be an object'); + } + if (!(this.options.plugin && isFunction(this.options.plugin.open))) { + throw new Error('OSC Plugin API #open is not implemented!'); + } + return this.options.plugin.open(options); + } + }, { + key: "status", + value: function status() { + if (!(this.options.plugin && isFunction(this.options.plugin.status))) { + throw new Error('OSC Plugin API #status is not implemented!'); + } + return this.options.plugin.status(); + } + }, { + key: "close", + value: function close() { + if (!(this.options.plugin && isFunction(this.options.plugin.close))) { + throw new Error('OSC Plugin API #close is not implemented!'); + } + return this.options.plugin.close(); + } + }, { + key: "send", + value: function send(packet, options) { + if (!(this.options.plugin && isFunction(this.options.plugin.send))) { + throw new Error('OSC Plugin API #send is not implemented!'); + } + if (!(packet instanceof TypedMessage || packet instanceof Message || packet instanceof Bundle || packet instanceof Packet)) { + throw new Error('OSC send() needs Messages, Bundles or Packets'); + } + if (options && !isObject(options)) { + throw new Error('OSC send() options argument has to be an object'); + } + return this.options.plugin.send(packet.pack(), options); + } + }]); + return OSC; + }(); + OSC.STATUS = STATUS; + OSC.Packet = Packet; + OSC.Bundle = Bundle; + OSC.Message = Message; + OSC.TypedMessage = TypedMessage; + OSC.DatagramPlugin = DatagramPlugin; + OSC.WebsocketClientPlugin = WebsocketClientPlugin; + OSC.WebsocketServerPlugin = WebsocketServerPlugin; + OSC.BridgePlugin = BridgePlugin; + + return OSC; + +})); diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 2965fa30..9f4a3610 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -1,4 +1,4 @@ -import OSC from './osc-js/osc.js'; +import OSC from './osc.js'; import { Pattern } from '@strudel.cycles/core/strudel.mjs'; const comm = new OSC(); diff --git a/packages/osc/package-lock.json b/packages/osc/package-lock.json index 33516920..be2ffb4a 100644 --- a/packages/osc/package-lock.json +++ b/packages/osc/package-lock.json @@ -1,76 +1,76 @@ { - "name": "@strudel.cycles/osc", - "version": "0.0.1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@strudel.cycles/osc", - "version": "0.0.1", - "license": "GPL-3.0-or-later", - "dependencies": { - "osc-js": "^2.3.0" - } - }, - "node_modules/isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/osc-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", - "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", - "dependencies": { - "isomorphic-ws": "4.0.1", - "ws": "8.5.0" - } - }, - "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - }, - "dependencies": { - "isomorphic-ws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", - "requires": {} - }, - "osc-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", - "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", - "requires": { - "isomorphic-ws": "4.0.1", - "ws": "8.5.0" - } - }, - "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "requires": {} - } - } + "name": "@strudel.cycles/osc", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@strudel.cycles/osc", + "version": "0.0.1", + "license": "GPL-3.0-or-later", + "dependencies": { + "osc-js": "^2.3.0" + } + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/osc-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", + "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", + "dependencies": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "requires": {} + }, + "osc-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/osc-js/-/osc-js-2.3.0.tgz", + "integrity": "sha512-P2Oy9tf8Z9lQw8JZeR62HNqbKdxj7Kqbsag+ImiJvyxPDReGMVt5LtZbMh/7Ve/wbYEGODkQdFAaLHFVkIlHPw==", + "requires": { + "isomorphic-ws": "4.0.1", + "ws": "8.5.0" + } + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} + } + } } From f9b043dc7ed54405ba79c2ef3ad3d1371d9c3a02 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 23:54:13 +0200 Subject: [PATCH 32/37] remove osc-js folder + remove umd stuff --- packages/osc/osc-js/LICENSE | 22 - packages/osc/osc-js/README.md | 5 - packages/osc/osc-js/osc.js | 1747 --------------------------------- packages/osc/osc.js | 9 +- 4 files changed, 1 insertion(+), 1782 deletions(-) delete mode 100644 packages/osc/osc-js/LICENSE delete mode 100644 packages/osc/osc-js/README.md delete mode 100644 packages/osc/osc-js/osc.js diff --git a/packages/osc/osc-js/LICENSE b/packages/osc/osc-js/LICENSE deleted file mode 100644 index 5a99e00b..00000000 --- a/packages/osc/osc-js/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -(The MIT License) - -Copyright (c) 2016 adzialocha (Andreas Dzialocha) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/osc/osc-js/README.md b/packages/osc/osc-js/README.md deleted file mode 100644 index 323d870c..00000000 --- a/packages/osc/osc-js/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Adapted from https://github.com/adzialocha/osc-js/ , with small fix. - -We'll return to using upstream version when this bug is resolved: - https://github.com/adzialocha/osc-js/issues/50 - diff --git a/packages/osc/osc-js/osc.js b/packages/osc/osc-js/osc.js deleted file mode 100644 index 976f250c..00000000 --- a/packages/osc/osc-js/osc.js +++ /dev/null @@ -1,1747 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.OSC = factory()); -})(this, (function () { 'use strict'; - - function ownKeys(object, enumerableOnly) { - var keys = Object.keys(object); - - if (Object.getOwnPropertySymbols) { - var symbols = Object.getOwnPropertySymbols(object); - enumerableOnly && (symbols = symbols.filter(function (sym) { - return Object.getOwnPropertyDescriptor(object, sym).enumerable; - })), keys.push.apply(keys, symbols); - } - - return keys; - } - - function _objectSpread2(target) { - for (var i = 1; i < arguments.length; i++) { - var source = null != arguments[i] ? arguments[i] : {}; - i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { - _defineProperty(target, key, source[key]); - }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { - Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); - }); - } - - return target; - } - - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - } - - function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - Object.defineProperty(Constructor, "prototype", { - writable: false - }); - return Constructor; - } - - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - } - - function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - Object.defineProperty(subClass, "prototype", { - writable: false - }); - if (superClass) _setPrototypeOf(subClass, superClass); - } - - function _getPrototypeOf(o) { - _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _getPrototypeOf(o); - } - - function _setPrototypeOf(o, p) { - _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { - o.__proto__ = p; - return o; - }; - - return _setPrototypeOf(o, p); - } - - function _isNativeReflectConstruct() { - if (typeof Reflect === "undefined" || !Reflect.construct) return false; - if (Reflect.construct.sham) return false; - if (typeof Proxy === "function") return true; - - try { - Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); - return true; - } catch (e) { - return false; - } - } - - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - function _possibleConstructorReturn(self, call) { - if (call && (typeof call === "object" || typeof call === "function")) { - return call; - } else if (call !== void 0) { - throw new TypeError("Derived constructors may only return object or undefined"); - } - - return _assertThisInitialized(self); - } - - function _createSuper(Derived) { - var hasNativeReflectConstruct = _isNativeReflectConstruct(); - - return function _createSuperInternal() { - var Super = _getPrototypeOf(Derived), - result; - - if (hasNativeReflectConstruct) { - var NewTarget = _getPrototypeOf(this).constructor; - - result = Reflect.construct(Super, arguments, NewTarget); - } else { - result = Super.apply(this, arguments); - } - - return _possibleConstructorReturn(this, result); - }; - } - - function _superPropBase(object, property) { - while (!Object.prototype.hasOwnProperty.call(object, property)) { - object = _getPrototypeOf(object); - if (object === null) break; - } - - return object; - } - - function _get() { - if (typeof Reflect !== "undefined" && Reflect.get) { - _get = Reflect.get; - } else { - _get = function _get(target, property, receiver) { - var base = _superPropBase(target, property); - - if (!base) return; - var desc = Object.getOwnPropertyDescriptor(base, property); - - if (desc.get) { - return desc.get.call(arguments.length < 3 ? target : receiver); - } - - return desc.value; - }; - } - - return _get.apply(this, arguments); - } - - function isInt(n) { - return Number(n) === n && n % 1 === 0; - } - function isFloat(n) { - return Number(n) === n && n % 1 !== 0; - } - function isNumber(n) { - return Number(n) === n; - } - function isString(n) { - return typeof n === 'string'; - } - function isBoolean(n) { - return typeof n === 'boolean'; - } - function isInfinity(n) { - return n === Infinity; - } - function isArray(n) { - return Object.prototype.toString.call(n) === '[object Array]'; - } - function isObject(n) { - return Object.prototype.toString.call(n) === '[object Object]'; - } - function isFunction(n) { - return typeof n === 'function'; - } - function isBlob(n) { - return n instanceof Uint8Array; - } - function isDate(n) { - return n instanceof Date; - } - function isUndefined(n) { - return typeof n === 'undefined'; - } - function isNull(n) { - return n === null; - } - function pad(n) { - return n + 3 & ~0x03; - } - function hasProperty(name) { - return Object.prototype.hasOwnProperty.call(typeof global !== 'undefined' ? global : window, - name); - } - function dataView(obj) { - if (obj.buffer) { - return new DataView(obj.buffer); - } else if (obj instanceof ArrayBuffer) { - return new DataView(obj); - } - return new DataView(new Uint8Array(obj)); - } - - function typeTag(item) { - if (isInt(item)) { - return 'i'; - } else if (isFloat(item)) { - return 'f'; - } else if (isString(item)) { - return 's'; - } else if (isBlob(item)) { - return 'b'; - } else if (isBoolean(item)) { - return item ? 'T' : 'F'; - } else if (isNull(item)) { - return 'N'; - } else if (isInfinity(item)) { - return 'I'; - } - throw new Error('OSC typeTag() found unknown value type'); - } - function prepareAddress(obj) { - var address = ''; - if (isArray(obj)) { - return "/".concat(obj.join('/')); - } else if (isString(obj)) { - address = obj; - if (address.length > 1 && address[address.length - 1] === '/') { - address = address.slice(0, address.length - 1); - } - if (address.length > 1 && address[0] !== '/') { - address = "/".concat(address); - } - return address; - } - throw new Error('OSC prepareAddress() needs addresses of type array or string'); - } - function prepareRegExPattern(str) { - var pattern; - if (!isString(str)) { - throw new Error('OSC prepareRegExPattern() needs strings'); - } - pattern = str.replace(/\./g, '\\.'); - pattern = pattern.replace(/\(/g, '\\('); - pattern = pattern.replace(/\)/g, '\\)'); - pattern = pattern.replace(/\{/g, '('); - pattern = pattern.replace(/\}/g, ')'); - pattern = pattern.replace(/,/g, '|'); - pattern = pattern.replace(/\[!/g, '[^'); - pattern = pattern.replace(/\?/g, '.'); - pattern = pattern.replace(/\*/g, '.*'); - return pattern; - } - var EncodeHelper = function () { - function EncodeHelper() { - _classCallCheck(this, EncodeHelper); - this.data = []; - this.byteLength = 0; - } - _createClass(EncodeHelper, [{ - key: "add", - value: function add(item) { - if (isBoolean(item) || isInfinity(item) || isNull(item)) { - return this; - } - var buffer = item.pack(); - this.byteLength += buffer.byteLength; - this.data.push(buffer); - return this; - } - }, { - key: "merge", - value: function merge() { - var result = new Uint8Array(this.byteLength); - var offset = 0; - this.data.forEach(function (data) { - result.set(data, offset); - offset += data.byteLength; - }); - return result; - } - }]); - return EncodeHelper; - }(); - - var Atomic = function () { - function Atomic(value) { - _classCallCheck(this, Atomic); - this.value = value; - this.offset = 0; - } - _createClass(Atomic, [{ - key: "pack", - value: function pack(method, byteLength) { - if (!(method && byteLength)) { - throw new Error('OSC Atomic cant\'t be packed without given method or byteLength'); - } - var data = new Uint8Array(byteLength); - var dataView = new DataView(data.buffer); - if (isUndefined(this.value)) { - throw new Error('OSC Atomic cant\'t be encoded with empty value'); - } - dataView[method](this.offset, this.value, false); - return data; - } - }, { - key: "unpack", - value: function unpack(dataView, method, byteLength) { - var initialOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; - if (!(dataView && method && byteLength)) { - throw new Error('OSC Atomic cant\'t be unpacked without given dataView, method or byteLength'); - } - if (!(dataView instanceof DataView)) { - throw new Error('OSC Atomic expects an instance of type DataView'); - } - this.value = dataView[method](initialOffset, false); - this.offset = initialOffset + byteLength; - return this.offset; - } - }]); - return Atomic; - }(); - - var AtomicInt32 = function (_Atomic) { - _inherits(AtomicInt32, _Atomic); - var _super = _createSuper(AtomicInt32); - function AtomicInt32(value) { - _classCallCheck(this, AtomicInt32); - if (value && !isInt(value)) { - throw new Error('OSC AtomicInt32 constructor expects value of type number'); - } - return _super.call(this, value); - } - _createClass(AtomicInt32, [{ - key: "pack", - value: function pack() { - return _get(_getPrototypeOf(AtomicInt32.prototype), "pack", this).call(this, 'setInt32', 4); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - return _get(_getPrototypeOf(AtomicInt32.prototype), "unpack", this).call(this, dataView, 'getInt32', 4, initialOffset); - } - }]); - return AtomicInt32; - }(Atomic); - - var STR_SLICE_SIZE = 65537; - var STR_ENCODING = 'utf-8'; - function charCodesToString(charCodes) { - if (hasProperty('Buffer')) { - return Buffer.from(charCodes).toString(STR_ENCODING); - } else if (hasProperty('TextDecoder')) { - return new TextDecoder(STR_ENCODING) - .decode(new Int8Array(charCodes)); - } - var str = ''; - for (var i = 0; i < charCodes.length; i += STR_SLICE_SIZE) { - str += String.fromCharCode.apply(null, charCodes.slice(i, i + STR_SLICE_SIZE)); - } - return str; - } - var AtomicString = function (_Atomic) { - _inherits(AtomicString, _Atomic); - var _super = _createSuper(AtomicString); - function AtomicString(value) { - _classCallCheck(this, AtomicString); - if (value && !isString(value)) { - throw new Error('OSC AtomicString constructor expects value of type string'); - } - return _super.call(this, value); - } - _createClass(AtomicString, [{ - key: "pack", - value: function pack() { - if (isUndefined(this.value)) { - throw new Error('OSC AtomicString can not be encoded with empty value'); - } - var terminated = "".concat(this.value, "\0"); - var byteLength = pad(terminated.length); - var buffer = new Uint8Array(byteLength); - for (var i = 0; i < terminated.length; i += 1) { - buffer[i] = terminated.charCodeAt(i); - } - return buffer; - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC AtomicString expects an instance of type DataView'); - } - var offset = initialOffset; - var charcode; - var charCodes = []; - for (; offset < dataView.byteLength; offset += 1) { - charcode = dataView.getUint8(offset); - if (charcode !== 0) { - charCodes.push(charcode); - } else { - offset += 1; - break; - } - } - if (offset === dataView.length) { - throw new Error('OSC AtomicString found a malformed OSC string'); - } - this.offset = pad(offset); - this.value = charCodesToString(charCodes); - return this.offset; - } - }]); - return AtomicString; - }(Atomic); - - var SECONDS_70_YEARS = 2208988800; - var TWO_POWER_32 = 4294967296; - var Timetag = function () { - function Timetag() { - var seconds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; - var fractions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - _classCallCheck(this, Timetag); - if (!(isInt(seconds) && isInt(fractions))) { - throw new Error('OSC Timetag constructor expects values of type integer number'); - } - this.seconds = seconds; - this.fractions = fractions; - } - _createClass(Timetag, [{ - key: "timestamp", - value: function timestamp(milliseconds) { - var seconds; - if (typeof milliseconds === 'number') { - seconds = milliseconds / 1000; - var rounded = Math.floor(seconds); - this.seconds = rounded + SECONDS_70_YEARS; - this.fractions = Math.round(TWO_POWER_32 * (seconds - rounded)); - return milliseconds; - } - seconds = this.seconds - SECONDS_70_YEARS; - return (seconds + Math.round(this.fractions / TWO_POWER_32)) * 1000; - } - }]); - return Timetag; - }(); - var AtomicTimetag = function (_Atomic) { - _inherits(AtomicTimetag, _Atomic); - var _super = _createSuper(AtomicTimetag); - function AtomicTimetag() { - var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Date.now(); - _classCallCheck(this, AtomicTimetag); - var timetag = new Timetag(); - if (value instanceof Timetag) { - timetag = value; - } else if (isInt(value)) { - timetag.timestamp(value); - } else if (isDate(value)) { - timetag.timestamp(value.getTime()); - } - return _super.call(this, timetag); - } - _createClass(AtomicTimetag, [{ - key: "pack", - value: function pack() { - if (isUndefined(this.value)) { - throw new Error('OSC AtomicTimetag can not be encoded with empty value'); - } - var _this$value = this.value, - seconds = _this$value.seconds, - fractions = _this$value.fractions; - var data = new Uint8Array(8); - var dataView = new DataView(data.buffer); - dataView.setInt32(0, seconds, false); - dataView.setInt32(4, fractions, false); - return data; - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC AtomicTimetag expects an instance of type DataView'); - } - var seconds = dataView.getUint32(initialOffset, false); - var fractions = dataView.getUint32(initialOffset + 4, false); - this.value = new Timetag(seconds, fractions); - this.offset = initialOffset + 8; - return this.offset; - } - }]); - return AtomicTimetag; - }(Atomic); - - var AtomicBlob = function (_Atomic) { - _inherits(AtomicBlob, _Atomic); - var _super = _createSuper(AtomicBlob); - function AtomicBlob(value) { - _classCallCheck(this, AtomicBlob); - if (value && !isBlob(value)) { - throw new Error('OSC AtomicBlob constructor expects value of type Uint8Array'); - } - return _super.call(this, value); - } - _createClass(AtomicBlob, [{ - key: "pack", - value: function pack() { - if (isUndefined(this.value)) { - throw new Error('OSC AtomicBlob can not be encoded with empty value'); - } - var byteLength = pad(this.value.byteLength); - var data = new Uint8Array(byteLength + 4); - var dataView = new DataView(data.buffer); - dataView.setInt32(0, this.value.byteLength, false); - data.set(this.value, 4); - return data; - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC AtomicBlob expects an instance of type DataView'); - } - var byteLength = dataView.getInt32(initialOffset, false); - this.value = new Uint8Array(dataView.buffer, initialOffset + 4, byteLength); - this.offset = pad(initialOffset + 4 + byteLength); - return this.offset; - } - }]); - return AtomicBlob; - }(Atomic); - - var AtomicFloat32 = function (_Atomic) { - _inherits(AtomicFloat32, _Atomic); - var _super = _createSuper(AtomicFloat32); - function AtomicFloat32(value) { - _classCallCheck(this, AtomicFloat32); - if (value && !isNumber(value)) { - throw new Error('OSC AtomicFloat32 constructor expects value of type float'); - } - return _super.call(this, value); - } - _createClass(AtomicFloat32, [{ - key: "pack", - value: function pack() { - return _get(_getPrototypeOf(AtomicFloat32.prototype), "pack", this).call(this, 'setFloat32', 4); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - return _get(_getPrototypeOf(AtomicFloat32.prototype), "unpack", this).call(this, dataView, 'getFloat32', 4, initialOffset); - } - }]); - return AtomicFloat32; - }(Atomic); - - var AtomicFloat64 = function (_Atomic) { - _inherits(AtomicFloat64, _Atomic); - var _super = _createSuper(AtomicFloat64); - function AtomicFloat64(value) { - _classCallCheck(this, AtomicFloat64); - if (value && !isNumber(value)) { - throw new Error('OSC AtomicFloat64 constructor expects value of type float'); - } - return _super.call(this, value); - } - _createClass(AtomicFloat64, [{ - key: "pack", - value: function pack() { - return _get(_getPrototypeOf(AtomicFloat64.prototype), "pack", this).call(this, 'setFloat64', 8); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - return _get(_getPrototypeOf(AtomicFloat64.prototype), "unpack", this).call(this, dataView, 'getFloat64', 8, initialOffset); - } - }]); - return AtomicFloat64; - }(Atomic); - - var MAX_INT64 = BigInt('9223372036854775807'); - var MIN_INT64 = BigInt('-9223372036854775808'); - var AtomicInt64 = function (_Atomic) { - _inherits(AtomicInt64, _Atomic); - var _super = _createSuper(AtomicInt64); - function AtomicInt64(value) { - _classCallCheck(this, AtomicInt64); - if (value && typeof value !== 'bigint') { - throw new Error('OSC AtomicInt64 constructor expects value of type BigInt'); - } - if (value && (value < MIN_INT64 || value > MAX_INT64)) { - throw new Error('OSC AtomicInt64 value is out of bounds'); - } - var tmp; - if (value) { - tmp = BigInt.asIntN(64, value); - } - return _super.call(this, tmp); - } - _createClass(AtomicInt64, [{ - key: "pack", - value: function pack() { - return _get(_getPrototypeOf(AtomicInt64.prototype), "pack", this).call(this, 'setBigInt64', 8); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - return _get(_getPrototypeOf(AtomicInt64.prototype), "unpack", this).call(this, dataView, 'getBigInt64', 8, initialOffset); - } - }]); - return AtomicInt64; - }(Atomic); - - var MAX_UINT64 = BigInt('18446744073709551615'); - var AtomicUInt64 = function (_Atomic) { - _inherits(AtomicUInt64, _Atomic); - var _super = _createSuper(AtomicUInt64); - function AtomicUInt64(value) { - _classCallCheck(this, AtomicUInt64); - if (value && typeof value !== 'bigint') { - throw new Error('OSC AtomicUInt64 constructor expects value of type BigInt'); - } - if (value && (value < 0 || value > MAX_UINT64)) { - throw new Error('OSC AtomicUInt64 value is out of bounds'); - } - var tmp; - if (value) { - tmp = BigInt.asUintN(64, value); - } - return _super.call(this, tmp); - } - _createClass(AtomicUInt64, [{ - key: "pack", - value: function pack() { - return _get(_getPrototypeOf(AtomicUInt64.prototype), "pack", this).call(this, 'setBigUint64', 8); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - return _get(_getPrototypeOf(AtomicUInt64.prototype), "unpack", this).call(this, dataView, 'getBigUint64', 8, initialOffset); - } - }]); - return AtomicUInt64; - }(Atomic); - - var VALUE_TRUE = true; - var VALUE_FALSE = false; - var VALUE_NONE = null; - var VALUE_INFINITY = Infinity; - - var TypedMessage = function () { - function TypedMessage(address, args) { - var _this = this; - _classCallCheck(this, TypedMessage); - this.offset = 0; - this.address = ''; - this.types = ''; - this.args = []; - if (!isUndefined(address)) { - if (!(isString(address) || isArray(address))) { - throw new Error('OSC Message constructor first argument (address) must be a string or array'); - } - this.address = prepareAddress(address); - } - if (!isUndefined(args)) { - if (!isArray(args)) { - throw new Error('OSC Message constructor second argument (args) must be an array'); - } - args.forEach(function (item) { - return _this.add(item.type, item.value); - }); - } - } - _createClass(TypedMessage, [{ - key: "add", - value: function add(type, item) { - if (isUndefined(type)) { - throw new Error('OSC Message needs a valid OSC Atomic Data Type'); - } - if (type === 'N') { - this.args.push(VALUE_NONE); - } else if (type === 'T') { - this.args.push(VALUE_TRUE); - } else if (type === 'F') { - this.args.push(VALUE_FALSE); - } else if (type === 'I') { - this.args.push(VALUE_INFINITY); - } else { - this.args.push(item); - } - this.types += type; - } - }, { - key: "pack", - value: function pack() { - var _this2 = this; - if (this.address.length === 0 || this.address[0] !== '/') { - throw new Error('OSC Message has an invalid address'); - } - var encoder = new EncodeHelper(); - encoder.add(new AtomicString(this.address)); - encoder.add(new AtomicString(",".concat(this.types))); - if (this.args.length > 0) { - var argument; - if (this.args.length > this.types.length) { - throw new Error('OSC Message argument and type tag mismatch'); - } - this.args.forEach(function (value, index) { - var type = _this2.types[index]; - if (type === 'i') { - argument = new AtomicInt32(value); - } else if (type === 'h') { - argument = new AtomicInt64(value); - } else if (type === 't') { - argument = new AtomicUInt64(value); - } else if (type === 'f') { - argument = new AtomicFloat32(value); - } else if (type === 'd') { - argument = new AtomicFloat64(value); - } else if (type === 's') { - argument = new AtomicString(value); - } else if (type === 'b') { - argument = new AtomicBlob(value); - } else if (type === 'T') { - argument = VALUE_TRUE; - } else if (type === 'F') { - argument = VALUE_FALSE; - } else if (type === 'N') { - argument = VALUE_NONE; - } else if (type === 'I') { - argument = VALUE_INFINITY; - } else { - throw new Error('OSC Message found unknown argument type'); - } - encoder.add(argument); - }); - } - return encoder.merge(); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC Message expects an instance of type DataView.'); - } - var address = new AtomicString(); - address.unpack(dataView, initialOffset); - var types = new AtomicString(); - types.unpack(dataView, address.offset); - if (address.value.length === 0 || address.value[0] !== '/') { - throw new Error('OSC Message found malformed or missing address string'); - } - if (types.value.length === 0 && types.value[0] !== ',') { - throw new Error('OSC Message found malformed or missing type string'); - } - var offset = types.offset; - var next; - var type; - var args = []; - for (var i = 1; i < types.value.length; i += 1) { - type = types.value[i]; - next = null; - if (type === 'i') { - next = new AtomicInt32(); - } else if (type === 'h') { - next = new AtomicInt64(); - } else if (type === 't') { - next = new AtomicUInt64(); - } else if (type === 'f') { - next = new AtomicFloat32(); - } else if (type === 'd') { - next = new AtomicFloat64(); - } else if (type === 's') { - next = new AtomicString(); - } else if (type === 'b') { - next = new AtomicBlob(); - } else if (type === 'T') { - args.push(VALUE_TRUE); - } else if (type === 'F') { - args.push(VALUE_FALSE); - } else if (type === 'N') { - args.push(VALUE_NONE); - } else if (type === 'I') { - args.push(VALUE_INFINITY); - } else { - throw new Error('OSC Message found unsupported argument type'); - } - if (next) { - offset = next.unpack(dataView, offset); - args.push(next.value); - } - } - this.offset = offset; - this.address = address.value; - this.types = types.value; - this.args = args; - return this.offset; - } - }]); - return TypedMessage; - }(); - var Message = function (_TypedMessage) { - _inherits(Message, _TypedMessage); - var _super = _createSuper(Message); - function Message() { - var _this3; - _classCallCheck(this, Message); - var address; - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - if (args.length > 0) { - address = args.shift(); - } - var oscArgs; - if (args.length > 0) { - if (args[0] instanceof Array) { - oscArgs = args.shift(); - } - } - _this3 = _super.call(this, address, oscArgs); - if (args.length > 0) { - _this3.types = args.map(function (item) { - return typeTag(item); - }).join(''); - _this3.args = args; - } - return _this3; - } - _createClass(Message, [{ - key: "add", - value: function add(item) { - _get(_getPrototypeOf(Message.prototype), "add", this).call(this, typeTag(item), item); - } - }]); - return Message; - }(TypedMessage); - - var BUNDLE_TAG = '#bundle'; - var Bundle = function () { - function Bundle() { - var _this = this; - _classCallCheck(this, Bundle); - this.offset = 0; - this.timetag = new AtomicTimetag(); - this.bundleElements = []; - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - if (args.length > 0) { - if (args[0] instanceof Date || isInt(args[0])) { - this.timetag = new AtomicTimetag(args[0]); - } else if (isArray(args[0])) { - args[0].forEach(function (item) { - _this.add(item); - }); - if (args.length > 1 && (args[1] instanceof Date || isInt(args[1]))) { - this.timetag = new AtomicTimetag(args[1]); - } - } else { - args.forEach(function (item) { - _this.add(item); - }); - } - } - } - _createClass(Bundle, [{ - key: "timestamp", - value: function timestamp(ms) { - if (!isInt(ms)) { - throw new Error('OSC Bundle needs an integer for setting the timestamp'); - } - this.timetag = new AtomicTimetag(ms); - } - }, { - key: "add", - value: function add(item) { - if (!(item instanceof Message || item instanceof Bundle)) { - throw new Error('OSC Bundle contains only Messages and Bundles'); - } - this.bundleElements.push(item); - } - }, { - key: "pack", - value: function pack() { - var encoder = new EncodeHelper(); - encoder.add(new AtomicString(BUNDLE_TAG)); - if (!this.timetag) { - this.timetag = new AtomicTimetag(); - } - encoder.add(this.timetag); - this.bundleElements.forEach(function (item) { - encoder.add(new AtomicInt32(item.pack().byteLength)); - encoder.add(item); - }); - return encoder.merge(); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC Bundle expects an instance of type DataView'); - } - var parentHead = new AtomicString(); - parentHead.unpack(dataView, initialOffset); - if (parentHead.value !== BUNDLE_TAG) { - throw new Error('OSC Bundle does not contain a valid #bundle head'); - } - var timetag = new AtomicTimetag(); - var offset = timetag.unpack(dataView, parentHead.offset); - this.bundleElements = []; - while (offset < dataView.byteLength) { - var head = new AtomicString(); - var size = new AtomicInt32(); - offset = size.unpack(dataView, offset); - var item = void 0; - head.unpack(dataView, offset); - if (head.value === BUNDLE_TAG) { - item = new Bundle(); - } else { - item = new Message(); - } - offset = item.unpack(dataView, offset); - this.bundleElements.push(item); - } - this.offset = offset; - this.timetag = timetag; - return this.offset; - } - }]); - return Bundle; - }(); - - var Packet = function () { - function Packet(value) { - _classCallCheck(this, Packet); - if (value && !(value instanceof Message || value instanceof Bundle)) { - throw new Error('OSC Packet value has to be Message or Bundle'); - } - this.value = value; - this.offset = 0; - } - _createClass(Packet, [{ - key: "pack", - value: function pack() { - if (!this.value) { - throw new Error('OSC Packet can not be encoded with empty body'); - } - return this.value.pack(); - } - }, { - key: "unpack", - value: function unpack(dataView) { - var initialOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - if (!(dataView instanceof DataView)) { - throw new Error('OSC Packet expects an instance of type DataView'); - } - if (dataView.byteLength % 4 !== 0) { - throw new Error('OSC Packet byteLength has to be a multiple of four'); - } - var head = new AtomicString(); - head.unpack(dataView, initialOffset); - var item; - if (head.value === BUNDLE_TAG) { - item = new Bundle(); - } else { - item = new Message(); - } - item.unpack(dataView, initialOffset); - this.offset = item.offset; - this.value = item; - return this.offset; - } - }]); - return Packet; - }(); - - var defaultOptions$5 = { - discardLateMessages: false - }; - var EventHandler = function () { - function EventHandler(options) { - _classCallCheck(this, EventHandler); - this.options = _objectSpread2(_objectSpread2({}, defaultOptions$5), options); - this.addressHandlers = []; - this.eventHandlers = { - open: [], - error: [], - close: [] - }; - this.uuid = 0; - } - _createClass(EventHandler, [{ - key: "dispatch", - value: function dispatch(packet, rinfo) { - var _this = this; - if (!(packet instanceof Packet)) { - throw new Error('OSC EventHander dispatch() accepts only arguments of type Packet'); - } - if (!packet.value) { - throw new Error('OSC EventHander dispatch() can\'t read empty Packets'); - } - if (packet.value instanceof Bundle) { - var bundle = packet.value; - return bundle.bundleElements.forEach(function (bundleItem) { - if (bundleItem instanceof Bundle) { - if (bundle.timetag.value.timestamp() < bundleItem.timetag.value.timestamp()) { - throw new Error('OSC Bundle timestamp is older than the timestamp of enclosed Bundles'); - } - return _this.dispatch(bundleItem); - } else if (bundleItem instanceof Message) { - var message = bundleItem; - return _this.notify(message.address, message, bundle.timetag.value.timestamp(), rinfo); - } - throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); - }); - } else if (packet.value instanceof Message) { - var message = packet.value; - return this.notify(message.address, message, 0, rinfo); - } - throw new Error('OSC EventHander dispatch() can\'t dispatch unknown Packet value'); - } - }, { - key: "call", - value: function call(name, data, rinfo) { - var success = false; - if (isString(name) && name in this.eventHandlers) { - this.eventHandlers[name].forEach(function (handler) { - handler.callback(data, rinfo); - success = true; - }); - return success; - } - var handlerKeys = Object.keys(this.addressHandlers); - var handlers = this.addressHandlers; - handlerKeys.forEach(function (key) { - var foundMatch = false; - var regex = new RegExp(prepareRegExPattern(prepareAddress(name)), 'g'); - var test = regex.test(key); - if (test && key.length === regex.lastIndex) { - foundMatch = true; - } - if (!foundMatch) { - var reverseRegex = new RegExp(prepareRegExPattern(prepareAddress(key)), 'g'); - var reverseTest = reverseRegex.test(name); - if (reverseTest && name.length === reverseRegex.lastIndex) { - foundMatch = true; - } - } - if (foundMatch) { - handlers[key].forEach(function (handler) { - handler.callback(data, rinfo); - success = true; - }); - } - }); - return success; - } - }, { - key: "notify", - value: function notify() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - if (args.length === 0) { - throw new Error('OSC EventHandler can not be called without any argument'); - } - if (args[0] instanceof Packet) { - return this.dispatch(args[0], args[1]); - } else if (args[0] instanceof Bundle || args[0] instanceof Message) { - return this.dispatch(new Packet(args[0]), args[1]); - } else if (!isString(args[0])) { - var packet = new Packet(); - packet.unpack(dataView(args[0])); - return this.dispatch(packet, args[1]); - } - var name = args[0]; - var data = null; - if (args.length > 1) { - data = args[1]; - } - var timestamp = null; - if (args.length > 2) { - if (isInt(args[2])) { - timestamp = args[2]; - } else if (args[2] instanceof Date) { - timestamp = args[2].getTime(); - } else { - throw new Error('OSC EventHandler timestamp has to be a number or Date'); - } - } - var rinfo = null; - if (args.length >= 3) { - rinfo = args[3]; - } - if (timestamp) { - var now = Date.now(); - if (now > timestamp) { - if (!this.options.discardLateMessages) { - return this.call(name, data, rinfo); - } - } - var that = this; - setTimeout(function () { - that.call(name, data, rinfo); - }, timestamp - now); - return true; - } - return this.call(name, data, rinfo); - } - }, { - key: "on", - value: function on(name, callback) { - if (!(isString(name) || isArray(name))) { - throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); - } - if (!isFunction(callback)) { - throw new Error('OSC EventHandler callback has to be a function'); - } - this.uuid += 1; - var handler = { - id: this.uuid, - callback: callback - }; - if (isString(name) && name in this.eventHandlers) { - this.eventHandlers[name].push(handler); - return this.uuid; - } - var address = prepareAddress(name); - if (!(address in this.addressHandlers)) { - this.addressHandlers[address] = []; - } - this.addressHandlers[address].push(handler); - return this.uuid; - } - }, { - key: "off", - value: function off(name, subscriptionId) { - if (!(isString(name) || isArray(name))) { - throw new Error('OSC EventHandler accepts only strings or arrays for address patterns'); - } - if (!isInt(subscriptionId)) { - throw new Error('OSC EventHandler subscription id has to be a number'); - } - var key; - var haystack; - if (isString(name) && name in this.eventHandlers) { - key = name; - haystack = this.eventHandlers; - } else { - key = prepareAddress(name); - haystack = this.addressHandlers; - } - if (key in haystack) { - return haystack[key].some(function (item, index) { - if (item.id === subscriptionId) { - haystack[key].splice(index, 1); - return true; - } - return false; - }); - } - return false; - } - }]); - return EventHandler; - }(); - - var dgram$1; - try { - dgram$1 = require('dgram'); - } catch(error) { - if (typeof window === 'undefined') { - throw(error); - } - } - var STATUS$4 = { - IS_NOT_INITIALIZED: -1, - IS_CONNECTING: 0, - IS_OPEN: 1, - IS_CLOSING: 2, - IS_CLOSED: 3 - }; - var defaultOpenOptions = { - host: 'localhost', - port: 41234, - exclusive: false - }; - var defaultSendOptions = { - host: 'localhost', - port: 41235 - }; - var defaultOptions$4 = { - type: 'udp4', - open: defaultOpenOptions, - send: defaultSendOptions - }; - function mergeOptions$1(base, custom) { - return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4), base), custom), {}, { - open: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.open), base.open), custom.open), - send: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$4.send), base.send), custom.send) - }); - } - var DatagramPlugin = function () { - function DatagramPlugin() { - var _this = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - _classCallCheck(this, DatagramPlugin); - if (!dgram$1) { - throw new Error('DatagramPlugin can not be used in browser context'); - } - this.options = mergeOptions$1({}, customOptions); - this.socket = dgram$1.createSocket(this.options.type); - this.socketStatus = STATUS$4.IS_NOT_INITIALIZED; - this.socket.on('message', function (message, rinfo) { - _this.notify(message, rinfo); - }); - this.socket.on('error', function (error) { - _this.notify('error', error); - }); - this.notify = function () {}; - } - _createClass(DatagramPlugin, [{ - key: "registerNotify", - value: function registerNotify(fn) { - this.notify = fn; - } - }, { - key: "status", - value: function status() { - return this.socketStatus; - } - }, { - key: "open", - value: function open() { - var _this2 = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var options = _objectSpread2(_objectSpread2({}, this.options.open), customOptions); - var port = options.port, - exclusive = options.exclusive; - this.socketStatus = STATUS$4.IS_CONNECTING; - this.socket.bind({ - address: options.host, - port: port, - exclusive: exclusive - }, function () { - _this2.socketStatus = STATUS$4.IS_OPEN; - _this2.notify('open'); - }); - } - }, { - key: "close", - value: function close() { - var _this3 = this; - this.socketStatus = STATUS$4.IS_CLOSING; - this.socket.close(function () { - _this3.socketStatus = STATUS$4.IS_CLOSED; - _this3.notify('close'); - }); - } - }, { - key: "send", - value: function send(binary) { - var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var options = _objectSpread2(_objectSpread2({}, this.options.send), customOptions); - var port = options.port, - host = options.host; - this.socket.send(Buffer.from(binary), 0, binary.byteLength, port, host); - } - }]); - return DatagramPlugin; - }(); - - var dgram; - try { - dgram = require('dgram'); - } catch(error) { - if (typeof window === 'undefined') { - throw(error); - } - } - var WebSocketServer$1 = typeof window === 'undefined' ? require('isomorphic-ws').Server : undefined; - var STATUS$3 = { - IS_NOT_INITIALIZED: -1, - IS_CONNECTING: 0, - IS_OPEN: 1, - IS_CLOSING: 2, - IS_CLOSED: 3 - }; - var defaultOptions$3 = { - udpServer: { - host: 'localhost', - port: 41234, - exclusive: false - }, - udpClient: { - host: 'localhost', - port: 41235 - }, - wsServer: { - host: 'localhost', - port: 8080 - }, - receiver: 'ws' - }; - function mergeOptions(base, custom) { - return _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3), base), custom), {}, { - udpServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpServer), base.udpServer), custom.udpServer), - udpClient: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.udpClient), base.udpClient), custom.udpClient), - wsServer: _objectSpread2(_objectSpread2(_objectSpread2({}, defaultOptions$3.wsServer), base.wsServer), custom.wsServer) - }); - } - var BridgePlugin = function () { - function BridgePlugin() { - var _this = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - _classCallCheck(this, BridgePlugin); - if (!dgram || !WebSocketServer$1) { - throw new Error('BridgePlugin can not be used in browser context'); - } - this.options = mergeOptions({}, customOptions); - this.websocket = null; - this.socket = dgram.createSocket('udp4'); - this.socketStatus = STATUS$3.IS_NOT_INITIALIZED; - this.socket.on('message', function (message) { - _this.send(message, { - receiver: 'ws' - }); - _this.notify(message.buffer); - }); - this.socket.on('error', function (error) { - _this.notify('error', error); - }); - this.notify = function () {}; - } - _createClass(BridgePlugin, [{ - key: "registerNotify", - value: function registerNotify(fn) { - this.notify = fn; - } - }, { - key: "status", - value: function status() { - return this.socketStatus; - } - }, { - key: "open", - value: function open() { - var _this2 = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var options = mergeOptions(this.options, customOptions); - this.socketStatus = STATUS$3.IS_CONNECTING; - this.socket.bind({ - address: options.udpServer.host, - port: options.udpServer.port, - exclusive: options.udpServer.exclusive - }, function () { - var wsServerOptions = {}; - if (options.wsServer.server) wsServerOptions.server = options.wsServer.server;else wsServerOptions = options.wsServer; - _this2.websocket = new WebSocketServer$1(wsServerOptions); - _this2.websocket.binaryType = 'arraybuffer'; - _this2.websocket.on('listening', function () { - _this2.socketStatus = STATUS$3.IS_OPEN; - _this2.notify('open'); - }); - _this2.websocket.on('error', function (error) { - _this2.notify('error', error); - }); - _this2.websocket.on('connection', function (client) { - client.on('message', function (message, rinfo) { - _this2.send(message, { - receiver: 'udp' - }); - _this2.notify(new Uint8Array(message), rinfo); - }); - }); - }); - } - }, { - key: "close", - value: function close() { - var _this3 = this; - this.socketStatus = STATUS$3.IS_CLOSING; - this.socket.close(function () { - _this3.websocket.close(function () { - _this3.socketStatus = STATUS$3.IS_CLOSED; - _this3.notify('close'); - }); - }); - } - }, { - key: "send", - value: function send(binary) { - var customOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var options = mergeOptions(this.options, customOptions); - var receiver = options.receiver; - if (receiver === 'udp') { - var data = binary instanceof Buffer ? binary : Buffer.from(binary); - this.socket.send(data, 0, data.byteLength, options.udpClient.port, options.udpClient.host); - } else if (receiver === 'ws') { - this.websocket.clients.forEach(function (client) { - client.send(binary, { - binary: true - }); - }); - } else { - throw new Error('BridgePlugin can not send message to unknown receiver'); - } - } - }]); - return BridgePlugin; - }(); - - var scope = typeof global === 'undefined' ? window : global; - var WebSocket = typeof __dirname === 'undefined' ? scope.WebSocket : require('isomorphic-ws'); - var STATUS$2 = { - IS_NOT_INITIALIZED: -1, - IS_CONNECTING: 0, - IS_OPEN: 1, - IS_CLOSING: 2, - IS_CLOSED: 3 - }; - var defaultOptions$2 = { - host: 'localhost', - port: 8080, - secure: false, - protocol: [] - }; - var WebsocketClientPlugin = function () { - function WebsocketClientPlugin(customOptions) { - _classCallCheck(this, WebsocketClientPlugin); - if (!WebSocket) { - throw new Error('WebsocketClientPlugin can\'t find a WebSocket class'); - } - this.options = _objectSpread2(_objectSpread2({}, defaultOptions$2), customOptions); - this.socket = null; - this.socketStatus = STATUS$2.IS_NOT_INITIALIZED; - this.notify = function () {}; - } - _createClass(WebsocketClientPlugin, [{ - key: "registerNotify", - value: function registerNotify(fn) { - this.notify = fn; - } - }, { - key: "status", - value: function status() { - return this.socketStatus; - } - }, { - key: "open", - value: function open() { - var _this = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); - var port = options.port, - host = options.host, - secure = options.secure, - protocol = options.protocol; - if (this.socket) { - this.close(); - } - var scheme = secure ? 'wss' : 'ws'; - var rinfo = { - address: host, - family: scheme, - port: port, - size: 0 - }; - this.socket = new WebSocket("".concat(scheme, "://").concat(host, ":").concat(port), protocol); - this.socket.binaryType = 'arraybuffer'; - this.socketStatus = STATUS$2.IS_CONNECTING; - this.socket.onopen = function () { - _this.socketStatus = STATUS$2.IS_OPEN; - _this.notify('open'); - }; - this.socket.onclose = function () { - _this.socketStatus = STATUS$2.IS_CLOSED; - _this.notify('close'); - }; - this.socket.onerror = function (error) { - _this.notify('error', error); - }; - this.socket.onmessage = function (message) { - _this.notify(message.data, rinfo); - }; - } - }, { - key: "close", - value: function close() { - this.socketStatus = STATUS$2.IS_CLOSING; - this.socket.close(); - } - }, { - key: "send", - value: function send(binary) { - this.socket.send(binary); - } - }]); - return WebsocketClientPlugin; - }(); - - var WebSocketServer = typeof __dirname !== 'undefined' ? require('isomorphic-ws').Server : undefined; - var STATUS$1 = { - IS_NOT_INITIALIZED: -1, - IS_CONNECTING: 0, - IS_OPEN: 1, - IS_CLOSING: 2, - IS_CLOSED: 3 - }; - var defaultOptions$1 = { - host: 'localhost', - port: 8080 - }; - var WebsocketServerPlugin = function () { - function WebsocketServerPlugin(customOptions) { - _classCallCheck(this, WebsocketServerPlugin); - if (!WebSocketServer) { - throw new Error('WebsocketServerPlugin can not be used in browser context'); - } - this.options = _objectSpread2(_objectSpread2({}, defaultOptions$1), customOptions); - this.socket = null; - this.socketStatus = STATUS$1.IS_NOT_INITIALIZED; - this.notify = function () {}; - } - _createClass(WebsocketServerPlugin, [{ - key: "registerNotify", - value: function registerNotify(fn) { - this.notify = fn; - } - }, { - key: "status", - value: function status() { - return this.socketStatus; - } - }, { - key: "open", - value: function open() { - var _this = this; - var customOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var options = _objectSpread2(_objectSpread2({}, this.options), customOptions); - var port = options.port, - host = options.host; - var rinfo = { - address: host, - family: 'wsserver', - port: port, - size: 0 - }; - if (this.socket) { - this.close(); - } - if (options.server) { - this.socket = new WebSocketServer({ - server: options.server - }); - } else { - this.socket = new WebSocketServer({ - host: host, - port: port - }); - } - this.socket.binaryType = 'arraybuffer'; - this.socketStatus = STATUS$1.IS_CONNECTING; - this.socket.on('listening', function () { - _this.socketStatus = STATUS$1.IS_OPEN; - _this.notify('open'); - }); - this.socket.on('error', function (error) { - _this.notify('error', error); - }); - this.socket.on('connection', function (client) { - client.on('message', function (message) { - _this.notify(new Uint8Array(message), rinfo); - }); - }); - } - }, { - key: "close", - value: function close() { - var _this2 = this; - this.socketStatus = STATUS$1.IS_CLOSING; - this.socket.close(function () { - _this2.socketStatus = STATUS$1.IS_CLOSED; - _this2.notify('close'); - }); - } - }, { - key: "send", - value: function send(binary) { - this.socket.clients.forEach(function (client) { - client.send(binary, { - binary: true - }); - }); - } - }]); - return WebsocketServerPlugin; - }(); - - var defaultOptions = { - discardLateMessages: false, - plugin: new WebsocketClientPlugin() - }; - var STATUS = { - IS_NOT_INITIALIZED: -1, - IS_CONNECTING: 0, - IS_OPEN: 1, - IS_CLOSING: 2, - IS_CLOSED: 3 - }; - var OSC = function () { - function OSC(options) { - _classCallCheck(this, OSC); - if (options && !isObject(options)) { - throw new Error('OSC options argument has to be an object.'); - } - this.options = _objectSpread2(_objectSpread2({}, defaultOptions), options); - this.eventHandler = new EventHandler({ - discardLateMessages: this.options.discardLateMessages - }); - var eventHandler = this.eventHandler; - if (this.options.plugin && this.options.plugin.registerNotify) { - this.options.plugin.registerNotify(function () { - return eventHandler.notify.apply(eventHandler, arguments); - }); - } - } - _createClass(OSC, [{ - key: "on", - value: function on(eventName, callback) { - if (!(isString(eventName) && isFunction(callback))) { - throw new Error('OSC on() needs event- or address string and callback function'); - } - return this.eventHandler.on(eventName, callback); - } - }, { - key: "off", - value: function off(eventName, subscriptionId) { - if (!(isString(eventName) && isInt(subscriptionId))) { - throw new Error('OSC off() needs string and number (subscriptionId) to unsubscribe'); - } - return this.eventHandler.off(eventName, subscriptionId); - } - }, { - key: "open", - value: function open(options) { - if (options && !isObject(options)) { - throw new Error('OSC open() options argument needs to be an object'); - } - if (!(this.options.plugin && isFunction(this.options.plugin.open))) { - throw new Error('OSC Plugin API #open is not implemented!'); - } - return this.options.plugin.open(options); - } - }, { - key: "status", - value: function status() { - if (!(this.options.plugin && isFunction(this.options.plugin.status))) { - throw new Error('OSC Plugin API #status is not implemented!'); - } - return this.options.plugin.status(); - } - }, { - key: "close", - value: function close() { - if (!(this.options.plugin && isFunction(this.options.plugin.close))) { - throw new Error('OSC Plugin API #close is not implemented!'); - } - return this.options.plugin.close(); - } - }, { - key: "send", - value: function send(packet, options) { - if (!(this.options.plugin && isFunction(this.options.plugin.send))) { - throw new Error('OSC Plugin API #send is not implemented!'); - } - if (!(packet instanceof TypedMessage || packet instanceof Message || packet instanceof Bundle || packet instanceof Packet)) { - throw new Error('OSC send() needs Messages, Bundles or Packets'); - } - if (options && !isObject(options)) { - throw new Error('OSC send() options argument has to be an object'); - } - return this.options.plugin.send(packet.pack(), options); - } - }]); - return OSC; - }(); - OSC.STATUS = STATUS; - OSC.Packet = Packet; - OSC.Bundle = Bundle; - OSC.Message = Message; - OSC.TypedMessage = TypedMessage; - OSC.DatagramPlugin = DatagramPlugin; - OSC.WebsocketClientPlugin = WebsocketClientPlugin; - OSC.WebsocketServerPlugin = WebsocketServerPlugin; - OSC.BridgePlugin = BridgePlugin; - - return OSC; - -})); diff --git a/packages/osc/osc.js b/packages/osc/osc.js index 7446c0e5..6194625a 100644 --- a/packages/osc/osc.js +++ b/packages/osc/osc.js @@ -1,8 +1,3 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.OSC = factory()); -})(this, (function () { 'use strict'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); @@ -1728,6 +1723,4 @@ OSC.WebsocketServerPlugin = WebsocketServerPlugin; OSC.BridgePlugin = BridgePlugin; - return OSC; - -})); + export default OSC; From 171f84506971ddde37643c66aba81cd806a36778 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Tue, 12 Apr 2022 23:54:56 +0200 Subject: [PATCH 33/37] add setup script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 4702ff10..3978a44d 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "test": "npm run test --workspaces --if-present", "bootstrap": "lerna bootstrap", + "setup": "npm i && npm run bootstrap && cd repl && npm i", "repl": "cd repl && npm run start", "osc": "cd packages/osc && npm run server" }, From 42e2531e8d27970d59a0e3067d2fcc9a4c6d77df Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Apr 2022 00:09:04 +0200 Subject: [PATCH 34/37] readme additions --- README.md | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index fb0ab91f..876e76fc 100644 --- a/README.md +++ b/README.md @@ -4,40 +4,42 @@ An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This is unstable software, please tread carefully. -Try it here: https://strudel.tidalcycles.org/ +- Try it here: +- Tutorial: +- Technical Blog Post: -Tutorial: https://strudel.tidalcycles.org/tutorial/ +## Running Locally -## Local development - -Run the REPL locally: +After cloning the project, you can run the REPL locally: ```bash -npm install -npx lerna bootstrap -cd repl -npm install -npm run start +npm run setup +npm run repl ``` -## Publish Packages +## Using Strudel In Your Project -To publish, just run: +There are multiple npm packages you can use to use strudel, or only parts of it, in your project: -```sh -npx lerna publish -``` +- [`core`](./packages/core/): tidal pattern engine +- [`mini`](./packages/mini): mini notation parser + core binding +- [`eval`](./packages/eval): user code evaluator. syntax sugar + highlighting +- [`tone`](./packages/tone): bindings for Tone.js instruments and effects +- [`osc`](./packages/osc): bindings to communicate via OSC +- [`midi`](./packages/midi): webmidi bindings +- [`tonal`](./packages/tonal): tonal functions +- [`xen`](./packages/xen): microtonal / xenharmonic functions -This will publish all packages that changed since the last version. +Click on the package names to find out more about each one. -## Style +## Contributing -For now, please try to copy the style of surrounding code. VS Code users can install the 'prettier' add-on which will use the .prettierrc configuration file for automatic formatting. +There are many ways to contribute to this project! See [contribution guide](./CONTRIBUTING.md). ## Community -There is a #strudel channel on the TidalCycles discord: https://discord.com/invite/HGEdXmRkzT +There is a #strudel channel on the TidalCycles discord: -You can also ask questions and find related discussions on the tidal club forum: https://club.tidalcycles.org/ +You can also ask questions and find related discussions on the tidal club forum: -The discord and forum is shared with the haskell (tidal) and python (vortex) siblings of this project. \ No newline at end of file +The discord and forum is shared with the haskell (tidal) and python (vortex) siblings of this project. From 6bdb0fee554ba3173f27d46451d1be95685303db Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Apr 2022 00:15:09 +0200 Subject: [PATCH 35/37] fix server import --- packages/osc/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/osc/server.js b/packages/osc/server.js index febe2d90..f765b284 100644 --- a/packages/osc/server.js +++ b/packages/osc/server.js @@ -1,4 +1,4 @@ -const OSC = require('./osc-js/osc.js'); +const OSC = require('osc-js'); const config = { receiver: 'ws', // @param {string} Where messages sent via 'send' method will be delivered to, 'ws' for Websocket clients, 'udp' for udp client From 3cd10bf4b399c7f7ce690fcd784e7096c1ecf80f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Apr 2022 00:15:36 +0200 Subject: [PATCH 36/37] package-lock --- package-lock.json | 1 + packages/osc/server.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 2fefcea2..28f72c01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9308,6 +9308,7 @@ } }, "packages/osc": { + "name": "@strudel.cycles/osc", "version": "0.0.1", "license": "GPL-3.0-or-later", "dependencies": { diff --git a/packages/osc/server.js b/packages/osc/server.js index febe2d90..f765b284 100644 --- a/packages/osc/server.js +++ b/packages/osc/server.js @@ -1,4 +1,4 @@ -const OSC = require('./osc-js/osc.js'); +const OSC = require('osc-js'); const config = { receiver: 'ws', // @param {string} Where messages sent via 'send' method will be delivered to, 'ws' for Websocket clients, 'udp' for udp client From 2060e868750c649bc84f67d1d0b330b925dd4262 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 13 Apr 2022 00:25:53 +0200 Subject: [PATCH 37/37] add queryArc + update readme --- packages/core/README.md | 8 +++++--- packages/core/strudel.mjs | 16 ++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index d570c09e..c4abf087 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -15,14 +15,14 @@ import { sequence, State, TimeSpan } from '@strudel.cycles/core'; const pattern = sequence('a', ['b', 'c']); -const events = pattern.query(new State(new TimeSpan(0, 2))); +const events = pattern.queryArc(0, 1); const spans = events.map( (event) => `${event.value}: ${event.whole.begin.toFraction()} - ${event.whole.end.toFraction()} `, ); ``` -spans: +yields: ```log a: 0 - 1/2 @@ -33,4 +33,6 @@ b: 3/2 - 7/4 c: 7/4 - 2 ``` -[play with @strudel.cycles/core on codesandbox](https://codesandbox.io/s/strudel-core-test-qmz6qr?file=/src/index.js). +- [play with @strudel.cycles/core on codesandbox](https://codesandbox.io/s/strudel-core-test-qmz6qr?file=/src/index.js). +- [open color pattern example](https://raw.githack.com/tidalcycles/strudel/package-examples/packages/core/examples/canvas.html) +- [open minimal repl example](https://raw.githack.com/tidalcycles/strudel/package-examples/packages/core/examples/metro.html) diff --git a/packages/core/strudel.mjs b/packages/core/strudel.mjs index ec1eaa2e..7fa58859 100644 --- a/packages/core/strudel.mjs +++ b/packages/core/strudel.mjs @@ -236,6 +236,10 @@ class Pattern { this.query = query; } + queryArc(begin, end) { + return this.query(new State(new TimeSpan(begin, end))); + } + _splitQueries() { // Splits queries at cycle boundaries. This makes some calculations // easier to express, as all events are then constrained to happen within @@ -686,12 +690,12 @@ class Pattern { } _chop(n) { - const slices = Array.from({length: n}, (x, i) => i); - const slice_objects = slices.map(i => ({begin: i/n, end: (i+1)/n})); - const func = function(o) { - return(sequence(slice_objects.map(slice_o => Object.assign({}, o, slice_o)))) - } - return(this._squeezeBind(func)); + const slices = Array.from({ length: n }, (x, i) => i); + const slice_objects = slices.map((i) => ({ begin: i / n, end: (i + 1) / n })); + const func = function (o) { + return sequence(slice_objects.map((slice_o) => Object.assign({}, o, slice_o))); + }; + return this._squeezeBind(func); } // cpm = cycles per minute