]> git.r.bdr.sh - rbdr/r.bdr.sh/blob - jekyll/js/unlimited_pizza/pepperoni.js
Remove unused files
[rbdr/r.bdr.sh] / jekyll / js / unlimited_pizza / pepperoni.js
1 'use strict';
2
3 const internals = {
4
5 config: {
6 convolverNode: {
7 requestMethod: 'GET',
8 requestLocation: '/reverb.ogg',
9 responseType: 'arraybuffer'
10 },
11 distortionNode: {
12 amount: 400
13 }
14 },
15
16 kTemplate: `<a class="record-button">Record.</a>
17 <div class="record-info">
18 <div class="record-progress">
19 <div class="record-progress-bar-container">
20 <div class="record-progress-bar"></div>
21 </div>
22 <a class="record-clear">Clear recording.</a>
23 </div>
24 <audio class="record-preview" controls></audio>
25 <div class="filter-switches">
26 <input class="filter-switch" name="bandpass-filter" type="checkbox" /> <label for="bandpass-filter">Band Pass</label>
27 <input class="filter-switch" name="hipass-filter" type="checkbox" /> <label for="hipass-filter">Hi Pass</label>
28 <input class="filter-switch" name="lopass-filter" type="checkbox" /> <label for="lopass-filter">Lo Pass</label>
29 <input class="filter-switch" name="reverb-filter" type="checkbox" /> <label for="reverb-filter">Reverb</label>
30 <input class="filter-switch" name="distort-filter" type="checkbox" /> <label for="distort-filter">Distort</label>
31 </div>
32 </div>`,
33 kPauseLabel : 'Pause.',
34 kRecordLabel : 'Record.',
35 };
36
37 const Pepperoni = class Pepperoni {
38 constructor() {
39
40 const context = new AudioContext();
41
42 const nodes = this._createNodes(context);
43
44 this._activatedNodes = [];
45 },
46
47 _createNodes(context) {
48
49 const delayNode = context.createDelay(1.0);
50
51 const convolverNode = context.createConvolver();
52 this._initializeConvolverNode(convolverNode);
53
54 const loPassFilterNode = context.createBiquadFilter();
55 loPassFilterNode.type = 'lowpass';
56 loPassFilterNode.frequency.value = 1000;
57 loPassFilterNode.gain.value = 25;
58
59 const hiPassFilterNode = context.createBiquadFilter();
60 hiPassFilterNode.type = 'highpass';
61 hiPassFilterNode.frequency.value = 3000;
62 hiPassFilterNode.gain.value = 25;
63
64 const bandPassFilterNode = context.createBiquadFilter();
65 bandPassFilterNode.type = 'bandpass';
66 bandPassFilterNode.frequency.value = 2000;
67 bandPassFilterNode.gain.value = 25;
68
69 const distortionNode = context.createWaveShaper();
70 distortionNode.curve = this._generateDistortion(400);
71 distortionNode.oversample = '4x';
72 }
73
74 // Generates a wave to be used with the distortion wave shaper node
75
76 _generateDistortion(amount = 50) {
77
78 const sampleRate = 44100;
79 const curve = new Float32Array(sampleRate);
80 const angle = Math.PI / 180;
81
82 for (let i = 0; i < sampleRate; ++i) {
83 const x = i * 2 / sampleRate - 1;
84 curve[i] = ( 3 + amount ) * x * 20 * angle / ( Math.PI + amount * Math.abs(x) );
85 }
86
87 return curve;
88 },
89
90 // Initializes a convolver node by requesting the reverb sound,
91 // decoding it, and attaching it
92
93 _initializeConvolverNode(node) {
94
95 const request = new XMLHttpRequest();
96 request.open(config.convolverNode.requestMethod, config.convolverNode.requestLocation);
97 request.responseType = config.convolverNode.responseType;
98 request.addEventListener('load', (event) => {
99
100 node.context.decodeAudioData(event.target.response, (buffer) => {
101
102 node.buffer = buffer;
103 });
104 });
105 request.send();
106 }
107
108 // Handles the XHR response to the reverb file
109
110
111
112 if (!this.source) {
113 this._getUserMedia({
114 audio : true
115 }, this._onUserMedia.bind(this), this._onUserMediaError.bind(this))
116 }
117
118 this.element.html(this.constructor.INNER_HTML);
119
120 this.controlButton = this.element.find('.record-button');
121 this.clearButton = this.element.find('.record-clear');
122 this.audioElement = this.element.find('audio');
123 this.progressBarContainer = this.element.find('.record-progress-bar-container');
124 this.progressBar = this.element.find('.record-progress-bar');
125 this.switches = this.element.find('.filter-switch');
126
127 this._bindEvents();
128 };
129
130 const Pepperoni.prototype = {
131
132 _createNodes() {
133
134 }
135
136 maxSize : 1048576,
137 recording : false,
138 source : null,
139 recorder : null,
140 context : null,
141 _delayNode : null,
142 _bandPassFilterNode : null,
143 _hiPassFilterNode : null,
144 _loPassFilterNode : null,
145 _convolverNode : null,
146 _distortionNode : null,
147 _activatedNodes : null,
148 workerPath : '/js/vendor/recorderjs/recorderWorker.js',
149 init : function init(config) {
150 },
151
152 record : function record() {
153 if (this.recorder && !this.recording) {
154 this._canRecord(function handleCanRecord(canRecord) {
155 if (canRecord) {
156 this.recording = true;
157 this.controlButton.addClass('recording')
158 this.controlButton.html(this.constructor.PAUSE);
159 this._interval = setInterval(this._onRecordCheck.bind(this), 100);
160 this.recorder.record();
161 }
162 }.bind(this));
163 }
164 },
165
166 stop : function stop() {
167 if (this.recorder && this.recording) {
168 this.recording = false;
169 this.controlButton.removeClass('recording')
170 this.controlButton.html(this.constructor.RECORD);
171 clearInterval(this._interval);
172 this.recorder.stop();
173 this.recorder.exportWAV();
174 }
175 },
176
177 clear : function clear() {
178 if (this.recorder) {
179 this.progressBar.width(0);
180 this.audioElement.attr('src', '');
181 this.audioElement[0].load();
182 this.recorder.clear()
183 }
184 },
185
186 finalize : function finalize(callback) {
187 if (this.recorder) {
188 this.recorder.exportWAV(callback);
189 }
190 },
191
192 getBuffer : function getBuffer(callback) {
193 if (this.recorder) {
194 this.recorder.getBuffer(callback);
195 }
196 },
197
198 _bindEvents : function bindEvents() {
199 var pepperoni = this;
200
201 this.controlButton.on('click', function () {
202 if (this.recording) {
203 this.stop();
204 } else {
205 this.record();
206 }
207 }.bind(this))
208
209 this.clearButton.on('click', function () {
210 if (!this.recording) {
211 this.clear();
212 }
213 }.bind(this))
214
215 this.switches.on('change', function (ev) {
216 if (!pepperoni.source) {
217 this.checked = false;
218 return false;
219 }
220 switch (this.name) {
221 case 'delay-filter':
222 if (this.checked) {
223 pepperoni._addNode(pepperoni._delayNode);
224 } else {
225 pepperoni._removeNode(pepperoni._delayNode);
226 }
227 break;
228
229 case 'hipass-filter':
230 if (this.checked) {
231 pepperoni._addNode(pepperoni._hiPassFilterNode);
232 } else {
233 pepperoni._removeNode(pepperoni._hiPassFilterNode);
234 }
235 break;
236
237 case 'bandpass-filter':
238 if (this.checked) {
239 pepperoni._addNode(pepperoni._bandPassFilterNode);
240 } else {
241 pepperoni._removeNode(pepperoni._bandPassFilterNode);
242 }
243 break;
244
245 case 'lopass-filter':
246 if (this.checked) {
247 pepperoni._addNode(pepperoni._loPassFilterNode);
248 } else {
249 pepperoni._removeNode(pepperoni._loPassFilterNode);
250 }
251 break;
252
253 case 'reverb-filter':
254 if (this.checked) {
255 pepperoni._addNode(pepperoni._convolverNode);
256 } else {
257 pepperoni._removeNode(pepperoni._convolverNode);
258 }
259 break;
260
261 case 'distort-filter':
262 if (this.checked) {
263 pepperoni._addNode(pepperoni._distortionNode);
264 } else {
265 pepperoni._removeNode(pepperoni._distortionNode);
266 }
267
268 break;
269 }
270 });
271 },
272
273 _onRecording : function _onRecording(buffer) {
274 this._buffer = buffer;
275
276 this.audioElement.attr('src', URL.createObjectURL(buffer));
277 this.audioElement[0].load();
278 },
279
280 _onUserMedia : function _onUserMedia(localMediaStream) {
281 this.source = this.context.createMediaStreamSource(localMediaStream);
282 this.recorder = new Recorder(this.source, {
283 workerPath : this.workerPath,
284 callback : this._onRecording.bind(this)
285 });
286 },
287
288 _onUserMediaError : function _onUserMediaError(error) {
289 console.log("Something went wrong", error);
290 this.disable();
291 },
292
293 _onRecordCheck : function _onRecordCheck() {
294 this._canRecord(function (canRecord, bufferSize) {
295 var width = bufferSize * this.progressBarContainer.width() / this.maxSize;
296 this.progressBar.width(width);
297 if (!canRecord) {
298 this.stop();
299 }
300 }.bind(this));
301 },
302
303 _canRecord : function _canRecord(callback) {
304 this.recorder.getBuffer(function getBuffer(buffer) {
305 var bufferSize = buffer[0].length + buffer[1].length;
306 callback && callback(bufferSize <= this.maxSize, bufferSize);
307 }.bind(this));
308 },
309
310 _addNode : function _addNode(node) {
311 var i;
312
313 i = this._activatedNodes.length;
314
315 this._activatedNodes.push(node);
316
317 if (i === 0) {
318 this.source.disconnect();
319 this.source.connect(node);
320 } else {
321 this._activatedNodes[i - 1].disconnect();
322 this._activatedNodes[i - 1].connect(node);
323 }
324
325 node.connect(this.recorder.node);
326 this.recorder.context = node.context;
327 this.recorder.node.connect(this.recorder.context.destination)
328
329 console.log("Adding: ", node);
330 },
331
332 _removeNode : function _removeNode(node) {
333 var i;
334
335 i = this._activatedNodes.indexOf(node);
336
337 node.disconnect();
338
339 if (i === 0 && i + 1 === this._activatedNodes.length) {
340 // It was the only one, connect source to recorder.
341 this.source.disconnect();
342 this.source.connect(this.recorder.node);
343 } else if (i === 0) {
344 // Normal 0 case, connect source to node. Recorder stays the same
345 this.source.disconnect();
346 this.source.connect(this._activatedNodes[i+1]);
347 } else if (i + 1 === this._activatedNodes.length) {
348 // It's not the 0 case, but we need to reconnect to recorder.
349 this._activatedNodes[i - 1].disconnect();
350 this._activatedNodes[i - 1].connect(this.recorder.node);
351 } else {
352 // Normal case, connect previous node to node
353 this._activatedNodes[i - 1].disconnect();
354 this._activatedNodes[i - 1].connect(this._activatedNodes[i + 1]);
355 }
356
357 this._activatedNodes.splice(i, 1);
358
359 console.log("Removing: ", node);
360 },
361
362 // Normalize get user media
363 _getUserMedia : (navigator.getUserMedia ||
364 navigator.webkitGetUserMedia ||
365 navigator.mozGetUserMedia ||
366 navigator.msGetUserMedia).bind(navigator)
367 }
368 });