diff options
Diffstat (limited to 'tools/mq_editor/viewer.js')
| -rw-r--r-- | tools/mq_editor/viewer.js | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/tools/mq_editor/viewer.js b/tools/mq_editor/viewer.js index b267806..e19ec3a 100644 --- a/tools/mq_editor/viewer.js +++ b/tools/mq_editor/viewer.js @@ -187,7 +187,7 @@ class SpectrogramViewer { const magDB = 10 * Math.log10(Math.max(squaredAmp[bin], 1e-20)); - const normalized = (magDB + 80) / 80; + const normalized = (magDB - (stftCache.maxDB - 80)) / 80; const clamped = Math.max(0, Math.min(1, normalized)); // Power law for better peak visibility const intensity = Math.pow(clamped, 2.); @@ -493,24 +493,34 @@ class SpectrogramViewer { if (!squaredAmp) return; const fftSize = cache.fftSize; - - // Draw bars - const numBars = 100; - const barWidth = width / numBars; const numBins = fftSize / 2; + const binWidth = cache.sampleRate / fftSize; + + // Log-scale frequency mapping (matches main spectrogram) + const logMin = Math.log2(this.freqStart); + const logMax = Math.log2(this.freqEnd); + const freqToX = (freq) => { + const norm = (Math.log2(Math.max(freq, this.freqStart)) - logMin) / (logMax - logMin); + return norm * width; + }; + + // Draw histogram bars — one per pixel column + for (let px = 0; px < width; ++px) { + const fStart = Math.pow(2, logMin + (px / width) * (logMax - logMin)); + const fEnd = Math.pow(2, logMin + ((px + 1) / width) * (logMax - logMin)); - for (let i = 0; i < numBars; ++i) { - const binIdx = Math.floor(i * numBins / numBars); - const magDB = 10 * Math.log10(Math.max(squaredAmp[binIdx], 1e-20)); + const bStart = Math.max(0, Math.floor(fStart / binWidth)); + const bEnd = Math.min(numBins - 1, Math.ceil(fEnd / binWidth)); - // Normalize to [0, 1] - const normalized = (magDB + 80) / 80; - const intensity = Math.max(0, Math.min(1, normalized)); + let sum = 0, count = 0; + for (let b = bStart; b <= bEnd; ++b) { sum += squaredAmp[b]; ++count; } + if (count === 0) continue; - const barHeight = intensity * height; - const x = i * barWidth; + const magDB = 10 * Math.log10(Math.max(sum / count, 1e-20)); + const intensity = Math.max(0, Math.min(1, (magDB - (cache.maxDB - 80)) / 80)); + const barHeight = Math.round(intensity * height); + if (barHeight === 0) continue; - // Color: cyan/yellow for original, green/lime for synth const gradient = ctx.createLinearGradient(0, height - barHeight, 0, height); if (useSynth) { gradient.addColorStop(0, '#4f8'); @@ -519,9 +529,25 @@ class SpectrogramViewer { gradient.addColorStop(0, '#4af'); gradient.addColorStop(1, '#fa4'); } - ctx.fillStyle = gradient; - ctx.fillRect(x, height - barHeight, barWidth - 1, barHeight); + ctx.fillRect(px, height - barHeight, 1, barHeight); + } + + // Overlay extracted peaks as red histogram bars + if (this.frames && this.frames.length > 0) { + let bestFrame = this.frames[0]; + let bestDt = Math.abs(bestFrame.time - this.spectrumTime); + for (const f of this.frames) { + const dt = Math.abs(f.time - this.spectrumTime); + if (dt < bestDt) { bestDt = dt; bestFrame = f; } + } + ctx.fillStyle = '#f44'; + for (const peak of bestFrame.peaks) { + if (peak.freq < this.freqStart || peak.freq > this.freqEnd) continue; + const x0 = Math.floor(freqToX(peak.freq)); + const x1 = Math.max(x0 + 1, Math.floor(freqToX(peak.freq * Math.pow(2, 1 / width)))); + ctx.fillRect(x0, 0, x1 - x0, height); + } } // Label @@ -544,19 +570,8 @@ class SpectrogramViewer { } getSpectrogramColor(intensity) { - if (intensity < 0.25) { - const t = intensity / 0.25; - return {r: 0, g: 0, b: Math.floor(t * 128)}; - } else if (intensity < 0.5) { - const t = (intensity - 0.25) / 0.25; - return {r: 0, g: Math.floor(t * 128), b: 128}; - } else if (intensity < 0.75) { - const t = (intensity - 0.5) / 0.25; - return {r: Math.floor(t * 255), g: 128 + Math.floor(t * 127), b: 128 - Math.floor(t * 128)}; - } else { - const t = (intensity - 0.75) / 0.25; - return {r: 255, g: 255 - Math.floor(t * 128), b: 0}; - } + const v = Math.floor(intensity * 255); + return {r: v, g: v, b: v}; } } |
