summaryrefslogtreecommitdiff
path: root/tools/mq_editor/viewer.js
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-18 06:02:32 +0100
committerskal <pascal.massimino@gmail.com>2026-02-18 06:02:32 +0100
commitbf3929220be7eddf32cebe12573b870fc9b54997 (patch)
tree27318902f41b0e4f5deb73831d9cfc03ca37b229 /tools/mq_editor/viewer.js
parent14c3bfe09f906e9b80d6100b126e59c9a88ac976 (diff)
fix(mq_editor): mini-spectrum and spectrogram display improvements
- Fix mini-spectrum: log-scale frequency axis, per-pixel bin averaging, red peak bars after extraction - Fix key handlers swallowing digits in input fields - Clamp hop size to min 64 to prevent hang - Store maxDB in STFTCache, use it to normalize both mini-spectrum and main spectrogram (fixes clipping at 0dB for pure tones) - Add Test WAV console validation for 440/660Hz peaks - Grayscale colormap for main spectrogram handoff(Gemini): mq_editor display fixes complete, tests not affected
Diffstat (limited to 'tools/mq_editor/viewer.js')
-rw-r--r--tools/mq_editor/viewer.js73
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};
}
}