Monorepo for Aesthetic.Computer aesthetic.computer
core reports stample-recording-bug.md
5.6 kB

Stample Recording & Playback Bug Report #

Date: 2026-02-07
File: system/public/aesthetic.computer/disks/stample.mjs

Symptoms #

  • Recording "only works once" — after the first recording, the strip buttons stop responding
  • Audio goes silent, especially when switching between stample and notepat
  • Sample playback doesn't recover after navigating away and back

Root Causes Found #

Bug 1: Strip Button Stuck in down=true State (PRIMARY) #

Location: act() → strip button up handler
Severity: Critical

The up callback returned false when e.pointer !== btn.downPointer (pointer ID mismatch between touch-down and lift events). The UI system (ui.mjs line 459) interprets return false as "keep btn.down = true". This permanently blocked future presses because the down handler checks if (btn.down) return false; as a guard.

On touch devices, pointer IDs can change between down and up events. This made the button permanently stuck after one use.

Fix: Always return true from the up handler — kill the sound unconditionally and release the button.

Bug 2: Dead Sound References in sounds[] Array #

Location: act() and sim()
Severity: Medium

After sounds[index]?.kill(0.1), the array entry was NOT cleared (sounds[index] remained a dead sound object). In sim(), sounds.find(s => s) found these killed sounds, causing bitmapProgress tracking to poll dead objects.

Fix: Set sounds[index] = undefined after killing.

Bug 3: Aggressive Mic Disconnect on Every Strip Press #

Location: act() → strip button down handler
Severity: High

Every strip button press called sound.microphone.disconnect(), which:

  1. Called detachMicrophone() in bios
  2. Disconnected the mic processor and mic node
  3. Stopped ALL media stream tracks (micStream.getTracks().forEach(t => t.stop()))
  4. Set microphone.connected = false

This completely destroyed the mic connection, requiring a full getUserMedia re-request. But micRecordButtonLabel wasn't updated to "Connect", so users thought they could record again immediately (it still said "Record"). They'd press Record, but it would reconnect instead. They had to press twice to record again.

Fix: Only interrupt the mic if it's actively recording (call cut() to stop the partial recording). Leave the connection intact otherwise. Also handle the "microphone-disconnect" event to update the button label.

Bug 4: microphone-disconnect Not Dispatched as Act Event #

Location: system/public/aesthetic.computer/lib/disk.mjs line 9631
Severity: Medium

The "microphone-disconnect" message from bios was handled in the disk worker but NOT forwarded to actAlerts. So e.is("microphone-disconnect") in stample's act() never fired, meaning the button label couldn't be updated on disconnect.

Fix: Added actAlerts.push("microphone-disconnect") in the handler.

Bug 5: No leave() Export for Cleanup #

Location: module exports
Severity: Low-Medium

Stample had no leave() function. When jumping to notepat, playing sounds and loops weren't explicitly killed. The bios does handle cleanup (killAllSound, clearSoundSampleCache, detachMicrophone), but having explicit cleanup prevents timing issues.

Fix: Added leave() that kills all active sounds, loops, and resets state.

Notepat Interaction #

When jump("notepat:stample") is called:

  1. Bios detachMicrophone() disconnects the mic
  2. Bios killAllSound() stops all speaker worklet sounds
  3. Bios clearSoundSampleCache() clears the worklet's cached buffers
  4. Bios deletes all sfx[] entries except the default sound

Notepat then boots and:

  • Loads the stample sample from IndexedDB (store["stample:sample"])
  • Re-registers it via sound.registerSample()
  • Sets wave = "stample" from the colon parameter

When returning to stample:

  • boot() re-runs, resets all state
  • Preloads "startup" (default sample) first
  • Then retrieves stored sample from IndexedDB, overriding the default
  • Re-registers the sample

This flow is correct and should work, provided the IndexedDB store was persisted. The persist calls in the recording up handler look correct.

Git History Summary #

Date Commit Description
2025-01-29 86cbd7d6 Initial creation as sprample
2025-01-29 b5adea25 Renamed to stample, sample spreading WIP
2025-01-29 1e9d4380 Add pats parameter support
2025-01-30 d87a5a22 Stample update
2025-02-04 7424d24c Pitch shift test
2025-02-04 63c31cd5 Y-axis scrub test
2025-02-23 cf10ff3d Sound system updates
2025-03-02–07 Multiple Multi-touch, general WIP
2025-03-25 7456c038 Resize/framing fixes
2025-03-29 e3380ebe Quick update for demo
2025-03-30 346e72c0 Stample todos
2025-06-27 3ddb6d5f UI pen updates
2025-09-30 75d3cc36 Fix stample scrub
2026-01-24–26 Multiple Major refactor: responsive layout system, bitmap loading, notepat integration
2026-01-27–28 Multiple KidLisp $code embedding, GPU effects, live audio updates
2026-02-01 c5d093e2 Scrub debugging
2026-02-05 f15dd3f5 Merge: accept remote stample.mjs
2026-02-06 05010c1e Fix duplicate floor declaration
2026-02-07 806b4d04 Stample fix (layout constants, KidLisp support)

Files Changed #

  • system/public/aesthetic.computer/disks/stample.mjs — 4 bug fixes
  • system/public/aesthetic.computer/lib/disk.mjs — 1 fix (microphone-disconnect event dispatch)