|
29 | 29 |
|
30 | 30 | namespace AetherSDR { |
31 | 31 |
|
| 32 | +// The ALC Gain gauge's face, named because two places need the SAME numbers |
| 33 | +// and one of them is "no reading". |
| 34 | +// |
| 35 | +// Not a display preference: the top is the HL2 modulator's makeup ceiling |
| 36 | +// (Hl2TxDsp::Config::alcMaxGainDb), so a reading pressed against it means the |
| 37 | +// ALC has run out of gain rather than that the face has run out of scale. |
| 38 | +// -20 covers the reductions this chain produces. |
| 39 | +static constexpr float kAlcGainGaugeMinDb = -20.0f; |
| 40 | +static constexpr float kAlcGainGaugeMaxDb = 40.0f; |
| 41 | + |
32 | 42 | // ── Triangle button (same as RxApplet) ────────────────────────────────────── |
33 | 43 |
|
34 | 44 | class CwTriBtn : public QPushButton { |
@@ -267,6 +277,51 @@ void PhoneCwApplet::buildPhonePanel() |
267 | 277 | m_compGauge->setHoverValuePopupEnabled(true); |
268 | 278 | vbox->addWidget(m_compGauge); |
269 | 279 |
|
| 280 | + // ── ALC Gain gauge (dB: -20 to +40) ────────────────────────────────── |
| 281 | + // Beside Compression because they answer the same kind of question — how |
| 282 | + // much is the chain changing my audio — where the ALC gauge below answers |
| 283 | + // where the audio ended up. The two are easily confused and the difference |
| 284 | + // is the whole reason this one exists: a post-ALC level meter sits pinned |
| 285 | + // near its target by construction, so an operator whose microphone is 30 dB |
| 286 | + // too quiet sees an ALC gauge that looks perfect. |
| 287 | + // |
| 288 | + // The range is the modulator's, not a preference: +40 dB is the HL2 |
| 289 | + // modulator's makeup ceiling (Hl2TxDsp::Config::alcMaxGainDb), so a reading |
| 290 | + // at the top means the ALC has run out of gain rather than that the face |
| 291 | + // has run out of scale. -20 covers the reductions this chain produces. |
| 292 | + // |
| 293 | + // The colour breaks are the modulator's too, not taste. The face's top is |
| 294 | + // alcMaxGainDb, so yellow at +20 is "half the makeup is spent" and red at |
| 295 | + // +30 is "three quarters of it is, and the last 10 dB is all that stands |
| 296 | + // between this microphone and an ALC that cannot reach its target" -- |
| 297 | + // which is a setup fault to fix at the gain control, not in software. The |
| 298 | + // reduction half is deliberately uncoloured: the ALC taking level away is |
| 299 | + // it working, at any depth this chain produces. |
| 300 | + m_alcGainGauge = new HGauge(kAlcGainGaugeMinDb, kAlcGainGaugeMaxDb, 30.0f, |
| 301 | + "ALC Gain", "dB", |
| 302 | + {{-20, "-20dB"}, {-10, "-10"}, {0, "0"}, {10, "+10"}, {20, "+20"}, |
| 303 | + {30, "+30"}, {40, "+40"}}, nullptr, 20.0f); |
| 304 | + m_alcGainGauge->setObjectName(QStringLiteral("phoneAlcGainGauge")); |
| 305 | + // The floor, not 0: see resetAlcGain(). A gauge built hidden must not be |
| 306 | + // holding a third-full bar for the moment it is revealed. |
| 307 | + m_alcGainGauge->setValueImmediate(kAlcGainGaugeMinDb); |
| 308 | + m_alcGainGauge->setAccessibleName("ALC gain gauge"); |
| 309 | + m_alcGainGauge->setAccessibleDescription( |
| 310 | + "Gain the transmit ALC is applying, in dB; 0 is unity"); |
| 311 | + m_alcGainGauge->setHoverValueFormatter([](float v) { |
| 312 | + // Signed, unlike Compression's face below, because both directions are |
| 313 | + // real here: the ALC both adds makeup and takes level away. |
| 314 | + return QStringLiteral("%1%2 dB") |
| 315 | + .arg(v > 0.0f ? QStringLiteral("+") : QString()) |
| 316 | + .arg(QString::number(v, 'f', 1)); |
| 317 | + }); |
| 318 | + m_alcGainGauge->setHoverValuePopupEnabled(true); |
| 319 | + // Built hidden. The Phone panel is shared with Flex, Icom and the sim, |
| 320 | + // none of which publish an ALCGAIN meter, and a row they cannot drive is |
| 321 | + // a change to their panel. setHasAlcGainMeter() is what reveals it. |
| 322 | + m_alcGainGauge->setVisible(m_hasAlcGainMeter); |
| 323 | + vbox->addWidget(m_alcGainGauge); |
| 324 | + |
270 | 325 | // ── ALC gauge (post-SW-ALC SSB-peak, dBFS) ────────────────────────── |
271 | 326 | // Mirrored in m_cwPanel; both gauges read from MeterModel::alcValueChanged |
272 | 327 | // so SSB operators watching mic gain see the same indicator CW |
@@ -1358,6 +1413,54 @@ void PhoneCwApplet::updateCompression(float compPeak) |
1358 | 1413 | m_compGauge->setValue(-compressionDb); |
1359 | 1414 | } |
1360 | 1415 |
|
| 1416 | +void PhoneCwApplet::updateAlcGain(float gainDb) |
| 1417 | +{ |
| 1418 | + if (!m_alcGainGauge) { |
| 1419 | + return; |
| 1420 | + } |
| 1421 | + // No clamp here: HGauge clamps to its own range, and clamping twice would |
| 1422 | + // hide the case worth seeing — a gain pressed against the modulator's |
| 1423 | + // ceiling, which reads as "the ALC has nothing left" rather than as a |
| 1424 | + // meter at the end of its travel. |
| 1425 | + m_alcGainGauge->setValue(gainDb); |
| 1426 | +} |
| 1427 | + |
| 1428 | +void PhoneCwApplet::resetAlcGain() |
| 1429 | +{ |
| 1430 | + if (!m_alcGainGauge) { |
| 1431 | + return; |
| 1432 | + } |
| 1433 | + // THE FACE FLOOR, NOT ZERO, and the distinction is the whole point of |
| 1434 | + // hasAlcGainValue(). This face runs -20..+40, so HGauge renders 0 dB as a |
| 1435 | + // bar one third full -- and 0 dB is also a real reading, "the ALC is |
| 1436 | + // holding at unity". Driving to 0 on unkey, on disconnect and as the first |
| 1437 | + // thing shown after a TX-slice change therefore painted a confident |
| 1438 | + // measurement in the one state where nothing has been measured. resetAlc() |
| 1439 | + // beside it drives to its own floor for the same reason; an empty bar is |
| 1440 | + // the only rendering of "no reading" this widget has. |
| 1441 | + m_alcGainGauge->setValueImmediate(kAlcGainGaugeMinDb); |
| 1442 | + m_alcGainGauge->clearPeak(); |
| 1443 | +} |
| 1444 | + |
| 1445 | +void PhoneCwApplet::setHasAlcGainMeter(bool has) |
| 1446 | +{ |
| 1447 | + if (m_hasAlcGainMeter == has) { |
| 1448 | + return; |
| 1449 | + } |
| 1450 | + m_hasAlcGainMeter = has; |
| 1451 | + if (!m_alcGainGauge) { |
| 1452 | + return; |
| 1453 | + } |
| 1454 | + // Discard the departing radio's last gain before hiding, for the same |
| 1455 | + // reason setMicLevelMeterState() resets the Level gauge at the lifecycle |
| 1456 | + // boundary: a reading kept behind a hidden widget comes back as the next |
| 1457 | + // radio's when the gauge is shown again. |
| 1458 | + if (!has) { |
| 1459 | + resetAlcGain(); |
| 1460 | + } |
| 1461 | + m_alcGainGauge->setVisible(has); |
| 1462 | +} |
| 1463 | + |
1361 | 1464 | void PhoneCwApplet::setAlcMeterUnit(const QString& unit) |
1362 | 1465 | { |
1363 | 1466 | if (unit == m_alcMeterUnit) { |
|
0 commit comments