]>
git.r.bdr.sh - rbdr/r.bdr.sh/blob - jekyll/js/unlimited_pizza/pepperoni.js
3 Class(UnlimitedPizza
, "Pepperoni").inherits(Widget
)({
5 <a class="record-button">⬤</a> \
6 <div class="record-info"> \
7 <div class="record-progress"> \
8 <div class="record-progress-bar-container"> \
9 <div class="record-progress-bar"></div> \
11 <a class="record-clear">X</a> \
13 <audio class="record-preview" controls></audio> \
14 <div class="filter-switches"> \
15 <input class="filter-switch" name="bandpass-filter" type="checkbox" /> <label for="bandpass-filter">Band Pass</label> \
16 <input class="filter-switch" name="hipass-filter" type="checkbox" /> <label for="hipass-filter">Hi Pass</label> \
17 <input class="filter-switch" name="lopass-filter" type="checkbox" /> <label for="lopass-filter">Lo Pass</label> \
18 <input class="filter-switch" name="reverb-filter" type="checkbox" /> <label for="reverb-filter">Reverb</label> \
19 <input class="filter-switch" name="distort-filter" type="checkbox" /> <label for="distort-filter">Distort</label> \
23 PAUSE : '▐▐',
32 _bandPassFilterNode : null,
33 _hiPassFilterNode : null,
34 _loPassFilterNode : null,
35 _convolverNode : null,
36 _distortionNode : null,
37 _activatedNodes : null,
38 workerPath : '/js/vendor/recorderjs/recorderWorker.js',
39 init : function init(config
) {
40 var channels
, frameCount
, reverbBuffer
, request
, requestHandler
;
42 Widget
.prototype.init
.call(this, config
);
45 this.context
= new (window
.AudioContext
|| window
.webkitAudioContext
)();
48 this._delayNode
= this.context
.createDelay(1.0);
49 this._bandPassFilterNode
= this.context
.createBiquadFilter();
50 this._hiPassFilterNode
= this.context
.createBiquadFilter();
51 this._loPassFilterNode
= this.context
.createBiquadFilter();
52 this._convolverNode
= this.context
.createConvolver();
53 this._distortionNode
= this.context
.createWaveShaper();
55 this._distortionNode
.curve
= this._generateDistortion(400);
56 this._distortionNode
.oversample
= '4x';
58 this._activatedNodes
= [];
61 this._loPassFilterNode
.type
= "lowpass";
62 this._loPassFilterNode
.frequency
.value
= 1000;
63 this._loPassFilterNode
.gain
.value
= 25;
66 this._hiPassFilterNode
.type
= "highpass";
67 this._hiPassFilterNode
.frequency
.value
= 3000;
68 this._hiPassFilterNode
.gain
.value
= 25;
71 this._bandPassFilterNode
.type
= "bandpass";
72 this._bandPassFilterNode
.frequency
.value
= 2000;
73 this._bandPassFilterNode
.gain
.value
= 25;
75 requestHandler
= function bufferFile(ev
) {
76 var request
= event
.target
;
77 console
.log("Reverb loading");
78 this.context
.decodeAudioData(request
.response
, function(buffer
){
79 console
.log("Reverb loaded");
80 this._convolverNode
.buffer
= buffer
;
84 request
= new XMLHttpRequest();
85 request
.open('GET', '/reverb.aiff', true);
86 request
.responseType
= 'arraybuffer';
87 request
.addEventListener('load', requestHandler
, false);
93 }, this._onUserMedia
.bind(this), this._onUserMediaError
.bind(this))
96 this.element
.html(this.constructor.INNER_HTML
);
98 this.controlButton
= this.element
.find('.record-button');
99 this.clearButton
= this.element
.find('.record-clear');
100 this.audioElement
= this.element
.find('audio');
101 this.progressBarContainer
= this.element
.find('.record-progress-bar-container');
102 this.progressBar
= this.element
.find('.record-progress-bar');
103 this.switches
= this.element
.find('.filter-switch');
108 record : function record() {
109 if (this.recorder
&& !this.recording
) {
110 this._canRecord(function handleCanRecord(canRecord
) {
112 this.recording
= true;
113 this.controlButton
.addClass('recording')
114 this.controlButton
.html(this.constructor.PAUSE
);
115 this._interval
= setInterval(this._onRecordCheck
.bind(this), 100);
116 this.recorder
.record();
122 stop : function stop() {
123 if (this.recorder
&& this.recording
) {
124 this.recording
= false;
125 this.controlButton
.removeClass('recording')
126 this.controlButton
.html(this.constructor.RECORD
);
127 clearInterval(this._interval
);
128 this.recorder
.stop();
129 this.recorder
.exportWAV();
133 clear : function clear() {
135 this.progressBar
.width(0);
136 this.audioElement
.attr('src', '');
137 this.audioElement
[0].load();
138 this.recorder
.clear()
142 finalize : function finalize(callback
) {
144 this.recorder
.exportWAV(callback
);
148 getBuffer : function getBuffer(callback
) {
150 this.recorder
.getBuffer(callback
);
154 _bindEvents : function bindEvents() {
155 var pepperoni
= this;
157 this.controlButton
.on('click', function () {
158 if (this.recording
) {
165 this.clearButton
.on('click', function () {
166 if (!this.recording
) {
171 this.switches
.on('change', function (ev
) {
172 if (!pepperoni
.source
) {
173 this.checked
= false;
179 pepperoni
._addNode(pepperoni
._delayNode
);
181 pepperoni
._removeNode(pepperoni
._delayNode
);
185 case 'hipass-filter':
187 pepperoni
._addNode(pepperoni
._hiPassFilterNode
);
189 pepperoni
._removeNode(pepperoni
._hiPassFilterNode
);
193 case 'bandpass-filter':
195 pepperoni
._addNode(pepperoni
._bandPassFilterNode
);
197 pepperoni
._removeNode(pepperoni
._bandPassFilterNode
);
201 case 'lopass-filter':
203 pepperoni
._addNode(pepperoni
._loPassFilterNode
);
205 pepperoni
._removeNode(pepperoni
._loPassFilterNode
);
209 case 'reverb-filter':
211 pepperoni
._addNode(pepperoni
._convolverNode
);
213 pepperoni
._removeNode(pepperoni
._convolverNode
);
217 case 'distort-filter':
219 pepperoni
._addNode(pepperoni
._distortionNode
);
221 pepperoni
._removeNode(pepperoni
._distortionNode
);
229 _onRecording : function _onRecording(buffer
) {
230 this._buffer
= buffer
;
232 this.audioElement
.attr('src', URL
.createObjectURL(buffer
));
233 this.audioElement
[0].load();
236 _onUserMedia : function _onUserMedia(localMediaStream
) {
237 this.source
= this.context
.createMediaStreamSource(localMediaStream
);
238 this.recorder
= new Recorder(this.source
, {
239 workerPath : this.workerPath
,
240 callback : this._onRecording
.bind(this)
244 _onUserMediaError : function _onUserMediaError(error
) {
245 console
.log("Something went wrong", error
);
249 _onRecordCheck : function _onRecordCheck() {
250 this._canRecord(function (canRecord
, bufferSize
) {
251 var width
= bufferSize
* this.progressBarContainer
.width() / this.maxSize
;
252 this.progressBar
.width(width
);
259 _canRecord : function _canRecord(callback
) {
260 this.recorder
.getBuffer(function getBuffer(buffer
) {
261 var bufferSize
= buffer
[0].length
+ buffer
[1].length
;
262 callback
&& callback(bufferSize
<= this.maxSize
, bufferSize
);
266 _addNode : function _addNode(node
) {
269 i
= this._activatedNodes
.length
;
271 this._activatedNodes
.push(node
);
274 this.source
.disconnect();
275 this.source
.connect(node
);
277 this._activatedNodes
[i
- 1].disconnect();
278 this._activatedNodes
[i
- 1].connect(node
);
281 node
.connect(this.recorder
.node
);
282 this.recorder
.context
= node
.context
;
283 this.recorder
.node
.connect(this.recorder
.context
.destination
)
285 console
.log("Adding: ", node
);
288 _removeNode : function _removeNode(node
) {
291 i
= this._activatedNodes
.indexOf(node
);
295 if (i
=== 0 && i
+ 1 === this._activatedNodes
.length
) {
296 // It was the only one, connect source to recorder.
297 this.source
.disconnect();
298 this.source
.connect(this.recorder
.node
);
299 } else if (i
=== 0) {
300 // Normal 0 case, connect source to node. Recorder stays the same
301 this.source
.disconnect();
302 this.source
.connect(this._activatedNodes
[i
+1]);
303 } else if (i
+ 1 === this._activatedNodes
.length
) {
304 // It's not the 0 case, but we need to reconnect to recorder.
305 this._activatedNodes
[i
- 1].disconnect();
306 this._activatedNodes
[i
- 1].connect(this.recorder
.node
);
308 // Normal case, connect previous node to node
309 this._activatedNodes
[i
- 1].disconnect();
310 this._activatedNodes
[i
- 1].connect(this._activatedNodes
[i
+ 1]);
313 this._activatedNodes
.splice(i
, 1);
315 console
.log("Removing: ", node
);
318 _generateDistortion : function generateDistortion(amount
) {
319 var k
= typeof amount
=== 'number' ? amount : 50,
321 curve
= new Float32Array(n_samples
),
325 for ( ; i
< n_samples
; ++i
) {
326 x
= i
* 2 / n_samples
- 1;
327 curve
[i
] = ( 3 + k
) * x
* 20 * deg
/ ( Math
.PI
+ k
* Math
.abs(x
) );
332 // Normalize get user media
333 _getUserMedia : (navigator
.getUserMedia
||
334 navigator
.webkitGetUserMedia
||
335 navigator
.mozGetUserMedia
||
336 navigator
.msGetUserMedia
).bind(navigator
)