Context:
The BOX-3 touch gamebook showed text + tappable choices but was silent.
We want narration through its ES8311 speaker while the text is on
screen — and tapping a choice must cut it instantly.
Approach:
Add a dedicated async, interruptible WAV player to cmd_exec (which owns
the speaker handle), streaming straight from the SD in small chunks so
any length plays without a big malloc. The gamebook plays each passage
WAV on render; a new tap (or returning to the menu) stops it.
Changes:
- cmd_exec.c/.h: cmd_exec_play_file_async(path) + cmd_exec_stop_play().
One persistent task streams a 16 kHz mono 16-bit WAV from the SD in
2 KB chunks (RAM-safe), and a new request / stop flag breaks the
stream mid-clip so playback is interruptible.
- gamebook.c: on entering a passage, play /sdcard/gamebook/<wav> if the
pack has audio (non-fatal when absent → stays text-only); stop the
narration when returning to the library.
Impact:
The BOX-3 reads the story aloud (16 kHz, matches AUDIO_SAMPLE_RATE)
while showing the text, and a tap cuts to the next passage. Audio is
optional — text-only packs still work.