Files

91 lines
2.7 KiB
Go
Raw Permalink Normal View History

package synth_test
import (
"math"
"testing"
"github.com/netsynth/netsynth/synth"
)
func TestLFOBounds(t *testing.T) {
lfo := synth.NewLFO(1.0, 0.5, 44100) // 1 Hz, depth 0.5
for i := 0; i < 44100; i++ {
val := lfo.Advance()
if val < -0.5 || val > 0.5 {
t.Errorf("LFO value %v out of bounds [-0.5, 0.5] at sample %d", val, i)
break
}
}
}
func TestLFOPeriod(t *testing.T) {
// A 1 Hz LFO should complete one cycle in exactly SampleRate samples
lfo := synth.NewLFO(1.0, 1.0, 44100)
// Advance to first zero-crossing (quarter period)
var firstPositive float64
for i := 0; i < 44100; i++ {
val := lfo.Advance()
if i == 0 {
firstPositive = val
}
// After one full cycle, value should be close to the first value
if i == 44099 {
lastVal := val
// They won't be exactly equal due to phase advancement, but should be close
if math.Abs(lastVal-firstPositive) > 0.01 {
t.Errorf("LFO not periodic: first=%v, after 1 cycle=%v", firstPositive, lastVal)
}
}
}
}
func TestPitchLFOFreq(t *testing.T) {
// 0 semitones should return baseHz unchanged
if synth.PitchLFOFreq(440.0, 0.0) != 440.0 {
t.Errorf("PitchLFOFreq(440, 0) should be 440, got %v", synth.PitchLFOFreq(440.0, 0.0))
}
// 12 semitones = one octave up
result := synth.PitchLFOFreq(440.0, 12.0)
if math.Abs(result-880.0) > 0.01 {
t.Errorf("PitchLFOFreq(440, 12) should be 880, got %v", result)
}
// Small detuning: 0.1 semitones
result = synth.PitchLFOFreq(440.0, 0.1)
if result <= 440.0 || result >= 445.0 {
t.Errorf("PitchLFOFreq(440, 0.1) should be slightly above 440, got %v", result)
}
}
func TestLFOConfigForGroup(t *testing.T) {
cfg := synth.LFOConfigForGroup("Web")
if cfg.PitchRate == 0 {
t.Error("Web group should have non-zero PitchRate")
}
if cfg.TremoloRate == 0 {
t.Error("Web group should have non-zero TremoloRate")
}
// Unknown group should return default
cfg2 := synth.LFOConfigForGroup("NonexistentGroup")
if cfg2.PitchRate == 0 {
t.Error("fallback config should have non-zero PitchRate")
}
}
func TestGroupLFORatesIncommensurable(t *testing.T) {
// Verify that no two groups share the exact same pitch or tremolo rate
groups := []string{"Infrastructure", "Web", "Mail", "Remote Access", "File Transfer", "Database", "VoIP", "Unknown"}
pitchRates := make(map[float64]string)
tremoloRates := make(map[float64]string)
for _, g := range groups {
cfg := synth.LFOConfigForGroup(g)
if prev, exists := pitchRates[cfg.PitchRate]; exists {
t.Errorf("groups %q and %q share PitchRate=%v", prev, g, cfg.PitchRate)
}
pitchRates[cfg.PitchRate] = g
if prev, exists := tremoloRates[cfg.TremoloRate]; exists {
t.Errorf("groups %q and %q share TremoloRate=%v", prev, g, cfg.TremoloRate)
}
tremoloRates[cfg.TremoloRate] = g
}
}