182 lines
4.9 KiB
HTML
182 lines
4.9 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
|
|
Brickworks
|
|
|
|
Copyright (C) 2022, 2023 Orastron Srl unipersonale
|
|
|
|
Brickworks is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
Brickworks is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Brickworks. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
File author: Stefano D'Angelo
|
|
|
|
-->
|
|
<html>
|
|
<head>
|
|
<title>Brickworks web synth example</title>
|
|
<script src="config.js"></script>
|
|
<script>
|
|
var audioCtx;
|
|
var midi;
|
|
|
|
var Synth = {
|
|
node: null,
|
|
moduleAdded: false,
|
|
wasmBytes: null,
|
|
|
|
init: async function () {
|
|
if (!this.moduleAdded) {
|
|
await audioCtx.audioWorklet.addModule("processor.js");
|
|
this.moduleAdded = true;
|
|
}
|
|
|
|
if (!this.wasmBytes)
|
|
this.wasmBytes = await fetch("module.wasm")
|
|
.then((response) => response.arrayBuffer())
|
|
.then((bytes) => bytes);
|
|
if (!this.wasmBytes.byteLength) {
|
|
this.wasmBytes = null;
|
|
throw "could not fetch WebAssembly module";
|
|
}
|
|
|
|
if (!this.node)
|
|
this.node = new AudioWorkletNode(audioCtx, "BWExample",
|
|
{
|
|
numberOfInputs: buses.filter(function (b) { return !b.output; }).length,
|
|
numberOfOutputs: buses.filter(function (b) { return b.output; }).length,
|
|
outputChannelCount: buses.filter(function (b) { return b.output}).map(function (b) { return b.stereo ? 2 : 1 }),
|
|
processorOptions: { wasmBytes: this.wasmBytes }
|
|
});
|
|
this.node.connect(audioCtx.destination);
|
|
},
|
|
|
|
noteOn: function (note, velocity) {
|
|
this.node.port.postMessage({ type: "noteOn", note: note, velocity: velocity });
|
|
},
|
|
|
|
noteOff: function (note) {
|
|
this.node.port.postMessage({ type: "noteOff", note: note });
|
|
},
|
|
|
|
pitchBend: function (bend) {
|
|
this.node.port.postMessage({ type: "pitchBend", pitchBend: bend });
|
|
},
|
|
|
|
modWheel: function (wheel) {
|
|
this.node.port.postMessage({ type: "modWheel", modWheel: wheel });
|
|
}
|
|
};
|
|
|
|
var initState = 0; // 0 = not inited, 1 = in progress, 2 = inited
|
|
|
|
window.addEventListener("load", async function (e) {
|
|
var start = document.getElementById("start");
|
|
var starting = document.getElementById("starting");
|
|
var main = document.getElementById("main");
|
|
var controls = document.getElementById("controls");
|
|
|
|
if (!navigator.requestMIDIAccess) {
|
|
alert("This won't work. Your browser doesn't support the Web MIDI API.");
|
|
return;
|
|
}
|
|
|
|
for (var i = 0; i < parameters.length; i++) {
|
|
var div = document.createElement("div");
|
|
controls.appendChild(div);
|
|
|
|
var label = document.createElement("label");
|
|
label.setAttribute("for", "p" + i);
|
|
label.innerText = parameters[i].name;
|
|
div.appendChild(label);
|
|
|
|
var range = document.createElement("input");
|
|
range.setAttribute("type", "range");
|
|
range.setAttribute("id", "p" + i);
|
|
range.setAttribute("name", "p" + i);
|
|
range.setAttribute("min", "0");
|
|
range.setAttribute("max", "1");
|
|
if (!parameters[i].step)
|
|
range.setAttribute("step", "any");
|
|
else
|
|
range.setAttribute("step", 1 / parameters[i].step);
|
|
range.value = parameters[i].defaultValue;
|
|
if (parameters[i].output)
|
|
range.setAttribute("readonly", "true");
|
|
else {
|
|
let index = i;
|
|
range.addEventListener("input", function (e) {
|
|
var p = Synth.node.parameters.get(parameters[index].name);
|
|
p.setValueAtTime(e.target.value, 0);
|
|
});
|
|
}
|
|
div.appendChild(range);
|
|
}
|
|
|
|
start.addEventListener("click", async function () {
|
|
initState = 1;
|
|
start.disabled = true;
|
|
starting.hidden = false;
|
|
|
|
try {
|
|
if (!audioCtx)
|
|
audioCtx = new AudioContext();
|
|
midi = await navigator.requestMIDIAccess();
|
|
await Synth.init();
|
|
|
|
Synth.node.port.onmessage = function (e) { document.getElementById("p" + e.data.index).value = e.data.value; };
|
|
|
|
function onMIDIMessage(e) {
|
|
switch (e.data[0] & 0xf0) {
|
|
case 0x90:
|
|
Synth.noteOn(e.data[1], e.data[2]);
|
|
break;
|
|
case 0x80:
|
|
Synth.noteOff(e.data[1]);
|
|
break;
|
|
case 0xe0:
|
|
Synth.pitchBend(e.data[2] << 7 | e.data[1]);
|
|
break;
|
|
case 0xb0:
|
|
if (e.data[1] == 1)
|
|
Synth.modWheel(e.data[2]);
|
|
break;
|
|
}
|
|
}
|
|
midi.inputs.forEach((entry) => { entry.onmidimessage = onMIDIMessage; });
|
|
|
|
initState = 2;
|
|
start.hidden = true;
|
|
starting.hidden = true;
|
|
main.hidden = false;
|
|
} catch (err) {
|
|
alert("Colud not initialize: " + err);
|
|
|
|
initState = 0;
|
|
start.disabled = false;
|
|
starting.hidden = true;
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<h1>Brickworks web synth example</h1>
|
|
<input id="start" type="button" value="Start">
|
|
<p id="starting" hidden>Starting...</p>
|
|
<div id="main" hidden>
|
|
<p>Just play notes on your MIDI device.</p>
|
|
<div id="controls">
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|