Skip to content

Commit 555bbc8

Browse files
authored
Merge branch 'main' into Abhijay007/Headless-testing
2 parents 49a6f89 + 401120d commit 555bbc8

16 files changed

+186
-71
lines changed

src/audioWorklet/ringBuffer.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class RingBuffer {
6767
for (let i = 0; i < sourceLength; ++i) {
6868
let writeIndex = (this._writeIndex + i) % this._length;
6969
for (let channel = 0; channel < this._channelCount; ++channel) {
70-
this._channelData[channel][writeIndex] = arraySequence[channel][i];
70+
if (arraySequence[channel])
71+
this._channelData[channel][writeIndex] = arraySequence[channel][i];
7172
}
7273
}
7374

src/audioin.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -50,40 +50,47 @@ p5sound.inputSources = [];
5050
*/
5151
class AudioIn {
5252
constructor(errorCallback) {
53-
// set up audio input
5453
/**
54+
* Set up audio input
5555
* @property {GainNode} input
5656
*/
5757
this.input = p5sound.audiocontext.createGain();
5858
/**
59+
* Send audio as an output, i.e. your computer's speaker.
5960
* @property {GainNode} output
6061
*/
6162
this.output = p5sound.audiocontext.createGain();
62-
6363
/**
64+
* Used to store the MediaStream object that is returned from the getUserMedia() API,
65+
* which allows access to the user's microphone. The stream is used to create a MediaStreamAudioSourceNode,
66+
* which is used as the audio source for the input and output gain nodes.
67+
* The stream is also used to check if the browser supports the MediaStreamTrack and mediaDevices API,
68+
* and if not, an errorCallback function is called or an alert is displayed.
6469
* @property {MediaStream|null} stream
6570
*/
6671
this.stream = null;
6772
/**
73+
* Used to access the "audio input" from the user's microphone.
74+
* It creates a MediaStream object that can be used to start and stop the mic and measure its volume using the getLevel() method or by connecting it to an FFT object.
75+
* MediaStream object can also be use to check if the browser supports MediaStreamTrack and mediaDevices and to add the AudioIn object to the soundArray for disposal on close.
6876
* @property {MediaStreamAudioSourceNode|null} mediaStream
6977
*/
7078
this.mediaStream = null;
7179
/**
80+
* Used to store the "current source of audio input", such as the user's microphone.
81+
* Initially set to "null" and can be updated as the user selects different audio sources.
82+
* Also used in conjunction with the "input" and "mediaStream" properties to control audio input.
7283
* @property {Number|null} currentSource
7384
*/
7485
this.currentSource = null;
75-
7686
/**
7787
* Client must allow browser to access their microphone / audioin source.
7888
* Default: false. Will become true when the client enables access.
79-
*
8089
* @property {Boolean} enabled
8190
*/
8291
this.enabled = false;
83-
8492
/**
8593
* Input amplitude, connect to it by default but not to master out
86-
*
8794
* @property {p5.Amplitude} amplitude
8895
*/
8996
this.amplitude = new Amplitude();

src/effect.js

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import CrossFade from 'Tone/component/CrossFade.js';
1313
* <a href="/reference/#/p5.Filter">p5.Filter</a>,
1414
* <a href="/reference/#/p5.Reverb">p5.Reverb</a>,
1515
* <a href="/reference/#/p5.EQ">p5.EQ</a>,
16+
* <a href="/reference/#/p5.Panner">p5.Panner</a>.
1617
* <a href="/reference/#/p5.Panner3D">p5.Panner3D</a>.
1718
*
1819
* @class p5.Effect

src/fft.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ class FFT {
298298
* <a href="https://en.wikipedia.org/wiki/Audio_frequency" target="_blank">
299299
* frequency</a>, or the average amount of energy between two
300300
* frequencies. Accepts Number(s) corresponding
301-
* to frequency (in Hz), or a "string" corresponding to predefined
301+
* to frequency (in Hz) (frequency must be >= 0), or a "string" corresponding to predefined
302302
* frequency ranges ("bass", "lowMid", "mid", "highMid", "treble").
303303
* Returns a range between 0 (no energy/volume at that frequency) and
304304
* 255 (maximum energy).
@@ -318,8 +318,8 @@ class FFT {
318318
* will return average amount of
319319
* energy that exists between the
320320
* two frequencies.
321-
* @return {Number} Energy Energy (volume/amplitude) from
322-
* 0 and 255.
321+
* @return {Number} Energy (volume/amplitude) from
322+
* 0 and 255.
323323
*
324324
*/
325325
getEnergy(frequency1, frequency2) {
@@ -350,7 +350,9 @@ class FFT {
350350
var index = Math.round((frequency1 / nyquist) * this.freqDomain.length);
351351
return this.freqDomain[index];
352352
}
353-
353+
if (frequency1 < 0 || frequency2 < 0) {
354+
throw 'invalid input for getEnergy(), frequency cannot be a negative number';
355+
}
354356
// if two parameters:
355357
// if second is higher than first
356358
if (frequency1 > frequency2) {

src/main.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ p5.prototype.outputVolume = function (vol, rampTime = 0, tFromNow = 0) {
8787
var now = p5sound.audiocontext.currentTime;
8888
var currentVol = p5sound.output.gain.value;
8989
p5sound.output.gain.cancelScheduledValues(now + tFromNow);
90-
p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
90+
if (rampTime !== 0)
91+
p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
9192
p5sound.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
9293
} else if (vol) {
9394
vol.connect(p5sound.output.gain);

src/monosynth.js

+7
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,21 @@ class MonoSynth extends AudioVoice {
7777
* @for p5.MonoSynth
7878
*/
7979
/**
80+
* Allows user to set the decay time of the envelope (ADSR) of the MonoSynth class.
81+
* It is a getter and setter that can be used to retrieve or change the decay time.
82+
* Used in conjunction with the attack, sustain, and release fields/functions to set the full envelope of the synthesizer.
8083
* @property {Number} decay
8184
* @for p5.MonoSynth
8285
*/
8386
/**
87+
* Allows the user to retrieve and adjust the sustain level of the envelope,
88+
* which controls the level at which the sound is sustained during the sustain phase of the envelope.
89+
* The default sustain level is set to 0.15.
8490
* @property {Number} sustain
8591
* @for p5.MonoSynth
8692
*/
8793
/**
94+
* Allows the user to access and change the release time of the envelope.
8895
* @property {Number} release
8996
* @for p5.MonoSynth
9097
*/

src/oscillator.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,14 @@ class Oscillator {
133133

134134
this.oscillator.connect(this.output);
135135
// stereo panning
136-
this.panPosition = 0.0;
137136
this.connection = p5sound.input; // connect to p5sound by default
138-
this.panner = new Panner(this.output, this.connection, 1);
139137

138+
if (typeof p5sound.audiocontext.createStereoPanner !== 'undefined') {
139+
this.panner = new Panner();
140+
this.output.connect(this.panner);
141+
} else {
142+
this.panner = new Panner(this.output, this.connection, 1);
143+
}
140144
//array of math operation signal chaining
141145
this.mathOps = [this.output];
142146

@@ -415,21 +419,20 @@ class Oscillator {
415419
* seconds from now
416420
*/
417421
pan(pval, tFromNow) {
418-
this.panPosition = pval;
419422
this.panner.pan(pval, tFromNow);
420423
}
421424

422425
/**
423-
* Returns the current value of panPosition , between Left (-1) and Right (1)
426+
* Returns the current value of pan position , between Left (-1) and Right (1)
424427
*
425428
* @method getPan
426429
* @for p5.Oscillator
427430
*
428-
* @returns {number} panPosition of oscillator , between Left (-1) and Right (1)
431+
* @returns {number} pan position of oscillator , between Left (-1) and Right (1)
429432
*/
430433

431434
getPan() {
432-
return this.panPosition;
435+
return this.panner.getPan();
433436
}
434437

435438
// get rid of the oscillator
@@ -442,6 +445,7 @@ class Oscillator {
442445
var now = p5sound.audiocontext.currentTime;
443446
this.stop(now);
444447
this.disconnect();
448+
this.panner.dispose();
445449
this.panner = null;
446450
this.oscillator = null;
447451
}

src/panner.js

+94-18
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,85 @@
1+
import Effect from './effect.js';
2+
13
import p5sound from './main';
24
var ac = p5sound.audiocontext;
35
var panner;
46
// Stereo panner
57
// if there is a stereo panner node use it
68
if (typeof ac.createStereoPanner !== 'undefined') {
7-
class Panner {
8-
constructor(input, output) {
9-
this.stereoPanner = this.input = ac.createStereoPanner();
10-
input.connect(this.stereoPanner);
11-
this.stereoPanner.connect(output);
9+
/**
10+
* The Panner class allows you to control the stereo
11+
* panning of a sound source. It uses the [StereoPannerNode](https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode),
12+
* which allows you to adjust the balance between the left and right channels of a sound source.
13+
*
14+
* This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>.
15+
* Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>,
16+
* <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and
17+
* <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available.
18+
*
19+
* @class p5.Panner
20+
* @extends p5.Effect
21+
*/
22+
class Panner extends Effect {
23+
constructor() {
24+
super();
25+
this.stereoPanner = this.ac.createStereoPanner();
26+
27+
this.input.connect(this.stereoPanner);
28+
this.stereoPanner.connect(this.wet);
1229
}
1330

31+
/**
32+
* Set the stereo pan position, a value of -1 means the sound will be fully panned
33+
* to the left, a value of 0 means the sound will be centered, and a value of 1 means
34+
* the sound will be fully panned to the right.
35+
* @method pan
36+
* @for p5.Panner
37+
* @param {Number} value A value between -1 and 1 that sets the pan position.
38+
*
39+
* @param {Number} [time] time in seconds that it will take for the panning to change to the specified value.
40+
*/
1441
pan(val, tFromNow) {
15-
var time = tFromNow || 0;
16-
var t = ac.currentTime + time;
17-
18-
this.stereoPanner.pan.linearRampToValueAtTime(val, t);
42+
if (typeof val === 'number') {
43+
let time = tFromNow || 0;
44+
this.stereoPanner.pan.linearRampToValueAtTime(
45+
val,
46+
this.ac.currentTime + time
47+
);
48+
} else if (typeof val !== 'undefined') {
49+
val.connect(this.stereoPanner.pan);
50+
}
1951
}
2052

21-
//not implemented because stereopanner
22-
//node does not require this and will automatically
23-
//convert single channel or multichannel to stereo.
24-
//tested with single and stereo, not with (>2) multichannel
25-
inputChannels() {}
26-
27-
connect(obj) {
28-
this.stereoPanner.connect(obj);
53+
/**
54+
* Return the current panning value.
55+
*
56+
* @method getPan
57+
* @for p5.Panner
58+
* @return {Number} current panning value, number between -1 (left) and 1 (right).
59+
*/
60+
getPan() {
61+
return this.stereoPanner.pan.value;
2962
}
3063

31-
disconnect() {
64+
/**
65+
* Get rid of the Panner and free up its resources / memory.
66+
*
67+
* @method dispose
68+
* @for p5.Panner
69+
*/
70+
dispose() {
71+
super.dispose();
3272
if (this.stereoPanner) {
3373
this.stereoPanner.disconnect();
74+
delete this.stereoPanner;
3475
}
3576
}
77+
78+
//not implemented because stereopanner
79+
//node does not require this and will automatically
80+
//convert single channel or multichannel to stereo.
81+
//tested with single and stereo, not with (>2) multichannel
82+
inputChannels() {}
3683
}
3784

3885
panner = Panner;
@@ -45,6 +92,7 @@ if (typeof ac.createStereoPanner !== 'undefined') {
4592
this.input = ac.createGain();
4693
input.connect(this.input);
4794

95+
this.panValue = 0;
4896
this.left = ac.createGain();
4997
this.right = ac.createGain();
5098
this.left.channelInterpretation = 'discrete';
@@ -70,6 +118,7 @@ if (typeof ac.createStereoPanner !== 'undefined') {
70118

71119
// -1 is left, +1 is right
72120
pan(val, tFromNow) {
121+
this.panValue = val;
73122
var time = tFromNow || 0;
74123
var t = ac.currentTime + time;
75124
var v = (val + 1) / 2;
@@ -79,6 +128,10 @@ if (typeof ac.createStereoPanner !== 'undefined') {
79128
this.right.gain.linearRampToValueAtTime(rightVal, t);
80129
}
81130

131+
getPan() {
132+
return this.panValue;
133+
}
134+
82135
inputChannels(numChannels) {
83136
if (numChannels === 1) {
84137
this.input.disconnect();
@@ -104,6 +157,29 @@ if (typeof ac.createStereoPanner !== 'undefined') {
104157
this.output.disconnect();
105158
}
106159
}
160+
161+
dispose() {
162+
if (this.input) {
163+
this.input.disconnect();
164+
delete this.input;
165+
}
166+
if (this.output) {
167+
this.output.disconnect();
168+
delete this.output;
169+
}
170+
if (this.left) {
171+
this.left.disconnect();
172+
delete this.left;
173+
}
174+
if (this.right) {
175+
this.right.disconnect();
176+
delete this.right;
177+
}
178+
if (this.splitter) {
179+
this.splitter.disconnect();
180+
delete this.splitter;
181+
}
182+
}
107183
}
108184
panner = Panner;
109185
}

src/peakDetect.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ class PeakDetect {
111111
this.currentValue = 0;
112112

113113
/**
114-
* isDetected is set to true when a peak is detected.
115-
*
114+
* It returns a boolean indicating whether a peak in the audio frequency spectrum has been detected or not.
116115
* @attribute isDetected {Boolean}
117116
* @default false
117+
* @property {Number} isDetected
118+
* @for p5.PeakDetect
118119
*/
119120
this.isDetected = false;
120121

0 commit comments

Comments
 (0)