Proof of concept with basic demo complete.
This commit is contained in:
parent
8ff106f1f5
commit
4dc5e64fa3
55
src/VisualizerCore.js
Normal file
55
src/VisualizerCore.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
export default function VisualizerCore(mediaSource, fftSize = 1024) {
|
||||||
|
this._stream = mediaSource;
|
||||||
|
this._analyzing = false;
|
||||||
|
this._updateListeners = [];
|
||||||
|
this._audioCtx = new window.AudioContext();
|
||||||
|
this._source = null; // Prepare for either a MediaStream or a MediaElement.
|
||||||
|
try {
|
||||||
|
this.source = this._audioCtx.createMediaStreamSource(this._stream);
|
||||||
|
} catch (e) {
|
||||||
|
this._source = this._audioCtx.createMediaElementSource(this._stream);
|
||||||
|
}
|
||||||
|
this._analyzer = this._audioCtx.createAnalyser();
|
||||||
|
this._analyzer.fftSize = fftSize;
|
||||||
|
this._source.connect(this._analyzer);
|
||||||
|
this._analyzer.connect(this._audioCtx.destination);
|
||||||
|
this._buffer = new Uint8Array(this._analyzer.frequencyBinCount);
|
||||||
|
|
||||||
|
this.lastUpdate = null;
|
||||||
|
|
||||||
|
this.analyze = function () {
|
||||||
|
if (this._analyzing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._analyzing = true;
|
||||||
|
requestAnimationFrame(this.update);
|
||||||
|
};
|
||||||
|
|
||||||
|
let _self = this;
|
||||||
|
this.update = function (timestamp) {
|
||||||
|
if (!_self._analyzing) return;
|
||||||
|
|
||||||
|
requestAnimationFrame(_self.update);
|
||||||
|
if (!_self.lastUpdate) {
|
||||||
|
_self.lastUpdate = timestamp;
|
||||||
|
}
|
||||||
|
let delta = timestamp - _self.lastUpdate;
|
||||||
|
_self._analyzer.getByteFrequencyData(_self._buffer);
|
||||||
|
|
||||||
|
_self._updateListeners.forEach(listener => {
|
||||||
|
listener(delta, _self._buffer);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
this.stop = function () {
|
||||||
|
this._analyzing = false;
|
||||||
|
};
|
||||||
|
this.addUpdateListener = function (listener) {
|
||||||
|
console.log("added listener.");
|
||||||
|
this._updateListeners.push(listener);
|
||||||
|
};
|
||||||
|
this.getNumberOfBins = function () {
|
||||||
|
return this._buffer.length;
|
||||||
|
};
|
||||||
|
}
|
1
src/audioshowkit.js
Normal file
1
src/audioshowkit.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
"use strict";
|
22
src/patterns/HorizontalBar.js
Normal file
22
src/patterns/HorizontalBar.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
export default function bindHorizontalBar(canvasElement, visualizerCore) {
|
||||||
|
let _width = canvasElement.width;
|
||||||
|
let _height = canvasElement.height;
|
||||||
|
let _canvasCtx = canvasElement.getContext("2d");
|
||||||
|
let _visualizerCore = visualizerCore;
|
||||||
|
let update = function (delta, bins) {
|
||||||
|
_canvasCtx.clearRect(0, 0, _width, _height); // clear canvas.
|
||||||
|
let barWidth = Math.floor(_width / bins.length) - 1; // -1 for 1 pixel gap between bars.
|
||||||
|
let barIndex = 0;
|
||||||
|
console.log("updating visuals.." + barWidth);
|
||||||
|
bins.forEach(bin => {
|
||||||
|
let normalBin = bin / 255.0;
|
||||||
|
_canvasCtx.fillStyle = "rgb(" + 0 + "," + bin + "," + bin + ")";
|
||||||
|
let barHeight = _height * normalBin;
|
||||||
|
_canvasCtx.fillRect(barIndex * barWidth, _height - barHeight, barWidth, barHeight);
|
||||||
|
barIndex += 1;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
_visualizerCore.addUpdateListener(update);
|
||||||
|
}
|
BIN
tests/Elektronomia - Collide.mp3
Normal file
BIN
tests/Elektronomia - Collide.mp3
Normal file
Binary file not shown.
17
tests/index.html
Normal file
17
tests/index.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||||
|
<title>AudioShowKit visual test</title>
|
||||||
|
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||||
|
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
|
||||||
|
<script defer type="module" src='script.js'></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button id="startbtn">Start.</button>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
0
tests/main.css
Normal file
0
tests/main.css
Normal file
24
tests/script.js
Normal file
24
tests/script.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import bindHorizontalBar from "../src/patterns/HorizontalBar.js";
|
||||||
|
import VisualizerCore from "../src/VisualizerCore.js";
|
||||||
|
|
||||||
|
// We will see if the visualizers core and event systems are working correctly.
|
||||||
|
let startBtn = document.getElementById("startbtn");
|
||||||
|
startBtn.addEventListener("click", async (ev) => {
|
||||||
|
let mediaStream = new Audio("../tests/Elektronomia - Collide.mp3");
|
||||||
|
mediaStream.addEventListener("canplaythrough", (ev) => {
|
||||||
|
let visCore = new VisualizerCore(mediaStream, 128);
|
||||||
|
let coreAndEventCanvas = document.createElement("canvas");
|
||||||
|
coreAndEventCanvas.width = 640;
|
||||||
|
coreAndEventCanvas.height = 200;
|
||||||
|
|
||||||
|
console.log("starting playthrough.");
|
||||||
|
mediaStream.play();
|
||||||
|
visCore.analyze();
|
||||||
|
document.body.appendChild(coreAndEventCanvas);
|
||||||
|
|
||||||
|
bindHorizontalBar(coreAndEventCanvas, visCore);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user