Browse Source

created some game controller tests in an effort to build an inviting interactive improvisational experience

master
Max Franlin 3 years ago
parent
commit
d4beedc154
43 changed files with 50049 additions and 456 deletions
  1. +46
    -0
      html5/gamePad.html
  2. BIN
      html5/imgs/new/nx.jpg
  3. BIN
      html5/imgs/new/ny.jpg
  4. BIN
      html5/imgs/new/nz.jpg
  5. BIN
      html5/imgs/new/px.jpg
  6. BIN
      html5/imgs/new/py.jpg
  7. BIN
      html5/imgs/new/pz.jpg
  8. BIN
      html5/imgs/skybox/milky_nx.jpg
  9. BIN
      html5/imgs/skybox/milky_ny.jpg
  10. BIN
      html5/imgs/skybox/milky_nz.jpg
  11. BIN
      html5/imgs/skybox/milky_px.jpg
  12. BIN
      html5/imgs/skybox/milky_py.jpg
  13. BIN
      html5/imgs/skybox/milky_pz.jpg
  14. +112
    -0
      html5/js/gamepad.js
  15. +40
    -0
      html5/js/myThree.cube.js
  16. +35
    -0
      html5/js/myThree.js
  17. +935
    -0
      html5/js/three.min.js
  18. +46265
    -0
      html5/js/threeJs.js
  19. +12
    -0
      html5/threeJs.html
  20. +199
    -0
      jackPatchConf/PD_Synth_Sax_Rec.xml
  21. +0
    -0
      nodeJS/controllerTest/index.js
  22. +54
    -44
      nodeJS/controllerTest/package-lock.json
  23. +2
    -2
      nodeJS/controllerTest/package.json
  24. +6
    -4
      nodeJS/controllerTest/public/index.html
  25. +144
    -0
      nodeJS/controllerTest/public/js/client.js
  26. +91
    -0
      nodeJS/controllerTest/public/js/marks.js
  27. +102
    -0
      nodeJS/controllerTest/public/js/mover.js
  28. +0
    -0
      nodeJS/controllerTest/public/styles/style.css
  29. +68
    -0
      nodeJS/controllerTest/test.js
  30. +0
    -196
      nodeJS/etherSeq/public/js/canvas01.js
  31. +0
    -32
      nodeJS/etherSeq/test.js
  32. +0
    -0
      nodeJS/polyPlayer/index.js
  33. +652
    -0
      nodeJS/polyPlayer/package-lock.json
  34. +19
    -0
      nodeJS/polyPlayer/package.json
  35. +22
    -0
      nodeJS/polyPlayer/public/index.html
  36. +56
    -0
      nodeJS/polyPlayer/public/js/SynthPoint.js
  37. +143
    -0
      nodeJS/polyPlayer/public/js/client.js
  38. +100
    -0
      nodeJS/polyPlayer/public/js/marks.js
  39. +46
    -0
      nodeJS/polyPlayer/public/js/mover.js
  40. +56
    -0
      nodeJS/polyPlayer/public/styles/style.css
  41. +68
    -0
      nodeJS/polyPlayer/test.js
  42. +277
    -178
      pureData/PedalImprovisation.pd
  43. +499
    -0
      pureData/euclid_midiout.pd

+ 46
- 0
html5/gamePad.html View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!--
Gamepad API Test
Written in 2013 by Ted Mielczarek <ted@mielczarek.org>
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
-->
<script type="text/javascript" src="js/gamepad.js"></script>
<style>
.buttons, .axes {
padding: 1em;
}
/*meter*/.axis {
min-width: 200px;
margin: 1em;
}
.button {
padding: 1em;
border-radius: 20px;
border: 1px solid black;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAxJREFUCNdjYPjPAAACAgEAqiqeJwAAAABJRU5ErkJggg==);
background-size: 0% 0%;
background-position: 50% 50%;
background-repeat: no-repeat;
}
.pressed {
border: 1px solid red;
}
</style>
</head>
<body>
<h2 id="start">Press a button on your controller to start</h2>
<a href="https://github.com/luser/gamepadtest"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub"></a>
</body>
</html>

BIN
html5/imgs/new/nx.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 54 KiB

BIN
html5/imgs/new/ny.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 51 KiB

BIN
html5/imgs/new/nz.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 53 KiB

BIN
html5/imgs/new/px.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 59 KiB

BIN
html5/imgs/new/py.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 19 KiB

BIN
html5/imgs/new/pz.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 58 KiB

BIN
html5/imgs/skybox/milky_nx.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 253 KiB

BIN
html5/imgs/skybox/milky_ny.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 341 KiB

BIN
html5/imgs/skybox/milky_nz.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 364 KiB

BIN
html5/imgs/skybox/milky_px.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 260 KiB

BIN
html5/imgs/skybox/milky_py.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 385 KiB

BIN
html5/imgs/skybox/milky_pz.jpg View File

Before After
Width: 1024  |  Height: 1024  |  Size: 406 KiB

+ 112
- 0
html5/js/gamepad.js View File

