jamulussoftware / jamulussoftware/jamulus

Input Boost can clip with the clip indicator dark: the level meter reads only negative samples

Aperta
#3,951 0 commenti 1 reazione 0 assegnatari Vedi su GitHub
Lingua principale
C
Stelle
1.1k
Fork
248
Merge medio
2g 3h
PR unite (30g)
9

Descrizione

**🤖 AI:** Input Boost can drive the signal into hard clipping while the clip indicator stays dark and the feedback auto-mute stays silent, because the level meter reads only negative samples.

**Describe the bug**

[#3834](https://github.com/jamulussoftware/jamulus/pull/3834) made Input Boost clamp with [`Float2Short`](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/util.h#L116-L128) instead of wrapping, so overload now clips. [The level meter](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/client.cpp#L1544-L1556) runs on that same buffer inside the same block, and [its loop](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/util.cpp#L129-L160) takes [`std::min` over negatives](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/util.h#L775) only, every third one. A clip that goes positive reads zero.

One cause, two consumers: the [clip indicator](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/levelmeter.cpp#L319-L326) and the [feedback auto-mute](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/clientdlg.cpp#L1086-L1088) both read the single value [`Update()` writes](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/util.h#L759-L777).

**To Reproduce**

A real client sending into a real server, with the server's own recording as the evidence and the client's clip indicator read off the screen. Three arms, same source peak, only the skew differs:

| source, Input Boost | within 1% of full scale, positive | negative | clip indicator |
|---|---|---|---|
| symmetric, 4x | 15.16% | 15.16% | lights |
| 6:1 positive-skewed, 4x | 15.05% | 0.00% | dark |
| 6:1 positive-skewed, 10x | 29.41% | 0.00% | dark |
| 2:1 positive-skewed, 4x | 16.37% | 0.00% | dark |
| 2:1 positive-skewed, 10x | 31.16% | 22.59% | lights |

The control and the 4x skewed arm clip by the same amount. The last two rows set the boundary: at a 2:1 crest asymmetry, which is the most any real recording to hand reaches over a loud 100 ms window, the indicator is still dark on 16.37% clipped samples at 4x — and lights at 10x only because that boost drives the quiet half to full scale as well. So what hides a clip is the quiet half staying below full scale, not the ratio itself.

**Expected behavior**

Clipping lights the clip indicator whichever way the waveform clips.

**Version of Jamulus**

3.12.5dev, built at `267bf6b7`. The end-to-end arm ran on Linux (g++ 13.3.0, Qt 5.15.13, JACK). The meter itself was additionally built and run from the same `src/util.cpp` on macOS 12.7.6 (Apple clang 14, Qt 5.15.2), on Windows 11 (MSVC 19.44, **Qt 6.10.2**) and on **aarch64** Linux (g++ 14.2.0, Qt 5.15.15): all four emit byte-identical output over 54 lines of arms, so neither the platform, the architecture, nor the Qt major version changes what the indicator does.

**Additional context**

- Driving the shipped `CStereoSignalLevelMeter` directly gives the same split at block level: at Input Boost 4x a symmetric and a 6:1 skewed source both pin 18.6% of samples at full scale, and only the symmetric one lights the indicator.
- The auto-mute inherits the bias and does more than light an indicator: it [mutes the channel](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/clientdlg.cpp#L1091-L1092) and opens a modal. Run end to end with detection enabled, the symmetric control at 4x opens *"Audio feedback or loud signal detected"* and it stays up for 11 of 14 sampled frames, while the 6:1 skewed source at 4x and at 10x never opens it. Its reach is narrow either way: [`DETECT_FEEDBACK_TIME_MS`](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/clientdlg.h#L90) is a single-shot 3-second window armed on connection, so it never sees a level that rises later in a session.
- The indicator needs [exactly `-32768`](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/global.h#L318-L319): an all-`-32767` block reads 8.0000000 and stays dark, all-`-32768` reads 8.0000424 and lights. corrados [intended that](https://github.com/jamulussoftware/jamulus/issues/423#issuecomment-653788939) in 2020, when nothing on this path applied gain above 1.
- Decimation: the stereo loop steps `i += 6` reading `[i]` and `[i+1]`, so four of every six sample positions are never examined. A single-sample clip is seen at interleaved index 0 and 1 and missed at 2, 3, 4 and 5.
- The recording is taken after Opus, which rings around a flat top, so "within 1% of full scale" is the measure rather than a count of exact `+32767` samples.
- The server keeps its own meter of the same type — [`CChannel::SignalLevelMeter`](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/channel.h#L252) is also a `CStereoSignalLevelMeter` — so it inherits the same bias, and the [channel meter](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/audiomixerboard.cpp#L775) it feeds over [`CLM_CHANNEL_LEVEL_LIST`](https://github.com/jamulussoftware/jamulus/blob/267bf6b762202954200839135778cdc194a2ab4e/src/protocol.h#L105) has its own clip indicator. In the runs above that indicator is dark on exactly the arms where the client's is, and lit on exactly the arms where the client's is. Two meters, computed independently at each end, agree row for row.
- The same thing happens on Windows through ASIO rather than JACK, using the [CI build](https://github.com/jamulussoftware/jamulus/actions/runs/34758695683) of this commit: with the 6:1 source at Input Boost 4x the server's recording reaches `+32767` on 7.57% of samples and −7797 at the other extreme, while the client's input meter carries no red pixel at all.
- Not measured: the end-to-end client path on macOS, and any real recording with a crest asymmetry beyond 2:1.

---

🤖 *This message was written by AI and reviewed by @mcfnord.*

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Inizia in src/util.cpp e src/util.h, in corrispondenza di CStereoSignalLevelMeter::Update, e segui il valore utilizzato da src/levelmeter.cpp e src/clientdlg.cpp. Riproduci i casi con asimmetria positiva e simmetrici descritti nell’issue, quindi verifica che il clipping positivo e negativo venga rilevato in modo coerente sia dall’indicatore di clip sia dal feedback auto-mute.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
cpp
Ambito
audio-video-rtc
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
68/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.