From 8ff8fdb292ea6f85eb14939dadedefee45c3ba27 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Fri, 31 Jul 2026 17:29:52 +0200 Subject: [PATCH] =?UTF-8?q?feat(sim):=20board-agnostic=20speaker=20seam=20?= =?UTF-8?q?=E2=80=94=20audio=20out=20plays=20on=20the=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setSpeakerMonitor mirrors setMicrophoneSource: a part that models a board with an on-board speaker/jack (reSpeaker Lite) gets the peak of each block the guest played, so it can light a meter, while the audio itself goes to the host's sound card via the engine bridge. Nothing is wired for it on the canvas — that is the point: a real board plugged into your speakers has no wire to draw. No-op on bridges without an audio path, which reads as a silent speaker. --- frontend/src/store/useSimulatorStore.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts index 4240d58d..b060735d 100644 --- a/frontend/src/store/useSimulatorStore.ts +++ b/frontend/src/store/useSimulatorStore.ts @@ -408,6 +408,19 @@ class Esp32BridgeShim { ).setMicrophoneSource?.(source); } + /** + * Watch the board's audio OUTPUT: the callback gets the peak level of each + * block the guest played (0..32767). The audio itself goes to the host's + * sound card — a board with an on-board speaker/jack plays through YOUR + * speakers, so nothing is wired for it on the canvas; this is only the + * "is it making sound" signal a part needs to animate. Pass null to stop. + * No-op on bridges without an audio path (a silent speaker). + */ + setSpeakerMonitor(cb: ((peak: number) => void) | null): void { + (this.bridge as { setSpeakerMonitor?: (c: ((p: number) => void) | null) => void }) + .setSpeakerMonitor?.(cb); + } + /** Remove a previously-registered virtual device. */ removeI2CDevice(addr: number, _bus: 0 | 1 = 0): void { this.i2cBusInstance.removeDevice(addr);