@ -0,0 +1,112 @@
var haveEvents = 'GamepadEvent' in window;
var haveWebkitEvents = 'WebKitGamepadEvent' in window;
var controllers = {};
var rAF = window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.requestAnimationFrame;
function connecthandler(e) {
addgamepad(e.gamepad);
}
function addgamepad(gamepad) {
controllers[gamepad.index] = gamepad; var d = document.createElement("div");
d.setAttribute("id", "controller" + gamepad.index);
var t = document.createElement("h1");
t.appendChild(document.createTextNode("gamepad: " + gamepad.id));
d.appendChild(t);
var b = document.createElement("div");
b.className = "buttons";
for (var i=0; i<gamepad.buttons.length; i++) {
var e = document.createElement("span");
e.className = "button";
//e.id = "b" + i;
e.innerHTML = i;
b.appendChild(e);
}
d.appendChild(b);
var a = document.createElement("div");
a.className = "axes";
for (i=0; i<gamepad.axes.length; i++) {
e = document.createElement("meter");
e.className = "axis";
//e.id = "a" + i;
e.setAttribute("min", "-1");
e.setAttribute("max", "1");
e.setAttribute("value", "0");
e.innerHTML = i;
a.appendChild(e);
}
d.appendChild(a);
document.getElementById("start").style.display = "none";
document.body.appendChild(d);
rAF(updateStatus);
}
function disconnecthandler(e) {
removegamepad(e.gamepad);
}
function removegamepad(gamepad) {
var d = document.getElementById("controller" + gamepad.index);
document.body.removeChild(d);
delete controllers[gamepad.index];
}
function updateStatus() {
scangamepads();
for (j in controllers) {
var controller = controllers[j];
var d = document.getElementById("controller" + j);
var buttons = d.getElementsByClassName("button");
for (var i=0; i<controller.buttons.length; i++) {
var b = buttons[i];
var val = controller.buttons[i];
var pressed = val == 1.0;
if (typeof(val) == "object") {
pressed = val.pressed;
val = val.value;
}
var pct = Math.round(val * 100) + "%";
b.style.backgroundSize = pct + " " + pct;
if (pressed) {
b.className = "button pressed";
} else {
b.className = "button";
}
}
var axes = d.getElementsByClassName("axis");
for (var i=0; i<controller.axes.length; i++) {
var a = axes[i];
a.innerHTML = i + ": " + controller.axes[i].toFixed(4);
a.setAttribute("value", controller.axes[i]);
}
}
rAF(updateStatus);
}
function scangamepads() {
var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
for (var i = 0; i < gamepads.length; i++) {
if (gamepads[i]) {
if (!(gamepads[i].index in controllers)) {
addgamepad(gamepads[i]);
} else {
controllers[gamepads[i].index] = gamepads[i];
}
}
}
}
if (haveEvents) {
window.addEventListener("gamepadconnected", connecthandler);
window.addEventListener("gamepaddisconnected", disconnecthandler);
} else if (haveWebkitEvents) {
window.addEventListener("webkitgamepadconnected", connecthandler);
window.addEventListener("webkitgamepaddisconnected", disconnecthandler);
} else {
setInterval(scangamepads, 500);
}

+ 40
- 0
html5/js/myThree.cube.js View File

@ -0,0 +1,40 @@
var camera, scene, renderer;
function init() {
camera = new THREE.PerspectiveCamera( 75, 900 / 700, 1, 5000 )
camera.position.z = 2000
//cubemap
let skyBox = new THREE.CubeTextureLoader()
skyBox.setCrossOrigin(true)
skyBox.load( [
'/imgs/new/px.jpg', '/imgs/new/nx.jpg',
'/imgs/new/py.jpg', '/imgs/new/ny.jpg',
'/imgs/new/pz.jpg', '/imgs/new/nz.jpg'
] );
// skyBox.format = THREE.RGBFormat;
scene = new THREE.Scene();
scene.background = skyBox;
// lights
scene.add (new THREE.AmbientLight(0xffffff))
// scene.add( new THREE.HemisphereLight( 0x606060, 0x404040 ) )
scene.add (new THREE.PointLight(0xffffff, 2))
// renderer
renderer = new THREE.WebGLRenderer()
renderer.setPixelRatio( window.devicePixelRatio )
renderer.setSize( 900, 700 )
document.body.appendChild( renderer.domElement )
}
window.onload = function() {
init()
animate()
}
let animate = () => {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}

+ 35
- 0
html5/js/myThree.js View File

@ -0,0 +1,35 @@
var scene = new THREE.Scene()
var camera = new THREE.PerspectiveCamera( 75, 900 / 700, 0.1, 1000 )
var renderer = new THREE.WebGLRenderer()
var geometry = new THREE.SphereGeometry( 1, 6, 6 )
var material = new THREE.MeshLambertMaterial( { color: 0x00ff00 } )
var sphere = new THREE.Mesh( geometry, material )
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 )
window.onload = function() {
renderer.setSize( 900, 700 )
document.body.appendChild( renderer.domElement )
scene.add( new THREE.HemisphereLight( 0x606060, 0x404040, 0.5 ) )
directionalLight.position.set(1, 1, 1)
scene.add(directionalLight)
scene.add(sphere)
directionalLight.target = sphere
camera.position.z = 5
animate()
}
let animate = () => {
requestAnimationFrame(animate)
sphere.rotation.x += 0.05
sphere.rotation.y += 0.05
renderer.render(scene, camera)
}

