]> git.r.bdr.sh - rbdr/r.bdr.sh/blobdiff - jekyll/js/unlimited_pizza/pepperoni.js
Updates with spoken word entertainment
[rbdr/r.bdr.sh] / jekyll / js / unlimited_pizza / pepperoni.js
index d8742434015839e200d4dab56fa8d16dc6618a3a..c20f285e8ba85bf1bbf45ffa5898a973e4432a2d 100644 (file)
@@ -1,3 +1,5 @@
+'use strict';
+
 Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
   INNER_HTML : ' \
 <a class="record-button">&#11044</a> \
@@ -9,6 +11,13 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
     <a class="record-clear">X</a> \
   </div> \
   <audio class="record-preview" controls></audio> \
+  <div class="filter-switches"> \
+    <input class="filter-switch" name="bandpass-filter" type="checkbox" /> <label for="bandpass-filter">Band Pass</label> \
+    <input class="filter-switch" name="hipass-filter" type="checkbox" /> <label for="hipass-filter">Hi Pass</label> \
+    <input class="filter-switch" name="lopass-filter" type="checkbox" /> <label for="lopass-filter">Lo Pass</label> \
+    <input class="filter-switch" name="reverb-filter" type="checkbox" /> <label for="reverb-filter">Reverb</label> \
+    <input class="filter-switch" name="distort-filter" type="checkbox" /> <label for="distort-filter">Distort</label> \
+  </div> \
 </div> \
   ',
   PAUSE : '&#9616;&#9616;',
@@ -19,14 +28,65 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
     source : null,
     recorder : null,
     context : null,
+    _delayNode : null,
+    _bandPassFilterNode : null,
+    _hiPassFilterNode : null,
+    _loPassFilterNode : null,
+    _convolverNode : null,
+    _distortionNode : null,
+    _activatedNodes : null,
     workerPath : '/js/vendor/recorderjs/recorderWorker.js',
     init : function init(config) {
+      var channels, frameCount, reverbBuffer, request, requestHandler;
+
       Widget.prototype.init.call(this, config);
 
       if (!this.context) {
         this.context = new (window.AudioContext || window.webkitAudioContext)();
       }
 
+      this._delayNode = this.context.createDelay(1.0);
+      this._bandPassFilterNode = this.context.createBiquadFilter();
+      this._hiPassFilterNode = this.context.createBiquadFilter();
+      this._loPassFilterNode = this.context.createBiquadFilter();
+      this._convolverNode = this.context.createConvolver();
+      this._distortionNode = this.context.createWaveShaper();
+
+      this._distortionNode.curve = this._generateDistortion(400);
+      this._distortionNode.oversample = '4x';
+
+      this._activatedNodes = [];
+
+      // config lo pass
+      this._loPassFilterNode.type = "lowpass";
+      this._loPassFilterNode.frequency.value = 1000;
+      this._loPassFilterNode.gain.value = 25;
+
+      // config hi pass
+      this._hiPassFilterNode.type = "highpass";
+      this._hiPassFilterNode.frequency.value = 3000;
+      this._hiPassFilterNode.gain.value = 25;
+
+      // config band pass
+      this._bandPassFilterNode.type = "bandpass";
+      this._bandPassFilterNode.frequency.value = 2000;
+      this._bandPassFilterNode.gain.value = 25;
+
+      requestHandler = function bufferFile(ev) {
+        var request = ev.target;
+        console.log("Reverb loading");
+        this.context.decodeAudioData(request.response, function(buffer){ 
+          console.log("Reverb loaded");
+          this._convolverNode.buffer = buffer;
+        }.bind(this));
+      }.bind(this);
+
+      request = new XMLHttpRequest();
+      request.open('GET', '/reverb.ogg', true);
+      request.responseType = 'arraybuffer';
+      request.addEventListener('load', requestHandler, false);
+      request.send();
+
       if (!this.source) {
         this._getUserMedia({
           audio : true
@@ -40,6 +100,7 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
       this.audioElement = this.element.find('audio');
       this.progressBarContainer = this.element.find('.record-progress-bar-container');
       this.progressBar = this.element.find('.record-progress-bar');
+      this.switches = this.element.find('.filter-switch');
 
       this._bindEvents();
     },
@@ -91,6 +152,8 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
     },
 
     _bindEvents : function bindEvents() {
+      var pepperoni = this;
+
       this.controlButton.on('click', function () {
         if (this.recording) {
           this.stop();
@@ -104,6 +167,63 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
           this.clear();
         }
       }.bind(this))
+
+      this.switches.on('change', function (ev) {
+        if (!pepperoni.source) {
+          this.checked = false;
+          return false;
+        }
+        switch (this.name) {
+          case 'delay-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._delayNode);
+            } else {
+              pepperoni._removeNode(pepperoni._delayNode);
+            }
+            break;
+
+          case 'hipass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._hiPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._hiPassFilterNode);
+            }
+            break;
+
+          case 'bandpass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._bandPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._bandPassFilterNode);
+            }
+            break;
+
+          case 'lopass-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._loPassFilterNode);
+            } else {
+              pepperoni._removeNode(pepperoni._loPassFilterNode);
+            }
+            break;
+
+          case 'reverb-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._convolverNode);
+            } else {
+              pepperoni._removeNode(pepperoni._convolverNode);
+            }
+            break;
+
+          case 'distort-filter':
+            if (this.checked) {
+              pepperoni._addNode(pepperoni._distortionNode);
+            } else {
+              pepperoni._removeNode(pepperoni._distortionNode);
+            }
+
+            break;
+        }
+      });
     },
 
     _onRecording : function _onRecording(buffer) {
@@ -143,6 +263,72 @@ Class(UnlimitedPizza, "Pepperoni").inherits(Widget)({
       }.bind(this));
     },
 
