Skip to content

Commit

Permalink
Merge branch 'main' into Abhijay007/Headless-testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhijay007 authored Jan 25, 2023
2 parents 49a6f89 + 401120d commit 555bbc8
Show file tree
Hide file tree
Showing 16 changed files with 186 additions and 71 deletions.
3 changes: 2 additions & 1 deletion src/audioWorklet/ringBuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class RingBuffer {
for (let i = 0; i < sourceLength; ++i) {
let writeIndex = (this._writeIndex + i) % this._length;
for (let channel = 0; channel < this._channelCount; ++channel) {
this._channelData[channel][writeIndex] = arraySequence[channel][i];
if (arraySequence[channel])
this._channelData[channel][writeIndex] = arraySequence[channel][i];
}
}

Expand Down
19 changes: 13 additions & 6 deletions src/audioin.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,40 +50,47 @@ p5sound.inputSources = [];
*/
class AudioIn {
constructor(errorCallback) {
// set up audio input
/**
* Set up audio input
* @property {GainNode} input
*/
this.input = p5sound.audiocontext.createGain();
/**
* Send audio as an output, i.e. your computer's speaker.
* @property {GainNode} output
*/
this.output = p5sound.audiocontext.createGain();

/**
* Used to store the MediaStream object that is returned from the getUserMedia() API,
* which allows access to the user's microphone. The stream is used to create a MediaStreamAudioSourceNode,
* which is used as the audio source for the input and output gain nodes.
* The stream is also used to check if the browser supports the MediaStreamTrack and mediaDevices API,
* and if not, an errorCallback function is called or an alert is displayed.
* @property {MediaStream|null} stream
*/
this.stream = null;
/**
* Used to access the "audio input" from the user's microphone.
* 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.
* 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.
* @property {MediaStreamAudioSourceNode|null} mediaStream
*/
this.mediaStream = null;
/**
* Used to store the "current source of audio input", such as the user's microphone.
* Initially set to "null" and can be updated as the user selects different audio sources.
* Also used in conjunction with the "input" and "mediaStream" properties to control audio input.
* @property {Number|null} currentSource
*/
this.currentSource = null;

/**
* Client must allow browser to access their microphone / audioin source.
* Default: false. Will become true when the client enables access.
*
* @property {Boolean} enabled
*/
this.enabled = false;

/**
* Input amplitude, connect to it by default but not to master out
*
* @property {p5.Amplitude} amplitude
*/
this.amplitude = new Amplitude();
Expand Down
1 change: 1 addition & 0 deletions src/effect.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import CrossFade from 'Tone/component/CrossFade.js';
* <a href="/reference/#/p5.Filter">p5.Filter</a>,
* <a href="/reference/#/p5.Reverb">p5.Reverb</a>,
* <a href="/reference/#/p5.EQ">p5.EQ</a>,
* <a href="/reference/#/p5.Panner">p5.Panner</a>.
* <a href="/reference/#/p5.Panner3D">p5.Panner3D</a>.
*
* @class p5.Effect
Expand Down
10 changes: 6 additions & 4 deletions src/fft.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class FFT {
* <a href="https://en.wikipedia.org/wiki/Audio_frequency" target="_blank">
* frequency</a>, or the average amount of energy between two
* frequencies. Accepts Number(s) corresponding
* to frequency (in Hz), or a "string" corresponding to predefined
* to frequency (in Hz) (frequency must be >= 0), or a "string" corresponding to predefined
* frequency ranges ("bass", "lowMid", "mid", "highMid", "treble").
* Returns a range between 0 (no energy/volume at that frequency) and
* 255 (maximum energy).
Expand All @@ -318,8 +318,8 @@ class FFT {
* will return average amount of
* energy that exists between the
* two frequencies.
* @return {Number} Energy Energy (volume/amplitude) from
* 0 and 255.
* @return {Number} Energy (volume/amplitude) from
* 0 and 255.
*
*/
getEnergy(frequency1, frequency2) {
Expand Down Expand Up @@ -350,7 +350,9 @@ class FFT {
var index = Math.round((frequency1 / nyquist) * this.freqDomain.length);
return this.freqDomain[index];
}

if (frequency1 < 0 || frequency2 < 0) {
throw 'invalid input for getEnergy(), frequency cannot be a negative number';
}
// if two parameters:
// if second is higher than first
if (frequency1 > frequency2) {
Expand Down
3 changes: 2 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ p5.prototype.outputVolume = function (vol, rampTime = 0, tFromNow = 0) {
var now = p5sound.audiocontext.currentTime;
var currentVol = p5sound.output.gain.value;
p5sound.output.gain.cancelScheduledValues(now + tFromNow);
p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
if (rampTime !== 0)
p5sound.output.gain.linearRampToValueAtTime(currentVol, now + tFromNow);
p5sound.output.gain.linearRampToValueAtTime(vol, now + tFromNow + rampTime);
} else if (vol) {
vol.connect(p5sound.output.gain);
Expand Down
7 changes: 7 additions & 0 deletions src/monosynth.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,21 @@ class MonoSynth extends AudioVoice {
* @for p5.MonoSynth
*/
/**
* Allows user to set the decay time of the envelope (ADSR) of the MonoSynth class.
* It is a getter and setter that can be used to retrieve or change the decay time.
* Used in conjunction with the attack, sustain, and release fields/functions to set the full envelope of the synthesizer.
* @property {Number} decay
* @for p5.MonoSynth
*/
/**
* Allows the user to retrieve and adjust the sustain level of the envelope,
* which controls the level at which the sound is sustained during the sustain phase of the envelope.
* The default sustain level is set to 0.15.
* @property {Number} sustain
* @for p5.MonoSynth
*/
/**
* Allows the user to access and change the release time of the envelope.
* @property {Number} release
* @for p5.MonoSynth
*/
Expand Down
16 changes: 10 additions & 6 deletions src/oscillator.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,14 @@ class Oscillator {

this.oscillator.connect(this.output);
// stereo panning
this.panPosition = 0.0;
this.connection = p5sound.input; // connect to p5sound by default
this.panner = new Panner(this.output, this.connection, 1);

if (typeof p5sound.audiocontext.createStereoPanner !== 'undefined') {
this.panner = new Panner();
this.output.connect(this.panner);
} else {
this.panner = new Panner(this.output, this.connection, 1);
}
//array of math operation signal chaining
this.mathOps = [this.output];

Expand Down Expand Up @@ -415,21 +419,20 @@ class Oscillator {
* seconds from now
*/
pan(pval, tFromNow) {
this.panPosition = pval;
this.panner.pan(pval, tFromNow);
}

/**
* Returns the current value of panPosition , between Left (-1) and Right (1)
* Returns the current value of pan position , between Left (-1) and Right (1)
*
* @method getPan
* @for p5.Oscillator
*
* @returns {number} panPosition of oscillator , between Left (-1) and Right (1)
* @returns {number} pan position of oscillator , between Left (-1) and Right (1)
*/

getPan() {
return this.panPosition;
return this.panner.getPan();
}

// get rid of the oscillator
Expand All @@ -442,6 +445,7 @@ class Oscillator {
var now = p5sound.audiocontext.currentTime;
this.stop(now);
this.disconnect();
this.panner.dispose();
this.panner = null;
this.oscillator = null;
}
Expand Down
112 changes: 94 additions & 18 deletions src/panner.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,85 @@
import Effect from './effect.js';

import p5sound from './main';
var ac = p5sound.audiocontext;
var panner;
// Stereo panner
// if there is a stereo panner node use it
if (typeof ac.createStereoPanner !== 'undefined') {
class Panner {
constructor(input, output) {
this.stereoPanner = this.input = ac.createStereoPanner();
input.connect(this.stereoPanner);
this.stereoPanner.connect(output);
/**
* The Panner class allows you to control the stereo
* panning of a sound source. It uses the [StereoPannerNode](https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode),
* which allows you to adjust the balance between the left and right channels of a sound source.
*
* This class extends <a href = "/reference/#/p5.Effect">p5.Effect</a>.
* Methods <a href = "/reference/#/p5.Effect/amp">amp()</a>, <a href = "/reference/#/p5.Effect/chain">chain()</a>,
* <a href = "/reference/#/p5.Effect/drywet">drywet()</a>, <a href = "/reference/#/p5.Effect/connect">connect()</a>, and
* <a href = "/reference/#/p5.Effect/disconnect">disconnect()</a> are available.
*
* @class p5.Panner
* @extends p5.Effect
*/
class Panner extends Effect {
constructor() {
super();
this.stereoPanner = this.ac.createStereoPanner();

this.input.connect(this.stereoPanner);
this.stereoPanner.connect(this.wet);
}

/**
* Set the stereo pan position, a value of -1 means the sound will be fully panned
* to the left, a value of 0 means the sound will be centered, and a value of 1 means
* the sound will be fully panned to the right.
* @method pan
* @for p5.Panner
* @param {Number} value A value between -1 and 1 that sets the pan position.
*
* @param {Number} [time] time in seconds that it will take for the panning to change to the specified value.
*/
pan(val, tFromNow) {
var time = tFromNow || 0;
var t = ac.currentTime + time;

this.stereoPanner.pan.linearRampToValueAtTime(val, t);
if (typeof val === 'number') {
let time = tFromNow || 0;
this.stereoPanner.pan.linearRampToValueAtTime(
val,
this.ac.currentTime + time
);
} else if (typeof val !== 'undefined') {
val.connect(this.stereoPanner.pan);
}
}

//not implemented because stereopanner
//node does not require this and will automatically
//convert single channel or multichannel to stereo.
//tested with single and stereo, not with (>2) multichannel
inputChannels() {}

connect(obj) {
this.stereoPanner.connect(obj);
/**
* Return the current panning value.
*
* @method getPan
* @for p5.Panner
* @return {Number} current panning value, number between -1 (left) and 1 (right).
*/
getPan() {
return this.stereoPanner.pan.value;
}

disconnect() {
/**
* Get rid of the Panner and free up its resources / memory.
*
* @method dispose
* @for p5.Panner
*/
dispose() {
super.dispose();
if (this.stereoPanner) {
this.stereoPanner.disconnect();
delete this.stereoPanner;
}
}

//not implemented because stereopanner
//node does not require this and will automatically
//convert single channel or multichannel to stereo.
//tested with single and stereo, not with (>2) multichannel
inputChannels() {}
}

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

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

// -1 is left, +1 is right
pan(val, tFromNow) {
this.panValue = val;
var time = tFromNow || 0;
var t = ac.currentTime + time;
var v = (val + 1) / 2;
Expand All @@ -79,6 +128,10 @@ if (typeof ac.createStereoPanner !== 'undefined') {
this.right.gain.linearRampToValueAtTime(rightVal, t);
}

getPan() {
return this.panValue;
}

inputChannels(numChannels) {
if (numChannels === 1) {
this.input.disconnect();
Expand All @@ -104,6 +157,29 @@ if (typeof ac.createStereoPanner !== 'undefined') {
this.output.disconnect();
}
}

dispose() {
if (this.input) {
this.input.disconnect();
delete this.input;
}
if (this.output) {
this.output.disconnect();
delete this.output;
}
if (this.left) {
this.left.disconnect();
delete this.left;
}
if (this.right) {
this.right.disconnect();
delete this.right;
}
if (this.splitter) {
this.splitter.disconnect();
delete this.splitter;
}
}
}
panner = Panner;
}
Expand Down
5 changes: 3 additions & 2 deletions src/peakDetect.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,11 @@ class PeakDetect {
this.currentValue = 0;

/**
* isDetected is set to true when a peak is detected.
*
* It returns a boolean indicating whether a peak in the audio frequency spectrum has been detected or not.
* @attribute isDetected {Boolean}
* @default false
* @property {Number} isDetected
* @for p5.PeakDetect
*/
this.isDetected = false;

Expand Down
Loading

0 comments on commit 555bbc8

Please sign in to comment.