Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.0.7 #39

Merged
merged 4 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3377,7 +3377,7 @@ declare class AudioX {
playPrevious(): void;
clearQueue(): void;
removeFromQueue(mediaTrack: MediaTrack): void;
getQueue(): MediaTrack[] | undefined;
getQueue(): MediaTrack[];
get id(): string | null;
static getAudioInstance(): HTMLAudioElement;
}
Expand Down
4 changes: 2 additions & 2 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "audio_x",
"version": "1.0.6",
"version": "1.0.7",
"description": "The audio player for the gen-x",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand All @@ -20,7 +20,8 @@
"equalizer",
"web-audio",
"audio_x",
"howlerjs"
"howler.js",
"soundmanager"
],
"author": "Ashish Kumar",
"license": "MIT",
Expand Down
129 changes: 92 additions & 37 deletions src/adapters/equalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,65 @@ class Equalizer {
private audioCtx: AudioContext;
private audioCtxStatus: EqualizerStatus;
private eqFilterBands: BiquadFilterNode[];
private readonly MAX_GAIN_SUM: number = 12; // Maximum sum of gains to avoid distortion

/**
* Creates an instance of Equalizer or returns the existing instance.
*/
constructor() {
if (Equalizer._instance) {
console.warn(
'Instantiation failed: cannot create multiple instance of Equalizer returning existing instance'
'Instantiation failed: cannot create multiple instances of Equalizer. Returning existing instance.'
);
return Equalizer._instance;
}

if (this.audioCtx === undefined && typeof AudioContext !== 'undefined') {
if (typeof AudioContext !== 'undefined') {
this.audioCtx = new AudioContext();
this.audioCtxStatus = 'ACTIVE';
this.init();
} else if (typeof (window as any).webkitAudioContext !== 'undefined') {
this.audioCtx = new (window as any).webkitAudioContext();
this.audioCtxStatus = 'ACTIVE';
this.init();
} else {
throw new Error('Web Audio API is not supported in this browser.');
}
this.initializeAudioContext();

Equalizer._instance = this;
}

/**
* Initializes the AudioContext, ensuring compatibility with older browsers.
* @private
*/
private initializeAudioContext() {
if (typeof AudioContext !== 'undefined') {
this.audioCtx = new AudioContext();
} else if (typeof (window as any).webkitAudioContext !== 'undefined') {
this.audioCtx = new (window as any).webkitAudioContext();
} else {
console.log('Equalizer not initialized, AudioContext failed');
this.audioCtxStatus = 'FAILED';
console.error('Web Audio API is not supported in this browser.');
}

// context state at this time is `undefined` in iOS8 Safari
if (
this.audioCtxStatus === 'ACTIVE' &&
this.audioCtx.state === 'suspended'
) {
var resume = () => {
this.audioCtx.resume();
setTimeout(() => {
if (this.audioCtx.state === 'running') {
document.body.removeEventListener('click', resume, false);
}
}, 0);
};

document.body.addEventListener('click', resume, false);
this.audioCtxStatus = 'ACTIVE';
this.init();

if (this.audioCtx.state === 'suspended') {
this.addResumeListener();
}
}

Equalizer._instance = this;
/**
* Adds a listener to resume the AudioContext on user interaction.
* @private
*/
private addResumeListener() {
const resume = () => {
this.audioCtx.resume();
setTimeout(() => {
if (this.audioCtx.state === 'running') {
document.body.removeEventListener('click', resume, false);
}
}, 0);
};

document.body.addEventListener('click', resume, false);
}

/**
* Initializes the equalizer by setting up the audio source and filter bands.
*/
init() {
try {
const audioInstance = AudioX.getAudioInstance();
Expand All @@ -70,7 +83,7 @@ class Equalizer {
});

const gainNode = this.audioCtx.createGain();
gainNode.gain.value = 1; //Normalize sound output
gainNode.gain.value = 1; // TODO: Normalize sound output

audioSource.connect(equalizerBands[0]);

Expand All @@ -84,41 +97,83 @@ class Equalizer {
this.audioCtxStatus = 'ACTIVE';
this.eqFilterBands = equalizerBands;
} catch (error) {
console.error('Equalizer initialization failed:', error);
this.audioCtxStatus = 'FAILED';
}
}

/**
* Sets the equalizer to a predefined preset.
* @param {keyof Preset} id - The ID of the preset to apply.
*/
setPreset(id: keyof Preset) {
const preset = presets.find((el) => el.id === id);
console.log({ preset });
if (!preset) {
console.error('Preset not found:', id);
return;
}

if (
!this.eqFilterBands ||
this.eqFilterBands.length !== preset?.gains.length
this.eqFilterBands.length !== preset.gains.length
) {
console.error('Invalid data provided.');
return;
}
for (let i = 0; i < this.eqFilterBands.length; i++) {
this.eqFilterBands[i].gain.value = preset?.gains[i];

const normalizedGains = this.normalizeGains(preset.gains);

this.eqFilterBands.forEach((band, index) => {
band.gain.value = normalizedGains[index];
});
}

/**
* Normalizes the gain values to avoid distortion.
* @param {number[]} gains - The gain values to normalize.
* @returns {number[]} The normalized gain values.
* @private
*/
private normalizeGains(gains: number[]): number[] {
const gainSum = gains.reduce((sum, gain) => sum + Math.abs(gain), 0);
if (gainSum > this.MAX_GAIN_SUM) {
const scale = this.MAX_GAIN_SUM / gainSum;
return gains.map((gain) => gain * scale);
}
return gains;
}

/**
* Retrieves the list of available presets.
* @returns {Preset[]} The list of available presets.
*/
static getPresets() {
return presets;
}

/**
* Gets the current status of the AudioContext.
* @returns {EqualizerStatus} The current status of the AudioContext.
*/
status() {
if (this.audioCtx.state === 'suspended') {
this.audioCtx.resume();
}
return this.audioCtxStatus;
}

/**
* Sets a custom equalizer configuration.
* @param {number[]} gains - The gain values for each band.
*/
setCustomEQ(gains: number[]) {
if (isValidArray(gains)) {
const normalizedGains = this.normalizeGains(gains);
this.eqFilterBands.forEach((band: BiquadFilterNode, index: number) => {
band.gain.value = gains[index];
band.gain.value = normalizedGains[index];
});
} else {
console.error('Invalid array of gains provided.');
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,7 @@ class AudioX {
}

getQueue() {
if (this._queue && this._queue.length) {
return this._queue;
}
return this._queue && isValidArray(this._queue) ? this._queue : [];
}

get id() {
Expand Down
Loading