mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
start work tx
This commit is contained in:
+569
-46
@@ -26,7 +26,7 @@ uses
|
||||
StdCtrls, ExtCtrls, ComCtrls, Buttons, Menus, Math, Types,
|
||||
LCLIntf, LCLType, GraphType,
|
||||
HPSDRProtocol, HPSDRNetwork,
|
||||
WDSPEngine, AudioOutput,
|
||||
WDSPEngine, AudioOutput, AudioInput,
|
||||
IntfGraphics, FPImage,
|
||||
Settings,
|
||||
WebServer;
|
||||
@@ -150,8 +150,9 @@ type
|
||||
FSWRV: Double;
|
||||
FSupplyV: Double;
|
||||
FPLLLock: Boolean;
|
||||
FHWPTT: Boolean;
|
||||
public
|
||||
constructor Create(AForm: TObject; FW, SW, SV: Double; PLL: Boolean);
|
||||
constructor Create(AForm: TObject; FW, SW, SV: Double; PLL, HWPTT: Boolean);
|
||||
procedure Execute;
|
||||
end;
|
||||
|
||||
@@ -180,9 +181,12 @@ type
|
||||
FPendingBoardType: Integer; // BoardType устройства для подключения
|
||||
|
||||
// ---- DSP + Audio ----
|
||||
FDSPEngine: TWDSPEngine;
|
||||
FAudioOut: TAudioOutput;
|
||||
FWDSPReady: Boolean; // True когда WDSP открыт и работает
|
||||
FDSPEngine: TWDSPEngine;
|
||||
FAudioOut: TAudioOutput;
|
||||
FAudioIn: TAudioInput;
|
||||
FAudioOutDevName: string; // текущее имя выходного устройства
|
||||
FAudioInDevName: string; // текущее имя входного устройства (TX mic)
|
||||
FWDSPReady: Boolean; // True когда WDSP открыт и работает
|
||||
|
||||
// ---- State ----
|
||||
FVfoA: Double;
|
||||
@@ -203,8 +207,11 @@ type
|
||||
FMarkerActive: Boolean; // True = линия видима
|
||||
FMarkerX: Integer; // X в пикселях (относительно ширины панели)
|
||||
FDriveLevel: Byte;
|
||||
FPAMaxPower: Double;
|
||||
FPABandCal: array[0..BAND_COUNT-1] of Double; // калибровка 38.8..100.0 на диапазон
|
||||
FRunning: Boolean;
|
||||
FTransmitting: Boolean;
|
||||
FHWPTTActive: Boolean; // True = hardware PTT нажата
|
||||
FMuted: Boolean;
|
||||
FVolume: Integer;
|
||||
FLastSMeter: Double;
|
||||
@@ -223,16 +230,25 @@ type
|
||||
// ---- Spectrum ----
|
||||
FSpectrumBuf: array[0..1023] of Single;
|
||||
FWfAvgBuf: array[0..1023] of Single;
|
||||
FWaterfallBuf: array[0..1023] of Single; // WDSP waterfall pixout=1 data
|
||||
FSpectrumBitmap: TBitmap;
|
||||
FWfAGCEnabled: Boolean;
|
||||
FWfNFEnabled: Boolean;
|
||||
FWfHigh: Double;
|
||||
FWfLow: Double;
|
||||
// Spectrum grid settings
|
||||
FSpecRefLevel: Double; // dBm top of scale (e.g. -20)
|
||||
FSpecRange: Double; // dB range (e.g. 110 → bottom = -130)
|
||||
FSpecGridStep: Double; // grid step in dB (e.g. 10)
|
||||
FWaterfallBitmap:TBitmap;
|
||||
FWaterfallTemp: TBitmap;
|
||||
FSpectrumWidth: Integer;
|
||||
FSpectrumHeight: Integer;
|
||||
FWaterfallHeight:Integer;
|
||||
// ---- Visibility settings ----
|
||||
FShowSpectrum: Boolean;
|
||||
FShowWaterfall: Boolean;
|
||||
FDisplayFPS: Integer; // таймер спектра: кадров в секунду (5..30)
|
||||
// ---- Splitter между спектром и водопадом ----
|
||||
FSplitter: TPanel; // визуальная полоса-разделитель
|
||||
FSplitterDrag: Boolean; // True = идёт перетаскивание
|
||||
@@ -268,6 +284,7 @@ type
|
||||
FWebSyncBool: Boolean;
|
||||
FWebSyncM: TThreadMethod;
|
||||
FCurrentBand: Integer; // текущий активный диапазон 0..10
|
||||
FSettingsForm: TObject; // TSettingsForm (cast при использовании)
|
||||
FDevMAC: array[0..5] of Byte; // MAC подключённого трансивера
|
||||
FPendingDev: THPSDRDevice; // устройство ожидающее открытия WDSP
|
||||
FBandCache: array[0..CFG_BAND_COUNT-1] of TBandSettings; // кэш диапазонов
|
||||
@@ -283,8 +300,9 @@ type
|
||||
|
||||
// ---- Toolbar ----
|
||||
PanelToolbar: TPanel;
|
||||
BtnDiscover: TFlatButton;
|
||||
BtnDiscover: TFlatButton;
|
||||
BtnStartStop: TFlatButton; // START / STOP (connect+run в одном)
|
||||
BtnSettings: TFlatButton; // открыть диалог настроек
|
||||
|
||||
// ---- Left panel ----
|
||||
PanelLeft: TPanel;
|
||||
@@ -397,10 +415,11 @@ type
|
||||
// DSP/Audio callbacks (вызываются из рабочих потоков)
|
||||
procedure OnAudioReady(const Left, Right: array of Single; Count: Integer);
|
||||
procedure OnSpectrumReady(const Pixels: array of Single; Count: Integer);
|
||||
procedure OnWaterfallReady(const Pixels: array of Single; Count: Integer);
|
||||
|
||||
// Public UI update (called from sync objects)
|
||||
procedure DoAddDevice(const Dev: THPSDRDevice; const Entry: string);
|
||||
procedure DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock: Boolean);
|
||||
procedure DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock, HWPTT: Boolean);
|
||||
procedure DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord);
|
||||
procedure DoUpdateDDCSeqOrNoDevice(DDCIdx: Integer; Seq: LongWord);
|
||||
|
||||
@@ -503,11 +522,18 @@ type
|
||||
procedure BtnWfAGCClick(Sender: TObject);
|
||||
procedure BtnWfNFClick(Sender: TObject);
|
||||
procedure BtnHidePanelClick(Sender: TObject);
|
||||
procedure BtnSettingsClick(Sender: TObject);
|
||||
procedure InvalidateGridCache;
|
||||
procedure PositionVfoOverlay;
|
||||
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
||||
procedure PbSpectrumDblClick(Sender: TObject);
|
||||
procedure TrkDriveChange(Sender: TObject);
|
||||
procedure TrkVolumeChange(Sender: TObject);
|
||||
function CalcDriveByte: Byte;
|
||||
function ActiveTXFreqHz: Double;
|
||||
procedure ApplyMOX(Active: Boolean);
|
||||
procedure OnTXIQReady(const Buf: array of Double; Count: Integer);
|
||||
procedure OnPASettingsChange(MaxPower: Double; const BandCal: array of Double);
|
||||
procedure BtnAGCModeClick(Sender: TObject);
|
||||
procedure TrkAGCChange(Sender: TObject);
|
||||
procedure PbFwdPowerPaint(Sender: TObject);
|
||||
@@ -527,6 +553,18 @@ type
|
||||
procedure SplitterMouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
|
||||
public
|
||||
// Методы для SettingsForm — немедленное применение настроек
|
||||
procedure ApplyDisplayParams(FFTSize, WinType, SpecDet, SpecAvgMode,
|
||||
SpecAvgCount: Integer; SpecBackmult: Double);
|
||||
procedure ApplyWaterfallParams(WfDet, WfAvgMode, WfAvgCount: Integer;
|
||||
WfBackmult: Double);
|
||||
procedure ApplyGridParams(RefLevel, Range, GridStep: Double);
|
||||
procedure ApplyAudioDevice(DevIndex: Integer; const DevName: string);
|
||||
procedure ApplyAudioInputDevice(DevIndex: Integer; const DevName: string);
|
||||
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||
procedure ApplyFPS(FPS: Integer);
|
||||
|
||||
published
|
||||
// Обработчики событий формы — должны быть в published для RTTI/LFM
|
||||
procedure FormCreate(Sender: TObject);
|
||||
@@ -542,6 +580,8 @@ var
|
||||
|
||||
implementation
|
||||
|
||||
uses SettingsForm;
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
// ===========================================================================
|
||||
@@ -581,7 +621,7 @@ begin
|
||||
end;
|
||||
|
||||
constructor TStatusUISync.Create(AForm: TObject;
|
||||
FW, SW, SV: Double; PLL: Boolean);
|
||||
FW, SW, SV: Double; PLL, HWPTT: Boolean);
|
||||
begin
|
||||
inherited Create;
|
||||
FForm := AForm;
|
||||
@@ -589,11 +629,12 @@ begin
|
||||
FSWRV := SW;
|
||||
FSupplyV := SV;
|
||||
FPLLLock := PLL;
|
||||
FHWPTT := HWPTT;
|
||||
end;
|
||||
|
||||
procedure TStatusUISync.Execute;
|
||||
begin
|
||||
TMainForm(FForm).DoUpdateStatus(FFwdW, FSWRV, FSupplyV, FPLLLock);
|
||||
TMainForm(FForm).DoUpdateStatus(FFwdW, FSWRV, FSupplyV, FPLLLock, FHWPTT);
|
||||
end;
|
||||
|
||||
constructor TDDCSeqSync.Create(AForm: TObject; Idx: Integer; Seq: LongWord);
|
||||
@@ -647,9 +688,13 @@ begin
|
||||
end;
|
||||
|
||||
function TMainForm.MakeGlobalSettings: TGlobalSettings;
|
||||
var i: Integer;
|
||||
begin
|
||||
Result.Volume := FVolume;
|
||||
Result.DriveLevel := FDriveLevel;
|
||||
Result.DriveLevel := TrkDrive.Position;
|
||||
Result.PAMaxPower := FPAMaxPower;
|
||||
for i := 0 to BAND_COUNT - 1 do
|
||||
Result.PABandCal[i] := FPABandCal[i];
|
||||
Result.ActiveVfo := FActiveVfo;
|
||||
Result.NRMode := BtnNR.Tag;
|
||||
Result.NBMode := BtnNB.Tag;
|
||||
@@ -661,6 +706,43 @@ begin
|
||||
Result.WfNFEnabled := FWfNFEnabled;
|
||||
Result.LastBand := FCurrentBand;
|
||||
Result.SampleRate := FSampleRate;
|
||||
// Display settings
|
||||
if FWDSPReady then
|
||||
begin
|
||||
Result.FFTSize := FDSPEngine.FFTSize;
|
||||
Result.WindowType := FDSPEngine.WindowType;
|
||||
Result.SpecDetector := FDSPEngine.SpecDetector;
|
||||
Result.SpecAvgMode := FDSPEngine.SpecAvgMode;
|
||||
Result.SpecAvgCount := FDSPEngine.SpecAvgCount;
|
||||
Result.SpecBackmult := FDSPEngine.SpecBackmult;
|
||||
Result.WfDetector := FDSPEngine.WfDetector;
|
||||
Result.WfAvgMode := FDSPEngine.WfAvgMode;
|
||||
Result.WfAvgCount := FDSPEngine.WfAvgCount;
|
||||
Result.WfBackmult := FDSPEngine.WfBackmult;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result.FFTSize := 4096;
|
||||
Result.WindowType := 5;
|
||||
Result.SpecDetector := 0;
|
||||
Result.SpecAvgMode := 3;
|
||||
Result.SpecAvgCount := 2;
|
||||
Result.SpecBackmult := 0.45;
|
||||
Result.WfDetector := 2;
|
||||
Result.WfAvgMode := 3;
|
||||
Result.WfAvgCount := 2;
|
||||
Result.WfBackmult := 0.45;
|
||||
end;
|
||||
Result.SpecRefLevel := FSpecRefLevel;
|
||||
Result.SpecRange := FSpecRange;
|
||||
Result.SpecGridStep := FSpecGridStep;
|
||||
Result.AudioSampleRate := FAudioOut.SampleRate;
|
||||
Result.ShowSpectrum := FShowSpectrum;
|
||||
Result.ShowWaterfall := FShowWaterfall;
|
||||
Result.DisplayFPS := FDisplayFPS;
|
||||
// Audio device names
|
||||
Result.AudioOutDevice := FAudioOutDevName;
|
||||
Result.AudioInDevice := FAudioInDevName;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SaveCurrentBand;
|
||||
@@ -751,7 +833,7 @@ end;
|
||||
|
||||
procedure TMainForm.FormCreate(Sender: TObject);
|
||||
var
|
||||
bi_, StartupRate: Integer;
|
||||
bi_, StartupRate, i: Integer;
|
||||
StartupVfoA, StartupVfoB: Double;
|
||||
begin
|
||||
FVfoA := 14200000;
|
||||
@@ -765,9 +847,11 @@ begin
|
||||
FCTun := False;
|
||||
FFilterBW := 2700;
|
||||
FSpecDrag := False;
|
||||
FDriveLevel := 100;
|
||||
FRunning := False;
|
||||
FTransmitting := False;
|
||||
FDriveLevel := 0;
|
||||
FPAMaxPower := 100.0;
|
||||
for i := 0 to BAND_COUNT - 1 do FPABandCal[i] := 100.0;
|
||||
FRunning := False;
|
||||
FTransmitting := False;
|
||||
FMuted := False;
|
||||
FVolume := 70;
|
||||
FCenterFreq := FVfoA;
|
||||
@@ -782,6 +866,11 @@ begin
|
||||
FWfAGCEnabled := False;
|
||||
FWfNFEnabled := False;
|
||||
FDevConnected := False;
|
||||
// Spectrum grid settings defaults
|
||||
FSpecRefLevel := -20.0;
|
||||
FSpecRange := 110.0;
|
||||
FSpecGridStep := 10.0;
|
||||
FSettingsForm := nil;
|
||||
FillChar(FDevMAC, SizeOf(FDevMAC), 0);
|
||||
|
||||
// Инициализируем кэш диапазонов умолчаниями
|
||||
@@ -847,7 +936,10 @@ begin
|
||||
FVfoOverlay := TVfoOverlay.Create(Self);
|
||||
FVfoOverlay.OnSelect := OnModeFilterSelect;
|
||||
FVfoOverlay.Visible := False;
|
||||
FPanelHidden := False;
|
||||
FPanelHidden := False;
|
||||
FShowSpectrum := True;
|
||||
FShowWaterfall := True;
|
||||
FDisplayFPS := 20;
|
||||
FSplitterRatio := 0.40; // 40% спектр, 60% водопад по умолчанию
|
||||
FSplitterDrag := False;
|
||||
|
||||
@@ -894,12 +986,15 @@ begin
|
||||
// Уменьшение с 1024 вдвое сокращает время построения downsampler в OpenChannel RXA
|
||||
// (~1300ms → ~650ms). Латентность: 512/48000 ≈ 10.7ms — допустимо для SDR.
|
||||
FDSPEngine := TWDSPEngine.Create(FSampleRate, 48000, 512);
|
||||
FDSPEngine.OnAudio := OnAudioReady;
|
||||
FDSPEngine.OnSpectrum := OnSpectrumReady;
|
||||
FDSPEngine.OnAudio := OnAudioReady;
|
||||
FDSPEngine.OnSpectrum := OnSpectrumReady;
|
||||
FDSPEngine.OnWaterfall := OnWaterfallReady;
|
||||
FDSPEngine.OnTXIQ := OnTXIQReady;
|
||||
|
||||
// Audio output — создаём объект сейчас, открываем после показа формы
|
||||
// Audio output/input — создаём объекты сейчас, открываем после показа формы
|
||||
// (Pa_Initialize на Linux пишет в stderr до перехвата сигналов FPC)
|
||||
FAudioOut := TAudioOutput.Create(48000);
|
||||
FAudioIn := TAudioInput.Create(48000);
|
||||
|
||||
FMeterTimer := TTimer.Create(Self);
|
||||
FMeterTimer.Interval := 100;
|
||||
@@ -937,6 +1032,8 @@ begin
|
||||
FNetwork.Free;
|
||||
FAudioOut.Close;
|
||||
FAudioOut.Free;
|
||||
FAudioIn.Close;
|
||||
FAudioIn.Free;
|
||||
FDSPEngine.Close;
|
||||
FDSPEngine.Free;
|
||||
FSpectrumBitmap.Free;
|
||||
@@ -1034,6 +1131,7 @@ begin
|
||||
X := 4;
|
||||
BtnDiscover := MakeBtn(PanelToolbar, 'DISCOVER', X, 3, 80, BTN_H, BtnDiscoverClick);
|
||||
BtnStartStop := MakeBtn(PanelToolbar, 'START', X+84, 3, 76, BTN_H, BtnStartStopClick);
|
||||
BtnSettings := MakeBtn(PanelToolbar, 'SETUP', X+164, 3, 66, BTN_H, BtnSettingsClick);
|
||||
|
||||
// ---- Status bar ----
|
||||
StatusBar1 := TStatusBar.Create(Self);
|
||||
@@ -1546,6 +1644,125 @@ begin
|
||||
TopOff := PanelSpanButtons.Height;
|
||||
// S-метр позиционируется отдельно в ResizeSMeter
|
||||
ResizeSMeter;
|
||||
|
||||
// ---- Оба скрыты ----
|
||||
if (not FShowSpectrum) and (not FShowWaterfall) then
|
||||
begin
|
||||
PbSpectrum.Visible := False;
|
||||
PbRuler.Visible := False;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.Visible := False;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := 0;
|
||||
FWaterfallHeight := 0;
|
||||
PositionSpanOverlayButtons;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Только спектр (водопад скрыт) ----
|
||||
if FShowSpectrum and (not FShowWaterfall) then
|
||||
begin
|
||||
AvailH := RH - TopOff - RULER_H;
|
||||
if AvailH < MIN_SH then AvailH := MIN_SH;
|
||||
SH := AvailH;
|
||||
WH := 0;
|
||||
PbSpectrum.SetBounds(0, TopOff, RW, SH);
|
||||
PbSpectrum.Visible := True;
|
||||
PbRuler.SetBounds(0, TopOff + SH, RW, RULER_H);
|
||||
PbRuler.Visible := True;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.Visible := False;
|
||||
PositionSpanOverlayButtons;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := SH;
|
||||
FWaterfallHeight := 0;
|
||||
if (FSpectrumBitmap <> nil) and (RW > 0) and (SH > 0) then
|
||||
begin
|
||||
FSpectrumBitmap.SetSize(RW, SH);
|
||||
FSpectrumBitmap.Canvas.Brush.Color := CLR_BG;
|
||||
FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, RW, SH));
|
||||
FreeAndNil(FSpecGradImg);
|
||||
FGridBitmapW := 0;
|
||||
FGridBitmapH := 0;
|
||||
FSpPtsLen := 0;
|
||||
end;
|
||||
if (FWaterfallBitmap <> nil) then
|
||||
begin
|
||||
FWaterfallBitmap.SetSize(1, 1);
|
||||
FWfBitmapW := 0;
|
||||
FWfBitmapH := 0;
|
||||
SetLength(FWfPixels, 0);
|
||||
end;
|
||||
if (FRulerBitmap <> nil) and (RW > 0) then
|
||||
begin
|
||||
FRulerBitmap.SetSize(RW, RULER_H);
|
||||
FRulerLastFreq := -1.0;
|
||||
FRulerLastVfo := -1.0;
|
||||
end;
|
||||
if RW > 0 then
|
||||
begin
|
||||
DrawSpectrum;
|
||||
PbSpectrum.Invalidate;
|
||||
PbRuler.Invalidate;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Только водопад (спектр скрыт): линейка под водопадом ----
|
||||
if (not FShowSpectrum) and FShowWaterfall then
|
||||
begin
|
||||
AvailH := RH - TopOff - RULER_H;
|
||||
if AvailH < MIN_WH then AvailH := MIN_WH;
|
||||
SH := 0;
|
||||
WH := AvailH;
|
||||
PbSpectrum.Visible := False;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.SetBounds(0, TopOff, RW, WH);
|
||||
PbWaterfall.Visible := True;
|
||||
PbRuler.SetBounds(0, TopOff + WH, RW, RULER_H);
|
||||
PbRuler.Visible := True;
|
||||
PositionSpanOverlayButtons;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := 0;
|
||||
FWaterfallHeight := WH;
|
||||
if (FSpectrumBitmap <> nil) then
|
||||
begin
|
||||
FSpectrumBitmap.SetSize(1, 1);
|
||||
FreeAndNil(FSpecGradImg);
|
||||
FGridBitmapW := 0;
|
||||
FGridBitmapH := 0;
|
||||
FSpPtsLen := 0;
|
||||
end;
|
||||
if (FWaterfallBitmap <> nil) and (RW > 0) and (WH > 0) then
|
||||
begin
|
||||
FWaterfallBitmap.SetSize(RW, WH);
|
||||
FWaterfallBitmap.Canvas.Brush.Color := clBlack;
|
||||
FWaterfallBitmap.Canvas.FillRect(Rect(0, 0, RW, WH));
|
||||
FWfBitmapW := 0;
|
||||
FWfBitmapH := 0;
|
||||
SetLength(FWfPixels, 0);
|
||||
end;
|
||||
if (FRulerBitmap <> nil) and (RW > 0) then
|
||||
begin
|
||||
FRulerBitmap.SetSize(RW, RULER_H);
|
||||
FRulerLastFreq := -1.0;
|
||||
FRulerLastVfo := -1.0;
|
||||
end;
|
||||
if RW > 0 then
|
||||
begin
|
||||
DrawWaterfall;
|
||||
PbWaterfall.Invalidate;
|
||||
PbRuler.Invalidate;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Оба видимы: стандартный режим со сплиттером ----
|
||||
PbSpectrum.Visible := True;
|
||||
PbRuler.Visible := True;
|
||||
PanelSplitter.Visible := True;
|
||||
PbWaterfall.Visible := True;
|
||||
|
||||
AvailH := RH - TopOff - RULER_H - SPLITTER_H;
|
||||
if AvailH < (MIN_SH + MIN_WH) then Exit;
|
||||
|
||||
@@ -1564,8 +1781,7 @@ begin
|
||||
// Линейка частот — всегда прижата к низу спектра
|
||||
PbRuler.SetBounds(0, TopOff + SH, RW, RULER_H);
|
||||
// Сплиттер — между линейкой и водопадом
|
||||
if PanelSplitter <> nil then
|
||||
PanelSplitter.SetBounds(0, TopOff + SH + RULER_H, RW, SPLITTER_H);
|
||||
PanelSplitter.SetBounds(0, TopOff + SH + RULER_H, RW, SPLITTER_H);
|
||||
// Водопад — под сплиттером
|
||||
PbWaterfall.SetBounds(0, TopOff + SH + RULER_H + SPLITTER_H, RW, WH);
|
||||
|
||||
@@ -1814,12 +2030,21 @@ end;
|
||||
procedure TMainForm.ResetSpectrumBuf;
|
||||
var i: Integer;
|
||||
begin
|
||||
for i := 0 to 1023 do FSpectrumBuf[i] := -130.0;
|
||||
for i := 0 to 1023 do FWfAvgBuf[i] := -120.0;
|
||||
for i := 0 to 1023 do FSpectrumBuf[i] := -130.0;
|
||||
for i := 0 to 1023 do FWfAvgBuf[i] := -120.0;
|
||||
for i := 0 to 1023 do FWaterfallBuf[i] := -120.0;
|
||||
FWfHigh := -50.0;
|
||||
FWfLow := -120.0;
|
||||
end;
|
||||
|
||||
procedure TMainForm.InvalidateGridCache;
|
||||
// Сбрасываем кэш фона/сетки — перерисуется на следующем тике DrawSpectrum
|
||||
begin
|
||||
FGridBitmapW := 0;
|
||||
FGridBitmapH := 0;
|
||||
FSpectrumDirty := True;
|
||||
end;
|
||||
|
||||
procedure TMainForm.FillDemoSpectrum;
|
||||
var
|
||||
i: Integer;
|
||||
@@ -2035,7 +2260,8 @@ begin
|
||||
if (W <= 0) or (H <= 0) then Exit;
|
||||
|
||||
C := FSpectrumBitmap.Canvas;
|
||||
DBmin := -130.0; DBmax := -20.0;
|
||||
DBmax := FSpecRefLevel;
|
||||
DBmin := FSpecRefLevel - FSpecRange;
|
||||
InvRange := 1.0 / (DBmax - DBmin);
|
||||
|
||||
// ── 1. Фон+сетка из кэша ───────────────────────────────────────────────
|
||||
@@ -2056,7 +2282,7 @@ begin
|
||||
GC.Font.Name := 'Courier New';
|
||||
GC.Font.Color := TColor($00A8C9D9);
|
||||
GC.Brush.Style := bsClear;
|
||||
dB := -40.0;
|
||||
dB := DBmax - FSpecGridStep;
|
||||
while dB >= DBmin do
|
||||
begin
|
||||
Yp := Round((DBmax - dB) * InvRange * H);
|
||||
@@ -2064,7 +2290,7 @@ begin
|
||||
GC.Pen.Width := 1;
|
||||
GC.MoveTo(0, Yp); GC.LineTo(W-1, Yp);
|
||||
GC.TextOut(1, Yp - 9, Format('%4.0f', [dB]));
|
||||
dB := dB - 10;
|
||||
dB := dB - FSpecGridStep;
|
||||
end;
|
||||
for i := 0 to 8 do
|
||||
begin
|
||||
@@ -2206,14 +2432,31 @@ begin
|
||||
H := FWaterfallBitmap.Height;
|
||||
if (W <= 0) or (H <= 0) then Exit;
|
||||
|
||||
// ── EMA + Peak + NF — один цикл по 1024 бинам ─────────────────────────
|
||||
// ── Источник данных водопада ─────────────────────────────────────────────
|
||||
// При работе WDSP: FWaterfallBuf заполнен из pixout=1 (уже усреднённые WDSP данные)
|
||||
// Без WDSP (demo): делаем EMA FSpectrumBuf → FWfAvgBuf
|
||||
PeakDB := -200.0; NFSum := 0.0; NFCount := 0;
|
||||
for X := 0 to 1023 do
|
||||
if FWDSPReady then
|
||||
begin
|
||||
AvgDB := FWfAvgBuf[X] * (1.0 - ALPHA_SPEC) + FSpectrumBuf[X] * ALPHA_SPEC;
|
||||
FWfAvgBuf[X] := AvgDB;
|
||||
if AvgDB > PeakDB then PeakDB := AvgDB;
|
||||
if AvgDB < FWfLow + 15.0 then begin NFSum := NFSum + AvgDB; Inc(NFCount); end;
|
||||
// Используем WDSP waterfall данные напрямую
|
||||
for X := 0 to 1023 do
|
||||
begin
|
||||
AvgDB := FWaterfallBuf[X];
|
||||
FWfAvgBuf[X] := AvgDB; // синхронизируем для AGC логики
|
||||
if AvgDB > PeakDB then PeakDB := AvgDB;
|
||||
if AvgDB < FWfLow + 15.0 then begin NFSum := NFSum + AvgDB; Inc(NFCount); end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Fallback: Pascal EMA от демо-спектра
|
||||
for X := 0 to 1023 do
|
||||
begin
|
||||
AvgDB := FWfAvgBuf[X] * (1.0 - ALPHA_SPEC) + FSpectrumBuf[X] * ALPHA_SPEC;
|
||||
FWfAvgBuf[X] := AvgDB;
|
||||
if AvgDB > PeakDB then PeakDB := AvgDB;
|
||||
if AvgDB < FWfLow + 15.0 then begin NFSum := NFSum + AvgDB; Inc(NFCount); end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ── AGC High/Low ────────────────────────────────────────────────────────
|
||||
@@ -2789,10 +3032,16 @@ var
|
||||
NowTick: QWord;
|
||||
ElapsedTick: QWord;
|
||||
begin
|
||||
// Синхронизируем размеры если PaintBox изменился (после ресайза)
|
||||
if (PbSpectrum.Width <> FSpectrumWidth) or
|
||||
(PbSpectrum.Height <> FSpectrumHeight) or
|
||||
(FSpectrumWidth = 0) then
|
||||
// Синхронизируем размеры если размер панели изменился (после ресайза).
|
||||
// Важно: проверяем только видимые панели — когда спектр скрыт,
|
||||
// PbSpectrum.Height может быть ненулевым при FSpectrumHeight=0,
|
||||
// что вызвало бы сброс буфера водопада на каждом тике.
|
||||
if (FSpectrumWidth = 0) or
|
||||
(FShowSpectrum and ((PbSpectrum.Width <> FSpectrumWidth) or
|
||||
(PbSpectrum.Height <> FSpectrumHeight))) or
|
||||
(FShowWaterfall and not FShowSpectrum and
|
||||
((PbWaterfall.Width <> FSpectrumWidth) or
|
||||
(PbWaterfall.Height <> FWaterfallHeight))) then
|
||||
ResizeSpectrumPanels;
|
||||
ResizeSMeter;
|
||||
if FSpectrumWidth <= 0 then Exit;
|
||||
@@ -2977,7 +3226,8 @@ begin
|
||||
else
|
||||
SWRV := 1.0;
|
||||
Sync := TStatusUISync.Create(Self, FwdW, SWRV, SupplyV,
|
||||
(Status.StatusBits and HPS_PLL_LOCKED) <> 0);
|
||||
(Status.StatusBits and HPS_PLL_LOCKED) <> 0,
|
||||
(Status.StatusBits and HPS_PTT) <> 0);
|
||||
try
|
||||
M := Sync.Execute;
|
||||
TThread.Synchronize(nil, M);
|
||||
@@ -2986,7 +3236,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock: Boolean);
|
||||
procedure TMainForm.DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock, HWPTT: Boolean);
|
||||
var
|
||||
PLLStr: string;
|
||||
begin
|
||||
@@ -2998,7 +3248,15 @@ begin
|
||||
StatusBar1.Panels[2].Text :=
|
||||
Format('Supply: %.1fV | FWD: %.0fW | SWR: %.1f | %s',
|
||||
[SupplyV, FwdW, SWRV, PLLStr]);
|
||||
// Panels[3] зарезервирована для RX stats (DDC seq/pkt count)
|
||||
|
||||
// Hardware PTT (foot switch / mic PTT) — обнаружение фронта
|
||||
if HWPTT <> FHWPTTActive then
|
||||
begin
|
||||
FHWPTTActive := HWPTT;
|
||||
// Hardware PTT включает/выключает передачу только если BtnMOX не нажата
|
||||
if not BtnMOX.Active then
|
||||
ApplyMOX(HWPTT);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnDDCIQCB(DDCIndex: Integer; const Data: TDDCIQPacket);
|
||||
@@ -3034,7 +3292,8 @@ end;
|
||||
|
||||
procedure TMainForm.OnMicPacketCB(const Data: TMicDataPacket);
|
||||
begin
|
||||
// TODO: WDSP TXA
|
||||
if FTransmitting and FWDSPReady then
|
||||
FDSPEngine.PushTXMicSamples16(Data.Samples, 64);
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
@@ -3147,8 +3406,10 @@ begin
|
||||
end;
|
||||
FWDSPReady := False;
|
||||
FDSPEngine := TWDSPEngine.Create(ASampleRate, 48000, 512);
|
||||
FDSPEngine.OnAudio := OnAudioReady;
|
||||
FDSPEngine.OnSpectrum := OnSpectrumReady;
|
||||
FDSPEngine.OnAudio := OnAudioReady;
|
||||
FDSPEngine.OnSpectrum := OnSpectrumReady;
|
||||
FDSPEngine.OnWaterfall := OnWaterfallReady;
|
||||
FDSPEngine.OnTXIQ := OnTXIQReady;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnDiscoverClick(Sender: TObject);
|
||||
@@ -3297,6 +3558,7 @@ var
|
||||
GenPkt: TGeneralPacket;
|
||||
DUCPkt: TDUCSpecificPacket;
|
||||
G_Settings: TGlobalSettings;
|
||||
i: Integer;
|
||||
begin
|
||||
BtnStartStop.Enabled := True;
|
||||
|
||||
@@ -3312,8 +3574,14 @@ begin
|
||||
FDevConnected := True;
|
||||
FSettings.LoadDevice(FDevMAC, G_Settings, FBandCache);
|
||||
FVolume := G_Settings.Volume;
|
||||
FDriveLevel := G_Settings.DriveLevel;
|
||||
FActiveVfo := G_Settings.ActiveVfo;
|
||||
// PA settings
|
||||
FPAMaxPower := G_Settings.PAMaxPower;
|
||||
for i := 0 to BAND_COUNT - 1 do
|
||||
FPABandCal[i] := G_Settings.PABandCal[i];
|
||||
// Slider position (0..100) and calibrated drive byte
|
||||
TrkDrive.Position := EnsureRange(G_Settings.DriveLevel, 0, 100);
|
||||
FDriveLevel := CalcDriveByte;
|
||||
FCurrentBand := G_Settings.LastBand;
|
||||
// SampleRate — глобальный, загружаем до RestoreBand
|
||||
if G_Settings.SampleRate > 0 then
|
||||
@@ -3327,6 +3595,53 @@ begin
|
||||
BtnANF.Tag := Ord(G_Settings.ANFEnabled); UpdateANFButton;
|
||||
FWfAGCEnabled := G_Settings.WfAGCEnabled; StyleButton(BtnWfAGC, FWfAGCEnabled);
|
||||
FWfNFEnabled := G_Settings.WfNFEnabled; StyleButton(BtnWfNF, FWfNFEnabled);
|
||||
FShowSpectrum := G_Settings.ShowSpectrum;
|
||||
FShowWaterfall := G_Settings.ShowWaterfall;
|
||||
if G_Settings.DisplayFPS > 0 then
|
||||
ApplyFPS(G_Settings.DisplayFPS);
|
||||
// Настройки дисплея и сетки
|
||||
if G_Settings.FFTSize > 0 then
|
||||
begin
|
||||
FSpecRefLevel := G_Settings.SpecRefLevel;
|
||||
FSpecRange := G_Settings.SpecRange;
|
||||
if G_Settings.SpecGridStep > 0 then FSpecGridStep := G_Settings.SpecGridStep;
|
||||
InvalidateGridCache;
|
||||
if FWDSPReady then
|
||||
begin
|
||||
FDSPEngine.SetFFTParams(G_Settings.FFTSize, G_Settings.WindowType);
|
||||
FDSPEngine.SetSpectrumDisplay(G_Settings.SpecDetector, G_Settings.SpecAvgMode,
|
||||
G_Settings.SpecAvgCount, G_Settings.SpecBackmult);
|
||||
FDSPEngine.SetWaterfallDisplay(G_Settings.WfDetector, G_Settings.WfAvgMode,
|
||||
G_Settings.WfAvgCount, G_Settings.WfBackmult);
|
||||
end;
|
||||
// Аудио устройство вывода
|
||||
FAudioOut.Close;
|
||||
if G_Settings.AudioSampleRate > 0 then
|
||||
FAudioOut.SampleRate := G_Settings.AudioSampleRate;
|
||||
if G_Settings.AudioOutDevice <> '' then
|
||||
begin
|
||||
FAudioOut.DeviceIndex := FAudioOut.FindDeviceByName(G_Settings.AudioOutDevice);
|
||||
FAudioOutDevName := G_Settings.AudioOutDevice;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FAudioOut.DeviceIndex := -1;
|
||||
FAudioOutDevName := '';
|
||||
end;
|
||||
FAudioOut.Open;
|
||||
// Аудио устройство ввода (TX mic)
|
||||
if G_Settings.AudioInDevice <> '' then
|
||||
begin
|
||||
FAudioIn.DeviceIndex := FAudioIn.FindDeviceByName(G_Settings.AudioInDevice);
|
||||
FAudioInDevName := G_Settings.AudioInDevice;
|
||||
FAudioIn.Open;
|
||||
end
|
||||
else
|
||||
begin
|
||||
FAudioIn.DeviceIndex := -1;
|
||||
FAudioInDevName := '';
|
||||
end;
|
||||
end;
|
||||
RestoreBand(FCurrentBand);
|
||||
|
||||
StatusBar1.Panels[0].Text := 'IP: ' + FNetwork.Device.IPAddress;
|
||||
@@ -4117,9 +4432,14 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnMOXClick(Sender: TObject);
|
||||
function TMainForm.ActiveTXFreqHz: Double;
|
||||
begin
|
||||
FTransmitting := not FTransmitting;
|
||||
if FActiveVfo = 0 then Result := FVfoA else Result := FVfoB;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyMOX(Active: Boolean);
|
||||
begin
|
||||
FTransmitting := Active;
|
||||
if FTransmitting then
|
||||
begin
|
||||
BtnMOX.ClrNorm := TColor($00000044);
|
||||
@@ -4128,7 +4448,19 @@ begin
|
||||
BtnMOX.Active := True;
|
||||
end else
|
||||
StyleButton(BtnMOX, False);
|
||||
if FWDSPReady then FDSPEngine.SetTXRun(FTransmitting);
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetTXRun(FTransmitting);
|
||||
if FNetwork.Connected and FNetwork.Running then
|
||||
begin
|
||||
FNetwork.UpdateState(FCenterFreq, ActiveTXFreqHz, FDriveLevel,
|
||||
FTransmitting, True, True);
|
||||
FNetwork.SendFullHP;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnMOXClick(Sender: TObject);
|
||||
begin
|
||||
ApplyMOX(not FTransmitting);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnMuteClick(Sender: TObject);
|
||||
@@ -4784,11 +5116,62 @@ end;
|
||||
|
||||
procedure TMainForm.TrkDriveChange(Sender: TObject);
|
||||
begin
|
||||
FDriveLevel := Round(TrkDrive.Position / 100.0 * 255);
|
||||
FDriveLevel := CalcDriveByte;
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetDriveLevel(TrkDrive.Position / 100.0);
|
||||
end;
|
||||
|
||||
function TMainForm.CalcDriveByte: Byte;
|
||||
var Cal: Double;
|
||||
begin
|
||||
if (FCurrentBand >= 0) and (FCurrentBand < BAND_COUNT) and (FPABandCal[FCurrentBand] > 0.0) then
|
||||
Cal := FPABandCal[FCurrentBand]
|
||||
else
|
||||
Cal := 100.0;
|
||||
Result := Round(TrkDrive.Position / 100.0 * Cal / 100.0 * 255.0);
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnTXIQReady(const Buf: array of Double; Count: Integer);
|
||||
var
|
||||
IData: array[0..239] of Integer;
|
||||
QData: array[0..239] of Integer;
|
||||
Offset, n, i: Integer;
|
||||
begin
|
||||
if not FNetwork.Connected then Exit;
|
||||
Offset := 0;
|
||||
while Offset < Count do
|
||||
begin
|
||||
FillChar(IData, SizeOf(IData), 0);
|
||||
FillChar(QData, SizeOf(QData), 0);
|
||||
n := Count - Offset;
|
||||
if n > 240 then n := 240;
|
||||
for i := 0 to n - 1 do
|
||||
begin
|
||||
IData[i] := Round(Buf[(Offset + i) * 2] * 8388607.0);
|
||||
QData[i] := Round(Buf[(Offset + i) * 2 + 1] * 8388607.0);
|
||||
end;
|
||||
FNetwork.SendDUCIQ(IData, QData);
|
||||
Inc(Offset, 240);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnPASettingsChange(MaxPower: Double;
|
||||
const BandCal: array of Double);
|
||||
var i: Integer;
|
||||
begin
|
||||
FPAMaxPower := MaxPower;
|
||||
for i := 0 to BAND_COUNT - 1 do
|
||||
begin
|
||||
if i <= High(BandCal) then
|
||||
FPABandCal[i] := BandCal[i]
|
||||
else
|
||||
FPABandCal[i] := 100.0;
|
||||
end;
|
||||
FDriveLevel := CalcDriveByte;
|
||||
if FNetwork.Connected and FNetwork.Running then
|
||||
FNetwork.UpdateState(FCenterFreq, FCenterFreq, FDriveLevel, FTransmitting, True, True);
|
||||
end;
|
||||
|
||||
procedure TMainForm.TrkVolumeChange(Sender: TObject);
|
||||
begin
|
||||
FVolume := TrkVolume.Position;
|
||||
@@ -4903,6 +5286,146 @@ begin
|
||||
FSpectrumDirty := True;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnWaterfallReady(const Pixels: array of Single;
|
||||
Count: Integer);
|
||||
var
|
||||
i, N: Integer;
|
||||
begin
|
||||
// Заполняем буфер водопада из WDSP pixout=1.
|
||||
// Вызывается из DSP-потока — Single-запись атомарна.
|
||||
N := Min(Count, 1024);
|
||||
for i := 0 to N - 1 do
|
||||
FWaterfallBuf[i] := Pixels[i];
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
// Settings apply methods (вызываются из TSettingsForm)
|
||||
// ===========================================================================
|
||||
|
||||
procedure TMainForm.ApplyDisplayParams(FFTSize, WinType, SpecDet, SpecAvgMode,
|
||||
SpecAvgCount: Integer; SpecBackmult: Double);
|
||||
begin
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetFFTParams(FFTSize, WinType);
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetSpectrumDisplay(SpecDet, SpecAvgMode, SpecAvgCount, SpecBackmult);
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyWaterfallParams(WfDet, WfAvgMode, WfAvgCount: Integer;
|
||||
WfBackmult: Double);
|
||||
begin
|
||||
if FWDSPReady then
|
||||
FDSPEngine.SetWaterfallDisplay(WfDet, WfAvgMode, WfAvgCount, WfBackmult);
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyGridParams(RefLevel, Range, GridStep: Double);
|
||||
begin
|
||||
FSpecRefLevel := RefLevel;
|
||||
FSpecRange := Range;
|
||||
if GridStep > 0 then FSpecGridStep := GridStep;
|
||||
InvalidateGridCache;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyAudioDevice(DevIndex: Integer; const DevName: string);
|
||||
begin
|
||||
if FAudioOut.IsOpen then
|
||||
FAudioOut.Close;
|
||||
FAudioOut.DeviceIndex := DevIndex;
|
||||
FAudioOutDevName := DevName;
|
||||
try
|
||||
if not FAudioOut.Open then
|
||||
StatusBar1.Panels[3].Text := 'Audio out: ' + FAudioOut.LastError
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Audio out: ' + IfThen(DevName = '', 'Default', DevName);
|
||||
except
|
||||
on E: Exception do
|
||||
StatusBar1.Panels[3].Text := 'Audio out err: ' + E.Message;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyAudioInputDevice(DevIndex: Integer; const DevName: string);
|
||||
begin
|
||||
if FAudioIn.IsOpen then
|
||||
FAudioIn.Close;
|
||||
FAudioIn.DeviceIndex := DevIndex;
|
||||
FAudioInDevName := DevName;
|
||||
if DevIndex >= 0 then
|
||||
begin
|
||||
try
|
||||
if not FAudioIn.Open then
|
||||
StatusBar1.Panels[3].Text := 'Mic: ' + FAudioIn.LastError
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Mic: ' + DevName;
|
||||
except
|
||||
on E: Exception do
|
||||
StatusBar1.Panels[3].Text := 'Mic err: ' + E.Message;
|
||||
end;
|
||||
end
|
||||
else
|
||||
StatusBar1.Panels[3].Text := 'Mic: none';
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||
begin
|
||||
FShowSpectrum := ShowSpectrum;
|
||||
FShowWaterfall := ShowWaterfall;
|
||||
ResizeSpectrumPanels;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ApplyFPS(FPS: Integer);
|
||||
begin
|
||||
if FPS < 1 then FPS := 1;
|
||||
if FPS > 60 then FPS := 60;
|
||||
FDisplayFPS := FPS;
|
||||
FSpectrumTimer.Interval := 1000 div FPS;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnSettingsClick(Sender: TObject);
|
||||
var
|
||||
SF: TSettingsForm;
|
||||
begin
|
||||
if not Assigned(FSettingsForm) then
|
||||
begin
|
||||
SF := TSettingsForm.Create(Self);
|
||||
FSettingsForm := SF;
|
||||
SF.OnDisplayChange := ApplyDisplayParams;
|
||||
SF.OnWaterfallChange := ApplyWaterfallParams;
|
||||
SF.OnGridChange := ApplyGridParams;
|
||||
SF.OnAudioDevChange := ApplyAudioDevice;
|
||||
SF.OnAudioInDevChange := ApplyAudioInputDevice;
|
||||
SF.OnVisibilityChange := ApplyVisibility;
|
||||
SF.OnFPSChange := ApplyFPS;
|
||||
SF.OnPAChange := OnPASettingsChange;
|
||||
end;
|
||||
SF := TSettingsForm(FSettingsForm);
|
||||
SF.LoadPASettings(FPAMaxPower, FPABandCal);
|
||||
// Перечисляем PA устройства
|
||||
SF.RefreshAudioDevices(FAudioOut, FAudioIn);
|
||||
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
||||
SF.LoadFPS(FDisplayFPS);
|
||||
// Загружаем текущие значения
|
||||
if FWDSPReady then
|
||||
SF.LoadValues(
|
||||
FDSPEngine.FFTSize,
|
||||
FDSPEngine.WindowType,
|
||||
FDSPEngine.SpecDetector,
|
||||
FDSPEngine.SpecAvgMode,
|
||||
FDSPEngine.SpecAvgCount,
|
||||
FDSPEngine.SpecBackmult,
|
||||
FDSPEngine.WfDetector,
|
||||
FDSPEngine.WfAvgMode,
|
||||
FDSPEngine.WfAvgCount,
|
||||
FDSPEngine.WfBackmult,
|
||||
FSpecRefLevel, FSpecRange, FSpecGridStep,
|
||||
FAudioOutDevName, FAudioInDevName)
|
||||
else
|
||||
SF.LoadValues(
|
||||
4096, 5, 0, 3, 2, 0.45,
|
||||
2, 3, 2, 0.45,
|
||||
FSpecRefLevel, FSpecRange, FSpecGridStep,
|
||||
FAudioOutDevName, FAudioInDevName);
|
||||
SF.Show;
|
||||
end;
|
||||
|
||||
procedure TMainForm.AfterShowTick(Sender: TObject);
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user