package synth_test import ( "testing" "github.com/netsynth/netsynth/synth" ) func TestEnvelopeStartsIdle(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) if env.State() != synth.EnvIdle { t.Errorf("expected EnvIdle, got %v", env.State()) } if env.Level() != 0 { t.Errorf("expected level=0 in idle, got %v", env.Level()) } } func TestEnvelopeTriggerStartsAttack(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) env.Trigger() if env.State() != synth.EnvAttack { t.Errorf("expected EnvAttack after Trigger, got %v", env.State()) } } func TestEnvelopeAttackReachesPeak(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) env.Trigger() // Advance through the full attack phase (2 seconds) for i := 0; i < synth.SampleRate*3; i++ { env.Advance() } if env.Level() < 0.8 { t.Errorf("expected level >= 0.8 after attack, got %v", env.Level()) } } func TestEnvelopeReleaseDecays(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) env.Trigger() // Build up for i := 0; i < synth.SampleRate*3; i++ { env.Advance() } peakLevel := env.Level() env.Release() // Advance through release (4 seconds) for i := 0; i < synth.SampleRate*6; i++ { env.Advance() } if env.Level() >= peakLevel*0.3 { t.Errorf("expected level to decay well below peak after release, peak=%v, current=%v", peakLevel, env.Level()) } } func TestBurstyEnvelopeNoSustain(t *testing.T) { env := synth.NewEnvelope(synth.BurstyEnvParams, synth.SampleRate, 1.0) env.Trigger() // Advance 2 seconds — bursty should have attacked, decayed (sustain=0), and be releasing for i := 0; i < synth.SampleRate*2; i++ { env.Advance() } // Should be very quiet (in release or idle) if env.Level() > 0.1 { t.Errorf("bursty envelope should be near zero after 2s, got %v (state=%v)", env.Level(), env.State()) } } func TestEnvelopeIdleOutputsZero(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) for i := 0; i < 100; i++ { val := env.Advance() if val != 0 { t.Errorf("idle envelope should output 0, got %v at sample %d", val, i) break } } } func TestEnvelopeRetriggerFromRelease(t *testing.T) { env := synth.NewEnvelope(synth.SustainedEnvParams, synth.SampleRate, 1.0) env.Trigger() for i := 0; i < synth.SampleRate*3; i++ { env.Advance() } env.Release() for i := 0; i < synth.SampleRate; i++ { env.Advance() } levelBeforeRetrigger := env.Level() // Re-trigger env.Trigger() for i := 0; i < synth.SampleRate*3; i++ { env.Advance() } if env.Level() <= levelBeforeRetrigger { t.Errorf("re-triggered envelope should rise above release level, before=%v, after=%v", levelBeforeRetrigger, env.Level()) } }