feat: configurable band count and frequency range for legacy graphic EQ
- Add Bands/Min Hz/Max Hz controls to legacy EQ section - Dynamic frequency generation with log spacing and auto-scaling Q - Import/export handles variable band counts, Q optional for shelves - Custom presets interpolate across different band counts - Update legacy EQ tutorial for new controls
This commit is contained in:
parent
0cfff0b0b2
commit
91eaa1f1dc
5 changed files with 283 additions and 38 deletions
77
index.html
77
index.html
|
|
@ -4174,6 +4174,54 @@
|
|||
×
|
||||
</button>
|
||||
|
||||
<div
|
||||
class="eq-howto-tab legacy"
|
||||
id="eq-howto-legacy"
|
||||
style="display: none"
|
||||
>
|
||||
<h4>Legacy EQ - Graphic Equalizer</h4>
|
||||
<ol>
|
||||
<li>
|
||||
Set the <b>number of bands</b> (3-32) and
|
||||
<b>frequency range</b> (Min/Max Hz) at the top to
|
||||
customize the equalizer layout.
|
||||
</li>
|
||||
<li>
|
||||
<b>Drag the sliders</b> to boost or cut each frequency
|
||||
band. Bands are spaced logarithmically across your range.
|
||||
</li>
|
||||
<li>
|
||||
Pick a <b>preset</b> (Bass Boost, Rock, Vocal, etc.) as a
|
||||
starting point - presets auto-scale to your band count.
|
||||
</li>
|
||||
<li>
|
||||
Adjust the <b>preamp</b> slider to raise or lower the overall
|
||||
level - reduce it if you hear distortion from large boosts.
|
||||
</li>
|
||||
<li>
|
||||
<b>Save</b> your own custom presets with a name so you can
|
||||
recall them later.
|
||||
</li>
|
||||
<li>
|
||||
<b>Export</b> saves the EQ in EqualizerAPO text format.
|
||||
<b>Export APO</b> saves a GraphicEQ config line you can paste
|
||||
directly into Equalizer APO's config.txt.
|
||||
</li>
|
||||
<li>
|
||||
<b>Import</b> loads EQ settings from EqualizerAPO text files
|
||||
or simple frequency/gain CSV files - points are mapped to
|
||||
your current bands automatically.
|
||||
</li>
|
||||
<li>
|
||||
Click <b>Reset</b> to flatten all bands back to 0 dB.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="eq-howto-tip">
|
||||
Tip: Cut problem frequencies rather than boosting others - it
|
||||
sounds cleaner and avoids clipping.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="eq-howto-tab autoeq" id="eq-howto-autoeq">
|
||||
<h4>AutoEQ - Headphone Correction</h4>
|
||||
<ol>
|
||||
|
|
@ -4297,6 +4345,35 @@
|
|||
|
||||
<!-- Legacy 16-Band Graphic EQ (visible in legacy mode) -->
|
||||
<div class="graphic-eq-section" id="graphic-eq-section" style="display: none">
|
||||
<div class="graphic-eq-config-row">
|
||||
<label>Bands</label>
|
||||
<input
|
||||
type="number"
|
||||
id="legacy-geq-band-count"
|
||||
min="3"
|
||||
max="32"
|
||||
value="16"
|
||||
class="geq-config-input"
|
||||
/>
|
||||
<label>Min Hz</label>
|
||||
<input
|
||||
type="number"
|
||||
id="legacy-geq-freq-min"
|
||||
min="10"
|
||||
max="96000"
|
||||
value="25"
|
||||
class="geq-config-input"
|
||||
/>
|
||||
<label>Max Hz</label>
|
||||
<input
|
||||
type="number"
|
||||
id="legacy-geq-freq-max"
|
||||
min="10"
|
||||
max="96000"
|
||||
value="20000"
|
||||
class="geq-config-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="graphic-eq-preset-row">
|
||||
<label for="legacy-graphic-eq-preset-select" class="graphic-eq-preset-label"
|
||||
>Preset</label
|
||||
|
|
|
|||
|
|
@ -148,13 +148,15 @@ class AudioContextManager {
|
|||
// Callbacks for audio graph changes (for visualizers like Butterchurn)
|
||||
this._graphChangeCallbacks = [];
|
||||
|
||||
// --- Graphic EQ (16-band, separate chain) ---
|
||||
// --- Graphic EQ (configurable bands, separate chain) ---
|
||||
this.geqFilters = [];
|
||||
this.geqPreampNode = null;
|
||||
this.geqOutputNode = null;
|
||||
this.isGraphicEQEnabled = equalizerSettings.isGraphicEqEnabled();
|
||||
this.geqFrequencies = [25, 40, 63, 100, 160, 250, 400, 630, 1000, 1600, 2500, 4000, 6300, 10000, 16000, 20000];
|
||||
this.geqGains = equalizerSettings.getGraphicEqGains();
|
||||
this.geqBandCount = equalizerSettings.getGraphicEqBandCount();
|
||||
this.geqFreqRange = equalizerSettings.getGraphicEqFreqRange();
|
||||
this.geqFrequencies = generateFrequencies(this.geqBandCount, this.geqFreqRange.min, this.geqFreqRange.max);
|
||||
this.geqGains = equalizerSettings.getGraphicEqGains(this.geqBandCount);
|
||||
this.geqPreamp = equalizerSettings.getGraphicEqPreamp();
|
||||
|
||||
// Load saved settings
|
||||
|
|
@ -1090,11 +1092,12 @@ class AudioContextManager {
|
|||
this.geqOutputNode = this.audioContext.createGain();
|
||||
this.geqOutputNode.gain.value = 1;
|
||||
|
||||
const geqQ = 2.5 * Math.sqrt(16 / this.geqBandCount);
|
||||
this.geqFilters = this.geqFrequencies.map((freq, i) => {
|
||||
const filter = this.audioContext.createBiquadFilter();
|
||||
filter.type = 'peaking';
|
||||
filter.frequency.value = freq;
|
||||
filter.Q.value = 2.5; // constant Q for 16-band
|
||||
filter.Q.value = geqQ;
|
||||
filter.gain.value = this.geqGains[i] || 0;
|
||||
return filter;
|
||||
});
|
||||
|
|
@ -1136,7 +1139,7 @@ class AudioContextManager {
|
|||
}
|
||||
|
||||
setGraphicEqBandGain(bandIndex, gainDb) {
|
||||
if (bandIndex < 0 || bandIndex >= 16) return;
|
||||
if (bandIndex < 0 || bandIndex >= this.geqBandCount) return;
|
||||
this.geqGains[bandIndex] = Math.max(-30, Math.min(30, gainDb));
|
||||
if (this.geqFilters[bandIndex] && this.audioContext) {
|
||||
const now = this.audioContext.currentTime;
|
||||
|
|
@ -1149,7 +1152,7 @@ class AudioContextManager {
|
|||
if (!Array.isArray(gains)) return;
|
||||
const now = this.audioContext?.currentTime || 0;
|
||||
gains.forEach((g, i) => {
|
||||
if (i >= 16) return;
|
||||
if (i >= this.geqBandCount) return;
|
||||
this.geqGains[i] = Math.max(-30, Math.min(30, g));
|
||||
if (this.geqFilters[i]) {
|
||||
this.geqFilters[i].gain.setTargetAtTime(this.geqGains[i], now, 0.01);
|
||||
|
|
@ -1158,6 +1161,51 @@ class AudioContextManager {
|
|||
equalizerSettings.setGraphicEqGains([...this.geqGains]);
|
||||
}
|
||||
|
||||
setGraphicEqBandCount(count) {
|
||||
const newCount = Math.max(3, Math.min(32, parseInt(count, 10) || 16));
|
||||
if (newCount === this.geqBandCount) return;
|
||||
|
||||
const oldGains = this.geqGains;
|
||||
this.geqBandCount = newCount;
|
||||
this.geqFrequencies = generateFrequencies(newCount, this.geqFreqRange.min, this.geqFreqRange.max);
|
||||
this.geqGains = equalizerSettings._interpolateGains(oldGains, newCount);
|
||||
|
||||
equalizerSettings.setGraphicEqBandCount(newCount);
|
||||
equalizerSettings.setGraphicEqGains(this.geqGains);
|
||||
|
||||
if (this.isInitialized && this.audioContext) {
|
||||
this._destroyGraphicEQ();
|
||||
this._createGraphicEQ();
|
||||
this._connectGraph();
|
||||
}
|
||||
}
|
||||
|
||||
setGraphicEqFreqRange(minFreq, maxFreq) {
|
||||
const newMin = Math.max(10, Math.min(96000, parseInt(minFreq, 10) || 25));
|
||||
const newMax = Math.max(10, Math.min(96000, parseInt(maxFreq, 10) || 20000));
|
||||
if (newMin >= newMax) return;
|
||||
if (newMin === this.geqFreqRange.min && newMax === this.geqFreqRange.max) return;
|
||||
|
||||
this.geqFreqRange = { min: newMin, max: newMax };
|
||||
this.geqFrequencies = generateFrequencies(this.geqBandCount, newMin, newMax);
|
||||
|
||||
equalizerSettings.setGraphicEqFreqRange(newMin, newMax);
|
||||
|
||||
if (this.isInitialized && this.audioContext) {
|
||||
this._destroyGraphicEQ();
|
||||
this._createGraphicEQ();
|
||||
this._connectGraph();
|
||||
}
|
||||
}
|
||||
|
||||
getGraphicEqFrequencies() {
|
||||
return this.geqFrequencies;
|
||||
}
|
||||
|
||||
getGraphicEqBandCount() {
|
||||
return this.geqBandCount;
|
||||
}
|
||||
|
||||
setGraphicEqPreamp(db) {
|
||||
this.geqPreamp = Math.max(-20, Math.min(20, parseFloat(db) || 0));
|
||||
if (this.geqPreampNode && this.audioContext) {
|
||||
|
|
|
|||
111
js/settings.js
111
js/settings.js
|
|
@ -1236,26 +1236,29 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
}
|
||||
|
||||
// ========================================
|
||||
// 16-Band Graphic Equalizer (Legacy EQ mode)
|
||||
// Graphic Equalizer (Legacy EQ mode) - Configurable Bands
|
||||
// ========================================
|
||||
const GEQ_LABELS = [
|
||||
'25',
|
||||
'40',
|
||||
'63',
|
||||
'100',
|
||||
'160',
|
||||
'250',
|
||||
'400',
|
||||
'630',
|
||||
'1K',
|
||||
'1.6K',
|
||||
'2.5K',
|
||||
'4K',
|
||||
'6.3K',
|
||||
'10K',
|
||||
'16K',
|
||||
'20K',
|
||||
];
|
||||
let geqBandCount = equalizerSettings.getGraphicEqBandCount();
|
||||
let geqFreqRange = equalizerSettings.getGraphicEqFreqRange();
|
||||
|
||||
const formatGeqFreq = (freq) => {
|
||||
if (freq >= 10000) return (freq / 1000).toFixed(0) + 'K';
|
||||
if (freq >= 1000) return (freq / 1000).toFixed(freq % 1000 === 0 ? 0 : 1) + 'K';
|
||||
return freq.toString();
|
||||
};
|
||||
|
||||
const generateGeqFrequencies = (count, min, max) => {
|
||||
const freqs = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const t = i / (count - 1);
|
||||
freqs.push(Math.round(min * Math.pow(max / min, t)));
|
||||
}
|
||||
return freqs;
|
||||
};
|
||||
|
||||
let GEQ_FREQUENCIES = generateGeqFrequencies(geqBandCount, geqFreqRange.min, geqFreqRange.max);
|
||||
let GEQ_LABELS = GEQ_FREQUENCIES.map(formatGeqFreq);
|
||||
|
||||
const geqBandsContainer = document.getElementById('graphic-eq-bands');
|
||||
const geqPreampSlider = document.getElementById('graphic-eq-preamp-slider');
|
||||
const geqPreampValue = document.getElementById('graphic-eq-preamp-value');
|
||||
|
|
@ -1268,11 +1271,15 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
const legacyGeqPresetSelect = document.getElementById('legacy-graphic-eq-preset-select');
|
||||
const legacyGeqResetBtn = document.getElementById('legacy-graphic-eq-reset-btn');
|
||||
|
||||
const geqBandCountInput = document.getElementById('legacy-geq-band-count');
|
||||
const geqFreqMinInput = document.getElementById('legacy-geq-freq-min');
|
||||
const geqFreqMaxInput = document.getElementById('legacy-geq-freq-max');
|
||||
|
||||
const geqPreampSliders = [geqPreampSlider, legacyGeqPreampSlider].filter(Boolean);
|
||||
const geqPreampValues = [geqPreampValue, legacyGeqPreampValue].filter(Boolean);
|
||||
const geqPresetSelects = [geqPresetSelect, legacyGeqPresetSelect].filter(Boolean);
|
||||
|
||||
let geqGains = equalizerSettings.getGraphicEqGains() || new Array(16).fill(0);
|
||||
let geqGains = equalizerSettings.getGraphicEqGains(geqBandCount) || new Array(geqBandCount).fill(0);
|
||||
let geqPreamp = equalizerSettings.getGraphicEqPreamp() || 0;
|
||||
const geqRange = equalizerSettings.getRange();
|
||||
|
||||
|
|
@ -1288,7 +1295,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
});
|
||||
};
|
||||
|
||||
// Build 16 vertical slider bands into a container
|
||||
// Build vertical slider bands into a container
|
||||
const buildGeqBands = (container, idPrefix) => {
|
||||
if (!container) return;
|
||||
container.innerHTML = '';
|
||||
|
|
@ -1359,7 +1366,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
select.addEventListener('change', () => {
|
||||
const key = select.value;
|
||||
if (!key) return;
|
||||
const presets = getPresetsForBandCount(16);
|
||||
const presets = getPresetsForBandCount(geqBandCount);
|
||||
const preset = presets[key];
|
||||
if (!preset) return;
|
||||
geqGains = [...preset.gains];
|
||||
|
|
@ -1375,7 +1382,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
// Wire up reset buttons
|
||||
[geqResetBtn, legacyGeqResetBtn].filter(Boolean).forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
geqGains = new Array(16).fill(0);
|
||||
geqGains = new Array(geqBandCount).fill(0);
|
||||
equalizerSettings.setGraphicEqGains(geqGains);
|
||||
audioContextManager.setGraphicEqAllGains(geqGains);
|
||||
geqSyncAllSliders();
|
||||
|
|
@ -1383,6 +1390,49 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
});
|
||||
});
|
||||
|
||||
// Band count and frequency range controls
|
||||
const rebuildGeq = () => {
|
||||
GEQ_FREQUENCIES = generateGeqFrequencies(geqBandCount, geqFreqRange.min, geqFreqRange.max);
|
||||
GEQ_LABELS = GEQ_FREQUENCIES.map(formatGeqFreq);
|
||||
buildGeqBands(geqBandsContainer, 'geq');
|
||||
buildGeqBands(legacyGeqBandsContainer, 'legacy-geq');
|
||||
geqSyncAllSliders();
|
||||
};
|
||||
|
||||
if (geqBandCountInput) {
|
||||
geqBandCountInput.value = geqBandCount;
|
||||
geqBandCountInput.addEventListener('change', () => {
|
||||
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);
|
||||
geqBandCount = newCount;
|
||||
audioContextManager.setGraphicEqBandCount(newCount);
|
||||
rebuildGeq();
|
||||
geqPresetSelects.forEach((s) => (s.value = ''));
|
||||
});
|
||||
}
|
||||
|
||||
if (geqFreqMinInput && geqFreqMaxInput) {
|
||||
geqFreqMinInput.value = geqFreqRange.min;
|
||||
geqFreqMaxInput.value = geqFreqRange.max;
|
||||
|
||||
const handleFreqRangeChange = () => {
|
||||
const newMin = Math.max(10, Math.min(96000, parseInt(geqFreqMinInput.value, 10) || 25));
|
||||
const newMax = Math.max(10, Math.min(96000, parseInt(geqFreqMaxInput.value, 10) || 20000));
|
||||
geqFreqMinInput.value = newMin;
|
||||
geqFreqMaxInput.value = newMax;
|
||||
if (newMin >= newMax) return;
|
||||
if (newMin === geqFreqRange.min && newMax === geqFreqRange.max) return;
|
||||
geqFreqRange = { min: newMin, max: newMax };
|
||||
audioContextManager.setGraphicEqFreqRange(newMin, newMax);
|
||||
rebuildGeq();
|
||||
};
|
||||
|
||||
geqFreqMinInput.addEventListener('change', handleFreqRangeChange);
|
||||
geqFreqMaxInput.addEventListener('change', handleFreqRangeChange);
|
||||
}
|
||||
|
||||
// Legacy EQ Import / Export
|
||||
const parseGeqLabelFrequency = (label) => {
|
||||
const normalized = String(label).trim().toLowerCase().replace(/\s+/g, '');
|
||||
|
|
@ -1395,7 +1445,6 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
}
|
||||
return Number.parseFloat(withoutHz);
|
||||
};
|
||||
const GEQ_FREQUENCIES = GEQ_LABELS.map((label) => parseGeqLabelFrequency(label));
|
||||
const legacyGeqExportBtn = document.getElementById('legacy-geq-export-btn');
|
||||
const legacyGeqExportCsvBtn = document.getElementById('legacy-geq-export-csv-btn');
|
||||
const legacyGeqImportBtn = document.getElementById('legacy-geq-import-btn');
|
||||
|
|
@ -1405,7 +1454,8 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
legacyGeqExportBtn.addEventListener('click', () => {
|
||||
const lines = [`Preamp: ${geqPreamp.toFixed(1)} dB`];
|
||||
GEQ_FREQUENCIES.forEach((freq, i) => {
|
||||
lines.push(`Filter ${i + 1}: ON PK Fc ${freq} Hz Gain ${geqGains[i].toFixed(1)} dB Q 1.41`);
|
||||
const q = (2.5 * Math.sqrt(16 / geqBandCount)).toFixed(2);
|
||||
lines.push(`Filter ${i + 1}: ON PK Fc ${freq} Hz Gain ${geqGains[i].toFixed(1)} dB Q ${q}`);
|
||||
});
|
||||
const blob = new Blob([lines.join('\n')], { type: 'text/plain' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
|
@ -1484,7 +1534,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
// Sort by frequency
|
||||
validPoints.sort((a, b) => a.freq - b.freq);
|
||||
|
||||
// Map imported points to the 16 GEQ bands using nearest-frequency matching
|
||||
// Map imported points to the GEQ bands using nearest-frequency matching
|
||||
const newGains = GEQ_FREQUENCIES.map((targetFreq) => {
|
||||
// Find the closest imported point by log-frequency distance
|
||||
let closest = validPoints[0];
|
||||
|
|
@ -1608,11 +1658,14 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
const customPresets = getLegacyGeqCustomPresets();
|
||||
if (customPresets[key]) {
|
||||
const gains = customPresets[key]?.gains;
|
||||
if (!Array.isArray(gains) || gains.length !== GEQ_FREQUENCIES.length) {
|
||||
if (!Array.isArray(gains) || gains.length === 0) {
|
||||
updateDeleteBtnVisibility();
|
||||
return;
|
||||
}
|
||||
geqGains = gains.map((g) => {
|
||||
const adjusted = gains.length !== geqBandCount
|
||||
? equalizerSettings._interpolateGains(gains, geqBandCount)
|
||||
: gains;
|
||||
geqGains = adjusted.map((g) => {
|
||||
const n = Number(g);
|
||||
return Number.isFinite(n)
|
||||
? Math.max(parseFloat(geqRange.min), Math.min(parseFloat(geqRange.max), n))
|
||||
|
|
@ -3812,6 +3865,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
const hp = document.getElementById('eq-howto-panel');
|
||||
if (hp && hp.style.display !== 'none') {
|
||||
const tabs = {
|
||||
legacy: document.getElementById('eq-howto-legacy'),
|
||||
autoeq: document.getElementById('eq-howto-autoeq'),
|
||||
parametric: document.getElementById('eq-howto-parametric'),
|
||||
speaker: document.getElementById('eq-howto-speaker'),
|
||||
|
|
@ -3834,6 +3888,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
const howtoPanel = document.getElementById('eq-howto-panel');
|
||||
const howtoClose = document.getElementById('eq-howto-close');
|
||||
const howtoTabs = {
|
||||
legacy: document.getElementById('eq-howto-legacy'),
|
||||
autoeq: document.getElementById('eq-howto-autoeq'),
|
||||
parametric: document.getElementById('eq-howto-parametric'),
|
||||
speaker: document.getElementById('eq-howto-speaker'),
|
||||
|
|
|
|||
|
|
@ -1700,10 +1700,12 @@ export const equalizerSettings = {
|
|||
localStorage.removeItem(this.AUTOEQ_LAST_HEADPHONE_KEY);
|
||||
},
|
||||
|
||||
// --- Graphic EQ (16-band) separate storage ---
|
||||
// --- Graphic EQ separate storage ---
|
||||
GEQ_ENABLED_KEY: 'graphic-eq-enabled',
|
||||
GEQ_GAINS_KEY: 'graphic-eq-gains',
|
||||
GEQ_PREAMP_KEY: 'graphic-eq-preamp',
|
||||
GEQ_BAND_COUNT_KEY: 'graphic-eq-band-count',
|
||||
GEQ_FREQ_RANGE_KEY: 'graphic-eq-freq-range',
|
||||
|
||||
isGraphicEqEnabled() {
|
||||
try {
|
||||
|
|
@ -1721,19 +1723,59 @@ export const equalizerSettings = {
|
|||
}
|
||||
},
|
||||
|
||||
getGraphicEqGains() {
|
||||
getGraphicEqBandCount() {
|
||||
try {
|
||||
const val = localStorage.getItem(this.GEQ_BAND_COUNT_KEY);
|
||||
if (val !== null) {
|
||||
const num = parseInt(val, 10);
|
||||
if (num >= 3 && num <= 32) return num;
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
return 16;
|
||||
},
|
||||
|
||||
setGraphicEqBandCount(count) {
|
||||
try {
|
||||
localStorage.setItem(this.GEQ_BAND_COUNT_KEY, String(count));
|
||||
} catch { /* ignore */ }
|
||||
},
|
||||
|
||||
getGraphicEqFreqRange() {
|
||||
try {
|
||||
const stored = localStorage.getItem(this.GEQ_FREQ_RANGE_KEY);
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
if (parsed && Number.isFinite(parsed.min) && Number.isFinite(parsed.max)) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
return { min: 25, max: 20000 };
|
||||
},
|
||||
|
||||
setGraphicEqFreqRange(min, max) {
|
||||
try {
|
||||
localStorage.setItem(this.GEQ_FREQ_RANGE_KEY, JSON.stringify({ min, max }));
|
||||
} catch { /* ignore */ }
|
||||
},
|
||||
|
||||
getGraphicEqGains(bandCount) {
|
||||
try {
|
||||
const stored = localStorage.getItem(this.GEQ_GAINS_KEY);
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
if (Array.isArray(parsed) && parsed.length === 16) {
|
||||
const expectedCount = bandCount || this.getGraphicEqBandCount();
|
||||
if (Array.isArray(parsed) && parsed.length === expectedCount) {
|
||||
return parsed.map((v) => (Number.isFinite(v) ? v : 0));
|
||||
}
|
||||
if (Array.isArray(parsed) && parsed.length > 0) {
|
||||
return this._interpolateGains(parsed, expectedCount);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return new Array(16).fill(0);
|
||||
return new Array(bandCount || this.getGraphicEqBandCount()).fill(0);
|
||||
},
|
||||
|
||||
setGraphicEqGains(gains) {
|
||||
|
|
|
|||
23
styles.css
23
styles.css
|
|
@ -7902,6 +7902,29 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.graphic-eq-config-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.graphic-eq-config-row label {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.geq-config-input {
|
||||
width: 70px;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid var(--border-color, #444);
|
||||
border-radius: 4px;
|
||||
background: var(--bg-secondary, #222);
|
||||
color: inherit;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.graphic-eq-preset-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
Loading…
Reference in a new issue