diff options
Diffstat (limited to 'tools/spectral_editor/script.js')
| -rw-r--r-- | tools/spectral_editor/script.js | 105 |
1 files changed, 79 insertions, 26 deletions
diff --git a/tools/spectral_editor/script.js b/tools/spectral_editor/script.js index 7877012..744ea97 100644 --- a/tools/spectral_editor/script.js +++ b/tools/spectral_editor/script.js @@ -358,6 +358,19 @@ function onReferenceLoaded(fileName) { // ============================================================================ function addCurve() { + // Generate a unique color for this curve + const colors = [ + '#0e639c', // Blue + '#00aa00', // Green + '#cc5500', // Orange + '#aa00aa', // Purple + '#00aaaa', // Cyan + '#aa5500', // Brown + '#ff69b4', // Pink + '#ffd700', // Gold + ]; + const color = colors[state.curves.length % colors.length]; + const curve = { id: state.nextCurveId++, controlPoints: [], // Empty initially, user will place points @@ -365,7 +378,8 @@ function addCurve() { type: 'gaussian', param1: 30.0, // sigma param2: 0.0 - } + }, + color: color }; state.curves.push(curve); @@ -411,7 +425,20 @@ function updateCurveUI() { if (curve.id === state.selectedCurveId) { div.classList.add('selected'); } - div.textContent = `Curve ${curve.id} (${curve.controlPoints.length} points)`; + + // Add color indicator + const colorDot = document.createElement('span'); + colorDot.style.display = 'inline-block'; + colorDot.style.width = '12px'; + colorDot.style.height = '12px'; + colorDot.style.borderRadius = '50%'; + colorDot.style.backgroundColor = curve.color || '#0e639c'; + colorDot.style.marginRight = '8px'; + colorDot.style.verticalAlign = 'middle'; + + div.appendChild(colorDot); + div.appendChild(document.createTextNode(`Curve ${curve.id} (${curve.controlPoints.length} points)`)); + div.addEventListener('click', () => { state.selectedCurveId = curve.id; state.selectedControlPointIdx = null; @@ -728,46 +755,69 @@ function drawReferenceSpectrogram(ctx) { } function drawProceduralSpectrogram(ctx) { - // Generate procedural spectrogram + // Draw each curve separately with its own color const numFrames = state.referenceNumFrames || 100; - const procedural = generateProceduralSpectrogram(numFrames); - // Draw as colored overlay - ctx.globalAlpha = 0.7; + ctx.globalAlpha = 0.6; - const imgData = ctx.createImageData(state.canvasWidth, state.canvasHeight); + state.curves.forEach(curve => { + if (curve.controlPoints.length === 0) return; - for (let frameIdx = 0; frameIdx < numFrames; frameIdx++) { - const x = Math.floor(frameIdx * state.pixelsPerFrame); - if (x >= state.canvasWidth) break; + // Generate spectrogram for this curve only + const curveSpec = new Float32Array(state.referenceDctSize * numFrames); + drawCurveToSpectrogram(curve, curveSpec, state.referenceDctSize, numFrames); - for (let bin = 0; bin < state.referenceDctSize; bin++) { - const y = state.canvasHeight - Math.floor(bin * state.pixelsPerBin); - if (y < 0 || y >= state.canvasHeight) continue; + // Parse curve color (hex to RGB) + const color = hexToRgb(curve.color || '#0e639c'); - const specValue = procedural[frameIdx * state.referenceDctSize + bin]; - const intensity = Math.min(255, Math.abs(specValue) * 50); + const imgData = ctx.createImageData(state.canvasWidth, state.canvasHeight); - const pixelIdx = (y * state.canvasWidth + x) * 4; - imgData.data[pixelIdx + 0] = 100; // R (blue-ish) - imgData.data[pixelIdx + 1] = 150; // G - imgData.data[pixelIdx + 2] = intensity; // B - imgData.data[pixelIdx + 3] = 255; // A + for (let frameIdx = 0; frameIdx < numFrames; frameIdx++) { + const x = Math.floor(frameIdx * state.pixelsPerFrame); + if (x >= state.canvasWidth) break; + + for (let bin = 0; bin < state.referenceDctSize; bin++) { + const y = state.canvasHeight - Math.floor(bin * state.pixelsPerBin); + if (y < 0 || y >= state.canvasHeight) continue; + + const specValue = curveSpec[frameIdx * state.referenceDctSize + bin]; + const intensity = Math.min(1.0, Math.abs(specValue) / 10.0); // Normalize to 0-1 + + if (intensity > 0.01) { // Only draw visible pixels + const pixelIdx = (y * state.canvasWidth + x) * 4; + imgData.data[pixelIdx + 0] = Math.floor(color.r * intensity); + imgData.data[pixelIdx + 1] = Math.floor(color.g * intensity); + imgData.data[pixelIdx + 2] = Math.floor(color.b * intensity); + imgData.data[pixelIdx + 3] = 255; + } + } } - } - ctx.putImageData(imgData, 0, 0); + ctx.putImageData(imgData, 0, 0); + }); + ctx.globalAlpha = 1.0; } +// Helper: Convert hex color to RGB +function hexToRgb(hex) { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : {r: 14, g: 99, b: 156}; // Default blue +} + function drawControlPoints(ctx) { state.curves.forEach(curve => { const isSelected = curve.id === state.selectedCurveId; + const curveColor = curve.color || '#0e639c'; // Draw Bezier curve path if (curve.controlPoints.length >= 2) { - ctx.strokeStyle = isSelected ? '#0e639c' : '#666666'; - ctx.lineWidth = 2; + ctx.strokeStyle = isSelected ? curveColor : '#666666'; + ctx.lineWidth = isSelected ? 3 : 2; ctx.beginPath(); for (let i = 0; i < curve.controlPoints.length; i++) { @@ -789,7 +839,7 @@ function drawControlPoints(ctx) { const screenPos = spectrogramToScreen(point.frame, point.freqHz); const isPointSelected = isSelected && idx === state.selectedControlPointIdx; - ctx.fillStyle = isPointSelected ? '#ffaa00' : (isSelected ? '#0e639c' : '#888888'); + ctx.fillStyle = isPointSelected ? '#ffaa00' : (isSelected ? curveColor : '#888888'); ctx.beginPath(); ctx.arc(screenPos.x, screenPos.y, 6, 0, 2 * Math.PI); ctx.fill(); @@ -826,6 +876,9 @@ function generateProceduralSpectrogram(numFrames) { function drawCurveToSpectrogram(curve, spectrogram, dctSize, numFrames) { if (curve.controlPoints.length === 0) return; + // Amplitude scaling factor to match typical DCT coefficient magnitudes + const AMPLITUDE_SCALE = 10.0; + for (let frame = 0; frame < numFrames; frame++) { // Evaluate Bezier curve at this frame const freqHz = evaluateBezierLinear(curve.controlPoints, frame, 'freqHz'); @@ -840,7 +893,7 @@ function drawCurveToSpectrogram(curve, spectrogram, dctSize, numFrames) { const profileValue = evaluateProfile(curve.profile, dist); const idx = frame * dctSize + bin; - spectrogram[idx] += amplitude * profileValue; + spectrogram[idx] += amplitude * profileValue * AMPLITUDE_SCALE; } } } |
