fix: address CodeRabbit review - shelf Q round-trip, IIR gain setters, import persistence, tooltip sum

This commit is contained in:
tryptz 2026-04-07 00:15:32 -04:00 committed by edideaur
parent 91eaa1f1dc
commit 55b49cc77a
3 changed files with 59 additions and 36 deletions

View file

@ -718,6 +718,23 @@ class AudioContextManager {
/**
* Set gain for a specific band
*/
/**
* Replace an IIR shelf filter node with updated coefficients and reconnect the chain.
*/
_replaceShelfFilter(index) {
const filter = this.filters[index];
if (!filter?._shelfType || !this.audioContext) return;
const type = this.currentTypes?.[index] || filter._shelfType;
const freq = this.frequencies[index];
const gain = this.currentGains[index] || 0;
const q = this.currentQs?.[index] > 0 ? this.currentQs[index] : this._calculateQ(index);
const coeffs = computeShelfCoefficients(type, freq, gain, q, this.audioContext.sampleRate);
const iir = this.audioContext.createIIRFilter(coeffs.feedforward, coeffs.feedback);
iir._shelfType = type;
try { filter.disconnect(); } catch { /* ignore */ }
this.filters[index] = iir;
}
setBandGain(bandIndex, gainDb) {
if (bandIndex < 0 || bandIndex >= this.bandCount) return;
@ -725,8 +742,13 @@ class AudioContextManager {
this.currentGains[bandIndex] = clampedGain;
if (this.filters[bandIndex] && this.audioContext) {
const now = this.audioContext.currentTime;
this.filters[bandIndex].gain.setTargetAtTime(clampedGain, now, 0.01);
if (this.filters[bandIndex]._shelfType) {
this._replaceShelfFilter(bandIndex);
this._connectGraph();
} else {
const now = this.audioContext.currentTime;
this.filters[bandIndex].gain.setTargetAtTime(clampedGain, now, 0.01);
}
}
equalizerSettings.setGains(this.currentGains);
@ -745,16 +767,26 @@ class AudioContextManager {
}
const now = this.audioContext?.currentTime || 0;
let needsReconnect = false;
adjustedGains.forEach((gain, index) => {
const clampedGain = this._clampGain(gain);
this.currentGains[index] = clampedGain;
if (this.filters[index]) {
this.filters[index].gain.setTargetAtTime(clampedGain, now, 0.01);
if (this.filters[index]._shelfType) {
this._replaceShelfFilter(index);
needsReconnect = true;
} else {
this.filters[index].gain.setTargetAtTime(clampedGain, now, 0.01);
}
}
});
if (needsReconnect) {
this._connectGraph();
}
equalizerSettings.setGains(this.currentGains);
}
@ -949,15 +981,9 @@ class AudioContextManager {
sortedBands.forEach((band, index) => {
if (index >= count) return;
const filterType = band.type === 'lowshelf' ? 'LSC' : band.type === 'highshelf' ? 'HSC' : 'PK';
if (band.type === 'lowshelf' || band.type === 'highshelf') {
lines.push(
`Filter ${index + 1}: ON ${filterType} Fc ${newFrequencies[index]} Hz Gain ${newGains[index].toFixed(1)} dB`
);
} else {
lines.push(
`Filter ${index + 1}: ON ${filterType} Fc ${newFrequencies[index]} Hz Gain ${newGains[index].toFixed(1)} dB Q ${newQs[index].toFixed(2)}`
);
}
lines.push(
`Filter ${index + 1}: ON ${filterType} Fc ${newFrequencies[index]} Hz Gain ${newGains[index].toFixed(1)} dB Q ${newQs[index].toFixed(2)}`
);
});
return lines.join('\n');
@ -976,17 +1002,11 @@ class AudioContextManager {
const gain = this.currentGains[index] || 0;
const type = (this.currentTypes && this.currentTypes[index]) || 'peaking';
const filterType = type === 'lowshelf' ? 'LSC' : type === 'highshelf' ? 'HSC' : 'PK';
const q = this.currentQs && this.currentQs[index] > 0 ? this.currentQs[index] : this._calculateQ(index);
const filterNum = index + 1;
if (type === 'lowshelf' || type === 'highshelf') {
lines.push(
`Filter ${filterNum}: ON ${filterType} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB`
);
} else {
const q = this.currentQs && this.currentQs[index] > 0 ? this.currentQs[index] : this._calculateQ(index);
lines.push(
`Filter ${filterNum}: ON ${filterType} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB Q ${q.toFixed(2)}`
);
}
lines.push(
`Filter ${filterNum}: ON ${filterType} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB Q ${q.toFixed(2)}`
);
});
return lines.join('\n');
@ -1067,7 +1087,8 @@ class AudioContextManager {
this._connectGraph();
}
// Persist all band settings
// Persist all band settings including custom frequencies
equalizerSettings.setCustomFrequencies(this.frequencies);
equalizerSettings.setGains(this.currentGains);
equalizerSettings.setBandTypes(this.currentTypes);
equalizerSettings.setBandQs(this.currentQs);

View file

@ -625,13 +625,9 @@ export class Equalizer {
const type = filter ? filter.type : 'peaking';
const typeMap = { peaking: 'PK', lowshelf: 'LSC', highshelf: 'HSC' };
const typeStr = typeMap[type] || 'PK';
const q = filter && !filter._shelfType ? filter.Q.value : this._calculateQ(index);
const filterNum = index + 1;
if (type === 'lowshelf' || type === 'highshelf') {
lines.push(`Filter ${filterNum}: ON ${typeStr} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB`);
} else {
const q = filter ? filter.Q.value : this._calculateQ(index);
lines.push(`Filter ${filterNum}: ON ${typeStr} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB Q ${q.toFixed(2)}`);
}
lines.push(`Filter ${filterNum}: ON ${typeStr} Fc ${freq} Hz Gain ${gain.toFixed(1)} dB Q ${q.toFixed(2)}`);
});
return lines.join('\n');

View file

@ -2210,17 +2210,23 @@ export async function initializeSettings(scrobbler, player, api, ui) {
// Show tooltip on drag
if (isDragged) {
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,0.8)';
const txt = `${Math.round(band.freq)} Hz ${band.gain > 0 ? '+' : ''}${band.gain.toFixed(1)} dB Q${band.q.toFixed(2)}`;
ctx.font = 'bold 11px system-ui, sans-serif';
const tw = ctx.measureText(txt).width + 12;
const tx = Math.min(x - tw / 2, rect.width - tw - 5);
const ty = y - 28;
ctx.fillRect(tx, ty, tw, 20);
const line1 = `${Math.round(band.freq)} Hz ${band.gain > 0 ? '+' : ''}${band.gain.toFixed(1)} dB Q${band.q.toFixed(2)}`;
const line2 = `Sum: ${nodeGain > 0 ? '+' : ''}${nodeGain.toFixed(1)} dB`;
const tw1 = ctx.measureText(line1).width;
const tw2 = ctx.measureText(line2).width;
const tw = Math.max(tw1, tw2) + 12;
const th = 34;
const tx = Math.max(5, Math.min(x - tw / 2, rect.width - tw - 5));
const ty = y - 44;
ctx.fillStyle = 'rgba(0,0,0,0.8)';
ctx.fillRect(tx, ty, tw, th);
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(txt, tx + tw / 2, ty + 10);
ctx.fillText(line1, tx + tw / 2, ty + 10);
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.fillText(line2, tx + tw / 2, ty + 24);
ctx.restore();
}
});