mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(tci): Stream.length — вещественные отсчёты всего блока, а не на канал
MSHV не декодировал FT4 по TCI (по виртуальному кабелю — декодировал).
Регрессия из dc6f996: там length аудио был переведён на «сэмплы на канал»
по формулировке §4.3, а живые клиенты считают по нему БАЙТЫ блока
(network.cpp: `int cr2 = pStream->length*bit_s;` с шагом `chan*bit_s`,
на передаче `quint32 cr3 = pStream->length*bit_s;`). При Channels=2
(умолчание MSHV) клиент разбирал половину каждого блока: звук с дырами
50%, водопад шире и грязнее, декодер разваливался. В моно дефекта не
видно — единицы совпадают, поэтому первый прогон стенда увёл в сторону.
Правка верна и по документу, а не только по клиенту: §3.4 после IQ
(«количество вещественных отсчётов… комплексных = length/channels»)
говорит «аудиопоток приёмника ПОЛНОСТЬЮ ПОВТОРЯЕТ IQ поток» и
перечисляет ровно три отличия — каналы, формат сэмплов, число сэмплов в
пакете. Единиц length среди них нет, поле в struct Stream одно.
Развилка по типу потока была вычитана из воздуха.
§4.3 путает две величины, и её формулировка верна лишь для моно:
AUDIO_STREAM_SAMPLES — кадры НА КАНАЛ, Stream.length — отсчёты ВСЕГО
блока. Что arg1 считает кадры, видно из самой §4.3 дважды: минимум
512/256/128/100 на 48/24/12/8 кГц даёт обещанные «не меньше 10 мс»
только при счёте на канал, и потолок data[16384] = 2048 × 2 × float32.
TX_CHRONO замыкает круг: клиент шлёт столько отсчётов, сколько названо
в length маркера, и возвращает то же число обратно.
Размер блока не менялся (2048@48к = 42.7 мс). Гипотеза про клиппинг
тапа RX_AUDIO проверена замером и снята: пик 0.115.
Стенд: проверки length переписаны на инвариант «байт = length × размер
отсчёта»; новый test/tci/ft4_bench.py снимает поток TCI и PipeWire-
источник одновременно, режет на нарезки FT4 по общим часам и гоняет
через настоящий jt9 --ft4 (блок разбирает КАК MSHV — этим и поймал).
Проверено вживую: MSHV декодирует FT4 по TCI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+18
-9
@@ -456,15 +456,24 @@ TCI-клиент отобрал бы звук у динамика и у брау
|
||||
в заголовке мы не будем ни в каком случае. Смена rate устройства или DDC пана
|
||||
на ходу пересобирает прореживание (`SetSourceRate`).
|
||||
|
||||
**Размер блока.** `AUDIO_STREAM_SAMPLES` — это сэмплы **на канал**, и у
|
||||
аудиопотоков ровно это число уходит в `Stream.length`: §4.3 говорит про arg1
|
||||
«количество сэмплов, указываемое в поле Stream.length», а умолчание 2048 при
|
||||
48 кГц сходится с потолком `data[16384]` только так — 2048 × 2 канала ×
|
||||
float32 = ровно 16384 байта, то есть `length` считает сэмплы, а не отсчёты.
|
||||
У **IQ** единица другая: §3.4 определяет число комплексных отсчётов как
|
||||
`length / channels`, поэтому там в `length` уходит `samples × channels`.
|
||||
Развилку держит `TCIFillHeader` (по типу потока), обратную — разбор
|
||||
`TX_AUDIO_STREAM` в `HandleBinary`. Смена любого параметра потока на ходу
|
||||
**Размер блока.** Две разные величины, которые §4.3 называет одним словом.
|
||||
`AUDIO_STREAM_SAMPLES` — это кадры **на канал** (умолчание 2048 при 48 кГц =
|
||||
42.7 мс), а `Stream.length` — вещественные отсчёты **всего блока**, то есть
|
||||
`кадры × channels`, и так у **всех** типов потока. Единицу `length` задаёт
|
||||
§3.4 для IQ («количество вещественных отсчётов… комплексных =
|
||||
`length/channels`») и тут же распространяет на аудио: «аудиопоток приёмника
|
||||
полностью повторяет IQ поток», отличия перечислены и их ровно три — каналы,
|
||||
формат сэмплов, число сэмплов в пакете. Формулировка §4.3 «arg1 — количество
|
||||
сэмплов, указываемое в поле Stream.length» верна только для моно, и однажды
|
||||
она уже увела нас в развилку по типу потока: у стерео клиент разбирал
|
||||
половину блока (звук с дырами 50%, FT4/FT8 не декодировались вовсе). Что
|
||||
`arg1` считает именно кадры на канал, видно из самой же §4.3: рекомендуемый
|
||||
минимум 512/256/128/100 сэмплов на 48/24/12/8 кГц даёт «не меньше 10 мс»
|
||||
только при счёте на канал, и потолок `data[16384]` сходится тем же счётом —
|
||||
2048 × 2 канала × float32 = ровно 16384 байта. Единое правило держит
|
||||
`TCIFillHeader`, обратное — разбор `TX_AUDIO_STREAM` в `HandleBinary`;
|
||||
`TX_CHRONO` замыкает круг (клиент шлёт столько отсчётов, сколько названо в
|
||||
`length` маркера). Смена любого параметра потока на ходу
|
||||
**перезапускает** уже идущие потоки этого клиента: блок с новой частотой
|
||||
посреди старого потока клиенты разбирают как мусор.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user