mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
fix(tx): чистый openHPSDR TX-тракт — задержка DUP, всплески TUN, фриз PTT-off
Диагностика временным TXLog (снят) вскрыла цепочку проблем TX-тракта: - Задержка ~200мс своего сигнала в DUP: за время приёма ринг PortAudio- микрофона наполнялся до упора (9600 сэмплов) и на старте TX бёрстом оседал стоячим запасом в DUC-очереди. Фикс: TAudioInput.Flush на RX→TX (заодно убрана передача в эфир аудио, записанного до нажатия PTT). - Всплески на TUN: (1) старт — радио начинало с пустого DUC-FIFO; (2) по ходу — пейсинг со строгой каденцией держал запас FIFO у нуля, джиттер 3-6мс давал underrun; (3) клип: голос из бэклога складывался с PostGen- тоном (стоит после ALC) поверх шкалы, а сам тон при mag=1.0 давал выброс Гиббса x1.18 на старте. Фиксы: pre-roll PrimeDUCIQ (THROTTLE + 3 блока подушки в очереди — sender метрит непрерывно, FIFO радио прижат 2000..2400), анти-старв доливка нулями до REANCHOR при просадке, TUN_TONE_MAG=0.83, мьют mic-входа TXA при активном тоне. - Огрызок TUN-тона в эфир на первом блоке следующего TX: стоп канала dmode=1 ждал фейд, который некому прокрутить (продюсер уже остановлен) — канал стопился по таймауту Sleep(1)x100 с недобранным сигналом в буферах. Это же было и «остаточным фризом ~106мс» GUI на отпускании PTT: чистый таймаут, фейд никогда не исполнялся. Фикс: dmode=0 + синхронный слив/продувка канала 4 нулевыми fexchange0 на стопе и старте (<1мс, штатные down-slew и flush). - Дисплей: ResetPixelBuffers(TX_DISP_ID) на старте TX — усредняющая история TX-анализатора показывала спектр тона прошлой сессии. - StopRunning при активном TUN не чистил DUC-очередь и не сбрасывал FTuning/тон — закрыто. Латентность тракта mic→радио теперь ~43мс (WDSP 11 + подушка 21 + FIFO 10.4). Проверено на эфире: q=0..30, fill/drops/underrun=0, clip=0, клоки радио/ПК без дрейфа (micRx 48000/с). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+53
-1
@@ -285,6 +285,10 @@ type
|
||||
FActiveDisplayID: Integer; // RX_DISP_ID или TX_DISP_ID
|
||||
FTXMicSource: TTXMicSource;
|
||||
FOnPullMic: TPullMicSamplesFunc;
|
||||
// TUN активен (PostGen-тон): mic-вход TXA зануляется в ProcessTXBlock.
|
||||
// PostGen стоит ПОСЛЕ ALC — голос из микрофона складывался бы с тоном
|
||||
// поверх полной шкалы (тон ~0.98) → клип 24-бит → сплэттер на спектре.
|
||||
FTXToneOn: Boolean;
|
||||
|
||||
// Кэшированные TX-параметры — применяются после OpenChannel(TXA) и при изменении.
|
||||
// Для Filter/Compressor/Leveler/ALC/PhaseRot/EQ/AM/FM/CTCSS.
|
||||
@@ -897,6 +901,7 @@ begin
|
||||
FTXMicHead := 0;
|
||||
FTXMicTail := 0;
|
||||
FTXActive := False;
|
||||
FTXToneOn := False;
|
||||
FKeepRXDuringTX := False;
|
||||
FMonitorRXDuringTX := False;
|
||||
FPostTXMuteUntil := 0;
|
||||
@@ -2140,6 +2145,8 @@ begin
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetTXRun(Run: Boolean);
|
||||
var
|
||||
k, Err: Integer;
|
||||
begin
|
||||
FDispPos := 0;
|
||||
FTXDispPos := 0;
|
||||
@@ -2150,7 +2157,30 @@ begin
|
||||
FTXMicHead := 0;
|
||||
FTXMicTail := 0;
|
||||
if FInitialized then
|
||||
begin
|
||||
SetChannelState(TXA_CHAN, 1, 0); // run, no delay
|
||||
// Продувка канала: страховка от остатка прошлой TX-сессии в буферах/
|
||||
// фильтрах TXA (без неё огрызок — после TUN это полноразмахный тон —
|
||||
// выплёвывался в эфир первым же блоком нового TX). Основной слив теперь
|
||||
// на стопе (ниже), но нештатные пути останова канал не чистят. 4 нулевых
|
||||
// блока через fexchange0, выход в мусор (не в FOnTXIQ/display); поток
|
||||
// ещё idle (FTXActive=False) — гонки нет.
|
||||
FillChar(FTXIn[0], FAudioBufSize * 2 * SizeOf(Double), 0);
|
||||
for k := 1 to 4 do
|
||||
begin
|
||||
Err := 0;
|
||||
fexchange0(TXA_CHAN, @FTXIn[0], @FTXOut[0], @Err);
|
||||
end;
|
||||
// Сброс TX-анализатора: его усредняющая история хранит спектр ПРОШЛОЙ
|
||||
// сессии (после TUN — тон), и при переключении на TX-дисплей первые
|
||||
// кадры показывали «всплеск» старого тона (виден в non-DUP, где на
|
||||
// экране TX-спектр; эфир при этом чист — в DUP старт чистый).
|
||||
// ResetPixelBuffers — лёгкое зануление pixel/average буферов (MW0LGE);
|
||||
// НЕ ApplyTXAnalyzerSettings: тот зовёт SetAnalyzer (перепланирование
|
||||
// FFT в UI-потоке) — давал видимую задержку отрисовки на старте TX.
|
||||
if FAnalyzerOpen then
|
||||
ResetPixelBuffers(TX_DISP_ID);
|
||||
end;
|
||||
// TX-DSP поток создаётся ОДИН раз и живёт весь сеанс. НЕ пересоздаём на каждом
|
||||
// T/R: join (WaitFor) давал фиксированные ~100 мс фриза GUI на отпускании PTT.
|
||||
// При FTXActive=False поток простаивает (см. TTXDSPThread.Execute: Continue).
|
||||
@@ -2164,7 +2194,24 @@ begin
|
||||
FTXActive := False; // поток уходит в простой (не трогает канал/ring)
|
||||
FActiveDisplayID := RX_DISP_ID;
|
||||
if FInitialized then
|
||||
SetChannelState(TXA_CHAN, 0, 1); // stop, with slew (поток уже idle)
|
||||
begin
|
||||
// Мгновенный стоп + синхронный слив. Раньше здесь был dmode=1: он
|
||||
// спинует Sleep(1)×100 в ожидании фейда, который должен прокрутить
|
||||
// fexchange — а продюсер уже остановлен, fexchange никто не зовёт →
|
||||
// чистый таймаут ~106мс (остаточный фриз GUI на отпускании PTT) и
|
||||
// канал, брошенный с недобранным сигналом в буферах. dmode=0 лишь
|
||||
// взводит downflag/flushflag и возвращается сразу; down-slew (фейд
|
||||
// 10мс) и штатный flush буферов исполняют наши же fexchange0 с нулевым
|
||||
// входом — суммарно <1мс, выход в мусор (в эфир не идёт: DUC-очередь
|
||||
// чистится контроллером на T/R).
|
||||
SetChannelState(TXA_CHAN, 0, 0); // stop, без ожидания
|
||||
FillChar(FTXIn[0], FAudioBufSize * 2 * SizeOf(Double), 0);
|
||||
for k := 1 to 4 do
|
||||
begin
|
||||
Err := 0;
|
||||
fexchange0(TXA_CHAN, @FTXIn[0], @FTXOut[0], @Err);
|
||||
end;
|
||||
end;
|
||||
FTXMicHead := 0;
|
||||
FTXMicTail := 0;
|
||||
end;
|
||||
@@ -2175,6 +2222,7 @@ var
|
||||
SignedFreq: Double;
|
||||
begin
|
||||
if not FInitialized then Exit;
|
||||
FTXToneOn := Enabled; // мьют mic-входа на TUN (см. ProcessTXBlock)
|
||||
if Enabled then
|
||||
begin
|
||||
// gen1 (PostGen) стоит после всех модуляторов и бандпасса.
|
||||
@@ -2232,6 +2280,10 @@ begin
|
||||
tail := (tail + 1) and (TX_MIC_RING - 1);
|
||||
end;
|
||||
FTXMicTail := tail; // Атомарно обновляем tail (один writer — TX thread)
|
||||
// TUN: ринг потребляем (иначе поток зациклится на «есть полный блок»),
|
||||
// но в TXA подаём тишину — тон PostGen должен идти без голоса поверх.
|
||||
if FTXToneOn then
|
||||
FillChar(FTXIn[0], FAudioBufSize * 2 * SizeOf(Double), 0);
|
||||
end else
|
||||
begin
|
||||
// Нет mic-данных — тишина (аналог piHPSDR: tx->mic_input_buffer заполняется нулями)
|
||||
|
||||
Reference in New Issue
Block a user