mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(vfo): кнопка SQL + ползунок FM-squelch в DSP-меню флага (main + слайсы)
В fly-out DSP появляется ряд SQL (тумблер + порог 0..100) только в режиме FM. Squelch работает per-slice: у слайсов свои WDSP-каналы, поэтому добавлены поля/сеттеры FMSQ в TSliceChan/TCtrlSlice, ApplyFMSQToChan и восстановление при переоткрытии канала. Роутинг события по SliceId (0=RXA, иначе слайс). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+19
-1
@@ -524,6 +524,7 @@ type
|
||||
procedure UpdateVfoOverlayVisibility; // флаг A виден: панель скрыта ИЛИ есть слайсы B+
|
||||
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
||||
procedure OnVfoOverlayDSPChange(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
||||
procedure OnVfoOverlaySquelchChange(SQLOn: Boolean; SQLLevel: Integer);
|
||||
procedure OnVfoOverlayAGCChange(AGCMode: Integer);
|
||||
procedure OnVfoOverlayVolume(Vol: Integer);
|
||||
procedure OnVfoOverlayMute(Sender: TObject);
|
||||
@@ -1515,10 +1516,12 @@ begin
|
||||
// панели флаг правит себя сам (DoHit), синк не нужен. Только дискретные поля —
|
||||
// SetState/SetDSPState безусловно инвалидируют (не звать на потоковых rfVfoA).
|
||||
if Assigned(FVfoOverlay) and FVfoOverlay.Visible and (not FPanelHidden) and
|
||||
(Field in [rfMode, rfFilter, rfNR, rfNB, rfSNB, rfANF, rfAGCMode]) then
|
||||
(Field in [rfMode, rfFilter, rfNR, rfNB, rfSNB, rfANF, rfAGCMode,
|
||||
rfFMSQ, rfFMSQLevel]) then
|
||||
begin
|
||||
FVfoOverlay.SetState(FController.FMode, FController.FFilterBW, FController.FVfoA, FController.FLastSMeter);
|
||||
FVfoOverlay.SetDSPState(FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF, FController.FAGCMode);
|
||||
FVfoOverlay.SetSquelchState(FController.FFMSQOn, FController.FFMSQLevel);
|
||||
end;
|
||||
finally
|
||||
FSyncingFromController := False;
|
||||
@@ -5128,6 +5131,7 @@ begin
|
||||
FVfoOverlay.Height := FVfoOverlay.BaseHeight; // растёт сам при открытии fly-out
|
||||
FVfoOverlay.SetState(FController.FMode, FController.FFilterBW, FController.FVfoA, FController.FLastSMeter);
|
||||
FVfoOverlay.SetDSPState(FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF, FController.FAGCMode);
|
||||
FVfoOverlay.SetSquelchState(FController.FFMSQOn, FController.FFMSQLevel);
|
||||
FVfoOverlay.Visible := True;
|
||||
PushVfoOverlayExtState;
|
||||
PushVfoOverlayAudioDevices;
|
||||
@@ -5292,6 +5296,7 @@ begin
|
||||
begin
|
||||
FVfoOverlay.SetState(FController.FMode, FController.FFilterBW, FController.FVfoA, FController.FLastSMeter);
|
||||
FVfoOverlay.SetDSPState(FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF, FController.FAGCMode);
|
||||
FVfoOverlay.SetSquelchState(FController.FFMSQOn, FController.FFMSQLevel);
|
||||
PositionVfoOverlay; // перепозиционируем при смене LSB↔USB
|
||||
end;
|
||||
end;
|
||||
@@ -5310,6 +5315,17 @@ begin
|
||||
FController.SetANF(ANFOn);
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnVfoOverlaySquelchChange(SQLOn: Boolean; SQLLevel: Integer);
|
||||
begin
|
||||
if CurSliceId <> 0 then
|
||||
begin
|
||||
FController.SetSliceFMSquelch(CurSliceId, SQLOn, SQLLevel);
|
||||
Exit;
|
||||
end;
|
||||
FController.SetFMSquelchLevel(SQLLevel);
|
||||
FController.SetFMSquelch(SQLOn);
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnVfoOverlayAGCChange(AGCMode: Integer);
|
||||
begin
|
||||
if CurSliceId <> 0 then
|
||||
@@ -5436,6 +5452,7 @@ procedure TMainForm.WireOverlayEvents(O: TVfoOverlay);
|
||||
begin
|
||||
O.OnSelect := OnModeFilterSelect;
|
||||
O.OnDSPChange := OnVfoOverlayDSPChange;
|
||||
O.OnSquelchChange := OnVfoOverlaySquelchChange;
|
||||
O.OnAGCChange := OnVfoOverlayAGCChange;
|
||||
O.OnVolume := OnVfoOverlayVolume;
|
||||
O.OnMute := OnVfoOverlayMute;
|
||||
@@ -5565,6 +5582,7 @@ begin
|
||||
end;
|
||||
O.SetState(S.Mode, BW, S.TargetHz, FController.SliceSMeter(SliceId));
|
||||
O.SetDSPState(0, 0, False, False, FController.FAGCMode);
|
||||
O.SetSquelchState(S.FMSQOn, S.FMSQLevel);
|
||||
O.SetExtState(Round(S.Volume * 100), S.Muted, False, False, False);
|
||||
// Список аудио-устройств (общий PA-список) + текущее устройство слайса.
|
||||
if Assigned(FController.FAudioOut) then
|
||||
|
||||
@@ -135,6 +135,8 @@ type
|
||||
AGC: TWDSPAGCMode;
|
||||
Volume: Double; // 0..1
|
||||
Muted: Boolean;
|
||||
FMSQOn: Boolean; // FM-squelch включён (слайс в режиме FM)
|
||||
FMSQLevel: Integer; // порог squelch 0..100
|
||||
DeviceIndex: Integer; // PortAudio-индекс (-1 = default)
|
||||
DevName: string;
|
||||
Audio: TAudioOutput; // владеет; свой поток вывода
|
||||
@@ -529,6 +531,7 @@ type
|
||||
procedure SetSliceVolume(Id: Integer; Vol: Double); // 0..1
|
||||
procedure SetSliceMute(Id: Integer; Mute: Boolean);
|
||||
procedure SetSliceDSP(Id, NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
||||
procedure SetSliceFMSquelch(Id: Integer; On_: Boolean; Level: Integer);
|
||||
function SliceSMeter(Id: Integer): Double; // dBm, из DSP-потока
|
||||
procedure SetSliceDevice(Id, DevIndex: Integer; const DevName: string);
|
||||
function SliceCount: Integer;
|
||||
@@ -1153,6 +1156,8 @@ begin
|
||||
FSlices[slot].AGC := AGC;
|
||||
FSlices[slot].Volume := Vol;
|
||||
FSlices[slot].Muted := False;
|
||||
FSlices[slot].FMSQOn := False; // squelch по умолчанию выключен
|
||||
FSlices[slot].FMSQLevel := 40;
|
||||
FSlices[slot].DeviceIndex := DevIndex;
|
||||
FSlices[slot].DevName := DevName;
|
||||
FSlices[slot].Audio := AO;
|
||||
@@ -1247,6 +1252,17 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TRadioController.SetSliceFMSquelch(Id: Integer; On_: Boolean; Level: Integer);
|
||||
var idx: Integer;
|
||||
begin
|
||||
idx := FindSliceIndex(Id);
|
||||
if idx < 0 then Exit;
|
||||
FSlices[idx].FMSQOn := On_;
|
||||
FSlices[idx].FMSQLevel := Level;
|
||||
if Assigned(FDSPEngine) then
|
||||
FDSPEngine.SetSliceFMSquelch(Id, On_, Level);
|
||||
end;
|
||||
|
||||
function TRadioController.SliceSMeter(Id: Integer): Double;
|
||||
begin
|
||||
if Assigned(FDSPEngine) then Result := FDSPEngine.GetSliceSMeter(Id)
|
||||
|
||||
+90
-1
@@ -41,6 +41,7 @@ function SliceColor(L: Char): TColor;
|
||||
type
|
||||
TModeFilterEvent = procedure(Mode: Integer; FilterBW: Integer) of object;
|
||||
TDSPChangeEvent = procedure(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean) of object;
|
||||
TSquelchEvent = procedure(SQLOn: Boolean; SQLLevel: Integer) of object;
|
||||
TAGCChangeEvent = procedure(AGCMode: Integer) of object;
|
||||
TVolumeEvent = procedure(Vol: Integer) of object;
|
||||
TAudioDeviceEvent = procedure(DevIndex: Integer; const DevName: string) of object;
|
||||
@@ -61,6 +62,9 @@ type
|
||||
FANFOn: Boolean;
|
||||
FAGCMode: Integer; // 0=FAST 1=MED 2=SLOW 3=LONG 4=OFF
|
||||
|
||||
FSQLOn: Boolean; // FM-шумоподавитель (squelch) включён
|
||||
FSQLLevel: Integer; // порог squelch 0..100
|
||||
|
||||
FVolume: Integer; // 0..100
|
||||
FMuted: Boolean;
|
||||
FSplit: Boolean;
|
||||
@@ -77,9 +81,12 @@ type
|
||||
FAudScroll: Integer; // прокрутка списка аудио-устройств (верхний индекс)
|
||||
FVolTrack: TRect; // трек громкости (локальные координаты)
|
||||
FVolDrag: Boolean;
|
||||
FSqlTrack: TRect; // трек squelch в DSP-панели (лок. координаты)
|
||||
FSqlDrag: Boolean;
|
||||
|
||||
FOnSelect: TModeFilterEvent;
|
||||
FOnDSPChange: TDSPChangeEvent;
|
||||
FOnSquelchChange: TSquelchEvent;
|
||||
FOnAGCChange: TAGCChangeEvent;
|
||||
FOnVolume: TVolumeEvent;
|
||||
FOnMute: TNotifyEvent;
|
||||
@@ -131,6 +138,8 @@ type
|
||||
function ComputeHeight: Integer;
|
||||
procedure SetPanel(P: TFlyPanel);
|
||||
procedure ApplyVolFromX(LX: Integer);
|
||||
procedure ApplySqlFromX(LX: Integer);
|
||||
function IsFM: Boolean;
|
||||
procedure RequestInvalidate;
|
||||
procedure RequestMeterInvalidate;
|
||||
procedure RefreshMeter(C: TCanvas);
|
||||
@@ -159,6 +168,7 @@ type
|
||||
procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double);
|
||||
procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean;
|
||||
AAGCMode: Integer);
|
||||
procedure SetSquelchState(AOn: Boolean; ALevel: Integer);
|
||||
procedure SetExtState(AVolume: Integer; AMuted, ASplit, ATx, ATxSel: Boolean);
|
||||
procedure SetAudioDevices(Names: TStrings; const Indices: array of Integer;
|
||||
const CurName: string);
|
||||
@@ -185,6 +195,7 @@ type
|
||||
property BaseHeight: Integer read ComputeHeight;
|
||||
property OnSelect: TModeFilterEvent read FOnSelect write FOnSelect;
|
||||
property OnDSPChange: TDSPChangeEvent read FOnDSPChange write FOnDSPChange;
|
||||
property OnSquelchChange: TSquelchEvent read FOnSquelchChange write FOnSquelchChange;
|
||||
property OnAGCChange: TAGCChangeEvent read FOnAGCChange write FOnAGCChange;
|
||||
property OnVolume: TVolumeEvent read FOnVolume write FOnVolume;
|
||||
property OnMute: TNotifyEvent read FOnMute write FOnMute;
|
||||
@@ -228,6 +239,8 @@ const
|
||||
HIT_AUD_DN = -28;
|
||||
HIT_SLICE_SEL = -29; // клик по бейджу буквы (выбрать слайс активным)
|
||||
HIT_CLOSE = -30; // × закрытия слайса (неглавные)
|
||||
HIT_SQL = -31; // тумблер FM-squelch (в DSP-панели)
|
||||
HIT_SQL_SLIDER = -32; // трек порога FM-squelch
|
||||
HIT_AGC_PICK_BASE = 100000;
|
||||
HIT_DEV_BASE = 200000;
|
||||
|
||||
@@ -402,6 +415,7 @@ begin
|
||||
FModeFilter[3] := 500; FModeFilter[4] := 500; FModeFilter[5] := 11000;
|
||||
FModeFilter[6] := 8000; FModeFilter[7] := 8000;
|
||||
FNRMode := 0; FNBMode := 0; FSNBOn := False; FANFOn := False; FAGCMode := 0;
|
||||
FSQLOn := False; FSQLLevel := 40; FSqlDrag := False;
|
||||
FVolume := 70; FMuted := False; FSplit := False; FTx := False;
|
||||
FTxSel := True; FSlice := 'A';
|
||||
FSliceId := 0; FIsMain := True; // по умолчанию — главный приёмник (слайс A)
|
||||
@@ -532,11 +546,19 @@ end;
|
||||
|
||||
{ ---- Высота с учётом fly-out ---- }
|
||||
|
||||
function TVfoOverlay.IsFM: Boolean;
|
||||
begin
|
||||
Result := FMode = 5; // индекс FM в OVL_MODE_NAMES (= MODE_FM контроллера)
|
||||
end;
|
||||
|
||||
function TVfoOverlay.PanelContentH: Integer;
|
||||
begin
|
||||
case FPanel of
|
||||
fpMode: Result := ROW_H*2 + IGAP + ROW_H + IGAP; // 2 ряда режимов + ряд фильтров
|
||||
fpDsp: Result := ROW_H + IGAP + ROW_H; // toggles + AGC
|
||||
fpDsp: begin
|
||||
Result := ROW_H + IGAP + ROW_H; // toggles + AGC
|
||||
if IsFM then Inc(Result, IGAP + ROW_H); // + ряд SQL (только FM)
|
||||
end;
|
||||
fpAud: Result := Min(Max(1, FDevNames.Count), AUD_MAX_VIS) * AUD_ROW_H;
|
||||
else Result := 0;
|
||||
end;
|
||||
@@ -796,6 +818,34 @@ begin
|
||||
RegisterHit(HR, HIT_AGC_PICK_BASE + I);
|
||||
BX := BRight;
|
||||
end;
|
||||
|
||||
// Ряд 3 (только FM): тумблер SQL + ползунок порога squelch
|
||||
if IsFM then
|
||||
begin
|
||||
Inc(Y, ROW_H + IGAP);
|
||||
// кнопка SQL слева (1/4 ширины)
|
||||
BRight := X + RowW div 4;
|
||||
HR := Rect(X, Y, BRight - 2, Y + ROW_H);
|
||||
DrawButton(C, HR, 'SQL', FSQLOn,
|
||||
(FHotIdx >= 0) and (FHitActions[FHotIdx] = HIT_SQL), 7);
|
||||
RegisterHit(HR, HIT_SQL);
|
||||
// ползунок порога справа
|
||||
BX := BRight + 4;
|
||||
FSqlTrack := Rect(BX, Y + ROW_H div 2 - 3, X + RowW, Y + ROW_H div 2 + 3);
|
||||
C.Brush.Color := CLR_BTN_NORM; C.Brush.Style := bsSolid;
|
||||
C.Pen.Color := CLR_BTN_NORM; C.Pen.Style := psSolid;
|
||||
C.RoundRect(FSqlTrack.Left, FSqlTrack.Top, FSqlTrack.Right, FSqlTrack.Bottom, 3, 3);
|
||||
BX := FSqlTrack.Left + Round(FSQLLevel/100.0 * (FSqlTrack.Right - FSqlTrack.Left));
|
||||
if FSQLOn then
|
||||
begin
|
||||
C.Brush.Color := CLR_ACCENT; C.Pen.Color := CLR_ACCENT;
|
||||
C.RoundRect(FSqlTrack.Left, FSqlTrack.Top, BX, FSqlTrack.Bottom, 3, 3);
|
||||
end;
|
||||
C.Brush.Color := CLR_TEXT; C.Pen.Color := CLR_TEXT;
|
||||
C.Ellipse(BX-4, Y + ROW_H div 2 - 5, BX+4, Y + ROW_H div 2 + 5);
|
||||
RegisterHit(Rect(FSqlTrack.Left - 4, Y, FSqlTrack.Right + 4, Y + ROW_H),
|
||||
HIT_SQL_SLIDER);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TVfoOverlay.DrawAudPanel(C: TCanvas; X, Y, RowW: Integer);
|
||||
@@ -1081,6 +1131,9 @@ begin
|
||||
HIT_BAR_AUD: begin SetPanel(fpAud); Exit; end;
|
||||
HIT_MUTE: begin FMuted := not FMuted; RequestInvalidate;
|
||||
if Assigned(FOnMute) then FOnMute(Self); Exit; end;
|
||||
HIT_SQL: begin FSQLOn := not FSQLOn; RequestInvalidate;
|
||||
if Assigned(FOnSquelchChange) then
|
||||
FOnSquelchChange(FSQLOn, FSQLLevel); Exit; end;
|
||||
HIT_SPLIT: begin if Assigned(FOnSplit) then FOnSplit(Self); Exit; end;
|
||||
HIT_TX: begin if Assigned(FOnTxSelect) then FOnTxSelect(Self); Exit; end;
|
||||
HIT_SLICE_SEL: begin if Assigned(FOnSliceSelect) then FOnSliceSelect(Self); Exit; end;
|
||||
@@ -1176,6 +1229,21 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TVfoOverlay.ApplySqlFromX(LX: Integer);
|
||||
var
|
||||
V: Integer;
|
||||
begin
|
||||
if FSqlTrack.Right <= FSqlTrack.Left then Exit;
|
||||
V := Round((LX - FSqlTrack.Left) / (FSqlTrack.Right - FSqlTrack.Left) * 100);
|
||||
if V < 0 then V := 0 else if V > 100 then V := 100;
|
||||
if V <> FSQLLevel then
|
||||
begin
|
||||
FSQLLevel := V;
|
||||
RequestInvalidate;
|
||||
if Assigned(FOnSquelchChange) then FOnSquelchChange(FSQLOn, FSQLLevel);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ ---- Внешний ввод (маршрутизируется MainForm поверх спектра) ---- }
|
||||
|
||||
function TVfoOverlay.HandleMouseDown(Button: TMouseButton; X, Y: Integer): Boolean;
|
||||
@@ -1200,6 +1268,12 @@ begin
|
||||
Result := True;
|
||||
Exit;
|
||||
end;
|
||||
if FSqlDrag then
|
||||
begin
|
||||
ApplySqlFromX(LX);
|
||||
Result := True;
|
||||
Exit;
|
||||
end;
|
||||
OldHot := FHotIdx;
|
||||
FHotIdx := -1;
|
||||
if (LX >= 0) and (LY >= 0) and (LX < Width) and (LY < Height) then
|
||||
@@ -1218,6 +1292,7 @@ begin
|
||||
Result := False;
|
||||
if not Visible then Exit;
|
||||
if FVolDrag then begin FVolDrag := False; Result := True; Exit; end;
|
||||
if FSqlDrag then begin FSqlDrag := False; Result := True; Exit; end;
|
||||
if (X >= Left) and (Y >= Top) and (X < Left + Width) and (Y < Top + Height) then
|
||||
Result := True; // клик был по накладке — не пускаем его в спектр
|
||||
end;
|
||||
@@ -1226,6 +1301,7 @@ function TVfoOverlay.HandleMouseLeave: Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
FVolDrag := False;
|
||||
FSqlDrag := False;
|
||||
if FHotIdx >= 0 then
|
||||
begin
|
||||
FHotIdx := -1;
|
||||
@@ -1250,6 +1326,11 @@ begin
|
||||
FVolDrag := True;
|
||||
ApplyVolFromX(X);
|
||||
end
|
||||
else if HV = HIT_SQL_SLIDER then
|
||||
begin
|
||||
FSqlDrag := True;
|
||||
ApplySqlFromX(X);
|
||||
end
|
||||
else
|
||||
DoHit(HV);
|
||||
Break;
|
||||
@@ -1298,6 +1379,14 @@ begin
|
||||
RequestInvalidate;
|
||||
end;
|
||||
|
||||
procedure TVfoOverlay.SetSquelchState(AOn: Boolean; ALevel: Integer);
|
||||
begin
|
||||
if (FSQLOn = AOn) and ((FSQLLevel = ALevel) or FSqlDrag) then Exit;
|
||||
FSQLOn := AOn;
|
||||
if not FSqlDrag then FSQLLevel := ALevel; // во время drag ведём сами
|
||||
RequestInvalidate;
|
||||
end;
|
||||
|
||||
procedure TVfoOverlay.SetExtState(AVolume: Integer; AMuted, ASplit, ATx, ATxSel: Boolean);
|
||||
begin
|
||||
if (AVolume = FVolume) and (AMuted = FMuted) and (ASplit = FSplit)
|
||||
|
||||
@@ -169,6 +169,8 @@ type
|
||||
NBMode: Integer; // 0=off,1=NB,2=NB2
|
||||
SNBOn: Boolean;
|
||||
ANFOn: Boolean;
|
||||
FMSQOn: Boolean; // FM-шумоподавитель (squelch) включён
|
||||
FMSQLevel: Integer; // порог squelch 0..100
|
||||
SMeter: Double; // последнее показание S-метра канала (dBm), пишет DSP-поток
|
||||
Opened: Boolean; // WDSP-канал реально открыт (после Open движка)
|
||||
end;
|
||||
@@ -384,6 +386,7 @@ type
|
||||
procedure ApplyNBToChan(Chan, NBMode: Integer);
|
||||
procedure ApplySNBToChan(Chan: Integer; On_: Boolean);
|
||||
procedure ApplyANFToChan(Chan: Integer; On_: Boolean);
|
||||
procedure ApplyFMSQToChan(Chan: Integer; Enable: Boolean; Level: Integer);
|
||||
procedure ApplyNoiseFilterState;
|
||||
procedure ProcessTXBlock; // вызывается из TTXDSPThread
|
||||
procedure FeedTXDisplaySample(const I, Q: Double);
|
||||
@@ -421,6 +424,7 @@ type
|
||||
procedure SetSliceNBMode(Id, Mode: Integer);
|
||||
procedure SetSliceSNB(Id: Integer; On_: Boolean);
|
||||
procedure SetSliceANF(Id: Integer; On_: Boolean);
|
||||
procedure SetSliceFMSquelch(Id: Integer; Enable: Boolean; Level: Integer);
|
||||
function GetSliceSMeter(Id: Integer): Double;
|
||||
function SliceCount: Integer;
|
||||
function HasSlice(Id: Integer): Boolean;
|
||||
@@ -1560,6 +1564,7 @@ begin
|
||||
ApplyNBToChan(Chan, FSlices[Idx].NBMode);
|
||||
ApplySNBToChan(Chan, FSlices[Idx].SNBOn);
|
||||
ApplyANFToChan(Chan, FSlices[Idx].ANFOn);
|
||||
ApplyFMSQToChan(Chan, FSlices[Idx].FMSQOn, FSlices[Idx].FMSQLevel);
|
||||
SetRXAPanelGain1(Chan, FSlices[Idx].Volume);
|
||||
SetRXAPanelSelect(Chan, 3);
|
||||
SetRXAPanelRun(Chan, 1);
|
||||
@@ -1797,6 +1802,21 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetSliceFMSquelch(Id: Integer; Enable: Boolean; Level: Integer);
|
||||
var idx: Integer;
|
||||
begin
|
||||
FSliceLock.Enter;
|
||||
try
|
||||
idx := FindSliceIdx(Id); if idx < 0 then Exit;
|
||||
FSlices[idx].FMSQOn := Enable;
|
||||
FSlices[idx].FMSQLevel := Level;
|
||||
if FSlices[idx].Opened then
|
||||
ApplyFMSQToChan(FSlices[idx].Chan, Enable, Level);
|
||||
finally
|
||||
FSliceLock.Leave;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TWDSPEngine.GetSliceSMeter(Id: Integer): Double;
|
||||
var idx: Integer;
|
||||
begin
|
||||
@@ -1985,6 +2005,19 @@ begin
|
||||
SetRXAANFRun(Chan, Ord(On_));
|
||||
end;
|
||||
|
||||
// FM-squelch на произвольном канале (RXA или слайс). Порог 0..100 → 0.0..0.5,
|
||||
// как в SetFMSquelch для главного приёмника.
|
||||
procedure TWDSPEngine.ApplyFMSQToChan(Chan: Integer; Enable: Boolean; Level: Integer);
|
||||
begin
|
||||
if Enable then
|
||||
begin
|
||||
SetRXAFMSQThreshold(Chan, Level / 200.0);
|
||||
SetRXAFMSQRun(Chan, 1);
|
||||
end
|
||||
else
|
||||
SetRXAFMSQRun(Chan, 0);
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.ApplyNRState;
|
||||
begin
|
||||
if not FInitialized then Exit;
|
||||
|
||||
Reference in New Issue
Block a user