diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-18 14:00:18 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-18 14:00:18 +0100 |
| commit | a9a60dfd2df938ef1e3ecc0a06d3d50cc329ef30 (patch) | |
| tree | d4bfa5597eda60db9c0ea3ad20c53c39e228819a /tools/mq_editor/fft.js | |
| parent | c3c1011cb6bf9bca28736b89049d76875a031ebe (diff) | |
Implements a more robust partial tracking algorithm by using phase
coherence to validate and link spectral peaks across frames. This
significantly improves tracking accuracy, especially for crossing or
closely-spaced partials.
Key changes:
- : The STFT cache now computes and stores the phase for each
frequency bin alongside the magnitude.
- : The peak detection logic now interpolates the
phase for sub-bin accuracy.
- : The core tracking algorithm was replaced with a
phase-aware model. It predicts the expected phase for a partial in
the next frame and uses a cost function combining both frequency and
phase error to find the best match.
This implementation follows the design outlined in the new document
.
handoff(Gemini): Phase prediction implemented. Further tuning of the cost function weights may be beneficial.
Diffstat (limited to 'tools/mq_editor/fft.js')
| -rw-r--r-- | tools/mq_editor/fft.js | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/tools/mq_editor/fft.js b/tools/mq_editor/fft.js index 10a5b45..0d54eae 100644 --- a/tools/mq_editor/fft.js +++ b/tools/mq_editor/fft.js @@ -132,18 +132,20 @@ class STFTCache { windowed[i] = frame[i] * w; } - // Compute FFT, store only squared amplitudes (re*re + im*im, no sqrt) + // Compute FFT, store squared amplitudes and phase const fftOut = realFFT(windowed); const squaredAmplitude = new Float32Array(this.fftSize / 2); + const phase = new Float32Array(this.fftSize / 2); for (let i = 0; i < this.fftSize / 2; ++i) { const re = fftOut[i * 2]; const im = fftOut[i * 2 + 1]; squaredAmplitude[i] = re * re + im * im; + phase[i] = Math.atan2(im, re); // Cache phase for tracking const db = 10 * Math.log10(Math.max(squaredAmplitude[i], 1e-20)); if (db > this.maxDB) this.maxDB = db; } - this.frames.push({time, offset, squaredAmplitude}); + this.frames.push({time, offset, squaredAmplitude, phase}); } if (!isFinite(this.maxDB)) this.maxDB = 0; |
