summaryrefslogtreecommitdiff
path: root/tools/editor
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-01-28 21:34:59 +0100
committerskal <pascal.massimino@gmail.com>2026-01-28 21:34:59 +0100
commitd82db7e301ff778b3c71a409263d696d9f561b74 (patch)
tree6d95a6ad24d4b7b84c1b8502be1347debc0f44d3 /tools/editor
parentf6f85dd2b83452f6a288740d60d1f76d8df7c53d (diff)
fix the spec editor a bit
Diffstat (limited to 'tools/editor')
-rw-r--r--tools/editor/dct.js2
-rw-r--r--tools/editor/index.html2
-rw-r--r--tools/editor/script.js113
3 files changed, 17 insertions, 100 deletions
diff --git a/tools/editor/dct.js b/tools/editor/dct.js
index f60f27e..e48ce2b 100644
--- a/tools/editor/dct.js
+++ b/tools/editor/dct.js
@@ -1,3 +1,5 @@
+const dctSize = 512; // Default DCT size, read from header
+
// --- Utility Functions for Audio Processing ---
// JavaScript equivalent of C++ idct_512
function javascript_idct_512(input) {
diff --git a/tools/editor/index.html b/tools/editor/index.html
index 6cb6af7..7c977e3 100644
--- a/tools/editor/index.html
+++ b/tools/editor/index.html
@@ -29,6 +29,8 @@
</div>
</div>
+ <script src="sdf.js"></script>
+ <script src="dct.js"></script>
<script src="script.js"></script>
</body>
</html>
diff --git a/tools/editor/script.js b/tools/editor/script.js
index aac52ff..abfd4f4 100644
--- a/tools/editor/script.js
+++ b/tools/editor/script.js
@@ -4,7 +4,6 @@
// --- Global Variables ---
let currentSpecData = null; // Stores the currently displayed/edited spectrogram data
let originalSpecData = null; // Stores the pristine, initially loaded spectrogram data
-let dctSize = 512; // Default DCT size, read from header
let undoStack = [];
let redoStack = [];
@@ -60,74 +59,6 @@ listenGeneratedButton.addEventListener('click', () => {
});
-// --- Utility Functions for Audio Processing ---
-// JavaScript equivalent of C++ idct_512
-function javascript_idct_512(input) {
- const output = new Float32Array(dctSize);
- const PI = Math.PI;
- const N = dctSize;
-
- for (let n = 0; n < N; ++n) {
- let sum = input[0] / 2.0;
- for (let k = 1; k < N; ++k) {
- sum += input[k] * Math.cos((PI / N) * k * (n + 0.5));
- }
- output[n] = sum * (2.0 / N);
- }
- return output;
-}
-
-// Hanning window for smooth audio transitions (JavaScript equivalent)
-function hanningWindow(size) {
- const window = new Float32Array(size);
- const PI = Math.PI;
- for (let i = 0; i < size; i++) {
- window[i] = 0.5 * (1 - Math.cos((2 * PI * i) / (size - 1)));
- }
- return window;
-}
-
-const hanningWindowArray = hanningWindow(dctSize); // Pre-calculate window
-
-// --- Signed Distance Functions (SDFs) ---
-// Generic 2D vector operations
-function vec2(x, y) { return { x: x, y: y }; }
-function length(v) { return Math.sqrt(v.x * v.x + v.y * v.y); }
-function dot(v1, v2) { return v1.x * v2.x + v1.y * v2.y; }
-function sub(v1, v2) { return vec2(v1.x - v2.x, v1.y - v2.y); }
-function mul(v, s) { return vec2(v.x * s, v.y * s); }
-function div(v, s) { return vec2(v.x / s, v.y / s); }
-function normalize(v) { return div(v, length(v)); }
-function clamp(x, minVal, maxVal) { return Math.max(minVal, Math.min(x, maxVal)); }
-function abs(v) { return vec2(Math.abs(v.x), Math.abs(v.y)); }
-function max(v1, v2) { return vec2(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y)); }
-function sign(x) { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); }
-
-// sdSegment(p, a, b) - signed distance to a line segment
-// p: point, a: segment start, b: segment end
-function sdSegment(p, a, b) {
- const pa = sub(p, a);
- const ba = sub(b, a);
- const h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
- return length(sub(pa, mul(ba, h)));
-}
-
-// sdEllipse(p, r) - signed distance to an ellipse (p relative to center, r is half-extents)
-// p: point relative to ellipse center, r: half-extents (rx, ry)
-function sdEllipse(p, r) {
- const k0 = vec2(1, length(div(p, r)));
- const k1 = vec2(length(div(p, r)), 1);
- const f = ((dot(div(mul(p, p), k0), vec2(1, 1)) < dot(div(mul(p, p), k1), vec2(1, 1))) ? k0 : k1);
- return length(sub(p, mul(r, normalize(mul(f, p))))) * sign(length(p) - r.x); // Simplified, original has length(p)-r.x which is only for circular
-}
-
-// sdBox(p, r) - signed distance to a rectangle (p relative to center, r is half-extents)
-// p: point relative to box center, r: half-extents (hx, hy)
-function sdBox(p, r) {
- const q = sub(abs(p), r);
- return length(max(q, vec2(0, 0))) + Math.min(0.0, Math.max(q.x, q.y));
-}
-
// --- Utility to map canvas coords to spectrogram bins/frames (LOG SCALE) ---
// Maps a linear frequency bin index to its corresponding frequency in Hz
function binIndexToFreq(binIndex) {
@@ -211,17 +142,6 @@ window.addEventListener('resize', () => {
// Initial call to set button states
updateUndoRedoButtons();
-// --- Utility for sizeof(float) in JS context ---
-// This is a workaround since typeof(float) is not directly available.
-// Float32Array.BYTES_PER_ELEMENT is used in handleFileSelect.
-function sizeof(type) {
- if (type === 'float') {
- return Float32Array.BYTES_PER_ELEMENT;
- }
- return 0;
-}
-
-
// --- File Handling Functions ---
async function handleFileSelect(event) {
const file = event.target.files[0];
@@ -247,7 +167,10 @@ async function handleFileSelect(event) {
return;
}
- dctSize = header.dct_size;
+ if (dctSize != header.dct_size) {
+ alert("Invalid dctSize in SPEC file");
+ return;
+ }
const dataStart = 16;
const numBytes = header.num_frames * header.dct_size * Float32Array.BYTES_PER_ELEMENT;
const spectralDataFloat = new Float32Array(buffer, dataStart, header.num_frames * header.dct_size);
@@ -281,9 +204,10 @@ canvas.addEventListener('mouseout', handleMouseUp); // Treat mouse out as mouse
// Function to get a color based on intensity (0 to 1)
function getColorForIntensity(intensity) {
// Example: Blue to white/yellow gradient
- const h = (1 - intensity) * 240; // Hue from blue (240) to red (0), inverse for intensity
- const s = 100; // Saturation
- const l = intensity * 50 + 50; // Lightness from 50 to 100
+ const log_intensity = Math.log(1. + intensity) / Math.log(2.);
+ const h = (1 - log_intensity) * 240; // Hue from blue (240) to red (0), inverse for intensity
+ const s = 60.; // Saturation
+ const l = log_intensity * 60 + 30; // Lightness from 30 to 90
return `hsl(${h}, ${s}%, ${l}%)`;
}
@@ -410,6 +334,10 @@ function handleMouseMove(event) {
break;
}
ctx.setLineDash([]); // Reset line dash
+
+ // debug the mouse position by draw a white square
+ ctx.fillStyle = '#fff';
+ ctx.fillRect(pos.x - 10, pos.y - 10, 20, 20);
}
function handleMouseUp(event) {
@@ -700,8 +628,6 @@ async function playSpectrogramData(specData) {
const audioBuffer = audioContext.createBuffer(1, totalAudioSamples, sampleRate);
const audioData = audioBuffer.getChannelData(0); // Mono channel
- const windowArray = hanningWindow(dctSize); // Generate Hanning window for each frame
-
// Convert spectrogram frames (frequency domain) to audio samples (time domain)
for (let frameIndex = 0; frameIndex < numFrames; frameIndex++) {
const spectralFrame = specData.data.slice(frameIndex * dctSize, (frameIndex + 1) * dctSize);
@@ -709,10 +635,7 @@ async function playSpectrogramData(specData) {
// Apply Hanning window for smooth transitions
for (let i = 0; i < dctSize; i++) {
- const globalIndex = frameIndex * dctSize + i;
- if (globalIndex < totalAudioSamples) {
- audioData[globalIndex] += timeDomainFrame[i] * windowArray[i];
- }
+ audioData[frameIndex * dctSize + i] = timeDomainFrame[i] * hanningWindowArray[i];
}
}
@@ -723,13 +646,3 @@ async function playSpectrogramData(specData) {
console.log(`Playing audio (Sample Rate: ${sampleRate}, Duration: ${audioBuffer.duration.toFixed(2)}s)`);
}
-
-// --- Utility for sizeof(float) in JS context ---
-// This is a workaround since typeof(float) is not directly available.
-// Float32Array.BYTES_PER_ELEMENT is used in handleFileSelect.
-function sizeof(type) {
- if (type === 'float') {
- return Float32Array.BYTES_PER_ELEMENT;
- }
- return 0;
-} \ No newline at end of file