| 237 | } |
| 238 | |
| 239 | void ClientRxChainWidget::toggleStageBypass(int boxIdx) |
| 240 | { |
| 241 | if (!m_audio || boxIdx < 0 || boxIdx >= m_boxes.size()) return; |
| 242 | const auto& box = m_boxes[boxIdx]; |
| 243 | |
| 244 | // DSP status tile toggle: client-side NR is exclusive, so a click |
| 245 | // here means "turn off whichever module is currently on", and a |
| 246 | // click while everything is off re-enables the last-active module |
| 247 | // saved by AetherDspWidget::onDspButtonClicked. |
| 248 | if (box.kind == TileKind::StatusDsp) { |
| 249 | const bool anyOn = m_audio->nr2Enabled() || m_audio->nr4Enabled() |
| 250 | || m_audio->mnrEnabled() || m_audio->dfnrEnabled() |
| 251 | || m_audio->rn2Enabled() || m_audio->nvAfxEnabled(); |
| 252 | if (anyOn) { |
| 253 | QMetaObject::invokeMethod(m_audio, [audio = m_audio]() { |
| 254 | if (audio->nr2Enabled()) audio->setNr2Enabled(false); |
| 255 | if (audio->nr4Enabled()) audio->setNr4Enabled(false); |
| 256 | if (audio->mnrEnabled()) audio->setMnrEnabled(false); |
| 257 | if (audio->dfnrEnabled()) audio->setDfnrEnabled(false); |
| 258 | if (audio->rn2Enabled()) audio->setRn2Enabled(false); |
| 259 | if (audio->nvAfxEnabled()) audio->setNvAfxEnabled(false); |
| 260 | }); |
| 261 | } else { |
| 262 | const QString name = AppSettings::instance() |
| 263 | .value("LastClientNr", "").toString(); |
| 264 | if (name.isEmpty()) return; |
| 265 | // NR2 enable goes through MainWindow's wisdom prep path — |
| 266 | // plain audio-thread setter can crash on bad FFTW plans. |
| 267 | if (name == "NR2") { |
| 268 | emit nr2EnableWithWisdomRequested(); |
| 269 | return; |
| 270 | } |
| 271 | QMetaObject::invokeMethod(m_audio, [audio = m_audio, name]() { |
| 272 | if (name == "NR4") audio->setNr4Enabled(true); |
| 273 | else if (name == "MNR") audio->setMnrEnabled(true); |
| 274 | else if (name == "DFNR") audio->setDfnrEnabled(true); |
| 275 | else if (name == "RN2") audio->setRn2Enabled(true); |
| 276 | else if (name == "BNR") audio->setNvAfxEnabled(true); |
| 277 | }); |
| 278 | } |
| 279 | return; |
| 280 | } |
| 281 | |
| 282 | if (box.kind != TileKind::Stage) return; |
| 283 | if (!isStageImplemented(box.stage)) return; |
| 284 | |
| 285 | const bool willEnable = isStageBypassed(box.stage); |
| 286 | switch (box.stage) { |
| 287 | case AudioEngine::RxChainStage::Eq: |
| 288 | if (auto* eq = m_audio->clientEqRx()) { |
| 289 | eq->setEnabled(willEnable); |
| 290 | m_audio->saveClientEqSettings(); |
| 291 | } |
| 292 | break; |
| 293 | case AudioEngine::RxChainStage::Gate: |
| 294 | if (auto* g = m_audio->clientGateRx()) { |
| 295 | g->setEnabled(willEnable); |
| 296 | m_audio->saveClientGateRxSettings(); |
nothing calls this directly
no test coverage detected