| 4323 | } |
| 4324 | |
| 4325 | void AudioEngine::loadClientCompSettings() |
| 4326 | { |
| 4327 | if (!m_clientCompTx) return; |
| 4328 | auto& s = AppSettings::instance(); |
| 4329 | m_clientCompTx->setEnabled( |
| 4330 | s.value("ClientCompTxEnabled", "False").toString() == "True"); |
| 4331 | m_clientCompTx->setThresholdDb( |
| 4332 | s.value("ClientCompTxThresholdDb", "-18.0").toFloat()); |
| 4333 | m_clientCompTx->setRatio( |
| 4334 | s.value("ClientCompTxRatio", "3.0").toFloat()); |
| 4335 | m_clientCompTx->setAttackMs( |
| 4336 | s.value("ClientCompTxAttackMs", "20.0").toFloat()); |
| 4337 | m_clientCompTx->setReleaseMs( |
| 4338 | s.value("ClientCompTxReleaseMs", "200.0").toFloat()); |
| 4339 | m_clientCompTx->setKneeDb( |
| 4340 | s.value("ClientCompTxKneeDb", "6.0").toFloat()); |
| 4341 | m_clientCompTx->setMakeupDb( |
| 4342 | s.value("ClientCompTxMakeupDb", "0.0").toFloat()); |
| 4343 | m_clientCompTx->setLimiterEnabled( |
| 4344 | s.value("ClientCompTxLimEnabled", "True").toString() == "True"); |
| 4345 | m_clientCompTx->setLimiterCeilingDb( |
| 4346 | s.value("ClientCompTxLimCeilingDb", "-1.0").toFloat()); |
| 4347 | m_clientCompTx->setDriveDb( |
| 4348 | s.value("ClientCompTxDriveDb", "0.0").toFloat()); |
| 4349 | m_clientCompTx->setPhaseRotatorStages( |
| 4350 | s.value("ClientCompTxPhaseRotatorStages", "0").toInt()); |
| 4351 | |
| 4352 | // Load the generalised chain — stored as a comma-separated list of |
| 4353 | // stage names (e.g. "Gate,Eq,DeEss,Comp,Tube,Enh"). Migrate from |
| 4354 | // the older two-state ClientCompTxChainOrder (0 = CompThenEq, |
| 4355 | // 1 = EqThenComp) if present. |
| 4356 | QVector<TxChainStage> stages; |
| 4357 | const QString stored = s.value("ClientCompTxChainStages", "").toString(); |
| 4358 | if (!stored.isEmpty()) { |
| 4359 | for (const QString& name : stored.split(',', Qt::SkipEmptyParts)) { |
| 4360 | const auto stage = stageFromName(name.trimmed()); |
| 4361 | if (stage != TxChainStage::None) stages.append(stage); |
| 4362 | } |
| 4363 | } else if (s.contains("ClientCompTxChainOrder")) { |
| 4364 | const int legacy = s.value("ClientCompTxChainOrder", "0").toInt(); |
| 4365 | // Preserve the user's Comp-vs-Eq preference from the old two- |
| 4366 | // option setting — bracket it with the default canonical |
| 4367 | // layout for the not-yet-implemented stages. |
| 4368 | stages = (legacy == 1) |
| 4369 | ? QVector<TxChainStage>{TxChainStage::Gate, TxChainStage::Eq, |
| 4370 | TxChainStage::DeEss, TxChainStage::Comp, |
| 4371 | TxChainStage::Tube, TxChainStage::Enh} |
| 4372 | : QVector<TxChainStage>{TxChainStage::Gate, TxChainStage::Comp, |
| 4373 | TxChainStage::Eq, TxChainStage::DeEss, |
| 4374 | TxChainStage::Tube, TxChainStage::Enh}; |
| 4375 | } |
| 4376 | if (stages.isEmpty()) stages = defaultChain(); |
| 4377 | |
| 4378 | // Append any canonical stages that are missing from the loaded |
| 4379 | // list — guarantees all 6 processor boxes are always visible in |
| 4380 | // the chain widget so users can reorder them ahead of time and |
| 4381 | // future phases slot in automatically without a second migration. |
| 4382 | for (auto canon : defaultChain()) { |
nothing calls this directly
no test coverage detected