fix: resolve remaining PR #523 review issues

Guard generateFrequencies against bandCount=1 division by zero, fix
inverted HRTF ITD delays for left-side sources, remove unused variable,
promote _interpolateGains to public API, and add NaN guard to widening.
This commit is contained in:
tryptz 2026-04-07 12:19:24 -04:00 committed by edideaur
parent 589504d7fd
commit 8c9a613bee
5 changed files with 22 additions and 15 deletions

View file

@ -12,6 +12,12 @@ function generateFrequencies(bandCount, minFreq = 20, maxFreq = 20000) {
const safeMin = Math.max(10, minFreq);
const safeMax = Math.min(96000, maxFreq);
if (bandCount <= 1) {
// Single band: use geometric mean of range
frequencies.push(Math.round(Math.sqrt(safeMin * safeMax)));
return frequencies;
}
for (let i = 0; i < bandCount; i++) {
// Logarithmic interpolation
const t = i / (bandCount - 1);
@ -175,7 +181,7 @@ class AudioContextManager {
this.frequencies = generateFrequencies(newCount, this.freqRange.min, this.freqRange.max);
// Interpolate current gains to new band count
const newGains = equalizerSettings._interpolateGains(this.currentGains, newCount);
const newGains = equalizerSettings.interpolateGains(this.currentGains, newCount);
this.currentGains = newGains;
equalizerSettings.setGains(newGains);
@ -1079,7 +1085,7 @@ class AudioContextManager {
// Ensure gains array matches current band count
let adjustedGains = gains;
if (gains.length !== this.bandCount) {
adjustedGains = equalizerSettings._interpolateGains(gains, this.bandCount);
adjustedGains = equalizerSettings.interpolateGains(gains, this.bandCount);
}
const now = this.audioContext?.currentTime || 0;
@ -1535,7 +1541,7 @@ class AudioContextManager {
const oldGains = this.geqGains;
this.geqBandCount = newCount;
this.geqFrequencies = generateFrequencies(newCount, this.geqFreqRange.min, this.geqFreqRange.max);
this.geqGains = equalizerSettings._interpolateGains(oldGains, newCount);
this.geqGains = equalizerSettings.interpolateGains(oldGains, newCount);
equalizerSettings.setGraphicEqBandCount(newCount);
equalizerSettings.setGraphicEqGains(this.geqGains);

View file

@ -201,7 +201,7 @@ export class Equalizer {
this.frequencyLabels = generateFrequencyLabels(this.frequencies);
// Interpolate current gains to new band count
const newGains = equalizerSettings._interpolateGains(this.currentGains, newCount);
const newGains = equalizerSettings.interpolateGains(this.currentGains, newCount);
this.currentGains = newGains;
equalizerSettings.setGains(newGains);
@ -455,7 +455,7 @@ export class Equalizer {
// Ensure gains array matches current band count
let adjustedGains = gains;
if (gains.length !== this.bandCount) {
adjustedGains = equalizerSettings._interpolateGains(gains, this.bandCount);
adjustedGains = equalizerSettings.interpolateGains(gains, this.bandCount);
}
const now = this.audioContext?.currentTime || 0;

View file

@ -65,8 +65,9 @@ export function generateHRTF(audioContext, azimuthDeg, elevationDeg = 0) {
const contraData = sourceOnRight ? leftData : rightData;
// Generate ipsilateral (near ear) IR — mostly a delayed impulse with slight coloring
const ipsiDelay = Math.max(0, sourceOnRight ? 0 : itdSamples);
const contraDelay = Math.max(0, sourceOnRight ? itdSamples : 0);
// Ipsilateral ear (near source) receives sound first; contralateral ear is delayed by ITD
const ipsiDelay = 0;
const contraDelay = Math.abs(itdSamples);
// Create frequency-domain representation for head shadow
const fftSize = IR_LENGTH;

View file

@ -1512,7 +1512,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
const newCount = Math.max(3, Math.min(32, parseInt(geqBandCountInput.value, 10) || 16));
geqBandCountInput.value = newCount;
if (newCount === geqBandCount) return;
geqGains = equalizerSettings._interpolateGains(geqGains, newCount);
geqGains = equalizerSettings.interpolateGains(geqGains, newCount);
geqBandCount = newCount;
equalizerSettings.setGraphicEqGains(geqGains);
audioContextManager.setGraphicEqBandCount(newCount);
@ -1778,7 +1778,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
return;
}
const adjusted =
gains.length !== geqBandCount ? equalizerSettings._interpolateGains(gains, geqBandCount) : gains;
gains.length !== geqBandCount ? equalizerSettings.interpolateGains(gains, geqBandCount) : gains;
geqGains = adjusted.map((g) => {
const n = Number(g);
return Number.isFinite(n)
@ -2446,7 +2446,6 @@ export async function initializeSettings(scrobbler, player, api, ui) {
else if (meas) graphShift = 75 - getNormalizationOffset(meas);
}
const sampleRate = autoeqSampleRate ? parseInt(autoeqSampleRate.value, 10) : 48000;
let closest = -1,
closestDist = Infinity;
activeBands.forEach((band, i) => {

View file

@ -1329,7 +1329,7 @@ export const equalizerSettings = {
}
// If different band count, try to interpolate or return flat
if (gains.length > 0) {
return this._interpolateGains(gains, count);
return this.interpolateGains(gains, count);
}
}
}
@ -1425,7 +1425,7 @@ export const equalizerSettings = {
}
// Interpolate stored Qs to match requested band count instead of discarding
if (Array.isArray(qs) && qs.length >= this.MIN_BANDS) {
return this._interpolateGains(qs, count);
return this.interpolateGains(qs, count);
}
}
} catch {
@ -1473,7 +1473,7 @@ export const equalizerSettings = {
/**
* Interpolate gains array to match target band count
*/
_interpolateGains(sourceGains, targetCount) {
interpolateGains(sourceGains, targetCount) {
if (sourceGains.length === targetCount) {
return [...sourceGains];
}
@ -1808,7 +1808,7 @@ export const equalizerSettings = {
return parsed.map((v) => (Number.isFinite(v) ? v : 0));
}
if (Array.isArray(parsed) && parsed.length > 0) {
return this._interpolateGains(parsed, expectedCount);
return this.interpolateGains(parsed, expectedCount);
}
}
} catch {
@ -1944,7 +1944,8 @@ export const binauralDspSettings = {
setWideningAmount(amount) {
const all = this._getAll();
all.wideningAmount = Math.max(0, Math.min(2, amount));
const n = Number(amount);
all.wideningAmount = Number.isFinite(n) ? Math.max(0, Math.min(2, n)) : 1.0;
this._setAll(all);
},