]>
git.r.bdr.sh - rbdr/r.bdr.sh/blob - jekyll/js/unlimited_pizza/pepperoni.js
1 Class(UnlimitedPizza
, "Pepperoni").inherits(Widget
)({
3 <a class="record-button">⬤</a> \
4 <div class="record-info"> \
5 <div class="record-progress"> \
6 <div class="record-progress-bar-container"> \
7 <div class="record-progress-bar"></div> \
9 <a class="record-clear">X</a> \
11 <audio class="record-preview" controls></audio> \
12 <div class="filter-switches"> \
13 <input class="filter-switch" name="bandpass-filter" type="checkbox" /> <label for="bandpass-filter">Band Pass</label> \
14 <input class="filter-switch" name="hipass-filter" type="checkbox" /> <label for="hipass-filter">Hi Pass</label> \
15 <input class="filter-switch" name="lopass-filter" type="checkbox" /> <label for="lopass-filter">Lo Pass</label> \
16 <input class="filter-switch" name="distort-filter" type="checkbox" /> <label for="distort-filter">Distort</label> \
20 PAUSE : '▐▐',
29 _bandPassFilterNode : null,
30 _hiPassFilterNode : null,
31 _loPassFilterNode : null,
32 _convolverNode : null,
33 _distortionNode : null,
34 _activatedNodes : null,
35 workerPath : '/js/vendor/recorderjs/recorderWorker.js',
36 init : function init(config
) {
37 Widget
.prototype.init
.call(this, config
);
40 this.context
= new (window
.AudioContext
|| window
.webkitAudioContext
)();
43 this._delayNode
= this.context
.createDelay(1.0);
44 this._bandPassFilterNode
= this.context
.createBiquadFilter();
45 this._hiPassFilterNode
= this.context
.createBiquadFilter();
46 this._loPassFilterNode
= this.context
.createBiquadFilter();
47 this._convolverNode
= this.context
.createConvolver();
48 this._distortionNode
= this.context
.createWaveShaper();
50 this._distortionNode
.curve
= this._generateDistortion(400);
51 this._distortionNode
.oversample
= '4x';
53 this._activatedNodes
= [];
56 this._loPassFilterNode
.type
= "lowpass";
57 this._loPassFilterNode
.frequency
.value
= 1000;
58 this._loPassFilterNode
.gain
.value
= 25;
61 this._hiPassFilterNode
.type
= "highpass";
62 this._hiPassFilterNode
.frequency
.value
= 3000;
63 this._hiPassFilterNode
.gain
.value
= 25;
66 this._bandPassFilterNode
.type
= "bandpass";
67 this._bandPassFilterNode
.frequency
.value
= 2000;
68 this._bandPassFilterNode
.gain
.value
= 25;
73 }, this._onUserMedia
.bind(this), this._onUserMediaError
.bind(this))
76 this.element
.html(this.constructor.INNER_HTML
);
78 this.controlButton
= this.element
.find('.record-button');
79 this.clearButton
= this.element
.find('.record-clear');
80 this.audioElement
= this.element
.find('audio');
81 this.progressBarContainer
= this.element
.find('.record-progress-bar-container');
82 this.progressBar
= this.element
.find('.record-progress-bar');
83 this.switches
= this.element
.find('.filter-switch');
88 record : function record() {
89 if (this.recorder
&& !this.recording
) {
90 this._canRecord(function handleCanRecord(canRecord
) {
92 this.recording
= true;
93 this.controlButton
.addClass('recording')
94 this.controlButton
.html(this.constructor.PAUSE
);
95 this._interval
= setInterval(this._onRecordCheck
.bind(this), 100);
96 this.recorder
.record();
102 stop : function stop() {
103 if (this.recorder
&& this.recording
) {
104 this.recording
= false;
105 this.controlButton
.removeClass('recording')
106 this.controlButton
.html(this.constructor.RECORD
);
107 clearInterval(this._interval
);
108 this.recorder
.stop();
109 this.recorder
.exportWAV();
113 clear : function clear() {
115 this.progressBar
.width(0);
116 this.audioElement
.attr('src', '');
117 this.audioElement
[0].load();
118 this.recorder
.clear()
122 finalize : function finalize(callback
) {
124 this.recorder
.exportWAV(callback
);
128 getBuffer : function getBuffer(callback
) {
130 this.recorder
.getBuffer(callback
);
134 _bindEvents : function bindEvents() {
135 var pepperoni
= this;
137 this.controlButton
.on('click', function () {
138 if (this.recording
) {
145 this.clearButton
.on('click', function () {
146 if (!this.recording
) {
151 this.switches
.on('change', function (ev
) {
152 if (!pepperoni
.source
) {
153 this.checked
= false;
159 pepperoni
._addNode(pepperoni
._delayNode
);
161 pepperoni
._removeNode(pepperoni
._delayNode
);
165 case 'hipass-filter':
167 pepperoni
._addNode(pepperoni
._hiPassFilterNode
);
169 pepperoni
._removeNode(pepperoni
._hiPassFilterNode
);
173 case 'bandpass-filter':
175 pepperoni
._addNode(pepperoni
._bandPassFilterNode
);
177 pepperoni
._removeNode(pepperoni
._bandPassFilterNode
);
181 case 'lopass-filter':
183 pepperoni
._addNode(pepperoni
._loPassFilterNode
);
185 pepperoni
._removeNode(pepperoni
._loPassFilterNode
);
189 case 'reverb-filter':
191 pepperoni
._addNode(pepperoni
._convolverNode
);
193 pepperoni
._removeNode(pepperoni
._convolverNode
);
197 case 'distort-filter':
199 pepperoni
._addNode(pepperoni
._distortionNode
);
201 pepperoni
._removeNode(pepperoni
._distortionNode
);
209 _onRecording : function _onRecording(buffer
) {
210 this._buffer
= buffer
;
212 this.audioElement
.attr('src', URL
.createObjectURL(buffer
));
213 this.audioElement
[0].load();
216 _onUserMedia : function _onUserMedia(localMediaStream
) {
217 this.source
= this.context
.createMediaStreamSource(localMediaStream
);
218 this.recorder
= new Recorder(this.source
, {
219 workerPath : this.workerPath
,
220 callback : this._onRecording
.bind(this)
224 _onUserMediaError : function _onUserMediaError(error
) {
225 console
.log("Something went wrong", error
);
229 _onRecordCheck : function _onRecordCheck() {
230 this._canRecord(function (canRecord
, bufferSize
) {
231 var width
= bufferSize
* this.progressBarContainer
.width() / this.maxSize
;
232 this.progressBar
.width(width
);
239 _canRecord : function _canRecord(callback
) {
240 this.recorder
.getBuffer(function getBuffer(buffer
) {
241 var bufferSize
= buffer
[0].length
+ buffer
[1].length
;
242 callback
&& callback(bufferSize
<= this.maxSize
, bufferSize
);
246 _addNode : function _addNode(node
) {
249 i
= this._activatedNodes
.length
;
251 this._activatedNodes
.push(node
);
254 this.source
.disconnect();
255 this.source
.connect(node
);
257 this._activatedNodes
[i
- 1].disconnect();
258 this._activatedNodes
[i
- 1].connect(node
);
261 node
.connect(this.recorder
.node
);
262 this.recorder
.context
= node
.context
;
263 this.recorder
.node
.connect(this.recorder
.context
.destination
)
265 console
.log("Adding: ", node
);
268 _removeNode : function _removeNode(node
) {
271 i
= this._activatedNodes
.indexOf(node
);
275 if (i
=== 0 && i
+ 1 === this._activatedNodes
.length
) {
276 // It was the only one, connect source to recorder.
277 this.source
.disconnect();
278 this.source
.connect(this.recorder
.node
);
279 } else if (i
=== 0) {
280 // Normal 0 case, connect source to node. Recorder stays the same
281 this.source
.disconnect();
282 this.source
.connect(this._activatedNodes
[i
+1]);
283 } else if (i
+ 1 === this._activatedNodes
.length
) {
284 // It's not the 0 case, but we need to reconnect to recorder.
285 this._activatedNodes
[i
- 1].disconnect();
286 this._activatedNodes
[i
- 1].connect(this.recorder
.node
);
288 // Normal case, connect previous node to node
289 this._activatedNodes
[i
- 1].disconnect();
290 this._activatedNodes
[i
- 1].connect(this._activatedNodes
[i
+ 1]);
293 this._activatedNodes
.splice(i
, 1);
295 console
.log("Removing: ", node
);
298 _generateDistortion : function generateDistortion(amount
) {
299 var k
= typeof amount
=== 'number' ? amount : 50,
301 curve
= new Float32Array(n_samples
),
305 for ( ; i
< n_samples
; ++i
) {
306 x
= i
* 2 / n_samples
- 1;
307 curve
[i
] = ( 3 + k
) * x
* 20 * deg
/ ( Math
.PI
+ k
* Math
.abs(x
) );
312 // Normalize get user media
313 _getUserMedia : (navigator
.getUserMedia
||
314 navigator
.webkitGetUserMedia
||
315 navigator
.mozGetUserMedia
||
316 navigator
.msGetUserMedia
).bind(navigator
)