You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sibling of #2301 (TX strip). Wires the existing-but-dead m_rxBtn
toggle in AetherialAudioStrip and lands the RX-mode counterpart
of every component the TX strip ships.
Goal
Make the strip's TX/RX toggle functional. Mirror the TX panel grid
chain widget for RX, with the chain order and layout the
maintainer specified.
Motivation
TX strip is built. RX side has only the docked ClientRxChainWidget + ClientRxDspApplet + scattered editors.
m_rxBtn already exists in the chain row at src/gui/AetherialAudioStrip.cpp:212-218 with a "coming soon"
tooltip — wiring it up is the entry point.
9 tiles total. RADIO and SPEAK are status-only endpoints —
same semantics as ClientRxChainWidget. RADIO greens when PC
Audio is enabled, SPEAK greens when output is unmuted.
ADSP (renamed from current "DSP") is a clickable launcher tile
for the in-strip ADSP panel (the AetherDsp NR cluster). Greens
when any of NR2 / NR4 / DFNR / BNR are active; rotates the
active module's short label.
The 6 middle stages (AGC-T / EQ / AGC-C / DESS / TUBE / EVO)
map onto RxChainStage enum values: Gate → "AGC-T", Eq → "EQ", Comp → "AGC-C", (new)DeEss → "DESS", Tube → "TUBE", Pudu → "EVO".
Existing relabel mapping is in src/gui/ClientRxChainWidget.cpp:74-77; DeEss is new and
needs to be added to the enum and that stageLabel() switch.
Single-click toggles bypass; double-click opens the panel —
identical to StripChainWidget.
Panel layout
7 cells, 2 : 1 : 2 : 2 cells per row across 4 rows (the EQ row
contains a single cell that spans both columns):
Add DeEss = 6 to AudioEngine::RxChainStage
(src/core/AudioEngine.h:286-293). Default chain order in AudioEngine.cpp:1726-1730 becomes: Eq, Gate, Comp, DeEss, Tube, Pudu — matching the chain order
left-to-right after the static endpoints. kMaxRxChainStages
already 8, headroom is fine.
Add case DeEss: /* TODO */ to the audio-thread block dispatch
(AudioEngine.cpp:1587-1592) and to the name↔enum maps
(:1699-1716).
Master RX bypass
Add setRxBypassed(bool), isRxBypassed(), rxBypassChanged(bool) as exact siblings of the TX equivalents
(AudioEngine.h:317-319). Same snapshot-and-restore semantics:
on bypass-on, snapshot the currently-enabled RX stages and disable
them; on bypass-off, re-enable only that snapshot. Manual stage
toggles during bypass survive the restore.
Persistence: AppSettings("RxChainBypassed"), sibling of TxChainBypassed.
Coexist via duplication
Same call as #2301: copy each TX Strip*Panel to a sibling StripRx*Panel (or rename appropriately for AGC), swap the engine
getters/setters to the RX-side equivalents, leave the TX panels
alone. Cutover deletion is a future pass.
Files to add
StripRxChainWidget.{h,cpp}
Mirror of StripChainWidget (~800 LOC). Same single-row painted
strip with drag-reorder + click semantics. Iterates RxChainStage
instead of TxChainStage. Status tiles: RADIO, ADSP, SPEAK.
StripAdspPanel is a thin wrapper around a fresh AetherDspWidget
instance — that widget is already designed for reuse
(AetherDspDialog and ClientRxDspApplet already share it).
Step-by-step
Step 1 — Engine RX scaffolding
Add RxChainStage::DeEss to the enum.
Update applyRxChain() block dispatch with a case DeEss
TODO branch.
Update name↔enum map functions to handle "DeEss".
Update default setRxChainStages order to include DeEss in
chain position (between Comp and Tube).
Endpoint tiles: RADIO (leftmost, green when PC Audio enabled),
ADSP (between RADIO and user stages), SPEAK (rightmost, green
when output unmuted).
User stages: AGC-T / EQ / AGC-C / DESS / TUBE / EVO via the
existing stageLabel() map (extended for DeEss).
Single-click: toggle bypass on user stages, open AetherDsp
in-strip panel (or focus it) on ADSP. Double-click: open the
in-strip panel (or open the floating editor while panels are
still iterating).
Drag-reorder: same as TX side — emits chainReordered() after
the engine has the new order.
Step 3 — Strip RX panels
6 stage panels duplicated from TX siblings, RX engine wiring.
1 StripAdspPanel wrapping AetherDspWidget.
Each panel renders a "— RX" suffix in its title to match the
TX panels' "— TX" convention seen in the screenshot.
Engine getters/setters for the RX stages: most don't exist yet
(RX block dispatch is all TODO). This issue ships UI
scaffolding bound to placeholder getters/setters; actual DSP is
out of scope.
Step 4 — Mode toggle wiring in AetherialAudioStrip
Two QStackedWidgets for the chain row and the panel grid. Page
0 = TX (existing widgets), page 1 = RX (new widgets).
m_rxBtn::toggled(true) switches both to page 1, repoints the
BYPASS button to RX bypass, updates the title-bar suffix.
Drop "coming soon" from the RX button tooltip.
Step 5 — Persistence
AppSettings("AetherialStripMode") — last selected TX/RX.
Restored on show. Default = TX.
AetherialStripGeometry / AetherialStripVisible stay shared
across modes (single window).
Step 6 — MainWindow wiring
stageEnabledChanged overload for RxChainStage so the docked ClientRxChainWidget repaints in lock-step.
BYPASS chain-applet button needs to know which mode the strip is
in, OR the docked applet gets its own RX BYPASS — TBD.
cutoffsDragRequested is TX-only; RX has no transmit filter, so
no RX equivalent.
Decisions made
Panel naming follows the user-facing label. Files and
classes are StripAgcTPanel, StripAgcCPanel, StripAdspPanel, StripEvoPanel — not the underlying engine enum names
(Gate / Comp / Pudu). For stages whose RX label matches the
engine enum (EQ, TUBE, DESS), use StripRxEqPanel, StripRxTubePanel, StripRxDeEssPanel so they're clearly the
RX siblings of the existing TX Strip*Panel files.
ADSP panel = wrapper for AetherDSP Settings
(AetherDspWidget). No full duplicate — the strip embeds a
fresh AetherDspWidget instance with strip-styled chrome. Same
pattern AetherDspDialog and ClientRxDspApplet already use.
BYPASS is coordinated across all four UI surfaces. The
docked ClientChainApplet already has a TX/RX toggle and its
own BYPASS button (src/gui/ClientChainApplet.cpp:91-174), so
the natural coordination is:
Docked BYPASS targets engine TX bypass when its mode = TX,
engine RX bypass when its mode = RX
Strip BYPASS targets engine TX bypass when strip mode = TX,
engine RX bypass when strip mode = RX
Engine emits txBypassChanged / rxBypassChanged per
mode; every BYPASS button observes both and updates its
visual state to match the bypass for whichever mode it is
currently displaying
Strip mode and docked mode are independent UI states — only the
engine state is shared. Step 1 lands the engine signal
(rxBypassChanged); Step 4 wires the strip's button to switch
observers on mode toggle; Step 6 extends the docked applet's onBypassToggled to dispatch to the engine setter for its
current mode.
Out of scope (subsequent issues)
Actual RX DSP implementations. RX block dispatch is stubbed
TODOs. This issue ships UI scaffolding only; each stage's
signal-processing implementation is a separate phase per memory project_tx_dsp_chain_architecture.md's pattern.
Cutover deletion. The docked ClientRxChainWidget / ClientRxDspApplet stay in place; deletion is a follow-up after
the strip is feature-complete.
Footer elements. RX equivalent of TX OUTPUT meter / master /
mute / S/N decoration — iteration 2+.
Hot-swap visuals. Animated TX↔RX transition (slide / cross-
fade). Not required for iteration 1; a hard swap is fine.
Plan: Aetherial Audio Channel Strip — RX DSP window
Sibling of #2301 (TX strip). Wires the existing-but-dead
m_rxBtntoggle in
AetherialAudioStripand lands the RX-mode counterpartof every component the TX strip ships.
Goal
Make the strip's TX/RX toggle functional. Mirror the TX panel grid
maintainer specified.
Motivation
ClientRxChainWidget+ClientRxDspApplet+ scattered editors.m_rxBtnalready exists in the chain row atsrc/gui/AetherialAudioStrip.cpp:212-218with a "coming soon"tooltip — wiring it up is the entry point.
Architecture decisions
Mode-aware AetherialAudioStrip, sibling RX widgets
The strip becomes mode-aware. The TX/RX toggle swaps:
StripChainWidget↔StripRxChainWidget)Implementation: two
QStackedWidgets (chain row, panel grid),indexed 0=TX / 1=RX, swapped on
m_rxBtn::toggled.Chain order
RADIOandSPEAKare status-only endpoints —same semantics as
ClientRxChainWidget. RADIO greens when PCAudio is enabled, SPEAK greens when output is unmuted.
ADSP(renamed from current "DSP") is a clickable launcher tilefor the in-strip ADSP panel (the AetherDsp NR cluster). Greens
when any of NR2 / NR4 / DFNR / BNR are active; rotates the
active module's short label.
AGC-T / EQ / AGC-C / DESS / TUBE / EVO)map onto
RxChainStageenum values:Gate → "AGC-T",Eq → "EQ",Comp → "AGC-C",(new)
DeEss → "DESS",Tube → "TUBE",Pudu → "EVO".Existing relabel mapping is in
src/gui/ClientRxChainWidget.cpp:74-77;DeEssis new andneeds to be added to the enum and that
stageLabel()switch.identical to
StripChainWidget.Panel layout
7 cells,
2 : 1 : 2 : 2cells per row across 4 rows (the EQ rowcontains a single cell that spans both columns):
Mapping mirrors the chain: row order follows signal flow
(ADSP → AGC-T, EQ wide, AGC-C → DESS, TUBE → EVO).
Engine: add
RxChainStage::DeEss+ master RX bypassNew stage value
Add
DeEss = 6toAudioEngine::RxChainStage(
src/core/AudioEngine.h:286-293). Default chain order inAudioEngine.cpp:1726-1730becomes:Eq, Gate, Comp, DeEss, Tube, Pudu— matching the chain orderleft-to-right after the static endpoints.
kMaxRxChainStagesalready 8, headroom is fine.
Add
case DeEss: /* TODO */to the audio-thread block dispatch(
AudioEngine.cpp:1587-1592) and to the name↔enum maps(
:1699-1716).Master RX bypass
Add
setRxBypassed(bool),isRxBypassed(),rxBypassChanged(bool)as exact siblings of the TX equivalents(
AudioEngine.h:317-319). Same snapshot-and-restore semantics:on bypass-on, snapshot the currently-enabled RX stages and disable
them; on bypass-off, re-enable only that snapshot. Manual stage
toggles during bypass survive the restore.
Persistence:
AppSettings("RxChainBypassed"), sibling ofTxChainBypassed.Coexist via duplication
Same call as #2301: copy each TX
Strip*Panelto a siblingStripRx*Panel(or rename appropriately for AGC), swap the enginegetters/setters to the RX-side equivalents, leave the TX panels
alone. Cutover deletion is a future pass.
Files to add
StripRxChainWidget.{h,cpp}Mirror of
StripChainWidget(~800 LOC). Same single-row paintedstrip with drag-reorder + click semantics. Iterates
RxChainStageinstead of
TxChainStage. Status tiles: RADIO, ADSP, SPEAK.Per-stage panels (7 total)
AetherDspWidget(thin wrapper)StripGatePanelStripEqPanelStripCompPanelStripDeEssPanelStripTubePanelStripPuduPanelNaming:
StripAdspPanel,StripAgcTPanel,StripRxEqPanel,StripAgcCPanel,StripRxDeEssPanel,StripRxTubePanel,StripEvoPanel. (Alternative: prefix everything withStripRx.Maintainer call.)
StripAdspPanelis a thin wrapper around a freshAetherDspWidgetinstance — that widget is already designed for reuse
(
AetherDspDialogandClientRxDspAppletalready share it).Step-by-step
Step 1 — Engine RX scaffolding
RxChainStage::DeEssto the enum.applyRxChain()block dispatch with acase DeEssTODO branch.
setRxChainStagesorder to include DeEss inchain position (between Comp and Tube).
setRxBypassed/isRxBypassed/rxBypassChangedandm_rxBypassSnapshot/m_isRxBypassedmembers.AppSettings("RxChainBypassed").Step 2 —
StripRxChainWidgetStripChainWidget.ADSP (between RADIO and user stages), SPEAK (rightmost, green
when output unmuted).
existing
stageLabel()map (extended for DeEss).in-strip panel (or focus it) on ADSP. Double-click: open the
in-strip panel (or open the floating editor while panels are
still iterating).
chainReordered()afterthe engine has the new order.
Step 3 — Strip RX panels
StripAdspPanelwrappingAetherDspWidget.TX panels' "— TX" convention seen in the screenshot.
(RX block dispatch is all TODO). This issue ships UI
scaffolding bound to placeholder getters/setters; actual DSP is
out of scope.
Step 4 — Mode toggle wiring in
AetherialAudioStripQStackedWidgets for the chain row and the panel grid. Page0 = TX (existing widgets), page 1 = RX (new widgets).
m_rxBtn::toggled(true)switches both to page 1, repoints theBYPASS button to RX bypass, updates the title-bar suffix.
Step 5 — Persistence
AppSettings("AetherialStripMode")— last selected TX/RX.Restored on show. Default = TX.
AetherialStripGeometry/AetherialStripVisiblestay sharedacross modes (single window).
Step 6 — MainWindow wiring
stageEnabledChangedoverload forRxChainStageso the dockedClientRxChainWidgetrepaints in lock-step.in, OR the docked applet gets its own RX BYPASS — TBD.
cutoffsDragRequestedis TX-only; RX has no transmit filter, sono RX equivalent.
Decisions made
Panel naming follows the user-facing label. Files and
classes are
StripAgcTPanel,StripAgcCPanel,StripAdspPanel,StripEvoPanel— not the underlying engine enum names(
Gate / Comp / Pudu). For stages whose RX label matches theengine enum (
EQ,TUBE,DESS), useStripRxEqPanel,StripRxTubePanel,StripRxDeEssPanelso they're clearly theRX siblings of the existing TX
Strip*Panelfiles.ADSP panel = wrapper for AetherDSP Settings
(
AetherDspWidget). No full duplicate — the strip embeds afresh
AetherDspWidgetinstance with strip-styled chrome. Samepattern
AetherDspDialogandClientRxDspAppletalready use.BYPASS is coordinated across all four UI surfaces. The
docked
ClientChainAppletalready has a TX/RX toggle and itsown BYPASS button (
src/gui/ClientChainApplet.cpp:91-174), sothe natural coordination is:
engine RX bypass when its mode = RX
engine RX bypass when strip mode = RX
txBypassChanged/rxBypassChangedpermode; every BYPASS button observes both and updates its
visual state to match the bypass for whichever mode it is
currently displaying
Strip mode and docked mode are independent UI states — only the
engine state is shared. Step 1 lands the engine signal
(
rxBypassChanged); Step 4 wires the strip's button to switchobservers on mode toggle; Step 6 extends the docked applet's
onBypassToggledto dispatch to the engine setter for itscurrent mode.
Out of scope (subsequent issues)
TODOs. This issue ships UI scaffolding only; each stage's
signal-processing implementation is a separate phase per memory
project_tx_dsp_chain_architecture.md's pattern.ClientRxChainWidget/ClientRxDspAppletstay in place; deletion is a follow-up afterthe strip is feature-complete.
mute / S/N decoration — iteration 2+.
fade). Not required for iteration 1; a hard swap is fine.