rx2 support work

This commit is contained in:
2026-05-27 11:29:39 +03:00
parent 047c9b0997
commit c2ca52511c
4 changed files with 1290 additions and 258 deletions
+67 -12
View File
@@ -151,6 +151,8 @@ type
// Текущее состояние для построения HP пакетов // Текущее состояние для построения HP пакетов
FCurrentRXFreq: Double; FCurrentRXFreq: Double;
FCurrentTXFreq: Double; FCurrentTXFreq: Double;
FDDCFreq: array[0..MAX_DDCS - 1] of Double;
FDDCEnabled: array[0..MAX_DDCS - 1] of Boolean;
FCurrentDrive: Byte; FCurrentDrive: Byte;
FIsTransmitting: Boolean; FIsTransmitting: Boolean;
FPTTActive: Boolean; // фактический PTT в HP-пакете (отдельно от Alex T/R) FPTTActive: Boolean; // фактический PTT в HP-пакете (отдельно от Alex T/R)
@@ -216,12 +218,18 @@ type
procedure SendDDCSpecific(const Pkt: TDDCSpecificPacket); procedure SendDDCSpecific(const Pkt: TDDCSpecificPacket);
procedure ConfigureDDCs(NumDDCs: Byte; SampleRate: Word; ADCSource: Byte = 0; procedure ConfigureDDCs(NumDDCs: Byte; SampleRate: Word; ADCSource: Byte = 0;
DitherEnabled: Boolean = True; RandomEnabled: Boolean = True); DitherEnabled: Boolean = True; RandomEnabled: Boolean = True);
procedure ConfigureDDCReceivers(ReceiverCount: Byte; SampleRate: Word;
RX1ADCSource: Byte = 0; RX2ADCSource: Byte = 0;
DitherEnabled: Boolean = True;
RandomEnabled: Boolean = True;
RX2SampleRate: Word = 0);
procedure SendDUCSpecific(const Pkt: TDUCSpecificPacket); procedure SendDUCSpecific(const Pkt: TDUCSpecificPacket);
procedure SendHighPriority(const Pkt: THighPriorityPacket); procedure SendHighPriority(const Pkt: THighPriorityPacket);
procedure SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double; procedure SetRunAndFreq(Run: Boolean; DDC0FreqHz, DUCFreqHz: Double;
DriveLevel: Byte = 100); DriveLevel: Byte = 100);
procedure UpdateState(RXFreqHz, TXFreqHz: Double; DriveLevel: Byte; procedure UpdateState(RXFreqHz, TXFreqHz: Double; DriveLevel: Byte;
Transmitting, PAEnabled, AlexEnabled: Boolean); Transmitting, PAEnabled, AlexEnabled: Boolean);
procedure SetDDCFrequency(DDCIndex: Integer; FreqHz: Double);
procedure SetStepAtten(dB: Byte); procedure SetStepAtten(dB: Byte);
procedure SetAlexConfig(const A: TAlexSettings); procedure SetAlexConfig(const A: TAlexSettings);
// Включение/настройка XVTR-режима. Все параметры применяются мгновенно // Включение/настройка XVTR-режима. Все параметры применяются мгновенно
@@ -608,6 +616,8 @@ begin
FWBSeqValid := False; FWBSeqValid := False;
FCurrentRXFreq := 7100000; FCurrentRXFreq := 7100000;
FCurrentTXFreq := 7100000; FCurrentTXFreq := 7100000;
FillChar(FDDCEnabled, SizeOf(FDDCEnabled), 0);
FDDCFreq[0] := FCurrentRXFreq;
FCurrentDrive := 0; FCurrentDrive := 0;
FIsTransmitting := False; FIsTransmitting := False;
FPAEnabled := True; FPAEnabled := True;
@@ -1376,15 +1386,29 @@ end;
procedure THPSDRNetwork.ConfigureDDCs(NumDDCs: Byte; SampleRate: Word; procedure THPSDRNetwork.ConfigureDDCs(NumDDCs: Byte; SampleRate: Word;
ADCSource: Byte; ADCSource: Byte;
DitherEnabled: Boolean; RandomEnabled: Boolean); DitherEnabled: Boolean; RandomEnabled: Boolean);
begin
ConfigureDDCReceivers(NumDDCs, SampleRate, ADCSource, ADCSource,
DitherEnabled, RandomEnabled);
end;
procedure THPSDRNetwork.ConfigureDDCReceivers(ReceiverCount: Byte; SampleRate: Word;
RX1ADCSource: Byte; RX2ADCSource: Byte;
DitherEnabled: Boolean; RandomEnabled: Boolean;
RX2SampleRate: Word);
var var
Pkt: TDDCSpecificPacket; Pkt: TDDCSpecificPacket;
i, ddc: Integer; i, ddc: Integer;
DDCBase: Integer; DDCBase: Integer;
ADCSource: Byte;
DDCRate: Word;
begin begin
FillChar(Pkt, SizeOf(Pkt), 0); FillChar(Pkt, SizeOf(Pkt), 0);
// ANAN-7000/8000/Saturn имеют 2 ADC if ReceiverCount < 1 then ReceiverCount := 1;
if FDevice.BoardType in [4, 5, 10] then // ORION=4, ORION2=5, SATURN=10 if ReceiverCount > 2 then ReceiverCount := 2;
// ANAN-100D/200D/7000/8000/Saturn имеют второй ADC/RX front-end.
if FDevice.BoardType in [3, 4, 5, 10] then
Pkt.NumADCs := 2 Pkt.NumADCs := 2
else else
Pkt.NumADCs := 1; Pkt.NumADCs := 1;
@@ -1402,9 +1426,17 @@ begin
else else
DDCBase := 0; DDCBase := 0;
for i := 0 to NumDDCs - 1 do FillChar(FDDCEnabled, SizeOf(FDDCEnabled), 0);
for i := 0 to ReceiverCount - 1 do
begin begin
ddc := DDCBase + i; ddc := DDCBase + i;
ADCSource := RX1ADCSource;
if i = 1 then ADCSource := RX2ADCSource;
if ADCSource >= Pkt.NumADCs then ADCSource := 0;
DDCRate := SampleRate;
if (i = 1) and (RX2SampleRate > 0) then DDCRate := RX2SampleRate;
FDDCEnabled[ddc] := True;
// Enable bit для DDC ddc // Enable bit для DDC ddc
Pkt.DDCEnable[ddc div 8] := Pkt.DDCEnable[ddc div 8] or Byte(1 shl (ddc mod 8)); Pkt.DDCEnable[ddc div 8] := Pkt.DDCEnable[ddc div 8] or Byte(1 shl (ddc mod 8));
// Config: 6 байт на DDC начиная с offset 17 в пакете → в массиве DDCConfig // Config: 6 байт на DDC начиная с offset 17 в пакете → в массиве DDCConfig
@@ -1412,8 +1444,8 @@ begin
// DDCConfig[ddc*6 + 1..2] = sample rate / 1000 (ksps) // DDCConfig[ddc*6 + 1..2] = sample rate / 1000 (ksps)
// DDCConfig[ddc*6 + 5] = bits per sample // DDCConfig[ddc*6 + 5] = bits per sample
Pkt.DDCConfig[ddc * 6] := ADCSource; Pkt.DDCConfig[ddc * 6] := ADCSource;
Pkt.DDCConfig[ddc * 6 + 1] := (SampleRate shr 8) and $FF; Pkt.DDCConfig[ddc * 6 + 1] := (DDCRate shr 8) and $FF;
Pkt.DDCConfig[ddc * 6 + 2] := SampleRate and $FF; Pkt.DDCConfig[ddc * 6 + 2] := DDCRate and $FF;
Pkt.DDCConfig[ddc * 6 + 3] := 0; Pkt.DDCConfig[ddc * 6 + 3] := 0;
Pkt.DDCConfig[ddc * 6 + 4] := 0; Pkt.DDCConfig[ddc * 6 + 4] := 0;
Pkt.DDCConfig[ddc * 6 + 5] := 24; // 24 bits per sample Pkt.DDCConfig[ddc * 6 + 5] := 24; // 24 bits per sample
@@ -1451,6 +1483,8 @@ procedure THPSDRNetwork.UpdateState(RXFreqHz, TXFreqHz: Double;
Transmitting, PAEnabled, AlexEnabled: Boolean); Transmitting, PAEnabled, AlexEnabled: Boolean);
begin begin
FCurrentRXFreq := RXFreqHz; FCurrentRXFreq := RXFreqHz;
FDDCFreq[0] := RXFreqHz;
FDDCFreq[2] := RXFreqHz;
FCurrentTXFreq := TXFreqHz; FCurrentTXFreq := TXFreqHz;
FCurrentDrive := DriveLevel; FCurrentDrive := DriveLevel;
FIsTransmitting := Transmitting; FIsTransmitting := Transmitting;
@@ -1458,6 +1492,15 @@ begin
FAlexEnabled := AlexEnabled; FAlexEnabled := AlexEnabled;
end; end;
procedure THPSDRNetwork.SetDDCFrequency(DDCIndex: Integer; FreqHz: Double);
begin
if (DDCIndex < Low(FDDCFreq)) or (DDCIndex > High(FDDCFreq)) then Exit;
FDDCFreq[DDCIndex] := FreqHz;
if (DDCIndex = 0) or (DDCIndex = 2) then
FCurrentRXFreq := FreqHz;
if FConnected then SendFullHP;
end;
procedure THPSDRNetwork.SetStepAtten(dB: Byte); procedure THPSDRNetwork.SetStepAtten(dB: Byte);
begin begin
if dB > 31 then dB := 31; if dB > 31 then dB := 31;
@@ -1473,6 +1516,9 @@ var
Alex1: LongWord; Alex1: LongWord;
IsOrion2: Boolean; IsOrion2: Boolean;
DDCBase: Integer; // 0 для HERMES, 2 для ORION/ORION2/ANGELIA DDCBase: Integer; // 0 для HERMES, 2 для ORION/ORION2/ANGELIA
DDCIdx: Integer;
DDCF: Double;
RX2Freq: Double;
begin begin
if not FConnected then Exit; if not FConnected then Exit;
@@ -1504,12 +1550,19 @@ begin
else else
DDCBase := 0; DDCBase := 0;
// DDC RX frequency (bytes 9 + DDC*4) // DDC RX frequencies (bytes 9 + DDC*4)
Ph := FreqToPhaseWord(FCurrentRXFreq); if FDDCFreq[DDCBase] <= 0 then FDDCFreq[DDCBase] := FCurrentRXFreq;
Buf[9 + DDCBase*4] := (Ph shr 24) and $FF; for DDCIdx := 0 to MAX_DDCS - 1 do
Buf[10 + DDCBase*4] := (Ph shr 16) and $FF; if FDDCEnabled[DDCIdx] or (DDCIdx = DDCBase) then
Buf[11 + DDCBase*4] := (Ph shr 8) and $FF; begin
Buf[12 + DDCBase*4] := Ph and $FF; DDCF := FDDCFreq[DDCIdx];
if DDCF <= 0 then DDCF := FCurrentRXFreq;
Ph := FreqToPhaseWord(DDCF);
Buf[9 + DDCIdx*4] := (Ph shr 24) and $FF;
Buf[10 + DDCIdx*4] := (Ph shr 16) and $FF;
Buf[11 + DDCIdx*4] := (Ph shr 8) and $FF;
Buf[12 + DDCIdx*4] := Ph and $FF;
end;
// DUC TX frequency (bytes 329-332) // DUC TX frequency (bytes 329-332)
Ph := FreqToPhaseWord(FCurrentTXFreq); Ph := FreqToPhaseWord(FCurrentTXFreq);
@@ -1537,7 +1590,9 @@ begin
// ALEX1 filter bits (bytes 1428-1431) — только Orion2/Saturn // ALEX1 filter bits (bytes 1428-1431) — только Orion2/Saturn
if IsOrion2 then if IsOrion2 then
begin begin
Alex1 := CalcAlex1(FCurrentRXFreq, FCurrentTXFreq, RX2Freq := FDDCFreq[DDCBase + 1];
if RX2Freq <= 0 then RX2Freq := FCurrentRXFreq;
Alex1 := CalcAlex1(RX2Freq, FCurrentTXFreq,
FIsTransmitting, FAlexConfig, FIsTransmitting, FAlexConfig,
FXvtrDisablePA); FXvtrDisablePA);
Buf[1428] := (Alex1 shr 24) and $FF; Buf[1428] := (Alex1 shr 24) and $FF;
+947 -15
View File
File diff suppressed because it is too large Load Diff
+8 -1
View File
@@ -26,6 +26,7 @@ type
FOnSpanSelect: TSpanSelectEvent; FOnSpanSelect: TSpanSelectEvent;
FOnHidePanel: THidePanelEvent; FOnHidePanel: THidePanelEvent;
FOnInvalidate: TNotifyEvent; FOnInvalidate: TNotifyEvent;
FFirstButtonCaption: string;
FLeft: Integer; FLeft: Integer;
FTop: Integer; FTop: Integer;
FWidth: Integer; FWidth: Integer;
@@ -54,6 +55,7 @@ type
property Width: Integer read FWidth; property Width: Integer read FWidth;
property Height: Integer read FHeight; property Height: Integer read FHeight;
property HotIdx: Integer read FHotIdx; property HotIdx: Integer read FHotIdx;
property FirstButtonCaption: string read FFirstButtonCaption write FFirstButtonCaption;
property OnSpanSelect: TSpanSelectEvent read FOnSpanSelect write FOnSpanSelect; property OnSpanSelect: TSpanSelectEvent read FOnSpanSelect write FOnSpanSelect;
property OnHidePanel: THidePanelEvent read FOnHidePanel write FOnHidePanel; property OnHidePanel: THidePanelEvent read FOnHidePanel write FOnHidePanel;
property OnInvalidate: TNotifyEvent read FOnInvalidate write FOnInvalidate; property OnInvalidate: TNotifyEvent read FOnInvalidate write FOnInvalidate;
@@ -200,7 +202,12 @@ begin
C.Brush.Style := bsClear; C.Brush.Style := bsClear;
C.Rectangle(HR); C.Rectangle(HR);
C.Font.Size := 8; C.Font.Size := 8;
if FPanelHidden then Cap := '>' else Cap := '<'; if FFirstButtonCaption <> '' then
Cap := FFirstButtonCaption
else if FPanelHidden then
Cap := '>'
else
Cap := '<';
TW := C.TextWidth(Cap); TW := C.TextWidth(Cap);
C.Font.Color := CLR_TEXT; C.Font.Color := CLR_TEXT;
C.Brush.Style := bsClear; C.Brush.Style := bsClear;
+268 -230
View File
@@ -229,6 +229,11 @@ type
// не меняется. // не меняется.
FPostTXMuteUntil: QWord; FPostTXMuteUntil: QWord;
FActiveDisplayID: Integer; // RX_DISP_ID или TX_DISP_ID FActiveDisplayID: Integer; // RX_DISP_ID или TX_DISP_ID
FRXChan: Integer;
FTXChan: Integer;
FRXDispID: Integer;
FTXDispID: Integer;
FTXEnabled: Boolean;
FTXMicSource: TTXMicSource; FTXMicSource: TTXMicSource;
FOnPullMic: TPullMicSamplesFunc; FOnPullMic: TPullMicSamplesFunc;
@@ -323,7 +328,12 @@ type
public public
constructor Create(SampleRate: Integer = 192000; constructor Create(SampleRate: Integer = 192000;
AudioRate: Integer = 48000; AudioRate: Integer = 48000;
BufSize: Integer = DSP_BUFSIZE); BufSize: Integer = DSP_BUFSIZE;
RXChan: Integer = RXA_CHAN;
TXChan: Integer = TXA_CHAN;
RXDispID: Integer = RX_DISP_ID;
TXDispID: Integer = TX_DISP_ID;
EnableTX: Boolean = True);
destructor Destroy; override; destructor Destroy; override;
// Открыть DSP каналы // Открыть DSP каналы
@@ -479,7 +489,7 @@ type
implementation implementation
// =========================================================================== // ===========================================================================
// TX DSP поток — читает mic ring buffer, вызывает fexchange0(TXA_CHAN), // TX DSP поток — читает mic ring buffer, вызывает fexchange0(FTXChan),
// сигнализирует о готовых IQ данных через FOnTXIQ callback. // сигнализирует о готовых IQ данных через FOnTXIQ callback.
// Аналог tx_thread в piHPSDR/transmitter.c // Аналог tx_thread в piHPSDR/transmitter.c
// =========================================================================== // ===========================================================================
@@ -715,11 +725,17 @@ end;
// Constructor / Destructor // Constructor / Destructor
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
constructor TWDSPEngine.Create(SampleRate, AudioRate, BufSize: Integer); constructor TWDSPEngine.Create(SampleRate, AudioRate, BufSize, RXChan, TXChan,
RXDispID, TXDispID: Integer; EnableTX: Boolean);
begin begin
inherited Create; inherited Create;
FSampleRate := SampleRate; FSampleRate := SampleRate;
FAudioRate := AudioRate; FAudioRate := AudioRate;
FRXChan := RXChan;
FTXChan := TXChan;
FRXDispID := RXDispID;
FTXDispID := TXDispID;
FTXEnabled := EnableTX;
// BufSize = dsp_size @ AudioRate (внутренний DSP буфер, piHPSDR buffer_size = 1024) // BufSize = dsp_size @ AudioRate (внутренний DSP буфер, piHPSDR buffer_size = 1024)
// FBufSize = in_size @ SampleRate = BufSize * (SampleRate/AudioRate) // FBufSize = in_size @ SampleRate = BufSize * (SampleRate/AudioRate)
// piHPSDR: in_size = buffer_size * sample_rate/48000 = 1024*4 = 4096 @ 192kHz // piHPSDR: in_size = buffer_size * sample_rate/48000 = 1024*4 = 4096 @ 192kHz
@@ -784,7 +800,7 @@ begin
FTXActive := False; FTXActive := False;
FKeepRXDuringTX := False; FKeepRXDuringTX := False;
FPostTXMuteUntil := 0; FPostTXMuteUntil := 0;
FActiveDisplayID := RX_DISP_ID; FActiveDisplayID := FRXDispID;
FTXMicSource := txmsRadio; FTXMicSource := txmsRadio;
FOnPullMic := nil; FOnPullMic := nil;
FTXThread := nil; FTXThread := nil;
@@ -865,19 +881,22 @@ begin
if FAnalyzerOpen then Exit; if FAnalyzerOpen then Exit;
Success := -1; Success := -1;
XCreateAnalyzer(RX_DISP_ID, @Success, 262144, 1, 1, nil); XCreateAnalyzer(FRXDispID, @Success, 262144, 1, 1, nil);
if Success <> 0 then if Success <> 0 then
begin begin
FLastError := Format('XCreateAnalyzer(RX) failed: %d', [Success]); FLastError := Format('XCreateAnalyzer(RX) failed: %d', [Success]);
Exit; Exit;
end; end;
// Отдельный analyzer для TX-спектра/водопада. Ошибку логируем в LastError, if FTXEnabled then
// но не считаем фатальной — RX без TX-display продолжает работать. begin
Success := -1; // Отдельный analyzer для TX-спектра/водопада. Ошибку логируем в LastError,
XCreateAnalyzer(TX_DISP_ID, @Success, 262144, 1, 1, nil); // но не считаем фатальной — RX без TX-display продолжает работать.
if Success <> 0 then Success := -1;
FLastError := Format('XCreateAnalyzer(TX) failed: %d', [Success]); XCreateAnalyzer(FTXDispID, @Success, 262144, 1, 1, nil);
if Success <> 0 then
FLastError := Format('XCreateAnalyzer(TX) failed: %d', [Success]);
end;
FFlp[0] := 0; FFlp[0] := 0;
ApplyAnalyzerSettings; ApplyAnalyzerSettings;
@@ -888,7 +907,7 @@ begin
end; end;
procedure TWDSPEngine.ApplyRXAnalyzerSettings; procedure TWDSPEngine.ApplyRXAnalyzerSettings;
// Применяет FFFTSize / FWindowType / FSpec* / FWf* к RX_DISP_ID. // Применяет FFFTSize / FWindowType / FSpec* / FWf* к FRXDispID.
var var
AnalyzerFFT, AvgCount, WfAvgCount, MaxW, Overlap, DisplayPixels: Integer; AnalyzerFFT, AvgCount, WfAvgCount, MaxW, Overlap, DisplayPixels: Integer;
Backmult, WfBackmult: Double; Backmult, WfBackmult: Double;
@@ -905,24 +924,24 @@ begin
AverageTimeToParams(FSpecAvgMode, FSpecAvgTimeMS, AvgCount, Backmult); AverageTimeToParams(FSpecAvgMode, FSpecAvgTimeMS, AvgCount, Backmult);
AverageTimeToParams(FWfAvgMode, FWfAvgTimeMS, WfAvgCount, WfBackmult); AverageTimeToParams(FWfAvgMode, FWfAvgTimeMS, WfAvgCount, WfBackmult);
SetAnalyzer(RX_DISP_ID, 2, 1, 1, @FFlp[0], AnalyzerFFT, DISPLAY_BLOCK_SIZE, SetAnalyzer(FRXDispID, 2, 1, 1, @FFlp[0], AnalyzerFFT, DISPLAY_BLOCK_SIZE,
FWindowType, 14.0, Overlap, 0, 0.0, 0.0, DisplayPixels, FWindowType, 14.0, Overlap, 0, 0.0, 0.0, DisplayPixels,
1, 0, 0.0, 0.0, MaxW); 1, 0, 0.0, 0.0, MaxW);
SetDisplayDetectorMode(RX_DISP_ID, 0, FSpecDetector); SetDisplayDetectorMode(FRXDispID, 0, FSpecDetector);
SetDisplayAverageMode (RX_DISP_ID, 0, FSpecAvgMode); SetDisplayAverageMode (FRXDispID, 0, FSpecAvgMode);
SetDisplayNumAverage (RX_DISP_ID, 0, AvgCount); SetDisplayNumAverage (FRXDispID, 0, AvgCount);
SetDisplayAvBackmult (RX_DISP_ID, 0, Backmult); SetDisplayAvBackmult (FRXDispID, 0, Backmult);
SetDisplayNormOneHz (RX_DISP_ID, 0, UsePanNormOneHz(FSpecDetector)); SetDisplayNormOneHz (FRXDispID, 0, UsePanNormOneHz(FSpecDetector));
SetDisplayDetectorMode(RX_DISP_ID, 1, FWfDetector); SetDisplayDetectorMode(FRXDispID, 1, FWfDetector);
SetDisplayAverageMode (RX_DISP_ID, 1, FWfAvgMode); SetDisplayAverageMode (FRXDispID, 1, FWfAvgMode);
SetDisplayNumAverage (RX_DISP_ID, 1, WfAvgCount); SetDisplayNumAverage (FRXDispID, 1, WfAvgCount);
SetDisplayAvBackmult (RX_DISP_ID, 1, WfBackmult); SetDisplayAvBackmult (FRXDispID, 1, WfBackmult);
SetDisplayNormOneHz (RX_DISP_ID, 1, 0); SetDisplayNormOneHz (FRXDispID, 1, 0);
SetDisplaySampleRate (RX_DISP_ID, FSampleRate); SetDisplaySampleRate (FRXDispID, FSampleRate);
end; end;
procedure TWDSPEngine.ApplyTXAnalyzerSettings; procedure TWDSPEngine.ApplyTXAnalyzerSettings;
// Применяет FTXFFTSize / FTXWindowType / FTXSpec* / FTXWf* к TX_DISP_ID. // Применяет FTXFFTSize / FTXWindowType / FTXSpec* / FTXWf* к FTXDispID.
// FFT/Window/Det/Avg отдельные от RX — TX-спектр обычно нужен мельче по FFT // FFT/Window/Det/Avg отдельные от RX — TX-спектр обычно нужен мельче по FFT
// (TX-полоса узкая) и с другим усреднением (быстрее реагировать на голос). // (TX-полоса узкая) и с другим усреднением (быстрее реагировать на голос).
var var
@@ -931,6 +950,7 @@ var
EffectiveFPS: Double; EffectiveFPS: Double;
const KEEP_TIME_SEC = 0.10; const KEEP_TIME_SEC = 0.10;
begin begin
if not FTXEnabled then Exit;
AnalyzerFFT := NormalizeFFTSize(FTXFFTSize); AnalyzerFFT := NormalizeFFTSize(FTXFFTSize);
FTXDispPos := 0; FTXDispPos := 0;
MaxW := AnalyzerFFT + Round(Min(KEEP_TIME_SEC * FTXSampleRate, MaxW := AnalyzerFFT + Round(Min(KEEP_TIME_SEC * FTXSampleRate,
@@ -941,27 +961,28 @@ begin
AverageTimeToParams(FTXSpecAvgMode, FTXSpecAvgTimeMS, AvgCount, Backmult); AverageTimeToParams(FTXSpecAvgMode, FTXSpecAvgTimeMS, AvgCount, Backmult);
AverageTimeToParams(FTXWfAvgMode, FTXWfAvgTimeMS, WfAvgCount, WfBackmult); AverageTimeToParams(FTXWfAvgMode, FTXWfAvgTimeMS, WfAvgCount, WfBackmult);
SetAnalyzer(TX_DISP_ID, 2, 1, 1, @FFlp[0], AnalyzerFFT, DISPLAY_BLOCK_SIZE, SetAnalyzer(FTXDispID, 2, 1, 1, @FFlp[0], AnalyzerFFT, DISPLAY_BLOCK_SIZE,
FTXWindowType, 14.0, Overlap, 0, 0.0, 0.0, DisplayPixels, FTXWindowType, 14.0, Overlap, 0, 0.0, 0.0, DisplayPixels,
1, 0, 0.0, 0.0, MaxW); 1, 0, 0.0, 0.0, MaxW);
SetDisplayDetectorMode(TX_DISP_ID, 0, FTXSpecDetector); SetDisplayDetectorMode(FTXDispID, 0, FTXSpecDetector);
SetDisplayAverageMode (TX_DISP_ID, 0, FTXSpecAvgMode); SetDisplayAverageMode (FTXDispID, 0, FTXSpecAvgMode);
SetDisplayNumAverage (TX_DISP_ID, 0, AvgCount); SetDisplayNumAverage (FTXDispID, 0, AvgCount);
SetDisplayAvBackmult (TX_DISP_ID, 0, Backmult); SetDisplayAvBackmult (FTXDispID, 0, Backmult);
SetDisplayNormOneHz (TX_DISP_ID, 0, UsePanNormOneHz(FTXSpecDetector)); SetDisplayNormOneHz (FTXDispID, 0, UsePanNormOneHz(FTXSpecDetector));
SetDisplayDetectorMode(TX_DISP_ID, 1, FTXWfDetector); SetDisplayDetectorMode(FTXDispID, 1, FTXWfDetector);
SetDisplayAverageMode (TX_DISP_ID, 1, FTXWfAvgMode); SetDisplayAverageMode (FTXDispID, 1, FTXWfAvgMode);
SetDisplayNumAverage (TX_DISP_ID, 1, WfAvgCount); SetDisplayNumAverage (FTXDispID, 1, WfAvgCount);
SetDisplayAvBackmult (TX_DISP_ID, 1, WfBackmult); SetDisplayAvBackmult (FTXDispID, 1, WfBackmult);
SetDisplayNormOneHz (TX_DISP_ID, 1, 0); SetDisplayNormOneHz (FTXDispID, 1, 0);
SetDisplaySampleRate (TX_DISP_ID, FTXSampleRate); SetDisplaySampleRate (FTXDispID, FTXSampleRate);
end; end;
procedure TWDSPEngine.ApplyAnalyzerSettings; procedure TWDSPEngine.ApplyAnalyzerSettings;
// Совместимый вход: применяет настройки и к RX, и к TX analyzer'у. // Совместимый вход: применяет настройки и к RX, и к TX analyzer'у.
begin begin
ApplyRXAnalyzerSettings; ApplyRXAnalyzerSettings;
ApplyTXAnalyzerSettings; if FTXEnabled then
ApplyTXAnalyzerSettings;
end; end;
procedure TWDSPEngine.CloseAnalyzer; procedure TWDSPEngine.CloseAnalyzer;
@@ -973,8 +994,9 @@ begin
FDisplayThread.WaitFor; FDisplayThread.WaitFor;
FreeAndNil(FDisplayThread); FreeAndNil(FDisplayThread);
end; end;
DestroyAnalyzer(RX_DISP_ID); DestroyAnalyzer(FRXDispID);
DestroyAnalyzer(TX_DISP_ID); if FTXEnabled then
DestroyAnalyzer(FTXDispID);
FAnalyzerOpen := False; FAnalyzerOpen := False;
end; end;
@@ -1011,7 +1033,7 @@ begin
end; end;
OpenChannel( OpenChannel(
RXA_CHAN, FRXChan,
FBufSize, FBufSize,
FAudioBufSize, FAudioBufSize,
FSampleRate, FSampleRate,
@@ -1023,45 +1045,49 @@ begin
0 0
); );
create_anbEXT(RXA_CHAN, 1, FBufSize, FSampleRate, 0.0001, 0.0001, 0.0001, 0.05, 20); create_anbEXT(FRXChan, 1, FBufSize, FSampleRate, 0.0001, 0.0001, 0.0001, 0.05, 20);
create_nobEXT(RXA_CHAN, 1, 0, FBufSize, FSampleRate, 0.0001, 0.0001, 0.0001, 0.05, 20); create_nobEXT(FRXChan, 1, 0, FBufSize, FSampleRate, 0.0001, 0.0001, 0.0001, 0.05, 20);
SetRXABandpassWindow(RXA_CHAN, 1); SetRXABandpassWindow(FRXChan, 1);
SetRXAMode(RXA_CHAN, ModeToWDSP(FMode)); SetRXAMode(FRXChan, ModeToWDSP(FMode));
SetRXAShiftRun(RXA_CHAN, 1); SetRXAShiftRun(FRXChan, 1);
SetRXAShiftFreq(RXA_CHAN, 0.0); SetRXAShiftFreq(FRXChan, 0.0);
RXASetPassband(RXA_CHAN, FFilterLow, FFilterHigh); RXASetPassband(FRXChan, FFilterLow, FFilterHigh);
SetAGC(FAGCMode, 50.0); SetAGC(FAGCMode, 50.0);
SetRXAPanelGain1(RXA_CHAN, FVolume); SetRXAPanelGain1(FRXChan, FVolume);
SetRXAPanelSelect(RXA_CHAN, 3); SetRXAPanelSelect(FRXChan, 3);
SetRXAPanelRun(RXA_CHAN, 1); SetRXAPanelRun(FRXChan, 1);
SetChannelState(RXA_CHAN, 1, 0); SetChannelState(FRXChan, 1, 0);
// TXA: mic @ FAudioRate → IQ @ FTXSampleRate (фиксированный DUC rate, не зависит от RX). if FTXEnabled then
// out_size = FAudioBufSize * FTXSampleRate/FAudioRate = FTXOutBufSize (4096 @ 192k tx). begin
// FTXOut уже имеет размер FTXOutBufSize*2. // TXA: mic @ FAudioRate → IQ @ FTXSampleRate (фиксированный DUC rate, не зависит от RX).
OpenChannel( // out_size = FAudioBufSize * FTXSampleRate/FAudioRate = FTXOutBufSize (4096 @ 192k tx).
TXA_CHAN, // FTXOut уже имеет размер FTXOutBufSize*2.
FAudioBufSize, OpenChannel(
FAudioBufSize, FTXChan,
FAudioRate, FAudioBufSize,
FAudioRate, FAudioBufSize,
FTXSampleRate, FAudioRate,
1, FAudioRate,
0, FTXSampleRate,
0.010, 0.010, 0.010, 0.010, 1,
0 0,
); 0.010, 0.010, 0.010, 0.010,
0
);
SetTXAMode(TXA_CHAN, ModeToWDSP(FMode)); SetTXAMode(FTXChan, ModeToWDSP(FMode));
SetTXAPanelRun(TXA_CHAN, 1); SetTXAPanelRun(FTXChan, 1);
// PatchPanel: 1=Q, 2=I. Mic подаётся в I (FTXIn[i*2]), Q=0 — выбираем I. // PatchPanel: 1=Q, 2=I. Mic подаётся в I (FTXIn[i*2]), Q=0 — выбираем I.
SetTXAPanelSelect(TXA_CHAN, 2); SetTXAPanelSelect(FTXChan, 2);
end;
FInitialized := True; FInitialized := True;
// Прокидываем все TX-параметры из FTX*-полей: фильтр, mic gain, EQ, // Прокидываем все TX-параметры из FTX*-полей: фильтр, mic gain, EQ,
// Leveler, ALC, Compressor, Phase Rotator, AM Carrier, FM, CTCSS. // Leveler, ALC, Compressor, Phase Rotator, AM Carrier, FM, CTCSS.
ApplyTXChainSettings; if FTXEnabled then
ApplyTXChainSettings;
ApplyNoiseFilterState; ApplyNoiseFilterState;
Result := True; Result := True;
@@ -1094,10 +1120,11 @@ begin
end; end;
CloseAnalyzer; CloseAnalyzer;
destroy_anbEXT(RXA_CHAN); destroy_anbEXT(FRXChan);
destroy_nobEXT(RXA_CHAN); destroy_nobEXT(FRXChan);
CloseChannel(RXA_CHAN); CloseChannel(FRXChan);
CloseChannel(TXA_CHAN); if FTXEnabled then
CloseChannel(FTXChan);
FInitialized := False; FInitialized := False;
end; end;
@@ -1179,7 +1206,7 @@ procedure TWDSPEngine.PushIQItemToDSP(const Item: TIQQueueItem);
// Вызывается из DSP потока — декодирует IQ и накапливает до FBufSize. // Вызывается из DSP потока — декодирует IQ и накапливает до FBufSize.
// В non-DUP TX (FTXActive and not FKeepRXDuringTX) полностью пропускаем // В non-DUP TX (FTXActive and not FKeepRXDuringTX) полностью пропускаем
// IQ-пакет: не кормим RX-анализатор и не накапливаем для fexchange0. // IQ-пакет: не кормим RX-анализатор и не накапливаем для fexchange0.
// Иначе TX leakage из DDC оседает в RXA pipeline / RX_DISP_ID FFT-истории // Иначе TX leakage из DDC оседает в RXA pipeline / FRXDispID FFT-истории
// и звучит/виден на водопаде первые секунды после возврата на RX. // и звучит/виден на водопаде первые секунды после возврата на RX.
var var
i, Pos: Integer; i, Pos: Integer;
@@ -1231,7 +1258,7 @@ begin
if FDispPos >= DISPLAY_BLOCK_SIZE then if FDispPos >= DISPLAY_BLOCK_SIZE then
begin begin
Spectrum0(1, RX_DISP_ID, 0, 0, @FDispBuf[0]); Spectrum0(1, FRXDispID, 0, 0, @FDispBuf[0]);
FDispPos := 0; FDispPos := 0;
end; end;
end; end;
@@ -1246,7 +1273,7 @@ begin
if FTXDispPos >= DISPLAY_BLOCK_SIZE then if FTXDispPos >= DISPLAY_BLOCK_SIZE then
begin begin
Spectrum0(1, TX_DISP_ID, 0, 0, @FTXDispBuf[0]); Spectrum0(1, FTXDispID, 0, 0, @FTXDispBuf[0]);
FTXDispPos := 0; FTXDispPos := 0;
end; end;
end; end;
@@ -1270,12 +1297,12 @@ begin
// DSP обработка // DSP обработка
Err := 0; Err := 0;
fexchange0(RXA_CHAN, @FRXIn[0], @FRXOut[0], @Err); fexchange0(FRXChan, @FRXIn[0], @FRXOut[0], @Err);
// S-meter: читаем ОДИН раз в DSP-колбэке и кешируем в FSMeter. // S-meter: читаем ОДИН раз в DSP-колбэке и кешируем в FSMeter.
// GetRXAMeter сбрасывает аккумулятор после вызова, поэтому второй // GetRXAMeter сбрасывает аккумулятор после вызова, поэтому второй
// вызов вернёт 0/-∞ — отсюда "падение до нуля". Только здесь! // вызов вернёт 0/-∞ — отсюда "падение до нуля". Только здесь!
FSMeter := GetRXAMeter(RXA_CHAN, RXA_S_AV); FSMeter := GetRXAMeter(FRXChan, RXA_S_AV);
// Аудио колбэк — FAudioBufSize сэмплов @ FAudioRate (после децимации 4:1). // Аудио колбэк — FAudioBufSize сэмплов @ FAudioRate (после децимации 4:1).
// При TX RX-аудио глушим (как в Thetis/piHPSDR при не-duplex MOX), // При TX RX-аудио глушим (как в Thetis/piHPSDR при не-duplex MOX),
@@ -1309,8 +1336,9 @@ procedure TWDSPEngine.SetMode(Mode: Integer);
begin begin
FMode := Mode; FMode := Mode;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAMode(RXA_CHAN, ModeToWDSP(Mode)); SetRXAMode(FRXChan, ModeToWDSP(Mode));
SetTXAMode(TXA_CHAN, ModeToWDSP(Mode)); if FTXEnabled then
SetTXAMode(FTXChan, ModeToWDSP(Mode));
// НЕ вызываем ApplyDefaultFilter — фильтр устанавливается явно из UI // НЕ вызываем ApplyDefaultFilter — фильтр устанавливается явно из UI
end; end;
@@ -1320,7 +1348,7 @@ begin
FFilterHigh := High; FFilterHigh := High;
if not FInitialized then Exit; if not FInitialized then Exit;
// RXASetPassband — правильный unified API, пересчитывает фильтр целиком // RXASetPassband — правильный unified API, пересчитывает фильтр целиком
RXASetPassband(RXA_CHAN, Low, High); RXASetPassband(FRXChan, Low, High);
end; end;
procedure TWDSPEngine.SetAGC(Mode: TWDSPAGCMode; FixedGain: Double); procedure TWDSPEngine.SetAGC(Mode: TWDSPAGCMode; FixedGain: Double);
@@ -1329,40 +1357,40 @@ begin
if not FInitialized then Exit; if not FInitialized then Exit;
// Точно по piHPSDR receiver.c: set_agc() // Точно по piHPSDR receiver.c: set_agc()
SetRXAAGCMode(RXA_CHAN, Ord(Mode)); SetRXAAGCMode(FRXChan, Ord(Mode));
SetRXAAGCSlope(RXA_CHAN, FAGCSlope); SetRXAAGCSlope(FRXChan, FAGCSlope);
SetRXAAGCTop(RXA_CHAN, FAGCTop); SetRXAAGCTop(FRXChan, FAGCTop);
case Mode of case Mode of
agcOff: agcOff:
SetRXAAGCFixed(RXA_CHAN, FixedGain); SetRXAAGCFixed(FRXChan, FixedGain);
agcLong: begin agcLong: begin
SetRXAAGCAttack(RXA_CHAN, 2); SetRXAAGCAttack(FRXChan, 2);
SetRXAAGCHang(RXA_CHAN, 2000); SetRXAAGCHang(FRXChan, 2000);
SetRXAAGCDecay(RXA_CHAN, 2000); SetRXAAGCDecay(FRXChan, 2000);
SetRXAAGCHangThreshold(RXA_CHAN, FAGCHangThreshold); SetRXAAGCHangThreshold(FRXChan, FAGCHangThreshold);
end; end;
agcSlow: begin agcSlow: begin
SetRXAAGCAttack(RXA_CHAN, 2); SetRXAAGCAttack(FRXChan, 2);
SetRXAAGCHang(RXA_CHAN, 1000); SetRXAAGCHang(FRXChan, 1000);
SetRXAAGCDecay(RXA_CHAN, 500); SetRXAAGCDecay(FRXChan, 500);
SetRXAAGCHangThreshold(RXA_CHAN, FAGCHangThreshold); SetRXAAGCHangThreshold(FRXChan, FAGCHangThreshold);
end; end;
agcMedium: begin agcMedium: begin
SetRXAAGCAttack(RXA_CHAN, 2); SetRXAAGCAttack(FRXChan, 2);
SetRXAAGCHang(RXA_CHAN, 0); SetRXAAGCHang(FRXChan, 0);
SetRXAAGCDecay(RXA_CHAN, 250); SetRXAAGCDecay(FRXChan, 250);
SetRXAAGCHangThreshold(RXA_CHAN, 100); SetRXAAGCHangThreshold(FRXChan, 100);
end; end;
agcFast: begin agcFast: begin
SetRXAAGCAttack(RXA_CHAN, 2); SetRXAAGCAttack(FRXChan, 2);
SetRXAAGCHang(RXA_CHAN, 0); SetRXAAGCHang(FRXChan, 0);
SetRXAAGCDecay(RXA_CHAN, 50); SetRXAAGCDecay(FRXChan, 50);
SetRXAAGCHangThreshold(RXA_CHAN, 100); SetRXAAGCHangThreshold(FRXChan, 100);
end; end;
end; end;
@@ -1374,14 +1402,14 @@ procedure TWDSPEngine.SetShift(ShiftHz: Double);
begin begin
FShiftHz := ShiftHz; FShiftHz := ShiftHz;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAShiftFreq(RXA_CHAN, ShiftHz); SetRXAShiftFreq(FRXChan, ShiftHz);
end; end;
procedure TWDSPEngine.SetAGCTop(TopDBm: Double); procedure TWDSPEngine.SetAGCTop(TopDBm: Double);
begin begin
FAGCTop := TopDBm; FAGCTop := TopDBm;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAAGCTop(RXA_CHAN, TopDBm); SetRXAAGCTop(FRXChan, TopDBm);
UpdateAGCLines(FLastSpectrumW); UpdateAGCLines(FLastSpectrumW);
end; end;
@@ -1389,14 +1417,14 @@ procedure TWDSPEngine.SetAGCSlope(Slope: Integer);
begin begin
FAGCSlope := Slope; FAGCSlope := Slope;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAAGCSlope(RXA_CHAN, Slope); SetRXAAGCSlope(FRXChan, Slope);
end; end;
procedure TWDSPEngine.SetAGCHangThreshold(Threshold: Integer); procedure TWDSPEngine.SetAGCHangThreshold(Threshold: Integer);
begin begin
FAGCHangThreshold := Threshold; FAGCHangThreshold := Threshold;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAAGCHangThreshold(RXA_CHAN, Threshold); SetRXAAGCHangThreshold(FRXChan, Threshold);
UpdateAGCLines(FLastSpectrumW); UpdateAGCLines(FLastSpectrumW);
end; end;
@@ -1413,8 +1441,8 @@ procedure TWDSPEngine.UpdateAGCLines(SpectrumW: Integer);
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
if SpectrumW <= 0 then Exit; // окно ещё не показано — не читаем if SpectrumW <= 0 then Exit; // окно ещё не показано — не читаем
GetRXAAGCHangLevel(RXA_CHAN, @FAGCHangLevel); GetRXAAGCHangLevel(FRXChan, @FAGCHangLevel);
GetRXAAGCThresh(RXA_CHAN, @FAGCThresh, GetRXAAGCThresh(FRXChan, @FAGCThresh,
SpectrumW, // реальная ширина дисплея в пикселях SpectrumW, // реальная ширина дисплея в пикселях
FSampleRate); FSampleRate);
end; end;
@@ -1423,65 +1451,65 @@ procedure TWDSPEngine.ApplyNRState;
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAANRVals(RXA_CHAN, 64, 16, 16e-4, 10e-7); SetRXAANRVals(FRXChan, 64, 16, 16e-4, 10e-7);
SetRXAANRPosition(RXA_CHAN, FILTER_NR_AGC_POSITION); SetRXAANRPosition(FRXChan, FILTER_NR_AGC_POSITION);
SetRXAANRRun(RXA_CHAN, Ord(FNRMode = NR_MODE_1)); SetRXAANRRun(FRXChan, Ord(FNRMode = NR_MODE_1));
SetRXAEMNRPosition(RXA_CHAN, FILTER_NR_AGC_POSITION); SetRXAEMNRPosition(FRXChan, FILTER_NR_AGC_POSITION);
SetRXAEMNRgainMethod(RXA_CHAN, FILTER_NR2_GAIN_METHOD); SetRXAEMNRgainMethod(FRXChan, FILTER_NR2_GAIN_METHOD);
SetRXAEMNRnpeMethod(RXA_CHAN, FILTER_NR2_NPE_METHOD); SetRXAEMNRnpeMethod(FRXChan, FILTER_NR2_NPE_METHOD);
SetRXAEMNRtrainZetaThresh(RXA_CHAN, FILTER_NR2_TRAINED_THRESHOLD); SetRXAEMNRtrainZetaThresh(FRXChan, FILTER_NR2_TRAINED_THRESHOLD);
SetRXAEMNRtrainT2(RXA_CHAN, FILTER_NR2_TRAINED_T2); SetRXAEMNRtrainT2(FRXChan, FILTER_NR2_TRAINED_T2);
SetRXAEMNRpost2Taper(RXA_CHAN, FILTER_NR2_POST_TAPER); SetRXAEMNRpost2Taper(FRXChan, FILTER_NR2_POST_TAPER);
SetRXAEMNRpost2Nlevel(RXA_CHAN, FILTER_NR2_POST_NLEVEL); SetRXAEMNRpost2Nlevel(FRXChan, FILTER_NR2_POST_NLEVEL);
SetRXAEMNRpost2Factor(RXA_CHAN, FILTER_NR2_POST_FACTOR); SetRXAEMNRpost2Factor(FRXChan, FILTER_NR2_POST_FACTOR);
SetRXAEMNRpost2Rate(RXA_CHAN, FILTER_NR2_POST_RATE); SetRXAEMNRpost2Rate(FRXChan, FILTER_NR2_POST_RATE);
SetRXAEMNRaeRun(RXA_CHAN, 1); SetRXAEMNRaeRun(FRXChan, 1);
SetRXAEMNRpost2Run(RXA_CHAN, FILTER_NR2_POST_RUN); SetRXAEMNRpost2Run(FRXChan, FILTER_NR2_POST_RUN);
SetRXAEMNRRun(RXA_CHAN, Ord(FNRMode = NR_MODE_2)); SetRXAEMNRRun(FRXChan, Ord(FNRMode = NR_MODE_2));
SetRXARNNRPosition(RXA_CHAN, FILTER_NR_AGC_POSITION); SetRXARNNRPosition(FRXChan, FILTER_NR_AGC_POSITION);
SetRXARNNRRun(RXA_CHAN, Ord(FNRMode = NR_MODE_3)); SetRXARNNRRun(FRXChan, Ord(FNRMode = NR_MODE_3));
SetRXASBNRreductionAmount(RXA_CHAN, FILTER_NR4_REDUCTION_AMOUNT); SetRXASBNRreductionAmount(FRXChan, FILTER_NR4_REDUCTION_AMOUNT);
SetRXASBNRsmoothingFactor(RXA_CHAN, FILTER_NR4_SMOOTHING_FACTOR); SetRXASBNRsmoothingFactor(FRXChan, FILTER_NR4_SMOOTHING_FACTOR);
SetRXASBNRwhiteningFactor(RXA_CHAN, FILTER_NR4_WHITENING_FACTOR); SetRXASBNRwhiteningFactor(FRXChan, FILTER_NR4_WHITENING_FACTOR);
SetRXASBNRnoiseRescale(RXA_CHAN, FILTER_NR4_NOISE_RESCALE); SetRXASBNRnoiseRescale(FRXChan, FILTER_NR4_NOISE_RESCALE);
SetRXASBNRpostFilterThreshold(RXA_CHAN, FILTER_NR4_POST_THRESHOLD); SetRXASBNRpostFilterThreshold(FRXChan, FILTER_NR4_POST_THRESHOLD);
SetRXASBNRnoiseScalingType(RXA_CHAN, FILTER_NR4_NOISE_SCALING_TYPE); SetRXASBNRnoiseScalingType(FRXChan, FILTER_NR4_NOISE_SCALING_TYPE);
SetRXASBNRPosition(RXA_CHAN, FILTER_NR_AGC_POSITION); SetRXASBNRPosition(FRXChan, FILTER_NR_AGC_POSITION);
SetRXASBNRRun(RXA_CHAN, Ord(FNRMode = NR_MODE_4)); SetRXASBNRRun(FRXChan, Ord(FNRMode = NR_MODE_4));
end; end;
procedure TWDSPEngine.ApplyNBState; procedure TWDSPEngine.ApplyNBState;
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
SetEXTANBTau(RXA_CHAN, FILTER_NB_TAU); SetEXTANBTau(FRXChan, FILTER_NB_TAU);
SetEXTANBHangtime(RXA_CHAN, FILTER_NB_HANGTIME); SetEXTANBHangtime(FRXChan, FILTER_NB_HANGTIME);
SetEXTANBAdvtime(RXA_CHAN, FILTER_NB_ADVTIME); SetEXTANBAdvtime(FRXChan, FILTER_NB_ADVTIME);
SetEXTANBThreshold(RXA_CHAN, FILTER_NB_THRESHOLD); SetEXTANBThreshold(FRXChan, FILTER_NB_THRESHOLD);
SetEXTANBRun(RXA_CHAN, Ord(FNBMode = NB_MODE_1)); SetEXTANBRun(FRXChan, Ord(FNBMode = NB_MODE_1));
SetEXTNOBMode(RXA_CHAN, FILTER_NB2_MODE); SetEXTNOBMode(FRXChan, FILTER_NB2_MODE);
SetEXTNOBTau(RXA_CHAN, FILTER_NB_TAU); SetEXTNOBTau(FRXChan, FILTER_NB_TAU);
SetEXTNOBHangtime(RXA_CHAN, FILTER_NB_HANGTIME); SetEXTNOBHangtime(FRXChan, FILTER_NB_HANGTIME);
SetEXTNOBAdvtime(RXA_CHAN, FILTER_NB_ADVTIME); SetEXTNOBAdvtime(FRXChan, FILTER_NB_ADVTIME);
SetEXTNOBThreshold(RXA_CHAN, FILTER_NB_THRESHOLD); SetEXTNOBThreshold(FRXChan, FILTER_NB_THRESHOLD);
SetEXTNOBRun(RXA_CHAN, Ord(FNBMode = NB_MODE_2)); SetEXTNOBRun(FRXChan, Ord(FNBMode = NB_MODE_2));
end; end;
procedure TWDSPEngine.ApplySNBState; procedure TWDSPEngine.ApplySNBState;
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXASNBARun(RXA_CHAN, Ord(FSNBEnabled)); SetRXASNBARun(FRXChan, Ord(FSNBEnabled));
end; end;
procedure TWDSPEngine.ApplyANFState; procedure TWDSPEngine.ApplyANFState;
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAANFPosition(RXA_CHAN, FILTER_NR_AGC_POSITION); SetRXAANFPosition(FRXChan, FILTER_NR_AGC_POSITION);
SetRXAANFRun(RXA_CHAN, Ord(FANFEnabled)); SetRXAANFRun(FRXChan, Ord(FANFEnabled));
end; end;
procedure TWDSPEngine.ApplyNoiseFilterState; procedure TWDSPEngine.ApplyNoiseFilterState;
@@ -1535,7 +1563,7 @@ end;
procedure TWDSPEngine.SetRXFMDeviation(Deviation: Double); procedure TWDSPEngine.SetRXFMDeviation(Deviation: Double);
begin begin
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAFMDeviation(RXA_CHAN, Deviation); SetRXAFMDeviation(FRXChan, Deviation);
end; end;
procedure TWDSPEngine.SetFMSquelch(Enable: Boolean; Level: Integer); procedure TWDSPEngine.SetFMSquelch(Enable: Boolean; Level: Integer);
@@ -1545,25 +1573,25 @@ begin
if Enable then if Enable then
begin begin
Threshold := Level / 200.0; // 0..100 → 0.0..0.5 Threshold := Level / 200.0; // 0..100 → 0.0..0.5
SetRXAFMSQThreshold(RXA_CHAN, Threshold); SetRXAFMSQThreshold(FRXChan, Threshold);
SetRXAFMSQRun(RXA_CHAN, 1); SetRXAFMSQRun(FRXChan, 1);
end end
else else
SetRXAFMSQRun(RXA_CHAN, 0); SetRXAFMSQRun(FRXChan, 0);
end; end;
procedure TWDSPEngine.SetVolume(Vol: Double); procedure TWDSPEngine.SetVolume(Vol: Double);
begin begin
FVolume := Max(0.0, Min(1.0, Vol)); FVolume := Max(0.0, Min(1.0, Vol));
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAPanelGain1(RXA_CHAN, FVolume); SetRXAPanelGain1(FRXChan, FVolume);
end; end;
procedure TWDSPEngine.SetMute(Mute: Boolean); procedure TWDSPEngine.SetMute(Mute: Boolean);
begin begin
FMuted := Mute; FMuted := Mute;
if not FInitialized then Exit; if not FInitialized then Exit;
SetRXAPanelRun(RXA_CHAN, Ord(not Mute)); SetRXAPanelRun(FRXChan, Ord(not Mute));
end; end;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1572,43 +1600,53 @@ end;
procedure TWDSPEngine.SetTXMode(Mode: Integer); procedure TWDSPEngine.SetTXMode(Mode: Integer);
begin begin
if not FTXEnabled then Exit;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAMode(TXA_CHAN, ModeToWDSP(Mode)); SetTXAMode(FTXChan, ModeToWDSP(Mode));
end; end;
procedure TWDSPEngine.SetTXFilter(Low, High: Integer); procedure TWDSPEngine.SetTXFilter(Low, High: Integer);
begin begin
if not FTXEnabled then Exit;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXABandpassFreqs(TXA_CHAN, Low, High); SetTXABandpassFreqs(FTXChan, Low, High);
end; end;
procedure TWDSPEngine.SetDriveLevel(Level: Double); procedure TWDSPEngine.SetDriveLevel(Level: Double);
begin begin
if not FTXEnabled then Exit;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAALCMaxGain(TXA_CHAN, Max(0.0, Min(1.0, Level))); SetTXAALCMaxGain(FTXChan, Max(0.0, Min(1.0, Level)));
end; end;
procedure TWDSPEngine.SetMicGain(GainDB: Double); procedure TWDSPEngine.SetMicGain(GainDB: Double);
begin begin
FTXMicGainDB := GainDB; FTXMicGainDB := GainDB;
if not FTXEnabled then Exit;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAPanelGain1(TXA_CHAN, Power(10.0, GainDB / 20.0)); SetTXAPanelGain1(FTXChan, Power(10.0, GainDB / 20.0));
end; end;
procedure TWDSPEngine.SetTXRun(Run: Boolean); procedure TWDSPEngine.SetTXRun(Run: Boolean);
begin begin
if not FTXEnabled then
begin
FTXActive := False;
FActiveDisplayID := FRXDispID;
Exit;
end;
FTXActive := Run; FTXActive := Run;
FDispPos := 0; FDispPos := 0;
FTXDispPos := 0; FTXDispPos := 0;
if Run then if Run then
FActiveDisplayID := TX_DISP_ID FActiveDisplayID := FTXDispID
else else
FActiveDisplayID := RX_DISP_ID; FActiveDisplayID := FRXDispID;
if Run then if Run then
begin begin
if FInitialized then if FInitialized then
SetChannelState(TXA_CHAN, 1, 0); // run, no delay SetChannelState(FTXChan, 1, 0); // run, no delay
// Сброс mic ring buffer и запуск TX потока // Сброс mic ring buffer и запуск TX потока
FTXMicHead := 0; FTXMicHead := 0;
FTXMicTail := 0; FTXMicTail := 0;
@@ -1619,7 +1657,7 @@ begin
end; end;
end else begin end else begin
if FInitialized then if FInitialized then
SetChannelState(TXA_CHAN, 0, 1); // stop, with slew SetChannelState(FTXChan, 0, 1); // stop, with slew
// Останавливаем TX поток // Останавливаем TX поток
if Assigned(FTXThread) then if Assigned(FTXThread) then
begin begin
@@ -1647,12 +1685,12 @@ begin
SignedFreq := -Abs(FreqHz) SignedFreq := -Abs(FreqHz)
else else
SignedFreq := Abs(FreqHz); SignedFreq := Abs(FreqHz);
SetTXAPostGenMode(TXA_CHAN, 0); // 0 = tone SetTXAPostGenMode(FTXChan, 0); // 0 = tone
SetTXAPostGenToneFreq(TXA_CHAN, SignedFreq); SetTXAPostGenToneFreq(FTXChan, SignedFreq);
SetTXAPostGenToneMag(TXA_CHAN, Max(0.0, Min(1.0, Mag))); SetTXAPostGenToneMag(FTXChan, Max(0.0, Min(1.0, Mag)));
SetTXAPostGenRun(TXA_CHAN, 1); SetTXAPostGenRun(FTXChan, 1);
end else end else
SetTXAPostGenRun(TXA_CHAN, 0); SetTXAPostGenRun(FTXChan, 0);
end; end;
procedure TWDSPEngine.SetDisplaySourceTX(UseTX: Boolean); procedure TWDSPEngine.SetDisplaySourceTX(UseTX: Boolean);
@@ -1664,9 +1702,9 @@ begin
FDispPos := 0; FDispPos := 0;
FTXDispPos := 0; FTXDispPos := 0;
if UseTX then if UseTX then
FActiveDisplayID := TX_DISP_ID FActiveDisplayID := FTXDispID
else else
FActiveDisplayID := RX_DISP_ID; FActiveDisplayID := FRXDispID;
end; end;
procedure TWDSPEngine.ProcessTXBlock; procedure TWDSPEngine.ProcessTXBlock;
@@ -1702,9 +1740,9 @@ begin
end; end;
Err := 0; Err := 0;
fexchange0(TXA_CHAN, @FTXIn[0], @FTXOut[0], @Err); fexchange0(FTXChan, @FTXIn[0], @FTXOut[0], @Err);
// TX сигнал → отдельный TX-analyzer (TX_DISP_ID). // TX сигнал → отдельный TX-analyzer (FTXDispID).
// Подаём чанками по DISPLAY_BLOCK_SIZE — analyzer ожидает именно такой // Подаём чанками по DISPLAY_BLOCK_SIZE — analyzer ожидает именно такой
// размер блока (см. SetAnalyzer). Если подавать FTXOut целиком // размер блока (см. SetAnalyzer). Если подавать FTXOut целиком
// (FTXOutBufSize пар), analyzer прочитает только первые DISPLAY_BLOCK_SIZE // (FTXOutBufSize пар), analyzer прочитает только первые DISPLAY_BLOCK_SIZE
@@ -1795,35 +1833,35 @@ begin
// Bandpass // Bandpass
if (FTXFilterLow > 0) and (FTXFilterHigh > FTXFilterLow) then if (FTXFilterLow > 0) and (FTXFilterHigh > FTXFilterLow) then
SetTXABandpassFreqs(TXA_CHAN, FTXFilterLow, FTXFilterHigh); SetTXABandpassFreqs(FTXChan, FTXFilterLow, FTXFilterHigh);
if FTXFilterWindow >= 0 then if FTXFilterWindow >= 0 then
SetTXABandpassWindow(TXA_CHAN, FTXFilterWindow); SetTXABandpassWindow(FTXChan, FTXFilterWindow);
if FTXFilterNC > 0 then if FTXFilterNC > 0 then
TXASetNC(TXA_CHAN, FTXFilterNC); TXASetNC(FTXChan, FTXFilterNC);
if FTXFilterMP >= 0 then if FTXFilterMP >= 0 then
TXASetMP(TXA_CHAN, FTXFilterMP); TXASetMP(FTXChan, FTXFilterMP);
// Mic gain (panel gain1) // Mic gain (panel gain1)
SetTXAPanelGain1(TXA_CHAN, Power(10.0, FTXMicGainDB / 20.0)); SetTXAPanelGain1(FTXChan, Power(10.0, FTXMicGainDB / 20.0));
// Compressor // Compressor
SetTXACompressorRun(TXA_CHAN, Ord(FTXCompressorOn)); SetTXACompressorRun(FTXChan, Ord(FTXCompressorOn));
SetTXACompressorGain(TXA_CHAN, FTXCompressorGain); SetTXACompressorGain(FTXChan, FTXCompressorGain);
// Leveler // Leveler
SetTXALevelerSt(TXA_CHAN, Ord(FTXLevelerOn)); SetTXALevelerSt(FTXChan, Ord(FTXLevelerOn));
SetTXALevelerTop(TXA_CHAN, FTXLevelerTop); SetTXALevelerTop(FTXChan, FTXLevelerTop);
SetTXALevelerDecay(TXA_CHAN, FTXLevelerDecay); SetTXALevelerDecay(FTXChan, FTXLevelerDecay);
// ALC // ALC
SetTXAALCSt(TXA_CHAN, Ord(FTXALCOn)); SetTXAALCSt(FTXChan, Ord(FTXALCOn));
SetTXAALCMaxGain(TXA_CHAN, FTXALCMaxGain); SetTXAALCMaxGain(FTXChan, FTXALCMaxGain);
SetTXAALCDecay(TXA_CHAN, FTXALCDecay); SetTXAALCDecay(FTXChan, FTXALCDecay);
// Phase Rotator // Phase Rotator
SetTXAPHROTRun(TXA_CHAN, Ord(FTXPhaseRotOn)); SetTXAPHROTRun(FTXChan, Ord(FTXPhaseRotOn));
SetTXAPHROTNstages(TXA_CHAN, FTXPhaseRotStages); SetTXAPHROTNstages(FTXChan, FTXPhaseRotStages);
SetTXAPHROTCorner(TXA_CHAN, FTXPhaseRotFreq); SetTXAPHROTCorner(FTXChan, FTXPhaseRotFreq);
// EQ TX (10-band: [0]=preamp, [1..10]=bands) // EQ TX (10-band: [0]=preamp, [1..10]=bands)
for i := 0 to 10 do for i := 0 to 10 do
@@ -1832,21 +1870,21 @@ begin
Freqs[i] := FTXEQFreqs[i]; Freqs[i] := FTXEQFreqs[i];
Qs[i] := 0.707; // умолчание Q Qs[i] := 0.707; // умолчание Q
end; end;
SetTXAEQProfile(TXA_CHAN, FTXEQNumBands, @Freqs[0], @Gains[0]); SetTXAEQProfile(FTXChan, FTXEQNumBands, @Freqs[0], @Gains[0]);
SetTXAEQRun(TXA_CHAN, Ord(FTXEQOn)); SetTXAEQRun(FTXChan, Ord(FTXEQOn));
// AM // AM
SetTXAAMCarrierLevel(TXA_CHAN, FTXAMCarrier); SetTXAAMCarrierLevel(FTXChan, FTXAMCarrier);
// FM // FM
SetTXAFMDeviation(TXA_CHAN, FTXFMDeviation); SetTXAFMDeviation(FTXChan, FTXFMDeviation);
if (FTXFMLowCut < FTXFMHighCut) then if (FTXFMLowCut < FTXFMHighCut) then
SetTXAFMAFFilter(TXA_CHAN, FTXFMLowCut, FTXFMHighCut); SetTXAFMAFFilter(FTXChan, FTXFMLowCut, FTXFMHighCut);
SetTXAFMEmphPosition(TXA_CHAN, FTXFMEmphPos); SetTXAFMEmphPosition(FTXChan, FTXFMEmphPos);
// CTCSS // CTCSS
SetTXACTCSSFreq(TXA_CHAN, FTXCTCSSFreq); SetTXACTCSSFreq(FTXChan, FTXCTCSSFreq);
SetTXACTCSSRun(TXA_CHAN, Ord(FTXCTCSSOn)); SetTXACTCSSRun(FTXChan, Ord(FTXCTCSSOn));
end; end;
procedure TWDSPEngine.SetTXFilterFull(Low, High, NC, MP, Window: Integer); procedure TWDSPEngine.SetTXFilterFull(Low, High, NC, MP, Window: Integer);
@@ -1859,10 +1897,10 @@ begin
FFilterLow := Low; FFilterLow := Low;
FFilterHigh := High; FFilterHigh := High;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXABandpassFreqs(TXA_CHAN, Low, High); SetTXABandpassFreqs(FTXChan, Low, High);
SetTXABandpassWindow(TXA_CHAN, Window); SetTXABandpassWindow(FTXChan, Window);
if NC > 0 then TXASetNC(TXA_CHAN, NC); if NC > 0 then TXASetNC(FTXChan, NC);
if MP >= 0 then TXASetMP(TXA_CHAN, MP); if MP >= 0 then TXASetMP(FTXChan, MP);
end; end;
procedure TWDSPEngine.SetTXCompressor(Enable: Boolean; GainDB: Double); procedure TWDSPEngine.SetTXCompressor(Enable: Boolean; GainDB: Double);
@@ -1870,8 +1908,8 @@ begin
FTXCompressorOn := Enable; FTXCompressorOn := Enable;
FTXCompressorGain := GainDB; FTXCompressorGain := GainDB;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXACompressorGain(TXA_CHAN, GainDB); SetTXACompressorGain(FTXChan, GainDB);
SetTXACompressorRun(TXA_CHAN, Ord(Enable)); SetTXACompressorRun(FTXChan, Ord(Enable));
end; end;
procedure TWDSPEngine.SetTXLeveler(Enable: Boolean; TopDB: Double; DecayMS: Integer); procedure TWDSPEngine.SetTXLeveler(Enable: Boolean; TopDB: Double; DecayMS: Integer);
@@ -1880,9 +1918,9 @@ begin
FTXLevelerTop := TopDB; FTXLevelerTop := TopDB;
FTXLevelerDecay := DecayMS; FTXLevelerDecay := DecayMS;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXALevelerTop(TXA_CHAN, TopDB); SetTXALevelerTop(FTXChan, TopDB);
SetTXALevelerDecay(TXA_CHAN, DecayMS); SetTXALevelerDecay(FTXChan, DecayMS);
SetTXALevelerSt(TXA_CHAN, Ord(Enable)); SetTXALevelerSt(FTXChan, Ord(Enable));
end; end;
procedure TWDSPEngine.SetTXALC(Enable: Boolean; MaxGainDB: Double; DecayMS: Integer); procedure TWDSPEngine.SetTXALC(Enable: Boolean; MaxGainDB: Double; DecayMS: Integer);
@@ -1891,9 +1929,9 @@ begin
FTXALCMaxGain := MaxGainDB; FTXALCMaxGain := MaxGainDB;
FTXALCDecay := DecayMS; FTXALCDecay := DecayMS;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAALCMaxGain(TXA_CHAN, MaxGainDB); SetTXAALCMaxGain(FTXChan, MaxGainDB);
SetTXAALCDecay(TXA_CHAN, DecayMS); SetTXAALCDecay(FTXChan, DecayMS);
SetTXAALCSt(TXA_CHAN, Ord(Enable)); SetTXAALCSt(FTXChan, Ord(Enable));
end; end;
procedure TWDSPEngine.SetTXPhaseRot(Enable: Boolean; Stages: Integer; FreqHz: Double); procedure TWDSPEngine.SetTXPhaseRot(Enable: Boolean; Stages: Integer; FreqHz: Double);
@@ -1902,9 +1940,9 @@ begin
FTXPhaseRotStages := Stages; FTXPhaseRotStages := Stages;
FTXPhaseRotFreq := FreqHz; FTXPhaseRotFreq := FreqHz;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAPHROTNstages(TXA_CHAN, Stages); SetTXAPHROTNstages(FTXChan, Stages);
SetTXAPHROTCorner(TXA_CHAN, FreqHz); SetTXAPHROTCorner(FTXChan, FreqHz);
SetTXAPHROTRun(TXA_CHAN, Ord(Enable)); SetTXAPHROTRun(FTXChan, Ord(Enable));
end; end;
procedure TWDSPEngine.SetTXEQ(Enable: Boolean; NumBands: Integer; procedure TWDSPEngine.SetTXEQ(Enable: Boolean; NumBands: Integer;
@@ -1924,15 +1962,15 @@ begin
F[i] := Freqs[i]; F[i] := Freqs[i];
end; end;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAEQProfile(TXA_CHAN, NumBands, @F[0], @G[0]); SetTXAEQProfile(FTXChan, NumBands, @F[0], @G[0]);
SetTXAEQRun(TXA_CHAN, Ord(Enable)); SetTXAEQRun(FTXChan, Ord(Enable));
end; end;
procedure TWDSPEngine.SetTXAMCarrierLevel(Level: Double); procedure TWDSPEngine.SetTXAMCarrierLevel(Level: Double);
begin begin
FTXAMCarrier := Level; FTXAMCarrier := Level;
if not FInitialized then Exit; if not FInitialized then Exit;
WDSP.SetTXAAMCarrierLevel(TXA_CHAN, Level); WDSP.SetTXAAMCarrierLevel(FTXChan, Level);
end; end;
procedure TWDSPEngine.SetTXFMParams(Deviation: Double; LowCut, HighCut, EmphPos: Integer); procedure TWDSPEngine.SetTXFMParams(Deviation: Double; LowCut, HighCut, EmphPos: Integer);
@@ -1942,10 +1980,10 @@ begin
FTXFMHighCut := HighCut; FTXFMHighCut := HighCut;
FTXFMEmphPos := EmphPos; FTXFMEmphPos := EmphPos;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXAFMDeviation(TXA_CHAN, Deviation); SetTXAFMDeviation(FTXChan, Deviation);
if LowCut < HighCut then if LowCut < HighCut then
SetTXAFMAFFilter(TXA_CHAN, LowCut, HighCut); SetTXAFMAFFilter(FTXChan, LowCut, HighCut);
SetTXAFMEmphPosition(TXA_CHAN, EmphPos); SetTXAFMEmphPosition(FTXChan, EmphPos);
end; end;
procedure TWDSPEngine.SetTXCTCSS(Enable: Boolean; FreqHz: Double); procedure TWDSPEngine.SetTXCTCSS(Enable: Boolean; FreqHz: Double);
@@ -1953,8 +1991,8 @@ begin
FTXCTCSSOn := Enable; FTXCTCSSOn := Enable;
FTXCTCSSFreq := FreqHz; FTXCTCSSFreq := FreqHz;
if not FInitialized then Exit; if not FInitialized then Exit;
SetTXACTCSSFreq(TXA_CHAN, FreqHz); SetTXACTCSSFreq(FTXChan, FreqHz);
SetTXACTCSSRun(TXA_CHAN, Ord(Enable)); SetTXACTCSSRun(FTXChan, Ord(Enable));
end; end;
function TWDSPEngine.TXMicRingAvail: Integer; function TWDSPEngine.TXMicRingAvail: Integer;
@@ -2016,7 +2054,7 @@ var
begin begin
if not FInitialized or not FAnalyzerOpen then Exit; if not FInitialized or not FAnalyzerOpen then Exit;
N := EnsureRange(FDisplayPixelCount, 1, SPECTRUM_PIXELS); N := EnsureRange(FDisplayPixelCount, 1, SPECTRUM_PIXELS);
DispID := FActiveDisplayID; // RX_DISP_ID или TX_DISP_ID, зависит от FTXActive DispID := FActiveDisplayID; // FRXDispID или FTXDispID, зависит от FTXActive
Flag := 0; Flag := 0;
GetPixels(DispID, 0, @PixBuf[0], @Flag); GetPixels(DispID, 0, @PixBuf[0], @Flag);
@@ -2176,11 +2214,11 @@ begin
FSpecAvgTimeMS := AvgTimeMS; FSpecAvgTimeMS := AvgTimeMS;
if not FAnalyzerOpen then Exit; if not FAnalyzerOpen then Exit;
AverageTimeToParams(FSpecAvgMode, FSpecAvgTimeMS, AvgCount, Backmult); AverageTimeToParams(FSpecAvgMode, FSpecAvgTimeMS, AvgCount, Backmult);
SetDisplayDetectorMode(RX_DISP_ID, 0, FSpecDetector); SetDisplayDetectorMode(FRXDispID, 0, FSpecDetector);
SetDisplayAverageMode(RX_DISP_ID, 0, FSpecAvgMode); SetDisplayAverageMode(FRXDispID, 0, FSpecAvgMode);
SetDisplayNumAverage(RX_DISP_ID, 0, AvgCount); SetDisplayNumAverage(FRXDispID, 0, AvgCount);
SetDisplayAvBackmult(RX_DISP_ID, 0, Backmult); SetDisplayAvBackmult(FRXDispID, 0, Backmult);
SetDisplayNormOneHz(RX_DISP_ID, 0, UsePanNormOneHz(FSpecDetector)); SetDisplayNormOneHz(FRXDispID, 0, UsePanNormOneHz(FSpecDetector));
end; end;
procedure TWDSPEngine.SetWaterfallDisplay(Detector, AvgMode: Integer; procedure TWDSPEngine.SetWaterfallDisplay(Detector, AvgMode: Integer;
@@ -2200,11 +2238,11 @@ begin
FWfAvgTimeMS := AvgTimeMS; FWfAvgTimeMS := AvgTimeMS;
if not FAnalyzerOpen then Exit; if not FAnalyzerOpen then Exit;
AverageTimeToParams(FWfAvgMode, FWfAvgTimeMS, AvgCount, Backmult); AverageTimeToParams(FWfAvgMode, FWfAvgTimeMS, AvgCount, Backmult);
SetDisplayDetectorMode(RX_DISP_ID, 1, FWfDetector); SetDisplayDetectorMode(FRXDispID, 1, FWfDetector);
SetDisplayAverageMode(RX_DISP_ID, 1, FWfAvgMode); SetDisplayAverageMode(FRXDispID, 1, FWfAvgMode);
SetDisplayNumAverage(RX_DISP_ID, 1, AvgCount); SetDisplayNumAverage(FRXDispID, 1, AvgCount);
SetDisplayAvBackmult(RX_DISP_ID, 1, Backmult); SetDisplayAvBackmult(FRXDispID, 1, Backmult);
SetDisplayNormOneHz(RX_DISP_ID, 1, 0); SetDisplayNormOneHz(FRXDispID, 1, 0);
end; end;
end. end.