summaryrefslogtreecommitdiff
path: root/tools/spectral_editor
diff options
context:
space:
mode:
Diffstat (limited to 'tools/spectral_editor')
-rw-r--r--tools/spectral_editor/script.js105
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;
}
}
}