+    _addNode : function _addNode(node) {
+      var i;
+
+      i = this._activatedNodes.length;
+
+      this._activatedNodes.push(node);
+
+      if (i === 0) {
+        this.source.disconnect();
+        this.source.connect(node);
+      } else {
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(node);
+      }
+
+      node.connect(this.recorder.node);
+      this.recorder.context = node.context;
+      this.recorder.node.connect(this.recorder.context.destination)
+
+      console.log("Adding: ", node);
+    },
+
+    _removeNode : function _removeNode(node) {
+      var i;
+
+      i = this._activatedNodes.indexOf(node);
+
+      node.disconnect();
+
+      if (i === 0 && i + 1 === this._activatedNodes.length) {
+        // It was the only one, connect source to recorder.
+        this.source.disconnect();
+        this.source.connect(this.recorder.node);
+      } else if (i === 0) {
+        // Normal 0 case, connect source to node. Recorder stays the same
+        this.source.disconnect();
+        this.source.connect(this._activatedNodes[i+1]);
+      } else if (i + 1 === this._activatedNodes.length) {
+        // It's not the 0 case, but we need to reconnect to recorder.
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(this.recorder.node);
+      } else {
+        // Normal case, connect previous node to node
+        this._activatedNodes[i - 1].disconnect();
+        this._activatedNodes[i - 1].connect(this._activatedNodes[i + 1]);
+      }
+
+      this._activatedNodes.splice(i, 1);
+
+      console.log("Removing: ", node);
+    },
+
+    _generateDistortion : function generateDistortion(amount) {
+      var k = typeof amount === 'number' ? amount : 50,
+        n_samples = 44100,
+        curve = new Float32Array(n_samples),
+        deg = Math.PI / 180,
+        i = 0,
+        x;
+      for ( ; i < n_samples; ++i ) {
+          x = i * 2 / n_samples - 1;
+          curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
+        }
+      return curve;
+    },
+
     // Normalize get user media
     _getUserMedia : (navigator.getUserMedia ||
                      navigator.webkitGetUserMedia ||