+ 935
- 0
html5/js/three.min.js
File diff suppressed because it is too large
View File


+ 46265
- 0
html5/js/threeJs.js
File diff suppressed because it is too large
View File


+ 12
- 0
html5/threeJs.html View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>threeJS</title>
<script type="text/javascript" src="js/three.min.js"></script>
<script type="text/javascript" src="js/myThree.js"></script>
</head>
<body style="max-width: 900px; margin: 50px auto;">
</body>
</html>

+ 199
- 0
jackPatchConf/PD_Synth_Sax_Rec.xml View File

@ -0,0 +1,199 @@
<!DOCTYPE patchbay>
<patchbay version="0.4.4" name="PD_Synth_Sax_Rec">
<output-sockets>
<socket exclusive="off" type="jack-audio" name="system" client="system">
<plug>capture_1</plug>
<plug>capture_2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour" client="ardour">
<plug>LTC-out</plug>
<plug>Click/audio_out 1</plug>
<plug>Click/audio_out 2</plug>
<plug>Monitor/audio_out 1</plug>
<plug>Monitor/audio_out 2</plug>
<plug>Master/audio_out 1</plug>
<plug>Master/audio_out 2</plug>
<plug>Sax \(ch1\)/audio_out 1</plug>
<plug>Synth \(ch2\)/audio_out 1</plug>
<plug>Sax \(ch1\)/audio_out 2</plug>
<plug>Synth \(ch2\)/audio_out 2</plug>
<plug>auditioner/audio_out 1</plug>
<plug>auditioner/audio_out 2</plug>
<plug>PureData/audio_out 1</plug>
<plug>PureData/audio_out 2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="pure_data_0" client="pure_data_0">
<plug>output0</plug>
<plug>output1</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="system 2" client="system">
<plug>capture_1</plug>
<plug>capture_1</plug>
<plug>capture_2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour 2" client="ardour">
<plug>Master/audio_out 1</plug>
<plug>Master/audio_out 2</plug>
<plug>Sax \(ch1\)/audio_out 1</plug>
<plug>Synth \(ch2\)/audio_out 1</plug>
<plug>Sax \(ch1\)/audio_out 2</plug>
<plug>Synth \(ch2\)/audio_out 2</plug>
<plug>auditioner/audio_out 1</plug>
<plug>auditioner/audio_out 2</plug>
<plug>PureData/audio_out 1</plug>
<plug>PureData/audio_out 2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour 3" client="ardour">
<plug>Click/audio_out 1</plug>
<plug>Click/audio_out 2</plug>
<plug>Monitor/audio_out 1</plug>
<plug>Monitor/audio_out 2</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="a2j" client="a2j">
<plug>Midi Through \[14\] \(capture\): Midi Through Port-0</plug>
<plug>CVpal \[24\] \(capture\): CVpal MIDI 1</plug>
<plug>USB MIDI Interface \[32\] \(capture\): USB MIDI Interface MIDI 1</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 1</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 2</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 3</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 4</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 5</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 6</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 7</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 8</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="ardour" client="ardour">
<plug>MIDI control out</plug>
<plug>MMC out</plug>
<plug>Scene out</plug>
<plug>MTC out</plug>
<plug>MIDI Clock out</plug>
<plug>auditioner/midi_out 1</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="a2j 2" client="a2j">
<plug>USB MIDI Interface \[32\] \(capture\): USB MIDI Interface MIDI 1</plug>
<plug>Pure Data \[130\] \(capture\): Pure Data Midi-Out 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="Midi Through" client="Midi Through">
<plug>Midi Through Port-0</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="CVpal" client="CVpal">
<plug>CVpal MIDI 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="USB MIDI Interface" client="USB MIDI Interface">
<plug>USB MIDI Interface MIDI 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="Pure Data" client="Pure Data">
<plug>Pure Data Midi-Out 1</plug>
<plug>Pure Data Midi-Out 2</plug>
<plug>Pure Data Midi-Out 3</plug>
<plug>Pure Data Midi-Out 4</plug>
<plug>Pure Data Midi-Out 5</plug>
<plug>Pure Data Midi-Out 6</plug>
<plug>Pure Data Midi-Out 7</plug>
<plug>Pure Data Midi-Out 8</plug>
</socket>
</output-sockets>
<input-sockets>
<socket exclusive="off" type="jack-audio" name="system" client="system">
<plug>playback_1</plug>
<plug>playback_2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour" client="ardour">
<plug>LTC-in</plug>
<plug>Monitor/audio_in 1</plug>
<plug>Monitor/audio_in 2</plug>
<plug>Master/audio_in 1</plug>
<plug>Master/audio_in 2</plug>
<plug>Sax \(ch1\)/audio_in 1</plug>
<plug>Synth \(ch2\)/audio_in 1</plug>
<plug>PureData/audio_in 1</plug>
<plug>PureData/audio_in 2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="pure_data_0" client="pure_data_0">
<plug>input0</plug>
<plug>input1</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour 2" client="ardour">
<plug>Sax \(ch1\)/audio_in 1</plug>
<plug>LTC-in</plug>
<plug>Synth \(ch2\)/audio_in 1</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour 3" client="ardour">
<plug>PureData/audio_in 1</plug>
<plug>PureData/audio_in 2</plug>
</socket>
<socket exclusive="off" type="jack-audio" name="ardour 4" client="ardour">
<plug>Monitor/audio_in 1</plug>
<plug>Monitor/audio_in 2</plug>
<plug>Master/audio_in 1</plug>
<plug>Master/audio_in 1</plug>
<plug>Master/audio_in 2</plug>
<plug>Master/audio_in 2</plug>
<plug>Monitor/audio_in 1</plug>
<plug>Monitor/audio_in 2</plug>
<plug>Master/audio_in 1</plug>
<plug>Master/audio_in 2</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="a2j" client="a2j">
<plug>Midi Through \[14\] \(playback\): Midi Through Port-0</plug>
<plug>CVpal \[24\] \(playback\): CVpal MIDI 1</plug>
<plug>USB MIDI Interface \[32\] \(playback\): USB MIDI Interface MIDI 1</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 1</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 2</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 3</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 4</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 5</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 6</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 7</plug>
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 8</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="ardour" client="ardour">
<plug>MIDI control in</plug>
<plug>MMC in</plug>
<plug>Scene in</plug>
<plug>MTC in</plug>
<plug>MIDI Clock in</plug>
</socket>
<socket exclusive="off" type="jack-midi" name="a2j 2" client="a2j">
<plug>Pure Data \[130\] \(playback\): Pure Data Midi-In 1</plug>
<plug>CVpal \[24\] \(playback\): CVpal MIDI 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="Midi Through" client="Midi Through">
<plug>Midi Through Port-0</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="CVpal" client="CVpal">
<plug>CVpal MIDI 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="USB MIDI Interface" client="USB MIDI Interface">
<plug>USB MIDI Interface MIDI 1</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="Pure Data" client="Pure Data">
<plug>Pure Data Midi-In 1</plug>
<plug>Pure Data Midi-In 2</plug>
<plug>Pure Data Midi-In 3</plug>
<plug>Pure Data Midi-In 4</plug>
<plug>Pure Data Midi-In 5</plug>
<plug>Pure Data Midi-In 6</plug>
<plug>Pure Data Midi-In 7</plug>
<plug>Pure Data Midi-In 8</plug>
</socket>
<socket exclusive="off" type="alsa-midi" name="a2jmidid" client="a2jmidid">
<plug>port</plug>
</socket>
</input-sockets>
<slots/>
<cables>
<cable output="system" input="pure_data_0" type="jack-audio"/>
<cable output="pure_data_0" input="ardour 3" type="jack-audio"/>
<cable output="system 2" input="ardour 2" type="jack-audio"/>
<cable output="ardour 2" input="ardour 4" type="jack-audio"/>
<cable output="ardour 3" input="system" type="jack-audio"/>
<cable output="a2j 2" input="a2j 2" type="jack-midi"/>
<cable output="Midi Through" input="a2jmidid" type="alsa-midi"/>
<cable output="CVpal" input="a2jmidid" type="alsa-midi"/>
<cable output="USB MIDI Interface" input="a2jmidid" type="alsa-midi"/>
<cable output="Pure Data" input="a2jmidid" type="alsa-midi"/>
</cables>
</patchbay>

