Skip to content

Commit fb5e96f

Browse files
committed
Add ring buffer to p5.Amplitude AudioWorklet processor
1 parent 515b366 commit fb5e96f

File tree

2 files changed

+60
-40
lines changed

2 files changed

+60
-40
lines changed

src/amplitude.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@ define(function (require) {
5353
this.audiocontext = p5sound.audiocontext;
5454
this._workletNode = new AudioWorkletNode(this.audiocontext, processorNames.amplitudeProcessor, {
5555
outputChannelCount: [1],
56+
57+
parameterData: { smoothing: smoothing || 0 },
5658
processorOptions: {
5759
normalize: false,
58-
smoothing: smoothing || 0
60+
smoothing: smoothing || 0,
61+
numInputChannels: 2,
62+
bufferSize: this.bufferSize
5963
}
6064
});
6165

src/audioWorklet/amplitudeProcessor.js

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1-
// import processor name via preval.require so that it's available as a value at compile time
1+
// import dependencies via preval.require so that they're available as values at compile time
22
const processorNames = preval.require('./processorNames');
3+
const RingBuffer = preval.require('./ringBuffer').default;
34

45
class AmplitudeProcessor extends AudioWorkletProcessor {
56
constructor(options) {
67
super();
78

89
const processorOptions = options.processorOptions || {};
9-
this.smoothing = processorOptions.smoothing || 0;
10+
this.numOutputChannels = options.outputChannelCount || 1;
11+
this.numInputChannels = processorOptions.numInputChannels || 2;
1012
this.normalize = processorOptions.normalize || false;
13+
this.smoothing = processorOptions.smoothing || 0;
14+
this.bufferSize = processorOptions.bufferSize || 2048;
15+
16+
this.inputRingBuffer = new RingBuffer(this.bufferSize, this.numInputChannels);
17+
this.outputRingBuffer = new RingBuffer(this.bufferSize, this.numOutputChannels);
18+
this.inputRingBufferArraySequence = new Array(this.numInputChannels).fill(null).map(() => new Float32Array(this.bufferSize));
1119

1220
this.stereoVol = [0, 0];
1321
this.stereoVolNorm = [0, 0];
@@ -30,53 +38,61 @@ class AmplitudeProcessor extends AudioWorkletProcessor {
3038
const output = outputs[0];
3139
const smoothing = this.smoothing;
3240

33-
for (let channel = 0; channel < input.length; ++channel) {
34-
const inputBuffer = input[channel];
35-
const bufLength = inputBuffer.length;
36-
37-
let sum = 0;
38-
for (var i = 0; i < bufLength; i++) {
39-
const x = inputBuffer[i];
40-
if (this.normalize) {
41-
sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1);
42-
} else {
43-
sum += x * x;
41+
this.inputRingBuffer.push(input);
42+
43+
if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {
44+
this.inputRingBuffer.pull(this.inputRingBufferArraySequence);
45+
46+
for (let channel = 0; channel < this.numInputChannels; ++channel) {
47+
const inputBuffer = this.inputRingBufferArraySequence[channel];
48+
const bufLength = inputBuffer.length;
49+
50+
let sum = 0;
51+
for (var i = 0; i < bufLength; i++) {
52+
const x = inputBuffer[i];
53+
if (this.normalize) {
54+
sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1);
55+
} else {
56+
sum += x * x;
57+
}
4458
}
45-
}
4659

47-
// ... then take the square root of the sum.
48-
const rms = Math.sqrt(sum / bufLength);
60+
// ... then take the square root of the sum.
61+
const rms = Math.sqrt(sum / bufLength);
4962

50-
this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * smoothing);
51-
this.volMax = Math.max(this.stereoVol[channel], this.volMax);
52-
}
63+
this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * smoothing);
64+
this.volMax = Math.max(this.stereoVol[channel], this.volMax);
65+
}
5366

54-
// calculate stero normalized volume and add volume from all channels together
55-
let volSum = 0;
56-
for (let index = 0; index < this.stereoVol.length; index++) {
57-
this.stereoVolNorm[index] = Math.max(Math.min(this.stereoVol[index] / this.volMax, 1), 0);
58-
volSum += this.stereoVol[index];
59-
}
67+
// calculate stero normalized volume and add volume from all channels together
68+
let volSum = 0;
69+
for (let index = 0; index < this.stereoVol.length; index++) {
70+
this.stereoVolNorm[index] = Math.max(Math.min(this.stereoVol[index] / this.volMax, 1), 0);
71+
volSum += this.stereoVol[index];
72+
}
6073

61-
// volume is average of channels
62-
const volume = volSum / this.stereoVol.length;
74+
// volume is average of channels
75+
const volume = volSum / this.stereoVol.length;
6376

64-
// normalized value
65-
const volNorm = Math.max(Math.min(volume / this.volMax, 1), 0);
77+
// normalized value
78+
const volNorm = Math.max(Math.min(volume / this.volMax, 1), 0);
6679

67-
this.port.postMessage({
68-
name: 'amplitude',
69-
volume: volume,
70-
volNorm: volNorm,
71-
stereoVol: this.stereoVol,
72-
stereoVolNorm: this.stereoVolNorm
73-
});
80+
this.port.postMessage({
81+
name: 'amplitude',
82+
volume: volume,
83+
volNorm: volNorm,
84+
stereoVol: this.stereoVol,
85+
stereoVolNorm: this.stereoVolNorm
86+
});
7487

75-
// pass input through to output
76-
for (let channel = 0; channel < output.length; ++channel) {
77-
output[channel].set(input[channel]);
88+
// pass input through to output
89+
this.outputRingBuffer.push(this.inputRingBufferArraySequence);
7890
}
7991

92+
// pull 128 frames out of the ring buffer
93+
// if the ring buffer does not have enough frames, the output will be silent
94+
this.outputRingBuffer.pull(output);
95+
8096
return true;
8197
}
8298
}

0 commit comments

Comments
 (0)