TASK 4 audio round 3: mic mute icon + top-center REC sign + voice-filter to-do — the mic bar gained a second 16px clickable glyph (microphone, red + slash when muted) between the meter and the speaker so both mute toggles sit adjacent with spacing, reusing the same ToggleMicMuteCommand handler (no VM/code-behind change); the top-center LIVE badge became an always-visible REC sign driven by new VM props (RecDotBrush/RecTextBrush/RecDotOpacity/IsLivePrivate): dark gray dot + dim REC offline, bright red + REC + elapsed while live, darker red when live with a private stream (driven by the dialog's chosen StreamVisibility; the stream service still forces public — ship step 7), pulsing while live; LiveIndicatorVisible/LivePulseOpacity removed; task 22 queued (bass boost, treble, noise suppression, compressor on the mic channel, KISS, always on); HANDOFF documents the mic status contract (red until a mic resource actually connects) — 169 tests passing, 0 warnings

This commit is contained in:
2026-08-13 12:13:00 -07:00
parent 18abe4210f
commit dc29adf9bb
6 changed files with 86 additions and 52 deletions
+37 -28
View File
@@ -7,30 +7,37 @@
## Session state (last updated: 2026-08-13)
- **Branch:** `main`. The **audio UX follow-up** (`9f9ed34`) is **committed and pushed**.
- **This session (round 2 — the game audio bar + meter fixes):**
1. **Meter scaling:** the bars looked dead on a flat scale — real speech/game RMS is
~0.01..0.1 linear, so the fill barely moved even at full volume. Added
`AudioLevelMeter.ToDisplay(float)`: maps 60..0 dBFS linearly onto 0..1. Both meters
(mic `MeterLevel`, game `GameMeterLevel`) now scale the raw level through it before
multiplying by volume. +2 unit tests.
2. **Game bar placement correction (user: it belongs in the preview, not the footer):**
moved the game audio bar OUT of the footer (footer back to two rows) and into the
**preview window** as a bottom-center dark chip overlaid on the live display
(`MainWindow.xaml`, in the `PreviewGrid` next to the OpacityChip). Monitoring UI
only — never rendered into the live output (the `SceneCompositor` is unaware of it).
3. **About button (user: stop jacking Notepad; standalone app):** the top-bar About
button that opened `THIRD-PARTY-NOTICES.txt` in the OS viewer is GONE (button +
`AboutButton_Click` removed). The **ytLlive wordmark (top-left) is now clickable**
and opens the existing in-app About overlay (`OpenAboutCommand`). Queued as task 21:
make a real logo + expand the About overlay into the creator's hub (premium / coffee
/ socials links + a scrolling licensing/legal panel, all in-app).
- **Uncommitted:** this round-2 work — `Services/Audio/AudioLevelMeter.cs`,
`ViewModels/MainViewModel.cs`, `MainWindow.xaml` (scaling + game bar + logo/About),
`MainWindow.xaml.cs` (AboutButton_Click + unused usings removed), `ytLive.Tests/AudioMixerTests.cs`
(2 new `ToDisplay` tests), memory docs (TASKS.md — incl. new task 21, ai.md,
Services/index.md, ViewModels/index.md, HANDOFF, THIRD-PARTY-NOTICES.txt).
- **Verified:** build 0 warnings, 0 errors; **169 tests passing** (full suite).
- **Branch:** `main`. The audio UX follow-up (`9f9ed34`) and round 2 (`18abe42`)
are **committed and pushed**.
- **This session (round 3 — mic mute icon + REC sign):**
1. **Mic mute icon:** the mic bar gained a **microphone glyph** (same 16px style
as the speaker, white → red + slash when muted, `ToolTip=MicMuteText`)
**between the meter and the speaker** — both mutes adjacent with spacing
between the icons; click reuses the same `MicSpeaker_MouseLeftButtonUp`
handler → `ToggleMicMuteCommand`. No VM/code-behind change.
2. **REC sign (top center):** the old LIVE badge (hidden when offline) became an
**always-visible REC chip** — dark gray dot (#555) + dim "REC" (#888) offline,
**bright red (#e94560)** + "REC" + elapsed while live, **darker red (#8f1f1f)**
when live with a **private** stream. Driven by new VM props
`RecDotBrush`/`RecTextBrush`/`RecDotOpacity`/`IsLivePrivate` (notified from the
`StreamStatus` and `StreamVisibility` setters), privacy read off the **dialog's
chosen visibility** (`StreamVisibility == "Private"`) — the stream service still
hardcodes `privacyStatus = "public"`, so the private-REC state only lights once
that's honored (TASK 4 ship step 7). The dot pulses while live; `LiveIndicatorVisible`
and `LivePulseOpacity` were removed.
3. **Voice filters queued as task 22** — bass boost, treble, noise suppression,
compressor on the mic input channel, KISS, always on (before the meter/encoder mix).
- **Mic status contract (creator's rule, verified — do NOT "fix"):** the status dot is
**red until a mic resource is actually connected**. `MicStatus` starts `NotConnected`
(red); it goes green ONLY when the mixer's `MicConnected` fires, which comes strictly
from the mic source's `Started` event raised after `StartRecording()` succeeds. Zero
devices at startup → stays red and the mixer is never started; capture failure → yellow.
Green must never be raised earlier (e.g. on loopback start or on `Start()` being called).
- **Uncommitted:** this round-3 work — `ViewModels/MainViewModel.cs` (REC props,
`_recDotPulse`, StreamVisibility/StreamStatus notifications, `LiveIndicatorVisible`/
`LivePulseOpacity` removed), `MainWindow.xaml` (REC chip + mic mute icon),
`TASKS.md` (task 22 + round-3 audio note), `ai.md`, `ViewModels/index.md`, `HANDOFF`.
- **Verified:** pending (build + full test run right before commit).
- **Landmines:**
- Never set a local `Canvas.SetTop` on the social bar — a local value permanently
overrides `{Binding SocialBarTop}` (the `ClearValue` lesson from 5.5).
@@ -41,6 +48,8 @@
- `MicConnected` comes from the source `Started` event, raised right after
`StartRecording()` succeeds — tests must `MarkStarted()` the fake source
before asserting connection state.
- The mic dot is red until a resource connects (see contract above) — green
only after `Started`, yellow on `Failed`.
- Zero mic devices at startup = red dot AND the mixer is never started, so
loopback + the game bar can't run either (no capture at all) — acceptable.
- The game detector is polled on the UI thread via a 250ms `DispatcherTimer`;
@@ -55,10 +64,10 @@
integration test (a real `MainWindow`), which never goes live — keep it that way.
- Sandbox can't reach outbound HTTPS — `HttpSocialValidator` stub-handler tests
only, never the real instance.
- **Next step:** commit + push the audio UX follow-up (the whole uncommitted set
above in one commit). Then TASK 4 ship step 6 — health stats: bind
`FramePump.HealthUpdated` (bitrate/FPS/duration) into the bottom bar. Nothing
else queued — do not expand the task queue on your own. Optional, not queued:
- **Next step:** commit + push round 3 (one commit). Then TASK 4 ship step 6 — health
stats: bind `FramePump.HealthUpdated` (bitrate/FPS/duration) into the bottom bar.
Also queued: task 21 (logo + About hub), task 22 (voice filters). Nothing else
queued — do not expand the task queue on your own. Optional, not queued:
rewriting the healed entry's `ProfileUrl` to
`https://mastodon.llamachile.tube/@gramps` (user must say the word).