GBC sound (T-Deck Max), mesh stays live in-game, fast waveform at 12 frames, wrap fix

SOUND (Max, ES8311; Pro stays silent)
- minigb_apu vendored from Meck-P4 (MIT), run at 22050 Hz: at 44100 it
  cost 3.6-4.0 ms of the 16.7 ms frame and the game fell to 0.98x, which
  drained the DMA queue and glitched. Per-frame timings (core / apu /
  i2s wait) now print with the speed line.
- Bring-up reuses the notification-tone path: shared Audio object owns
  I2S port 0 (with MCLK), XL9555 routing and amp, then codec init after
  the clocks are running. Raw PCM written per frame; a repeated sample
  every sixth frame keeps production a hair above the DAC so its clock
  paces the game instead of the queue running dry.
- Software gain 1/8 (codec DAC sits at 0 dB); GBC_AUDIO_SHIFT to tune.
- 950 ms delay line (PSRAM) so sound lands with the picture, which
  reaches the glass ~1 s after its frame; GBC_AUDIO_DELAY_MS to tune.
- Games start muted; mic key toggles the codec mute in both keyboard
  drivers' raw mode; footer shows the current hint. Amp off on quit.
- Notification tones skipped while a game runs (game owns the codec).

MESH LIVE DURING PLAY
- The OTA-style radio pause is gone (GBC_PAUSE_RADIO=1 restores it):
  the mesh runs on the other core and already tolerates the panel
  blocking the loop. Game header now matches the home screen's -- the
  cumulative unread channel count where the node name goes, clock,
  battery percent. "New:" toasts suppressed only while a ROM is running
  (Snake and Minesweeper keep them).

DISPLAY
- Fast register waveform set to 12 frames per push (FAST_LUT_FRAMES):
  judged the best balance of UI speed and contrast. Interface only; the
  game keeps the factory waveform.
- Windowed game refresh dropped: measured to save nothing, and it left
  the footer row unrefreshed. Normal partial refresh, change-detected.
- Adafruit GFX auto-wrap turned off in the e-ink driver (all e-ink
  builds): it dropped a glyph onto the next line's margin when a line
  ran a few pixels past the edge (seen with Larger Noto in compose).
  Compose wrap width also allows for the driver's 2-unit x offset.
- Game start does one full refresh (tried as a ghosting fix; NPC
  ghosting in Pokemon Gold is the game + dither + factory partial
  waveform and shows on the stock build too).

Files: examples/companion_radio/{main.cpp, ui-new/GBCEmulatorScreen.{h,cpp},
ui-new/UITask.cpp, ui-new/minigb_apu.{c,h}}, src/helpers/ui/GxEPDDisplay.cpp,
src/helpers/ui/GxEPD2_310_GDEQ031T10_FAST.cpp,
variants/lilygo_tdeck_{max,pro}/TCA8418Keyboard.h
This commit is contained in:
pelgraine committed 2026-09-15 18:42:55 +10:00
1 parent 1bad37d1ad
commit 5a911619f7
7 files changed
+959 -23

No files matched your search

+13 -1
View File
@@ -53,6 +53,7 @@ private:
bool _rawJoypad;
volatile uint8_t _rawMask; // Peanut-GB direct.joypad bit layout, set = held
volatile bool _rawExit; // Q or Shift+Backspace press-edge latch
volatile bool _rawMute; // Mic key press-edge latch (game sound mute toggle)
bool _rawShiftL; // left Shift (35) physically held
bool _rawShiftR; // right Shift (31) physically held
@@ -73,6 +74,10 @@ private:
if (pressed) _rawExit = true;
return 0;
}
if (keyCode == 34) { // Mic = mute toggle
if (pressed) _rawMute = true;
return 0;
}
if (keyCode == 11) { // Backspace: Shift+Backspace = quit
if (pressed && (_rawShiftL || _rawShiftR)) _rawExit = true;
return 0;
@@ -211,7 +216,7 @@ public:
: _addr(addr), _wire(wire), _initialized(false),
_shiftActive(false), _shiftConsumed(false), _shiftHeld(false), _leftShiftHeld(false), _rightShiftHeld(false), _shiftUsedWhileHeld(false), _altActive(false), _symActive(false), _micHeld(false), _lastShiftTime(0),
_enterHeld(false), _enterPressTime(0),
_rawJoypad(false), _rawMask(0), _rawExit(false), _rawShiftL(false), _rawShiftR(false) {}
_rawJoypad(false), _rawMask(0), _rawExit(false), _rawMute(false), _rawShiftL(false), _rawShiftR(false) {}
bool begin() {
// Check if device responds
@@ -461,6 +466,7 @@ public:
_rawJoypad = on;
_rawMask = 0;
_rawExit = false;
_rawMute = false;
_rawShiftL = _rawShiftR = false;
_shiftActive = _shiftHeld = _leftShiftHeld = _rightShiftHeld = false;
_shiftUsedWhileHeld = _shiftConsumed = false;
@@ -475,6 +481,12 @@ public:
_rawExit = false;
return e;
}
// Mic key press-edge latch, consumed on read.
bool rawMutePressed() {
bool m = _rawMute;
_rawMute = false;
return m;
}
bool isMicHeld() const { return _micHeld; }
// Check if shift was pressed within the last N milliseconds
+13 -1
View File
@@ -49,6 +49,7 @@ private:
bool _rawJoypad;
volatile uint8_t _rawMask; // Peanut-GB direct.joypad bit layout, set = held
volatile bool _rawExit; // Q or Shift+Backspace press-edge latch
volatile bool _rawMute; // Mic key press-edge latch (game sound mute toggle)
bool _rawShiftL; // left Shift (35) physically held
bool _rawShiftR; // right Shift (31) physically held
@@ -66,6 +67,10 @@ private:
if (pressed) _rawExit = true;
return;
}
if (keyCode == 34) { // Mic = mute toggle
if (pressed) _rawMute = true;
return;
}
if (keyCode == 11) { // Backspace: Shift+Backspace = quit
if (pressed && (_rawShiftL || _rawShiftR)) _rawExit = true;
return;
@@ -203,7 +208,7 @@ public:
: _addr(addr), _wire(wire), _initialized(false),
_shiftActive(false), _shiftConsumed(false), _shiftHeld(false), _shiftUsedWhileHeld(false), _altActive(false), _symActive(false), _micHeld(false), _lastShiftTime(0),
_enterHeld(false), _enterPressTime(0),
_rawJoypad(false), _rawMask(0), _rawExit(false), _rawShiftL(false), _rawShiftR(false) {}
_rawJoypad(false), _rawMask(0), _rawExit(false), _rawMute(false), _rawShiftL(false), _rawShiftR(false) {}
bool begin() {
// Check if device responds
@@ -431,6 +436,7 @@ public:
_rawJoypad = on;
_rawMask = 0;
_rawExit = false;
_rawMute = false;
_rawShiftL = _rawShiftR = false;
_shiftActive = _shiftHeld = false;
_shiftUsedWhileHeld = _shiftConsumed = false;
@@ -445,6 +451,12 @@ public:
_rawExit = false;
return e;
}
// Mic key press-edge latch, consumed on read.
bool rawMutePressed() {
bool m = _rawMute;
_rawMute = false;
return m;
}
bool isMicHeld() const { return _micHeld; }
// Check if shift was pressed within the last N milliseconds