Files
yoloyolo/synth/waveform_test.go
T
gurix 88dee31264 test(05-01): add failing tests for WaveformType and WaveformPresetHarmonics
- TestWaveformPresetHarmonics_Sine: expects exactly {Ratio:1, Amplitude:1.0}
- TestWaveformPresetHarmonics_Square: expects odd harmonics with 1/k amplitude below Nyquist
- TestWaveformPresetHarmonics_Sawtooth: expects all harmonics with 1/k amplitude below Nyquist
- TestWaveformPresetHarmonics_Triangle: expects odd harmonics with alternating 1/k^2 amplitude
- TestWaveformPresetHarmonics_Custom: expects nil return
- TestBandlimitedHarmonicsNoAliasing: checks all ClassFreqConfigs entries at all waveform types
- TestWaveformPresetHarmonics_SquareOddOnly: odd ratios only
- TestWaveformPresetHarmonics_TriangleOddOnly: odd ratios only
- TestWaveformPresetHarmonics_SawtoothConsecutive: consecutive ratios starting at 1
2026-03-26 17:33:03 +01:00

137 lines
4.3 KiB
Go

package synth_test
import (
"testing"
"github.com/netsynth/netsynth/synth"
)
func TestWaveformPresetHarmonics_Sine(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformSine, 440.0, 44100)
if len(harmonics) != 1 {
t.Fatalf("WaveformSine: expected 1 harmonic, got %d", len(harmonics))
}
if harmonics[0].Ratio != 1 {
t.Errorf("WaveformSine: expected Ratio=1, got %d", harmonics[0].Ratio)
}
if harmonics[0].Amplitude != 1.0 {
t.Errorf("WaveformSine: expected Amplitude=1.0, got %.4f", harmonics[0].Amplitude)
}
}
func TestWaveformPresetHarmonics_Square(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformSquare, 440.0, 44100)
if len(harmonics) == 0 {
t.Fatal("WaveformSquare: expected at least one harmonic, got 0")
}
nyquist := 22050.0
for _, h := range harmonics {
if float64(h.Ratio)*440.0 >= nyquist {
t.Errorf("WaveformSquare: harmonic ratio %d exceeds Nyquist (freq=%.1f)", h.Ratio, float64(h.Ratio)*440.0)
}
expectedAmp := 1.0 / float64(h.Ratio)
if abs(h.Amplitude-expectedAmp) > 1e-9 {
t.Errorf("WaveformSquare: harmonic %d: expected amplitude %.6f, got %.6f", h.Ratio, expectedAmp, h.Amplitude)
}
}
}
func TestWaveformPresetHarmonics_Sawtooth(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformSawtooth, 440.0, 44100)
if len(harmonics) == 0 {
t.Fatal("WaveformSawtooth: expected at least one harmonic, got 0")
}
nyquist := 22050.0
for _, h := range harmonics {
if float64(h.Ratio)*440.0 >= nyquist {
t.Errorf("WaveformSawtooth: harmonic ratio %d exceeds Nyquist (freq=%.1f)", h.Ratio, float64(h.Ratio)*440.0)
}
expectedAmp := 1.0 / float64(h.Ratio)
if abs(h.Amplitude-expectedAmp) > 1e-9 {
t.Errorf("WaveformSawtooth: harmonic %d: expected amplitude %.6f, got %.6f", h.Ratio, expectedAmp, h.Amplitude)
}
}
}
func TestWaveformPresetHarmonics_Triangle(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformTriangle, 440.0, 44100)
if len(harmonics) == 0 {
t.Fatal("WaveformTriangle: expected at least one harmonic, got 0")
}
nyquist := 22050.0
sign := 1.0
for i, h := range harmonics {
if float64(h.Ratio)*440.0 >= nyquist {
t.Errorf("WaveformTriangle: harmonic ratio %d exceeds Nyquist (freq=%.1f)", h.Ratio, float64(h.Ratio)*440.0)
}
expectedAmp := sign / float64(h.Ratio*h.Ratio)
if abs(h.Amplitude-expectedAmp) > 1e-9 {
t.Errorf("WaveformTriangle: harmonic %d (index %d): expected amplitude %.6f, got %.6f", h.Ratio, i, expectedAmp, h.Amplitude)
}
sign = -sign
}
}
func TestWaveformPresetHarmonics_Custom(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformCustom, 440.0, 44100)
if harmonics != nil {
t.Errorf("WaveformCustom: expected nil, got %v", harmonics)
}
}
func TestBandlimitedHarmonicsNoAliasing(t *testing.T) {
waveforms := []synth.WaveformType{
synth.WaveformSine,
synth.WaveformSquare,
synth.WaveformSawtooth,
synth.WaveformTriangle,
}
for _, cfg := range synth.ClassFreqConfigs {
for _, wt := range waveforms {
harmonics := synth.WaveformPresetHarmonics(wt, cfg.BaseHz, 44100)
for _, h := range harmonics {
freq := float64(h.Ratio) * cfg.BaseHz
if freq >= 22050.0 {
t.Errorf("waveform %d, baseHz=%.1f: harmonic ratio %d produces freq=%.1f >= Nyquist 22050", wt, cfg.BaseHz, h.Ratio, freq)
}
}
}
}
}
func TestWaveformPresetHarmonics_SquareOddOnly(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformSquare, 440.0, 44100)
for _, h := range harmonics {
if h.Ratio%2 == 0 {
t.Errorf("WaveformSquare: found even ratio %d (should be odd-only)", h.Ratio)
}
}
}
func TestWaveformPresetHarmonics_TriangleOddOnly(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformTriangle, 440.0, 44100)
for _, h := range harmonics {
if h.Ratio%2 == 0 {
t.Errorf("WaveformTriangle: found even ratio %d (should be odd-only)", h.Ratio)
}
}
}
func TestWaveformPresetHarmonics_SawtoothConsecutive(t *testing.T) {
harmonics := synth.WaveformPresetHarmonics(synth.WaveformSawtooth, 440.0, 44100)
for i, h := range harmonics {
expected := i + 1
if h.Ratio != expected {
t.Errorf("WaveformSawtooth: index %d: expected ratio %d, got %d", i, expected, h.Ratio)
}
}
}
// abs returns the absolute value of x.
func abs(x float64) float64 {
if x < 0 {
return -x
}
return x
}