Files
uopi/internal/dsp/fft.go
T
Martino Ferrari f7f297c3df Add synthetic array (waveform) DSP support + UX improvements
Adds full array/waveform support through the synthetic DSP engine: a
dsp.Sample value model (scalar or []float64), array ops (index, slice,
sum, mean, min, max, length, fft) with an in-tree radix-2 FFT, and static
type propagation (OpOutputType) that the editor mirrors to colour wires by
data type and flag invalid wirings. Stateful filters and lua stay
scalar-only. Adds a waveform plot mode (x-vs-index trace).

Also: errored-node hover reasons, S/N add-signal/add-node HUD shortcuts in
the synthetic editor, and view-mode widgets that blend with the canvas
background (chrome kept in edit mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-20 17:06:55 +02:00

59 lines
1.4 KiB
Go

package dsp
import "math"
// nextPow2 returns the smallest power of two >= n (and at least 1).
func nextPow2(n int) int {
p := 1
for p < n {
p <<= 1
}
return p
}
// fftRadix2 computes the in-place iterative radix-2 Cooley-Tukey FFT of the
// complex signal held in re/im. len(re) == len(im) must be a power of two. The
// transform overwrites re/im with the frequency-domain result. This is a small
// self-contained implementation (no external dependency) used by the synthetic
// fft op.
func fftRadix2(re, im []float64) {
n := len(re)
if n <= 1 {
return
}
// Bit-reversal permutation.
for i, j := 1, 0; i < n; i++ {
bit := n >> 1
for ; j&bit != 0; bit >>= 1 {
j ^= bit
}
j ^= bit
if i < j {
re[i], re[j] = re[j], re[i]
im[i], im[j] = im[j], im[i]
}
}
// Danielson-Lanczos butterflies.
for length := 2; length <= n; length <<= 1 {
ang := -2 * math.Pi / float64(length)
wReal, wImag := math.Cos(ang), math.Sin(ang)
for i := 0; i < n; i += length {
curReal, curImag := 1.0, 0.0
half := length >> 1
for k := 0; k < half; k++ {
a := i + k
b := i + k + half
tReal := curReal*re[b] - curImag*im[b]
tImag := curReal*im[b] + curImag*re[b]
re[b] = re[a] - tReal
im[b] = im[a] - tImag
re[a] += tReal
im[a] += tImag
curReal, curImag = curReal*wReal-curImag*wImag, curReal*wImag+curImag*wReal
}
}
}
}