mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
fix TX треск: SoundCard mic не подменять тишиной + DUC packetizer с переносом хвоста
Два источника искажений при передаче с микрофона компьютера: 1. SoundCard mic путь в TX-потоке (WDSPEngine.pas) при неполном блоке подменял голосовой хвост в кольце тишиной. PortAudio отдаёт по 128 сэмплов, в кольце часто < FAudioBufSize → ProcessTXBlock уходил в else-ветку и слал блок нулей, оставляя голос на следующий тик. Результат: чередование «голос/тишина» = треск ≈50–100 Гц. Теперь подмена тишиной только при Avail=0; иначе ждём следующий тик. Добавлен PushTXMicSamplesD — батч-пуш с одной будилкой семафора. 2. DUC IQ packetizer (MainForm.pas/OnTXIQReady) добивал последний неполный пакет нулями. FTXOutBufSize не кратен 240 (4096 mod 240=16), из-за чего в каждом TX-блоке возникал провал ≈1.16 мс каждые ≈21 мс ≈ 47 Гц гул. Теперь хвост переносится в следующий вызов через FDUCPendingI/Q/Count; шлются только полные пакеты по 240 пар. Дополнительно: ScaleIQ24 клампит результат в [-2^23, 2^23-1] чтобы пики от EQ/компрессора (V чуть >1.0) не оборачивались через 24-bit wrap → щелчки на громких сэмплах. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+36
-6
@@ -383,8 +383,10 @@ type
|
||||
// Если MicSource=SoundCard, эти сэмплы игнорируются.
|
||||
procedure PushTXMicSamples16(const Src: array of SmallInt; N: Integer);
|
||||
// Прямой push double-сэмпла (-1..+1), для sound-card пути.
|
||||
// Должен вызываться из ОДНОГО потока (PortAudio callback).
|
||||
// Должен вызываться из ОДНОГО потока.
|
||||
procedure PushTXMicSampleD(const S: Double);
|
||||
// Batch-вариант: пушит N сэмплов одним вызовом, будит TX-поток один раз.
|
||||
procedure PushTXMicSamplesD(const Src: array of Double; N: Integer);
|
||||
|
||||
// Настройки анализатора (применяются немедленно если открыт)
|
||||
procedure SetFFTParams(FFTSize, WinType: Integer);
|
||||
@@ -563,13 +565,18 @@ begin
|
||||
|
||||
if Terminated then Break;
|
||||
|
||||
// Если mic-данных не было — всё равно обрабатываем один блок тишины.
|
||||
// Аналог piHPSDR: если mic_ring пуст, tx_add_mic_sample получает 0.0.
|
||||
// Это держит DUC IQ поток и обновляет спектр/водопад TX-сигналом.
|
||||
// Если mic-данных не было — обрабатываем один блок тишины, чтобы
|
||||
// DUC IQ поток не прерывался и спектр/водопад обновлялись.
|
||||
// НО для sound-card mic неполный блок (0 < Avail < AudioBufSize) нельзя
|
||||
// подменять тишиной: PortAudio часто отдаёт 128-сэмпловые callback'и,
|
||||
// и если в кольце уже есть голосовой хвост — он застрянет, а в эфир
|
||||
// уйдёт тишина. Слышно как чередование «голос/тишина» = треск ≈50–100 Гц.
|
||||
// В этом случае ждём следующий тик, хвост накопится до полного блока.
|
||||
Avail := (FEngine.FTXMicHead - FEngine.FTXMicTail + TX_MIC_RING)
|
||||
and (TX_MIC_RING - 1);
|
||||
if Avail < FEngine.FAudioBufSize then
|
||||
FEngine.ProcessTXBlock;
|
||||
if (Avail = 0) or (FEngine.FTXMicSource <> txmsSoundCard) then
|
||||
if Avail < FEngine.FAudioBufSize then
|
||||
FEngine.ProcessTXBlock;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -1624,6 +1631,29 @@ begin
|
||||
RTLEventSetEvent(FTXMicSem);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.PushTXMicSamplesD(const Src: array of Double; N: Integer);
|
||||
// Batch-вариант: одна будилка семафора на N сэмплов.
|
||||
var
|
||||
i, cnt, newHead: Integer;
|
||||
begin
|
||||
cnt := N;
|
||||
if cnt > Length(Src) then cnt := Length(Src);
|
||||
|
||||
for i := 0 to cnt - 1 do
|
||||
begin
|
||||
newHead := (FTXMicHead + 1) and (TX_MIC_RING - 1);
|
||||
if newHead <> FTXMicTail then
|
||||
begin
|
||||
FTXMicRing[FTXMicHead] := Src[i];
|
||||
FTXMicHead := newHead;
|
||||
end;
|
||||
// overrun → дроп
|
||||
end;
|
||||
|
||||
if cnt > 0 then
|
||||
RTLEventSetEvent(FTXMicSem);
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TX chain: применение всех TX-параметров к WDSP-каналу
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user