nodeJS/etherSeq/index.js → nodeJS/controllerTest/index.js View File


nodeJS/etherSeq/package-lock.json → nodeJS/controllerTest/package-lock.json View File

@ -1,5 +1,5 @@
{
"name": "sockets",
"name": "clientTest",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
@ -76,16 +76,6 @@
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.16"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"bytes": {
@ -134,9 +124,9 @@
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
@ -172,6 +162,16 @@
"debug": "3.1.0",
"engine.io-parser": "2.1.2",
"ws": "3.3.3"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"engine.io-client": {
@ -190,6 +190,16 @@
"ws": "3.3.3",
"xmlhttprequest-ssl": "1.5.5",
"yeast": "0.1.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"engine.io-parser": {
@ -249,16 +259,6 @@
"type-is": "1.6.16",
"utils-merge": "1.0.1",
"vary": "1.1.2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"finalhandler": {
@ -273,16 +273,6 @@
"parseurl": "1.3.2",
"statuses": "1.4.0",
"unpipe": "1.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"forwarded": {
@ -502,16 +492,6 @@
"on-finished": "2.3.0",
"range-parser": "1.2.0",
"statuses": "1.4.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"serve-static": {
@ -541,6 +521,16 @@
"socket.io-adapter": "1.1.1",
"socket.io-client": "2.1.0",
"socket.io-parser": "3.2.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"socket.io-adapter": {
@ -567,6 +557,16 @@
"parseuri": "0.0.5",
"socket.io-parser": "3.2.0",
"to-array": "0.1.4"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"socket.io-parser": {
@ -577,6 +577,16 @@
"component-emitter": "1.2.1",
"debug": "3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"statuses": {

nodeJS/etherSeq/package.json → nodeJS/controllerTest/package.json View File

@ -1,7 +1,7 @@
{
"name": "etherSeq",
"name": "clientTest",
"version": "1.0.0",
"description": "Sockets and WebAudio API test",
"description": "Testing multiple clients through sockets",
"main": "index.js",
"scripts": {
"test": "test.js"

nodeJS/etherSeq/public/index.html → nodeJS/controllerTest/public/index.html View File

@ -1,19 +1,21 @@
<!DOCTYPE html>
<html>
<html >
<head>
<meta charset="utf-8">
<title>canvas01</title>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<link rel="stylesheet" type="text/css" href="styles/style.css">
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script type="text/javascript" src="js/marks.js"></script>
<script type="text/javascript" src="js/mover.js"></script>
</head>
<body>
<div id='container'>
<canvas id='seq' width="800px" height="500px"></canvas>
<button name="clear">Clear</button>
</div>
<script type="text/javascript" src="js/canvas01.js"></script>
<script type="text/javascript" src="js/client.js"></script>
</body>
</html>

+ 144
- 0
nodeJS/controllerTest/public/js/client.js View File

@ -0,0 +1,144 @@
// SOCKET CONNECTION
let socket = io.connect('http://' + window.location.host) // for internal testing
// AUDIO ENGINE
let audioEngine = new (window.AudioContext || window.webkitAudioContext)()
let masterGain = audioEngine.createGain()
let compressor = audioEngine.createDynamicsCompressor()
let waveForm = 'sine', iter = 0
// CONTROLLERS
var haveEvents = 'GamepadEvent' in window
var haveWebkitEvents = 'WebKitGamepadEvent' in window
var controllers = {}
// movers
let movers = [], marks = [], pointIter = 0, clients = [], noteMax = 3
// ANIMATION
let newFrame = window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.requestAnimationFrame
// CANVAS Init
var myGameArea = {
canvas : document.getElementById('seq'),
start : function() {
this.context = this.canvas.getContext("2d")
this.interval = setInterval(updateGameArea, 20)
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
}
}
// ------ CONTROLLER PROCESS
// Controller initialisation
// also creates a new mover object
function controllerInit(event, connecting) {
var gamepad = event.gamepad
if (connecting) {
// adds controller to array
controllers[gamepad.index] = gamepad
// add prePress boolean to buttons
for (but in controllers[gamepad.index].buttons) {
controllers[gamepad.index].buttons[but].prePress = false
}
// adds new mover and marks object to array
movers[gamepad.index] = new Mover(myGameArea.context, 30, "red", 10, 120)
marks[gamepad.index] = new Mark(myGameArea.context, "red")
movers[gamepad.index].play()
console.log("gamepad " + gamepad.index + " is connected")
} else {
// removes mover assigned to gamepad
movers[gamepad.index].stop()
delete movers[gamepad.index]
// removes disconnected controller from array
delete controllers[gamepad.index]
console.log("gamepad " + gamepad.index + " has disconnected")
}
newFrame(updateStatus)
}
// Controller interaction updating
// Looping
function updateStatus() {
for (j in controllers) {
var controller = controllers[j]
// Button presses
if (controller.buttons[0].pressed) {
if (controller.buttons[0].prePress != controller.buttons[0].pressed) {
marks[controller.index].build(movers[controller.index].x, movers[controller.index].y)
}
controller.buttons[0].prePress = true
} else {
controller.buttons[0].prePress = false
}
movers[controller.index].speedX =+ applyDeadzone(controller.axes[0], 0.25) * 10
movers[controller.index].speedY =+ applyDeadzone(controller.axes[1], 0.25) * 10
movers[controller.index].radius += applyDeadzone(controller.axes[3], 0.25) * 10
}
newFrame(updateStatus)
}
if (haveEvents) {
window.addEventListener("gamepadconnected", function(e) { controllerInit(e, true) }, false)
window.addEventListener("gamepaddisconnected", function(e) { controllerInit(e, false) }, false)
} else if (haveWebkitEvents) {
window.addEventListener("webkitgamepadconnected", function(e) { controllerInit(e, true) }, false)
window.addEventListener("webkitgamepaddisconnected", function(e) { controllerInit(e, false) }, false)
}
var applyDeadzone = function(number, threshold){
percentage = (Math.abs(number) - threshold) / (1 - threshold);
if(percentage < 0)
percentage = 0;
return percentage * (number > 0 ? 1 : -1);
}
// ------ GAME PROCESS
// creates the game area
function startGame() {
myGameArea.start()
}
// updates the movers in the gameArea
function updateGameArea() {
myGameArea.clear()
for (p in movers) {
movers[p].move()
movers[p].update()
}
for (m in marks) {
marks[m].draw()
marks[m].update()
}
}
// ------ ON WINDOW LOAD
window.onload = function() {
// AUDIO
compressor.threshold.value = -50
compressor.knee.value = 40
compressor.ratio.value = 12
compressor.attack.value = 0.1
compressor.release.value = 0.25
compressor.connect(masterGain)
masterGain.connect(audioEngine.destination)
masterGain.gain.value = 0.5
startGame()
}

+ 91
- 0
nodeJS/controllerTest/public/js/marks.js View File

@ -0,0 +1,91 @@
class Mark {
constructor(_ctx, _color) {
this.context = _ctx
this.color = _color
this.points = []
this.targets = []
this.pointIter = 0
this.markMax = 3
this.distance = (a, b) => {
const dx = a.x - b.x
const dy = a.y - b.y
return { dist: Math.hypot(dx, dy), x: dx, y: dy }
}
}
build(_x, _y) {
let index = null, builder = true
if (this.points.length <= 0) {
this.points.push({ x: _x, y: _y })
this.targets.push({ x: _x, y: _y })
index = 0
} else {
for (p in this.points) {
if (this.distance({ x: _x, y: _y }, this.points[p]).dist < 20 ) {
builder = false
this.points.splice(p, 1)
this.targets.splice(p, 1)
index = m
}
}
if (builder) {
if (this.points.length < this.markMax){
this.points.push({ x: _x, y: _y })
this.targets.push({ x: _x, y: _y })
index = this.points.length-1
} else {
index = this.pointIter % this.markMax
if (this.points[index] != this.targets[index]) {
this.targets[index] = {x: _x, y: _y}
}
// this.points[index].x = _x
// this.points[index].y = _y
this.pointIter++
}
}
}
}
draw() {
for (p in this.points) {
this.context.fillStyle = 'black'
this.context.fillRect(this.points[p].x - 2, this.points[p].y - 2, 4, 4)
}
if (this.points.length > 1) {
this.context.beginPath()
for (p in this.points) {
if (p == 0){
this.context.lineTo(this.points[p].x, this.points[p].y)
} else {
this.context.lineTo(this.points[p].x, this.points[p].y)
}
}
this.context.closePath()
this.context.stroke()
}
this.context.save()
}
update() {
if (this.targets.length > 0){
for (let t in this.targets) {
var dist = this.distance(this.targets[t], this.points[t])
var easing = 0.05
if(Math.abs(dist.x) > 1) {
this.points[t].x += dist.x * easing
}
// calculate the new ypos value
if(Math.abs(dist.y) > 1) {
this.points[t].y += dist.y * easing
}
}
}
}
}

+ 102
- 0
nodeJS/controllerTest/public/js/mover.js View File

@ -0,0 +1,102 @@
class Mover {
constructor(_ctx, _r, _c, _x, _y) {
// GRAPHIC CONSTRUCT
this.radius = _r
this.color = _c
this.context = _ctx
this.speedX = 0
this.speedY = 0
this.x = _x
this.y = _y
// AUDIO CONSTRUCT
this.startTime = audioEngine.currentTime
this.g = audioEngine.createGain()
this.v = audioEngine.createOscillator()
this.p = audioEngine.createStereoPanner()
this.g.connect(this.p)
this.p.connect(compressor)
this.p.pan.value = (this.x / (this.context.canvas.clientWidth)) - 1
this.g.gain.value = 0.5
this.voices = ['sine', 'sawtooth', 'triangle', 'square']
this.v.select = 0
this.v.type = this.voices[this.v.select % 4]
this.v.connect(this.g)
this.v.start()
}
static distance(a, b) {
const dx = a.x - b.x
const dy = a.y - b.y
return Math.hypot(dx, dy)
}
update() {
// this.v.type = this.voices[this.v.select % 4]
this.context.fillStyle = this.color
this.shape(Math.abs(this.radius), this.x, this.y)
this.v.frequency.value = this.context.canvas.clientHeight - this.y
this.p.pan.value = (this.x / (this.context.canvas.clientWidth)) - 1
}
move() {
this.x += this.speedX
this.y += this.speedY
if (this.x > this.context.canvas.width + this.radius) {
this.x = 0 - this.radius
} else if (this.x < 0 - this.radius) {
this.x = this.context.canvas.clientWidth + this.radius
}
if (this.y > this.context.canvas.height + this.radius) {
this.y = 0 - this.radius
} else if (this.y < 0 - this.radius) {
this.y = this.context.canvas.clientHeight + this.radius
}
}
shape() {
this.context.fillStyle = this.color
this.context.fillRect(this.x - 2, this.y - 2, 4, 4)
}
play(_a, _d, _sv) {
_a = typeof amount === 'number' ? amount * 1000 : 0.15
_d = typeof amount === 'number' ? amount * 1000 : 0.5
_sv = typeof amount === 'number' ? amount : 0.4
// clear preScheduled events
this.g.gain.cancelScheduledValues(this.startTime)
// initial value
this.g.gain.setValueAtTime(0.001, this.startTime)
// attack
this.g.gain.setTargetAtTime(0.99, this.startTime, _a)
// decay
this.g.gain.setTargetAtTime(_sv, this.startTime + _a, _d)
}
endNote(_r) {
_r = typeof amount === 'number' ? amount * 1000 : 0.2
// sustain and release
this.g.gain.setTargetAtTime(0.0, audioEngine.currentTime, _r)
}
stop(_r) {
_r = typeof amount === 'number' ? amount * 1000 : 0.2
// sustain and release
this.g.gain.setTargetAtTime(0.0, audioEngine.currentTime, _r)
setTimeout( () => {
this.v.stop()
this.p.disconnect()
this.g.disconnect()
}, (_r + 3) * 1000)
}
}

nodeJS/etherSeq/public/styles/style.css → nodeJS/controllerTest/public/styles/style.css View File


+ 68
- 0
nodeJS/controllerTest/test.js View File

@ -0,0 +1,68 @@
// GLOBAL VARS
const port = 3000
const clients = {}
// WEB SETUP
let express = require('express')
let app = express()
let server = app.listen(process.env.PORT || port, listen)
// feedback to show server running
function listen() {
let host = server.address().address
let port = server.address().port
console.log('\nserving from http://' + host + ':' + port + '\n')
}
app.use(express.static('public'))
// SOCKETS SETUP
let io = require('socket.io')(server)
io.sockets.on('connection', newConnection)
// CLIENT CONNECTION
function newConnection(socket) {
console.log(socket.id + ' connected')
io.sockets.connected[socket.id].emit('noteArrays', clients)
clients[socket.id] = {color: 'rgb( ' + parseInt(Math.random() * 255) + ', ' + parseInt(Math.random() * 255) + ', ' + parseInt(Math.random() * 255) + ')', points: []}
// console.log(clients)
socket.broadcast.emit('newClient', {id: socket.id, points: clients[socket.id] })
// CLIENT DISCONNECTED
socket.on('disconnect', () => {
console.log(socket.id + ' disconnected.')
delete clients[socket.id]
io.sockets.emit('disClient', {id : socket.id})
})
// POINTS UPDATE (per id)
socket.on('newNote', (data) => {
data = {
id: socket.id,
index: data.index,
mousePos: data.mousePos,
waveForm: data.waveForm,
color: clients[socket.id].color,
action: data.action
}
if (data.action) {
clients[socket.id].points[data.index] = data.mousePos
} else {
clients[socket.id].points.splice(data.index, 1)
}
socket.broadcast.emit('pointUpdate', data)
})
// CLEAR NOTES (per id)
socket.on('clearNotes', () => {
for (var i = clients[socket.id].points.length - 1; i >= 0; i--) {
clients[socket.id].points.splice(i, 1)
}
socket.broadcast.emit('clearPoints', socket.id)
})
}

+ 0
- 196
nodeJS/etherSeq/public/js/canvas01.js View File

@ -1,196 +0,0 @@
//
// Experimentation with HTML5 canvas as a noteboard of sorts.
// Playing with turning on and off notes over X/Y coords affecting freq and pan
//
// SOCKETS
const socket = io.connect('http://localhost:3000')
console.log(socket)
// AUDIO ENGINE
const audioEngine = new (window.AudioContext || window.webkitAudioContext)()
const masterGain = audioEngine.createGain()
const compressor = audioEngine.createDynamicsCompressor();
// CANVAS and POINTS
const canvas = document.getElementById('seq'), context = canvas.getContext('2d')
const clearButton = document.querySelector('button[name="clear"]')
let point = [], pointIter = 0
socket.on('sendNote', hello)
function hello(data) {
console.log('hello')
console.log(data)
pointDraw(data[1].x, data[1].y, '#00FF00')
}
// On windown load
window.onload = function() {
console.log('initiate voices etc.')
compressor.threshold.value = -50;
compressor.knee.value = 40;
compressor.ratio.value = 12;
compressor.attack.value = 0.1;
compressor.release.value = 0.25;
compressor.connect(masterGain)
masterGain.connect(audioEngine.destination)
masterGain.gain.value = 0.5
window.requestAnimationFrame(animate)
canvas.addEventListener("mousedown", (evt) => {
let mousePos = getMousePos(canvas, evt)
pointDraw(mousePos, '#FF0000')
}, false)
clearButton.addEventListener("click", (evt) => {
for (var i = point.length - 1; i >= 0; i--) {
point[i].stop()
point.splice(i,1)
}
}, false)
}
function pointDraw(_mousePos, _colour) {
if (point.length <= 0) {
// Create and play voice class
point.push(new PointGen(_mousePos.x, _mousePos.y,_colour))
point[0].play()
// Socket.io send note data
socket.emit('sendNote', [0, point[0] ])
} else {
let builder = true
for (let p in point) {
if (PointGen.distance(_mousePos, point[p]) < 20 ) {
builder = false
point[p].stop()
point.splice(p, 1)
socket.emit('stopNote')
}
}
if (builder) {
if (point.length < 5){
point.push(new PointGen(_mousePos.x, _mousePos.y,_colour))
point[point.length - 1].play()
// Socket.io send note data
socket.emit('sendNote', [point.length - 1, point[point.length - 1] ])
} else {
point[pointIter % 5].update(_mousePos.x, _mousePos.y)
pointIter++
// Socket.io send note data
socket.emit('sendNote', [pointIter % 5, point[pointIter % 5] ])
}
}
}
}
// Animation Loop
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height)
context.save()
if (point.length > 0) {
for (let p in point) {
point[p].draw()
}
}
window.requestAnimationFrame(animate)
}
// Mouse position on canvas
function getMousePos(canvas, evt) {
let rect = canvas.getBoundingClientRect()
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
}
}
// Point generator class
class PointGen {
constructor(_x, _y, _hex) {
// variables
this.x = _x
this.y = _y
this.colour = _hex
this.wave = 'sine'
this.frequency = (canvas.height + 30) - this.y
this.pan = (this.x / canvas.width) - 1
this.gain = 0.0
this.startTime = audioEngine.currentTime
// initialisers
this.g = audioEngine.createGain()
this.v = audioEngine.createOscillator()
this.p = audioEngine.createStereoPanner();
// settings
this.p.pan.value = this.pan
this.g.gain.value = this.gain
this.v.type = this.wave
this.v.frequency.setValueAtTime(this.frequency, audioEngine.currentTime)
// audio connections
this.g.connect(this.p)
this.p.connect(compressor)
this.v.connect(this.g)
this.v.start()
}
static distance(a, b) {
const dx = a.x - b.x
const dy = a.y - b.y
return Math.hypot(dx, dy)
}
draw() {
context.fillStyle = this.colour
context.fillRect(this.x - 10, this.y - 10, 20, 20)
context.save()
}
update(_xNew, _yNew) {
this.x = _xNew
this.y = _yNew
this.v.frequency.exponentialRampToValueAtTime((canvas.height + 30) - this.y, audioEngine.currentTime + 0.2)
this.p.pan.value = (this.x / (canvas.width)) - 1
}
play(_a, _d, _sv) {
_a = typeof amount === 'number' ? amount * 1000 : 0.15
_d = typeof amount === 'number' ? amount * 1000 : 0.5
_sv = typeof amount === 'number' ? amount : 0.4
// clear preScheduled events
this.g.gain.cancelScheduledValues(this.startTime + 0.0)
// initial value
this.g.gain.setValueAtTime(0.0, this.startTime)
// attack
this.g.gain.setTargetAtTime(0.99, this.startTime, _a)
// decay
this.g.gain.setTargetAtTime(_sv, this.startTime + _a, _d)
}
stop(_r) {
_r = typeof amount === 'number' ? amount * 1000 : 0.2
// sustain and release
this.g.gain.setTargetAtTime(0.0, audioEngine.currentTime, _r)
setTimeout( () => {
this.v.stop()
this.p.disconnect()
this.g.disconnect()
}, (_r + 3) * 1000)
}
}

+ 0
- 32
nodeJS/etherSeq/test.js View File

@ -1,32 +0,0 @@
// GLOBAL VARS
const port = 3000;
// FILE SYSTEM REQUIRES
const fs = require("fs")
const express = require('express')
const app = express()
const server = app.listen(port)
const socket = require('socket.io')
const io = socket(server)
// WEB SETUP
app.use(express.static('public'))
console.log("Server running on port " + port)
io.sockets.on('connection', newConnection);
function newConnection(socket) {
console.log("connection : " + socket.id)
socket.on('sendNote', (data) => {
console.log(data)
socket.broadcast.emit('sendNote', data)
})
socket.on('stopNote', () => {
console.log('stopNote')
})
}

+ 0
- 0
nodeJS/polyPlayer/index.js View File


+ 652
- 0
nodeJS/polyPlayer/package-lock.json View File

@ -0,0 +1,652 @@
{
"name": "clientTest",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
"requires": {
"mime-types": "2.1.18",
"negotiator": "0.6.1"
}
},
"after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
},
"base64id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
},
"better-assert": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"requires": {
"callsite": "1.0.0"
}
},
"blob": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
"integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "1.0.4",
"debug": "2.6.9",
"depd": "1.1.2",
"http-errors": "1.6.3",
"iconv-lite": "0.4.19",
"on-finished": "2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.16"
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"engine.io": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz",
"integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==",
"requires": {
"accepts": "1.3.5",
"base64id": "1.0.0",
"cookie": "0.3.1",
"debug": "3.1.0",
"engine.io-parser": "2.1.2",
"ws": "3.3.3"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"engine.io-client": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
"requires": {
"component-emitter": "1.2.1",
"component-inherit": "0.0.3",
"debug": "3.1.0",
"engine.io-parser": "2.1.2",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "3.3.3",
"xmlhttprequest-ssl": "1.5.5",
"yeast": "0.1.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"engine.io-parser": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz",
"integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "0.0.7",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.4",
"has-binary2": "1.0.2"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.3",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
"integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
"requires": {
"accepts": "1.3.5",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.2",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",