Skip to content

Commit 838f3ac

Browse files
authored
replacement es5 classes to es6 classes feat p5.SoundRecorder (#532)
* Replacement of es5 functiond to es6 classes feat p5.SoundRecorder * removed saveSound method from soundRecorder , as it should be a global method to be used by soundFile , so placed that in helpers.js
1 parent 147d826 commit 838f3ac

File tree

3 files changed

+142
-134
lines changed

3 files changed

+142
-134
lines changed

src/app.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ p5.prototype.userStartAudio = userStartAudio;
77

88
import './master';
99

10-
import { freqToMidi } from './helpers';
10+
import { freqToMidi, saveSound } from './helpers';
1111
p5.prototype.freqToMidi = freqToMidi;
12+
p5.prototype.saveSound = saveSound;
1213

1314
import './errorHandler';
1415
import './audioWorklet';
@@ -69,11 +70,14 @@ p5.SoundLoop = SoundLoop;
6970
import Compressor from './compressor';
7071
p5.Compressor = Compressor;
7172

72-
import './soundRecorder';
7373

7474
import peakDetect from './peakDetect';
7575
p5.peakDetect = peakDetect;
7676

77+
import SoundRecorder from './soundRecorder';
78+
p5.SoundRecorder = SoundRecorder;
79+
80+
7781
import Distortion from './distortion';
7882
p5.Distortion = Distortion;
7983

src/helpers.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,23 @@ export function safeBufferSize(idealBufferSize) {
334334
return bufferSize;
335335
}
336336

337+
/**
338+
* Save a p5.SoundFile as a .wav file. The browser will prompt the user
339+
* to download the file to their device.
340+
* For uploading audio to a server, use
341+
* <a href="/docs/reference/#/p5.SoundFile/saveBlob">`p5.SoundFile.saveBlob`</a>.
342+
*
343+
* @for p5
344+
* @method saveSound
345+
* @param {p5.SoundFile} soundFile p5.SoundFile that you wish to save
346+
* @param {String} fileName name of the resulting .wav file.
347+
*/
348+
// add to p5.prototype as this is used by the p5 `save()` method.
349+
export function saveSound(soundFile, fileName) {
350+
const dataView = convertToWav(soundFile.buffer);
351+
p5.prototype.writeFile([dataView], fileName, 'wav');
352+
}
353+
337354
// export default {
338355
// // convertToWav: convertToWav,
339356
// // midiToFreq: midiToFreq,

src/soundRecorder.js

Lines changed: 119 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// inspiration: recorder.js, Tone.js & typedarray.org
22

33
import p5sound from './master';
4-
import { convertToWav, safeBufferSize } from './helpers';
4+
import { safeBufferSize } from './helpers';
55
import processorNames from './audioWorklet/processorNames';
66

77
const ac = p5sound.audiocontext;
@@ -80,145 +80,132 @@ const ac = p5sound.audiocontext;
8080
* }
8181
* </div></code>
8282
*/
83-
p5.SoundRecorder = function () {
84-
this.input = ac.createGain();
85-
this.output = ac.createGain();
86-
87-
this._inputChannels = 2;
88-
this._outputChannels = 2; // stereo output, even if input is mono
89-
90-
const workletBufferSize = safeBufferSize(1024);
91-
92-
this._workletNode = new AudioWorkletNode(
93-
ac,
94-
processorNames.recorderProcessor,
95-
{
96-
outputChannelCount: [this._outputChannels],
97-
processorOptions: {
98-
numInputChannels: this._inputChannels,
99-
bufferSize: workletBufferSize,
100-
},
101-
}
102-
);
103-
104-
this._workletNode.port.onmessage = function (event) {
105-
if (event.data.name === 'buffers') {
106-
const buffers = [
107-
new Float32Array(event.data.leftBuffer),
108-
new Float32Array(event.data.rightBuffer),
109-
];
110-
this._callback(buffers);
111-
}
112-
}.bind(this);
83+
class SoundRecorder {
84+
constructor() {
85+
this.input = ac.createGain();
86+
this.output = ac.createGain();
87+
88+
this._inputChannels = 2;
89+
this._outputChannels = 2; // stereo output, even if input is mono
90+
91+
const workletBufferSize = safeBufferSize(1024);
92+
93+
this._workletNode = new AudioWorkletNode(
94+
ac,
95+
processorNames.recorderProcessor,
96+
{
97+
outputChannelCount: [this._outputChannels],
98+
processorOptions: {
99+
numInputChannels: this._inputChannels,
100+
bufferSize: workletBufferSize,
101+
},
102+
}
103+
);
104+
105+
this._workletNode.port.onmessage = function (event) {
106+
if (event.data.name === 'buffers') {
107+
const buffers = [
108+
new Float32Array(event.data.leftBuffer),
109+
new Float32Array(event.data.rightBuffer),
110+
];
111+
this._callback(buffers);
112+
}
113+
}.bind(this);
114+
115+
/**
116+
* callback invoked when the recording is over
117+
* @private
118+
* @type Function(Float32Array)
119+
*/
120+
this._callback = function () {};
121+
122+
// connections
123+
this._workletNode.connect(p5.soundOut._silentNode);
124+
this.setInput();
125+
126+
// add this p5.SoundFile to the soundArray
127+
p5sound.soundArray.push(this);
128+
}
113129

114130
/**
115-
* callback invoked when the recording is over
116-
* @private
117-
* @type Function(Float32Array)
131+
* Connect a specific device to the p5.SoundRecorder.
132+
* If no parameter is given, p5.SoundRecorer will record
133+
* all audible p5.sound from your sketch.
134+
*
135+
* @method setInput
136+
* @for p5.SoundRecorder
137+
* @param {Object} [unit] p5.sound object or a web audio unit
138+
* that outputs sound
118139
*/
119-
this._callback = function () {};
120-
121-
// connections
122-
this._workletNode.connect(p5.soundOut._silentNode);
123-
this.setInput();
124-
125-
// add this p5.SoundFile to the soundArray
126-
p5sound.soundArray.push(this);
127-
};
128-
129-
/**
130-
* Connect a specific device to the p5.SoundRecorder.
131-
* If no parameter is given, p5.SoundRecorer will record
132-
* all audible p5.sound from your sketch.
133-
*
134-
* @method setInput
135-
* @for p5.SoundRecorder
136-
* @param {Object} [unit] p5.sound object or a web audio unit
137-
* that outputs sound
138-
*/
139-
p5.SoundRecorder.prototype.setInput = function (unit) {
140-
this.input.disconnect();
141-
this.input = null;
142-
this.input = ac.createGain();
143-
this.input.connect(this._workletNode);
144-
this.input.connect(this.output);
145-
if (unit) {
146-
unit.connect(this.input);
147-
} else {
148-
p5.soundOut.output.connect(this.input);
140+
setInput(unit) {
141+
this.input.disconnect();
142+
this.input = null;
143+
this.input = ac.createGain();
144+
this.input.connect(this._workletNode);
145+
this.input.connect(this.output);
146+
if (unit) {
147+
unit.connect(this.input);
148+
} else {
149+
p5.soundOut.output.connect(this.input);
150+
}
149151
}
150-
};
151152

152-
/**
153-
* Start recording. To access the recording, provide
154-
* a p5.SoundFile as the first parameter. The p5.SoundRecorder
155-
* will send its recording to that p5.SoundFile for playback once
156-
* recording is complete. Optional parameters include duration
157-
* (in seconds) of the recording, and a callback function that
158-
* will be called once the complete recording has been
159-
* transfered to the p5.SoundFile.
160-
*
161-
* @method record
162-
* @for p5.SoundRecorder
163-
* @param {p5.SoundFile} soundFile p5.SoundFile
164-
* @param {Number} [duration] Time (in seconds)
165-
* @param {Function} [callback] The name of a function that will be
166-
* called once the recording completes
167-
*/
168-
p5.SoundRecorder.prototype.record = function (sFile, duration, callback) {
169-
this._workletNode.port.postMessage({ name: 'start', duration: duration });
170-
171-
if (sFile && callback) {
172-
this._callback = function (buffer) {
173-
sFile.setBuffer(buffer);
174-
callback();
175-
};
176-
} else if (sFile) {
177-
this._callback = function (buffer) {
178-
sFile.setBuffer(buffer);
179-
};
153+
/**
154+
* Start recording. To access the recording, provide
155+
* a p5.SoundFile as the first parameter. The p5.SoundRecorder
156+
* will send its recording to that p5.SoundFile for playback once
157+
* recording is complete. Optional parameters include duration
158+
* (in seconds) of the recording, and a callback function that
159+
* will be called once the complete recording has been
160+
* transfered to the p5.SoundFile.
161+
*
162+
* @method record
163+
* @for p5.SoundRecorder
164+
* @param {p5.SoundFile} soundFile p5.SoundFile
165+
* @param {Number} [duration] Time (in seconds)
166+
* @param {Function} [callback] The name of a function that will be
167+
* called once the recording completes
168+
*/
169+
record(sFile, duration, callback) {
170+
this._workletNode.port.postMessage({ name: 'start', duration: duration });
171+
172+
if (sFile && callback) {
173+
this._callback = function (buffer) {
174+
sFile.setBuffer(buffer);
175+
callback();
176+
};
177+
} else if (sFile) {
178+
this._callback = function (buffer) {
179+
sFile.setBuffer(buffer);
180+
};
181+
}
180182
}
181-
};
182183

183-
/**
184-
* Stop the recording. Once the recording is stopped,
185-
* the results will be sent to the p5.SoundFile that
186-
* was given on .record(), and if a callback function
187-
* was provided on record, that function will be called.
188-
*
189-
* @method stop
190-
* @for p5.SoundRecorder
191-
*/
192-
p5.SoundRecorder.prototype.stop = function () {
193-
this._workletNode.port.postMessage({ name: 'stop' });
194-
};
184+
/**
185+
* Stop the recording. Once the recording is stopped,
186+
* the results will be sent to the p5.SoundFile that
187+
* was given on .record(), and if a callback function
188+
* was provided on record, that function will be called.
189+
*
190+
* @method stop
191+
* @for p5.SoundRecorder
192+
*/
193+
stop() {
194+
this._workletNode.port.postMessage({ name: 'stop' });
195+
}
195196

196-
p5.SoundRecorder.prototype.dispose = function () {
197-
// remove reference from soundArray
198-
var index = p5sound.soundArray.indexOf(this);
199-
p5sound.soundArray.splice(index, 1);
197+
dispose() {
198+
// remove reference from soundArray
199+
var index = p5sound.soundArray.indexOf(this);
200+
p5sound.soundArray.splice(index, 1);
200201

201-
this._callback = function () {};
202-
if (this.input) {
203-
this.input.disconnect();
202+
this._callback = function () {};
203+
if (this.input) {
204+
this.input.disconnect();
205+
}
206+
this.input = null;
207+
this._workletNode = null;
204208
}
205-
this.input = null;
206-
this._workletNode = null;
207-
};
209+
}
208210

209-
/**
210-
* Save a p5.SoundFile as a .wav file. The browser will prompt the user
211-
* to download the file to their device.
212-
* For uploading audio to a server, use
213-
* <a href="/docs/reference/#/p5.SoundFile/saveBlob">`p5.SoundFile.saveBlob`</a>.
214-
*
215-
* @for p5
216-
* @method saveSound
217-
* @param {p5.SoundFile} soundFile p5.SoundFile that you wish to save
218-
* @param {String} fileName name of the resulting .wav file.
219-
*/
220-
// add to p5.prototype as this is used by the p5 `save()` method.
221-
p5.prototype.saveSound = function (soundFile, fileName) {
222-
const dataView = convertToWav(soundFile.buffer);
223-
p5.prototype.writeFile([dataView], fileName, 'wav');
224-
};
211+
export default SoundRecorder;

0 commit comments

Comments
 (0)