diff --git a/server/assets/js/audio.js b/server/assets/js/audio.js
new file mode 120000
index 0000000..f939c3f
--- /dev/null
+++ b/server/assets/js/audio.js
@@ -0,0 +1 @@
+../../../static/js/audio.js
\ No newline at end of file
diff --git a/static/index.html b/static/index.html
index 90ed225..3d03203 100755
--- a/static/index.html
+++ b/static/index.html
@@ -57,11 +57,13 @@
+
+
@@ -167,7 +170,7 @@
var code, canvas, gl, buffer, currentProgram, vertexPosition, screenVertexPosition, panButton,
parameters = { startTime: Date.now(), time: 0, mouseX: 0.5, mouseY: 0.5, screenWidth: 0, screenHeight: 0 },
surface = { centerX: 0, centerY: 0, width: 1, height: 1, isPanning: false, isZooming: false, lastX: 0, lastY: 0 },
- frontTarget, backTarget, screenProgram, getWebGL, resizer = {}, compileOnChangeCode = true;
+ frontTarget, backTarget, screenProgram, getWebGL, resizer = {}, compileOnChangeCode = true, audio;
init();
if (gl) { animate(); }
@@ -464,6 +467,8 @@
compileScreenProgram();
+ audio = new Audio();
+
}
function isCodeVisible() {
@@ -615,6 +620,7 @@
// Cache uniforms
+ cacheUniformLocation( program, 'audio' );
cacheUniformLocation( program, 'time' );
cacheUniformLocation( program, 'mouse' );
cacheUniformLocation( program, 'resolution' );
@@ -873,11 +879,13 @@
if ( !currentProgram ) return;
parameters.time = Date.now() - parameters.startTime;
+ audio.tick();
// Set uniforms for custom shader
gl.useProgram( currentProgram );
+ gl.uniform3f( currentProgram.uniformsCache[ 'audio' ], audio.fft[0], audio.fft[1], audio.fft[2]);
gl.uniform1f( currentProgram.uniformsCache[ 'time' ], parameters.time / 1000 );
gl.uniform2f( currentProgram.uniformsCache[ 'mouse' ], parameters.mouseX, parameters.mouseY );
gl.uniform2f( currentProgram.uniformsCache[ 'resolution' ], parameters.screenWidth, parameters.screenHeight );
diff --git a/static/js/audio.js b/static/js/audio.js
new file mode 100644
index 0000000..1f5f2e9
--- /dev/null
+++ b/static/js/audio.js
@@ -0,0 +1,51 @@
+'use strict';
+
+function Audio(numBins, cutoff, smooth, scale) {
+
+ numBins = numBins || 3;
+ smooth = smooth || 0.4;
+
+ function tick() {
+ if (this.meyda) {
+ var features = this.meyda.get()
+ if (features) {
+ var reducer = (accumulator, currentValue) => accumulator + currentValue;
+
+ var spacing = Math.floor(features.loudness.specific.length / this.bins.length);
+ this.prevBins = this.bins.slice(0);
+
+ this.bins = this.bins.map((bin, index) =>
+ features.loudness.specific.slice(index * spacing, (index + 1) * spacing).reduce(reducer) / spacing
+ ).map((bin, index) =>
+ bin * (1.0 - smooth) + this.prevBins[index] * smooth);
+
+ this.fft = this.bins;
+ }
+ }
+ }
+
+ function init() {
+ this.bins = Array(numBins).fill(0)
+ this.prevBins = Array(numBins).fill(0)
+ this.fft = Array(numBins).fill(0)
+
+ window.navigator.mediaDevices.getUserMedia({ video: false, audio: true })
+ .then((stream) => {
+ var context = new AudioContext()
+ var audio_stream = context.createMediaStreamSource(stream)
+
+ this.meyda = Meyda.createMeydaAnalyzer({
+ audioContext: context,
+ source: audio_stream,
+ featureExtractors: [
+ 'loudness',
+ ]
+ })
+ })
+ .catch((err) => console.log('ERROR', err))
+
+ return this;
+ }
+
+ return { init: init, tick: tick }.init();
+}
diff --git a/static/js/helpers.js b/static/js/helpers.js
index 6987ca8..72b8e86 100755
--- a/static/js/helpers.js
+++ b/static/js/helpers.js
@@ -29,7 +29,7 @@ function load_url_code() {
} else {
- readURL( '5d00000100b70200000000000000381c88cdaf8125d4569ed1e6e6c09c2fe72b7d489ad9d27ce026c1d90b38e6a986e7c482f98001c7d016ca8db7da32debe67fc602659f4e96ae150d75ea26ae8e8f4056e0b845d0814a2acee3a47ec45af66fb0405385eaedd50db968497c1cbbd79f0634d5534182b2093986dae5ac7e840eb137f39f5b27efbb488f4e85faa6f4c942182673e75dca44f7ffbd8c25c5a2763cb750b9b4e14b9fd5c15ca81ed7ef88a4f77a114cd2d7f675b6a05b467bd164f4058dd3250e6fcdc9d7c195dccdc63b304e1f8c7aaccb1edb7992aa1341e96aa6e8b1ca044e70207be752de1b41e4e07843ab895b2a1995b97085afff70f5eff9d2b630a4c5e43e7ce6f977616d57c97935342e48d0ee9ad3462804ae5608b6872b9749632bf8514fea3ebf9d64b10deb3ff041395050deffbf038e3' );
+ readURL( '5d00000100d60200000000000000381c88cdaf8125d4569ed1e6e6c09c2fe72b7d489ad9d27ce026c1d90b38e6a986e7c482f98001c7d016ca8db7da32debe67fc602659f4e96ae150d75ea26ae8e8f4056e0b845d0814a2acee3a47ec45af66fb0405385eaedd50db96849576df40f68ac1f04d2242410844cf7b7c883d2803f15cf0f6b33dce2666bae51a560d4083e7e96b057f5ac52018a3be3c75cb4128cc380d70aaba02275face760062222cd7c0c2cda05d4181f5f99ed9f060acab16c128965b3685f12c10b889dd4d361cd6a4bfc05bcb7c0c89619d4326efb5ab2c4b2aa6d0cc1922e28225e5026ca4268450a870271c6ec94f151d07030db4ec02909f1b3af98175767eacfd7a8b503b714c3d588172612cee547ee15a963020fe5cb3e45cb542b746e27691006d0806d71ec67db2042c197abd6c02127e0cb973d8cd28b0282dbfffa91c4e0' );
}
}