gibberwocky
Version:
music sequencing for Live and Max/MSP
295 lines (227 loc) • 7.13 kB
HTML
<html>
<head>
<style>
html, body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
color:#000;
font-size: 10;
overflow:auto;
font-family: monospace;
}
.post {
white-space: -moz-pre-wrap; /* Firefox 1.0-2.0 */
white-space: pre-wrap; /* current browsers */
}
</style>
</head>
<body>
<b id="play"></b>
<b id="bpm"></b> bpm
<b id="signature"></b>
<b id="bar"></b>
<b id="beat"></b>
<b id="connection"></b>
<div id="send"></div>
<div id="post"></div>
<script>
///// utils /////
// get url args:
var querystring = (function() {
var qstr = window.location.search;
var query = {};
var a = qstr.substr(1).split('&');
for (var i = 0; i < a.length; i++) {
var b = a[i].split('=');
query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
}
return query;
})();
// debug messaging:
function post(msg) {
document.getElementById("post").innerHTML += msg + "<br>";
//console.log(msg);
}
// randoms
function random(n) {
return Math.floor(Math.random()*n);
}
function pick(arr) {
return arr[random(arr.length)];
}
///// websocket /////
var wsocket;
var connected = false;
var connectTask;
var track = querystring.track || 0;
function ws_connect() {
if (connected) {
if (connectTask != undefined) {
clearInterval(connectTask);
connectTask = undefined;
}
}
if ('WebSocket' in window) {
var host = querystring.host || "localhost";
var port = querystring.port || "8081";
var address = "ws://" + host + ":" + port;
document.getElementById("connection").innerHTML = 'connecting to ' + address;
wsocket = new WebSocket(address);
wsocket.onopen = function(ev) {
document.getElementById("connection").innerHTML = 'connected to ' + address;
connected = true;
// cancel the auto-reconnect task:
if (connectTask != undefined) clearInterval(connectTask);
connectTask = undefined;
// handshake
send("get_scene");
};
wsocket.onclose = function(ev) {
document.getElementById("connection").innerHTML = 'disconnected from ' + address;
connected = false;
// set up an auto-reconnect task:
if (connectTask != undefined) connectTask = setInterval(ws_connect, 4000);
};
wsocket.onmessage = function(ev) {
handlemessage(ev.data);
};
wsocket.onerror = function(ev) {
post("WebSocket error");
};
} else {
post("WebSockets are not available in this browser!!!");
}
}
function send(msg) {
if(wsocket != undefined) wsocket.send(msg);
document.getElementById("send").innerHTML = msg;
}
var lom = {};
var gens = [];
function handlemessage(msg) {
if (msg.charAt(0) == "{") {
lom = JSON.parse(msg);
post("received object");
console.log(lom);
// clear memory:
gens = [];
// set up the globals:
document.getElementById("bar").innerHTML = lom.bar;
document.getElementById("beat").innerHTML = lom.bit;
document.getElementById("signature").innerHTML = lom.sig;
document.getElementById("bpm").innerHTML = lom.bpm;
document.getElementById("play").innerHTML = lom.ply;
} else {
var parts = msg.split(" ");
var track = parts[0];
// or search for first device with midi_input == 1
// subsequent devices are effects
var device = pick(lom.tracks[track].devices);
var cmd = parts[1];
var arg = parts[2];
if (cmd == "seq") {
var beat = +arg;
// demo: generate notes etc.
var notes = [ 60, 62, 64, 65, 67, 71, 72 ];
var msgarr = [];
for (var j=0; j<2; j++) {
var divs = Math.pow(2, random((j+1)*2)+1);
var div = 1/divs;
var pitch = pick(notes);
var dur = 500*div;
for (var i=0; i<divs; i++) {
var phase = i*div;
var vel = 60 + random(30);
// this way works too:
//msgarr.push(track + " add " + beat + " " + phase + " note " + pitch + " " + vel + " " + dur);
msgarr.push(track + " add " + beat + " " + phase + " duration " + dur);
msgarr.push(track + " add " + beat + " " + phase + " velocity " + vel);
msgarr.push(track + " add " + beat + " " + phase + " pitch " + pitch);
}
}
var phase = 0;
// "set" a parameter:
var param = pick(device.parameters);
if (param.name != "Device On") {
var val;
if (param.quantized) {
val = param.min + random(param.max - param.min);
} else {
val = param.min + Math.random() * (param.max - param.min);
}
msgarr.push(track + " add " + beat + " " + phase + " zet " + param.id + " " + val );
//console.log(param.name, " ", val);
}
var param = pick(device.parameters);
if (param.name != "Device On") {
var val = Math.random();
msgarr.push(track + " add " + beat + " " + phase + " set " + param.id + " " + val );
//console.log(param.name, " ", val);
}
// mute / solo testing:
if (random(4) == 0) {
if (random(2)) {
msgarr.push(track + " add " + beat + " " + phase + " mute " + random(2));
} else {
msgarr.push(track + " add " + beat + " " + phase + " solo " + random(2));
}
}
// gen testing:
// unset?
if (random(16) < gens.length) {
var which = random(gens.length);
var id = gens[which];
gens.splice(which, 1);
msgarr.push(track + " add " + beat + " " + phase + " ungen " + id);
}
if (random(16) < gens.length && random(2) == 0) {
// set a parameter:
var which = random(gens.length);
var id = gens[which];
msgarr.push(track + " add " + beat + " " + phase + " genp " + id + " p0 " + random(4));
} else {
// add a new mapping:
var param = pick(device.parameters);
if (param.name != "Device On") {
var code = "Param p0(" + random(4) + ");";
code += "out1 = 1 - rate(in1, (p0+1)*" + (1/Math.pow(2, random(4))) + ");";
// wrap the code in quotes:
code = '"' + code + '"';
var msg = track + " add " + beat + " " + phase + " gen " + param.id + " " + code;
msgarr.push(msg);
//console.log (msg);
gens.push(param.id);
}
}
send(msgarr.join("~"));
} else if (cmd == "bar") {
var bar = +arg;
document.getElementById("bar").innerHTML = bar;
} else if (cmd == "bit") {
var beat = +arg;
document.getElementById("beat").innerHTML = beat;
} else if (cmd == "ply") {
var play = +arg;
document.getElementById("play").innerHTML = play;
} else if (cmd == "sig") {
var signature = arg;
document.getElementById("signature").innerHTML = signature;
} else if (cmd == "bpm") {
var bpm = +arg;
document.getElementById("bpm").innerHTML = bpm;
} else if (cmd == "err") {
post("received " + msg);
} else if (cmd == "clr") {
document.getElementById("post").innerHTML = "";
} else {
post("received " + msg);
}
}
}
///// start up /////
ws_connect();
</script>
</body>
</html>