Commit Graph

2 Commits

Author SHA1 Message Date
ciegovolador 6a1f79e331 fix(sim): monophonic buzzer guard — replace note on pitch change (no stacking)
A melody / continuous tone (consecutive tone() with no noTone() between) is
back-to-back nonzero-OCR PWM writes with no note-off, so startTone() overwrote
activeOsc without stopping the previous node — oscillators stacked and were
never stopped (reported: created 6, started 6, never stopped 6).

Add a monophonic guard at the top of startTone(): release the live note
(gain ramp + stop) before starting the new one, so a pitch change REPLACES
rather than STACKS. Extract a shared releaseActive(off) helper (also used by
stopTone). Add two melody tests: one asserts starts === stops (no orphans),
monotonic onsets and per-note pitch; one asserts a melody ending without a
trailing noTone() leaves only the final note ringing (stops === starts - 1).

The metronome path is unaffected (each click is an onset→note-off pair, so the
guard never fires there); the three existing metronome tests stay green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 02:35:33 -03:00
ciegovolador b06f500ad6 fix(sim): mature the buzzer — per-note oscillators, sim-time scheduling, ramps + metronome tests
Builds on the previous commit; reworks the buzzer audio for glitch-free,
cross-browser playback and adds a metronome quality suite.

- Per-note oscillators with short attack/release ramps, instead of one
  long-lived oscillator gated by gain: a fresh fixed frequency per note and no
  gain/frequency automation on a persistent node — Firefox in particular clicks
  and glitches the pitch otherwise.
- Schedule onsets by their SIMULATED inter-onset spacing (exact, even) with a
  light latency hold, instead of a wall-clock average. Turning a control (BPM,
  K…) re-locks immediately and the rhythm stays even — no bursts, no overlaps,
  no audio drifting away from the display.
- Place each note-off relative to its own onset, preserving the exact click
  length from the simulation (the onset scheduler now tracks onsets only).
- Poll PWM every 256 cycles (was 64): finer than any audible pulse, lighter on
  the frame loop.
- New src/__tests__/buzzer-metronome.test.ts: drives the buzzer as a metronome
  against a controllable audio clock and asserts even spacing, one oscillator
  per click with no overlap, correct pitch per metric level, burst absorption,
  and a clean re-lock on tempo change.

All simulation-parts + metronome tests pass (57).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 09:22:57 -03:00