From 77f9e10fdc55a47a5bebf766e521d250813e00eb Mon Sep 17 00:00:00 2001 From: tryptz <216453278+tryptz@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:57:22 +0000 Subject: [PATCH] style: auto-fix linting issues --- js/autoeq-data.js | 14 +++--- js/autoeq-engine.js | 92 ++++++++++++++++++++++------------ js/autoeq-importer.js | 112 ++++++++++++++++++++++++++++++++++-------- styles.css | 5 ++ 4 files changed, 164 insertions(+), 59 deletions(-) diff --git a/js/autoeq-data.js b/js/autoeq-data.js index 784fbfb..e9015c7 100644 --- a/js/autoeq-data.js +++ b/js/autoeq-data.js @@ -2,7 +2,6 @@ // Target Curves & Data Parser - Ported from Seap Engine // Contains target frequency response curves and raw data parser - // Raw content synchronized with features/autoeq/Targets/ directory const RAW_HARMAN_OE_2018 = ` @@ -2713,7 +2712,6 @@ const RAW_HIFI_ENDGAME_2026_MKII = ` 20000.00 72.378 `; - const RAW_PEQDB_ULTRA = ` 20.00 83.153 20.36 83.149 @@ -3487,7 +3485,6 @@ const RAW_PEQDB_DIAMOND_BETA = ` 20000.00 72.028 `; - const RAW_SEAP = ` 20.00 82.982 20.36 82.975 @@ -4301,7 +4298,6 @@ const RAW_FLAT_LINE = ` 20000.00 75.000 `; - // --- PARSER --- /** * Parse raw frequency/gain text data into [{freq, gain}] arrays @@ -4331,15 +4327,17 @@ function parseRawData(raw) { const hasHeader = /[a-zA-Z]/.test(firstLine); if (hasHeader) { - const headers = firstLine.split(delimiter).map(h => h.trim().toLowerCase().replace(/['"]+/g, '')); - const fIdx = headers.findIndex(h => h.includes('freq') || h === 'f'); + const headers = firstLine.split(delimiter).map((h) => h.trim().toLowerCase().replace(/['"]+/g, '')); + const fIdx = headers.findIndex((h) => h.includes('freq') || h === 'f'); if (fIdx > -1) freqIdx = fIdx; - const rIdx = headers.findIndex(h => h === 'raw'); + const rIdx = headers.findIndex((h) => h === 'raw'); if (rIdx > -1) { gainIdx = rIdx; } else { - const splIdx = headers.findIndex(h => h.includes('spl') || h.includes('gain') || h.includes('db') || h.includes('mag')); + const splIdx = headers.findIndex( + (h) => h.includes('spl') || h.includes('gain') || h.includes('db') || h.includes('mag') + ); if (splIdx > -1 && splIdx !== freqIdx) gainIdx = splIdx; } } diff --git a/js/autoeq-engine.js b/js/autoeq-engine.js index 6a9fa7f..d7b7a5c 100644 --- a/js/autoeq-engine.js +++ b/js/autoeq-engine.js @@ -21,42 +21,55 @@ const DB_DIVISOR = 40; function calculateBiquadResponse(f, band, sr = DEFAULT_SR) { if (!band.enabled) return 0; if (!band.type || band.type.length === 0) return 0; - const w = 2 * PI * band.freq / sr; - const p = 2 * PI * f / sr; + const w = (2 * PI * band.freq) / sr; + const p = (2 * PI * f) / sr; const s = Math.sin(w) / (2 * band.q); const A = Math.pow(DB_BASE, band.gain / DB_DIVISOR); const c = Math.cos(w); - let b0 = 0, b1 = 0, b2 = 0, a0 = 0, a1 = 0, a2 = 0; + let b0 = 0, + b1 = 0, + b2 = 0, + a0 = 0, + a1 = 0, + a2 = 0; const t = band.type[0]; if (t === 'p') { - b0 = 1 + s * A; b1 = -2 * c; b2 = 1 - s * A; - a0 = 1 + s / A; a1 = -2 * c; a2 = 1 - s / A; + b0 = 1 + s * A; + b1 = -2 * c; + b2 = 1 - s * A; + a0 = 1 + s / A; + a1 = -2 * c; + a2 = 1 - s / A; } else if (t === 'l') { const sq = 2 * Math.sqrt(A) * s; - b0 = A * ((A + 1) - (A - 1) * c + sq); - b1 = 2 * A * ((A - 1) - (A + 1) * c); - b2 = A * ((A + 1) - (A - 1) * c - sq); - a0 = (A + 1) + (A - 1) * c + sq; - a1 = -2 * ((A - 1) + (A + 1) * c); - a2 = (A + 1) + (A - 1) * c - sq; + b0 = A * (A + 1 - (A - 1) * c + sq); + b1 = 2 * A * (A - 1 - (A + 1) * c); + b2 = A * (A + 1 - (A - 1) * c - sq); + a0 = A + 1 + (A - 1) * c + sq; + a1 = -2 * (A - 1 + (A + 1) * c); + a2 = A + 1 + (A - 1) * c - sq; } else if (t === 'h') { const sq = 2 * Math.sqrt(A) * s; - b0 = A * ((A + 1) + (A - 1) * c + sq); - b1 = -2 * A * ((A - 1) + (A + 1) * c); - b2 = A * ((A + 1) + (A - 1) * c - sq); - a0 = (A + 1) - (A - 1) * c + sq; - a1 = 2 * ((A - 1) - (A + 1) * c); - a2 = (A + 1) - (A - 1) * c - sq; + b0 = A * (A + 1 + (A - 1) * c + sq); + b1 = -2 * A * (A - 1 + (A + 1) * c); + b2 = A * (A + 1 + (A - 1) * c - sq); + a0 = A + 1 - (A - 1) * c + sq; + a1 = 2 * (A - 1 - (A + 1) * c); + a2 = A + 1 - (A - 1) * c - sq; } else { return 0; } const _a0 = 1 / a0; - const b0n = b0 * _a0, b1n = b1 * _a0, b2n = b2 * _a0; - const a1n = a1 * _a0, a2n = a2 * _a0; - const cp = Math.cos(p), c2p = Math.cos(2 * p); + const b0n = b0 * _a0, + b1n = b1 * _a0, + b2n = b2 * _a0; + const a1n = a1 * _a0, + a2n = a2 * _a0; + const cp = Math.cos(p), + c2p = Math.cos(2 * p); const n = b0n * b0n + b1n * b1n + b2n * b2n + 2 * (b0n * b1n + b1n * b2n) * cp + 2 * b0n * b2n * c2p; const d = 1 + a1n * a1n + a2n * a2n + 2 * (a1n + a1n * a2n) * cp + 2 * a2n * c2p; return 10 * Math.log10(n / d); @@ -74,7 +87,10 @@ function interpolate(freq, data) { if (freq >= data[data.length - 1].freq) return data[data.length - 1].gain; for (let i = 0; i < data.length - 1; i++) { if (freq >= data[i].freq && freq <= data[i + 1].freq) { - return data[i].gain + (freq - data[i].freq) / (data[i + 1].freq - data[i].freq) * (data[i + 1].gain - data[i].gain); + return ( + data[i].gain + + ((freq - data[i].freq) / (data[i + 1].freq - data[i].freq)) * (data[i + 1].gain - data[i].gain) + ); } } return 0; @@ -86,7 +102,8 @@ function interpolate(freq, data) { * @returns {number} Average gain in midrange */ function getNormalizationOffset(data) { - let sum = 0, count = 0; + let sum = 0, + count = 0; for (const p of data) { if (p.freq >= 250 && p.freq <= 2500) { sum += p.gain; @@ -108,18 +125,29 @@ function getNormalizationOffset(data) { * @param {number} maxQ - Maximum Q factor * @returns {Array<{id: number, type: string, freq: number, gain: number, q: number, enabled: boolean}>} */ -function runAutoEqAlgorithm(measurement, target, bandCount, maxFreq = 16000, minFreq = 20, maxQ = 5.0, sampleRate = DEFAULT_SR) { +function runAutoEqAlgorithm( + measurement, + target, + bandCount, + maxFreq = 16000, + minFreq = 20, + maxQ = 5.0, + sampleRate = DEFAULT_SR +) { if (minFreq > maxFreq) return []; const off = getNormalizationOffset(target) - getNormalizationOffset(measurement); - let err = measurement.map(p => ({ freq: p.freq, gain: (p.gain + off) - interpolate(p.freq, target) })); + let err = measurement.map((p) => ({ freq: p.freq, gain: p.gain + off - interpolate(p.freq, target) })); - const hasInRangePoints = err.some(p => p.freq >= minFreq && p.freq <= maxFreq); + const hasInRangePoints = err.some((p) => p.freq >= minFreq && p.freq <= maxFreq); if (!hasInRangePoints) return []; const out = []; for (let i = 0; i < bandCount; i++) { - let maxDev = 0, maxWeightedDev = 0, peakFreq = 1000, peakIdx = 0; + let maxDev = 0, + maxWeightedDev = 0, + peakFreq = 1000, + peakIdx = 0; // Scan for maximum weighted error for (let j = 0; j < err.length; j++) { @@ -158,8 +186,10 @@ function runAutoEqAlgorithm(measurement, target, bandCount, maxFreq = 16000, min if (Math.abs(gain) < 0.2) break; // Q factor calculation from error bandwidth (half-gain points) - let upperFreq = peakFreq, lowerFreq = peakFreq; - let foundLower = false, foundUpper = false; + let upperFreq = peakFreq, + lowerFreq = peakFreq; + let foundLower = false, + foundUpper = false; const thresholdError = maxDev / 2; for (let k = peakIdx; k >= 0; k--) { if (Math.abs(err[k].gain) < Math.abs(thresholdError)) { @@ -179,9 +209,9 @@ function runAutoEqAlgorithm(measurement, target, bandCount, maxFreq = 16000, min // If half-gain boundary not found on one side, mirror the other side // to avoid degenerate bandwidth = 0 producing extremely narrow filters if (!foundLower && foundUpper) { - lowerFreq = peakFreq * peakFreq / upperFreq; + lowerFreq = (peakFreq * peakFreq) / upperFreq; } else if (!foundUpper && foundLower) { - upperFreq = peakFreq * peakFreq / lowerFreq; + upperFreq = (peakFreq * peakFreq) / lowerFreq; } else if (!foundLower && !foundUpper) { // Neither boundary found — use 1 octave default lowerFreq = peakFreq / Math.SQRT2; @@ -212,7 +242,7 @@ function runAutoEqAlgorithm(measurement, target, bandCount, maxFreq = 16000, min out.push(newBand); // Update error curve by applying the new band's response - err = err.map(p => ({ ...p, gain: p.gain + calculateBiquadResponse(p.freq, newBand, sampleRate) })); + err = err.map((p) => ({ ...p, gain: p.gain + calculateBiquadResponse(p.freq, newBand, sampleRate) })); } return out.sort((a, b) => a.freq - b.freq).map((b, i) => ({ ...b, id: i })); diff --git a/js/autoeq-importer.js b/js/autoeq-importer.js index 0cd1cf0..5a5d798 100644 --- a/js/autoeq-importer.js +++ b/js/autoeq-importer.js @@ -12,23 +12,83 @@ const CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24 hours // 5 most popular headphones — pre-loaded as defaults and shown in the headphone select // All measured on Rtings B&K 5128 rig for consistency const POPULAR_HEADPHONES = [ - { name: 'Sony WH-1000XM5 (Rtings)', type: 'over-ear', path: 'Rtings/Bruel & Kjaer 5128 over-ear/Sony WH-1000XM5', fileName: 'Sony WH-1000XM5.csv' }, - { name: 'Apple AirPods Pro2 (Rtings)', type: 'in-ear', path: 'Rtings/Bruel & Kjaer 5128 in-ear/Apple AirPods Pro2', fileName: 'Apple AirPods Pro2.csv' }, - { name: 'Sony WF-1000XM5 (Rtings)', type: 'in-ear', path: 'Rtings/Bruel & Kjaer 5128 in-ear/Sony WF-1000XM5', fileName: 'Sony WF-1000XM5.csv' }, - { name: 'Samsung Galaxy Buds3 Pro (Rtings)', type: 'in-ear', path: 'Rtings/Bruel & Kjaer 5128 in-ear/Samsung Galaxy Buds3 Pro', fileName: 'Samsung Galaxy Buds3 Pro.csv' }, - { name: 'Sennheiser HD 600 (Rtings)', type: 'over-ear', path: 'Rtings/Bruel & Kjaer 5128 over-ear/Sennheiser HD 600', fileName: 'Sennheiser HD 600.csv' }, + { + name: 'Sony WH-1000XM5 (Rtings)', + type: 'over-ear', + path: 'Rtings/Bruel & Kjaer 5128 over-ear/Sony WH-1000XM5', + fileName: 'Sony WH-1000XM5.csv', + }, + { + name: 'Apple AirPods Pro2 (Rtings)', + type: 'in-ear', + path: 'Rtings/Bruel & Kjaer 5128 in-ear/Apple AirPods Pro2', + fileName: 'Apple AirPods Pro2.csv', + }, + { + name: 'Sony WF-1000XM5 (Rtings)', + type: 'in-ear', + path: 'Rtings/Bruel & Kjaer 5128 in-ear/Sony WF-1000XM5', + fileName: 'Sony WF-1000XM5.csv', + }, + { + name: 'Samsung Galaxy Buds3 Pro (Rtings)', + type: 'in-ear', + path: 'Rtings/Bruel & Kjaer 5128 in-ear/Samsung Galaxy Buds3 Pro', + fileName: 'Samsung Galaxy Buds3 Pro.csv', + }, + { + name: 'Sennheiser HD 600 (Rtings)', + type: 'over-ear', + path: 'Rtings/Bruel & Kjaer 5128 over-ear/Sennheiser HD 600', + fileName: 'Sennheiser HD 600.csv', + }, ]; // Static fallback list in case GitHub API fails — popular picks + additional well-known models const FALLBACK_INDEX = [ ...POPULAR_HEADPHONES, - { name: 'Sennheiser HD 600 (Filk)', type: 'over-ear', path: 'Filk/over-ear/Sennheiser HD 600', fileName: 'Sennheiser HD 600.csv' }, - { name: 'Sennheiser HD 600 (Innerfidelity)', type: 'over-ear', path: 'Innerfidelity/over-ear/Sennheiser HD 600', fileName: 'Sennheiser HD 600.csv' }, - { name: 'Samsung Galaxy Buds2 Pro (Rtings)', type: 'in-ear', path: 'Rtings/Bruel & Kjaer 5128 in-ear/Samsung Galaxy Buds2 Pro', fileName: 'Samsung Galaxy Buds2 Pro.csv' }, - { name: 'Sony WF-1000XM5 (Kazi)', type: 'in-ear', path: 'Kazi/in-ear/Sony WF-1000XM5', fileName: 'Sony WF-1000XM5.csv' }, - { name: 'Samsung Galaxy Buds3 Pro (DHRME)', type: 'in-ear', path: 'DHRME/in-ear/Samsung Galaxy Buds3 Pro', fileName: 'Samsung Galaxy Buds3 Pro.csv' }, - { name: 'Apple AirPods Pro (Super Review)', type: 'in-ear', path: 'Super Review/in-ear/Apple AirPods Pro', fileName: 'Apple AirPods Pro.csv' }, - { name: 'Sennheiser HD 600 (2020) (Kuulokenurkka)', type: 'over-ear', path: 'Kuulokenurkka/over-ear/Sennheiser HD 600 (2020)', fileName: 'Sennheiser HD 600 (2020).csv' }, + { + name: 'Sennheiser HD 600 (Filk)', + type: 'over-ear', + path: 'Filk/over-ear/Sennheiser HD 600', + fileName: 'Sennheiser HD 600.csv', + }, + { + name: 'Sennheiser HD 600 (Innerfidelity)', + type: 'over-ear', + path: 'Innerfidelity/over-ear/Sennheiser HD 600', + fileName: 'Sennheiser HD 600.csv', + }, + { + name: 'Samsung Galaxy Buds2 Pro (Rtings)', + type: 'in-ear', + path: 'Rtings/Bruel & Kjaer 5128 in-ear/Samsung Galaxy Buds2 Pro', + fileName: 'Samsung Galaxy Buds2 Pro.csv', + }, + { + name: 'Sony WF-1000XM5 (Kazi)', + type: 'in-ear', + path: 'Kazi/in-ear/Sony WF-1000XM5', + fileName: 'Sony WF-1000XM5.csv', + }, + { + name: 'Samsung Galaxy Buds3 Pro (DHRME)', + type: 'in-ear', + path: 'DHRME/in-ear/Samsung Galaxy Buds3 Pro', + fileName: 'Samsung Galaxy Buds3 Pro.csv', + }, + { + name: 'Apple AirPods Pro (Super Review)', + type: 'in-ear', + path: 'Super Review/in-ear/Apple AirPods Pro', + fileName: 'Apple AirPods Pro.csv', + }, + { + name: 'Sennheiser HD 600 (2020) (Kuulokenurkka)', + type: 'over-ear', + path: 'Kuulokenurkka/over-ear/Sennheiser HD 600 (2020)', + fileName: 'Sennheiser HD 600 (2020).csv', + }, ]; /** @@ -39,7 +99,11 @@ const FALLBACK_INDEX = [ */ async function fetchAutoEqIndex() { // Migrate: remove old localStorage cache to free quota - try { localStorage.removeItem(OLD_LS_CACHE_KEY); } catch { /* ignore */ } + try { + localStorage.removeItem(OLD_LS_CACHE_KEY); + } catch { + /* ignore */ + } // 1. Try loading from IndexedDB cache try { @@ -61,7 +125,9 @@ async function fetchAutoEqIndex() { const timeoutId = setTimeout(() => controller.abort(), 8000); let response; try { - response = await fetch('https://api.github.com/repos/jaakkopasanen/AutoEq/git/trees/master?recursive=1', { signal: controller.signal }); + response = await fetch('https://api.github.com/repos/jaakkopasanen/AutoEq/git/trees/master?recursive=1', { + signal: controller.signal, + }); } finally { clearTimeout(timeoutId); } @@ -73,7 +139,9 @@ async function fetchAutoEqIndex() { console.warn('[AutoEQ] GitHub API limit reached. Using stale cache.'); return cached.data; } - } catch { /* ignore */ } + } catch { + /* ignore */ + } console.warn('[AutoEQ] GitHub API error. Using fallback.'); return FALLBACK_INDEX; } @@ -92,13 +160,15 @@ async function fetchAutoEqIndex() { const fileNameLower = fileName.toLowerCase(); // Skip non-measurement files (EQ presets, not raw frequency response) - if (fileNameLower.includes('parametriceq') || + if ( + fileNameLower.includes('parametriceq') || fileNameLower.includes('fixedbandeq') || fileNameLower.includes('graphiceq') || fileNameLower.includes('convolution') || fileNameLower.includes('fixed band eq') || fileNameLower.includes('parametric eq') || - fileNameLower.includes('graphic eq')) { + fileNameLower.includes('graphic eq') + ) { continue; } @@ -144,7 +214,9 @@ async function fetchAutoEqIndex() { try { const cached = await db.getSetting(CACHE_KEY); if (cached?.data) return cached.data; - } catch { /* ignore */ } + } catch { + /* ignore */ + } } else { console.error('[AutoEQ] Failed to fetch index:', err); } @@ -205,12 +277,12 @@ function searchHeadphones(query, entries, typeFilter = 'all', limit = 100) { let filtered = entries; if (typeFilter !== 'all') { - filtered = filtered.filter(e => e.type === typeFilter); + filtered = filtered.filter((e) => e.type === typeFilter); } if (query && query.trim()) { const lower = query.toLowerCase().trim(); - filtered = filtered.filter(e => e.name.toLowerCase().includes(lower)); + filtered = filtered.filter((e) => e.name.toLowerCase().includes(lower)); } return filtered.slice(0, limit); diff --git a/styles.css b/styles.css index 2150620..81caf61 100644 --- a/styles.css +++ b/styles.css @@ -7910,6 +7910,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { background: rgb(255 255 255 / 0.5); border: 1px dashed rgb(255 255 255 / 0.3); } + .legend-corrected .legend-dot { background: #f472b6; } @@ -8109,6 +8110,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { .autoeq-status.error { color: var(--destructive); } + .autoeq-status.success { color: var(--primary); } @@ -8941,12 +8943,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn { .speaker-eq-slider-value.bass { color: #22d3ee; } + .speaker-eq-slider-value.room { color: #f59e0b; } + .speaker-eq-section .autoeq-control-label.bass { color: #22d3ee; } + .speaker-eq-section .autoeq-control-label.room { color: #f59e0b; }