Published
Edited
Feb 17, 2022
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
record = app.querySelector(".record")
Insert cell
stop = app.querySelector(".stop")
Insert cell
soundClips = app.querySelector(".sound-clips")
Insert cell
canvas = app.querySelector(".visualizer")
Insert cell
mainSection = {
const main = document.querySelector(".main-controls");
main.onresize = () => (canvas.width = main.offsetWidth);
main.onresize();
return main;
}
Insert cell
mutable debug = ""
Insert cell
mainBlock = {
if (navigator.mediaDevices.getUserMedia) {
const constraints = { audio: true };
let chunks = [];

let onSuccess = function (stream) {
const mediaRecorder = new MediaRecorder(stream);

visualize(stream, mediaRecorder);

record.onclick = function () {
mediaRecorder.start();
record.style.background = "red";

stop.disabled = false;
record.disabled = true;
mutable debug = [];
};

stop.onclick = function () {
mediaRecorder.stop();
record.style.background = "";
record.style.color = "";

stop.disabled = true;
record.disabled = false;
};

mediaRecorder.onstop = function (e) {
const clipName = "My Unnamed clip";

const clipContainer = htl.html`<article class="clip">`;
const clipLabel = htl.html`<input type=text value=${clipName} >`;
const audio = htl.html`<audio controls="">`;
const saveButton = htl.html`<button class="save">Save`;
const deleteButton = htl.html`<button class="delete">Delete`;

clipContainer.append(audio, clipLabel, deleteButton, saveButton);
soundClips.append(clipContainer);

audio.controls = true;
const blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
chunks = [];
const audioURL = URL.createObjectURL(blob);
audio.src = audioURL;

saveButton.onclick = function (e) {
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = `${clipLabel.value}.ogg`;
link.click();
document.removeChild(link);
};

deleteButton.onclick = function (e) {
let evtTgt = e.target;
evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
};
};

mediaRecorder.ondataavailable = function (e) {
chunks.push(e.data);
mutable debug.push(e);
};
};

let onError = function (err) {
console.log("The following error occured: " + err);
};

navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
} else {
throw "getUserMedia not supported on your browser!";
}

const audioCtx = new AudioContext();
const canvasCtx = canvas.getContext("2d");

let animationFrameId = null;
invalidation.then(() => {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
});

function visualize(stream, recorder) {
const source = audioCtx.createMediaStreamSource(stream);

const analyser = audioCtx.createAnalyser();
analyser.fftSize = 2048;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);

source.connect(analyser);
//analyser.connect(audioCtx.destination);

const silenceDetect = document.querySelector("#silencedetect");
let silenceCount = 0;
draw();

function draw() {
const WIDTH = canvas.width;
const HEIGHT = canvas.height;

animationFrameId = requestAnimationFrame(draw);

analyser.getByteTimeDomainData(dataArray);

canvasCtx.fillStyle = "rgb(200, 200, 200)";
canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

canvasCtx.lineWidth = 2;
canvasCtx.strokeStyle = "rgb(0, 0, 0)";

canvasCtx.beginPath();

let sliceWidth = (WIDTH * 1.0) / bufferLength;
let x = 0;
let silence = true;
for (let i = 0; i < bufferLength; i++) {
let v = dataArray[i] / 128.0;
if (Math.abs(v - 1) > 0.01) silence = false;
let y = (v * HEIGHT) / 2;

if (i === 0) {
canvasCtx.moveTo(x, y);
} else {
canvasCtx.lineTo(x, y);
}

x += sliceWidth;
}

canvasCtx.lineTo(canvas.width, canvas.height / 2);
canvasCtx.stroke();
if (silenceDetect.checked) {
if (silence) silenceCount++;
else silenceCount = 0;
if (silenceCount > 60) {
// Half a second
if (recorder.state == "recording") recorder.pause();
} else {
if (recorder.state == "paused") recorder.resume();
}
canvasCtx.fillStyle = "red";
canvasCtx.fillText(
(silence ? "silence " : "") + recorder.state,
10,
20
);
} else {
if (recorder.state == "paused") recorder.resume();
silenceCount = 0;
}
}
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more