diff --git a/SOUND_DESIGN_HANDOFF.md b/SOUND_DESIGN_HANDOFF.md index cdc6295..d559b65 100644 --- a/SOUND_DESIGN_HANDOFF.md +++ b/SOUND_DESIGN_HANDOFF.md @@ -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 diff --git a/app/src/main/java/com/onthelevel/feature/level/AudioLevelAssist.kt b/app/src/main/java/com/onthelevel/feature/level/AudioLevelAssist.kt index d06f79a..1c8d1b2 100644 --- a/app/src/main/java/com/onthelevel/feature/level/AudioLevelAssist.kt +++ b/app/src/main/java/com/onthelevel/feature/level/AudioLevelAssist.kt @@ -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()