Doc cleanup: handoff + load-listener comment match shipped bullseye audio

Codex re-audit of 0cb315f was functional-green (81 tests, clean build,
device-green) with two non-runtime doc findings:
- SOUND_DESIGN_HANDOFF.md still described the retired "Level on lock,
  once, then silence" behavior. Now documents immediate bullseye
  alignment (enter <=0.2 / exit >=0.35 spatial hysteresis, no dwell) and
  the looping level.wav, with the velocity lock kept separate for
  lime/label/haptic.
- The SoundPool load listener's comment still said "one-shot Level";
  updated to describe the pending-loop-start path.

No code behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jay
2026-07-17 11:47:23 -04:00
parent 0cb315fdcc
commit f8aa27e6cb
2 changed files with 20 additions and 9 deletions
+18 -7
View File
@@ -8,7 +8,9 @@ the same 500 Hz blip:
- **Edge mode (1-D)**: sonar staircase, one discrete report per settle event.
- **Surface mode (2-D)**: continuous proximity ticking — tick rate rises as
you approach the bullseye; on lock, `level.wav` plays as the arrival sound.
you approach the bullseye; the moment you're on center, the ticks give way to
the looping `level.wav` bullseye sound. One vocabulary: faster ticks = closer,
bullseye sound = centered right now.
The staircase does NOT ship in surface mode. All earlier discussion of 2-D
dominant-axis mapping is dead — surface is axis-agnostic warmer/colder by
@@ -30,12 +32,21 @@ Rules — these are the difference between this and the old rejected
~8 ticks/s (near). Hard cap at 8/s; beyond ~10/s it fuses into a buzz.
2. **Loudness stays constant** as rate rises. The acceleration is the signal;
volume ramping is what turns it into a panic siren.
3. On entering the lock zone: stop ticking, play `level.wav` once, then stay
silent while level holds.
4. **Hysteresis on the lock boundary** (enter slightly inside, exit slightly
outside) so the arrival sound can't retrigger repeatedly at the threshold.
5. Ticking runs continuously, no settle gate — in this mode the realtime rate
IS the feedback. The settle-then-sound rule below applies to edge mode.
3. On entering the center zone: stop ticking and **immediately** start the
looping `level.wav` — no dwell, no velocity gate, even on a fast pass. A
momentary alignment is real locating information; that little zone needs the
most help. `level.wav` loops while you rest on center and stops the instant
you leave (ticks resume).
4. **Spatial hysteresis** on the zone (enter ≤0.2°, rearm only after leaving
≥0.35°) — *not* a time debounce, which would hide a legitimate quick
re-crossing. Alignment is measured from the same hypot(pitch, roll) that
drives the bubble, so the sound can't lag the visual.
5. Ticking runs continuously outside the zone, no settle gate — the realtime
rate IS the feedback. (The settle-then-sound rule applies to edge mode.)
6. The stronger **"held level" confirmation — persistent lime, the on-screen
label, and the haptic — is decided separately** by the velocity-aware lock
(≤0.2° and moving slowly for ~175 ms). The locating *sound* never waits on
it: a fast fly-through gets the bullseye cue but not the "you nailed it."
Rejected candidates kept for reference in AudioGenerator: the sustained
"energy field" loops (`bullseye-field-*.wav`) and the alternate ticks
@@ -148,8 +148,8 @@ private class SonarSoundPool(context: Context) {
soundPool.setOnLoadCompleteListener { _, sampleId, status ->
if (status == 0) {
loaded += sampleId
// The one-shot Level can't rely on a retry (the policy fires it once), so
// play a queued Level the moment its sample lands.
// If ALIGNED arrived before the Level sample finished loading, start the loop
// the moment it lands (ensureLevelLooping set levelPending instead of dropping it).
if (sampleId == levelSound && levelPending) {
levelPending = false
startLevelLoop()