mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
WIP: TX implementation — per-device settings, separate analyzer, sound-card mic
- Settings: TTXSettings record + LoadTX/SaveTX, JSON section "tx" per MAC - WDSPEngine: separate TX_DISP_ID analyzer with own FFT/Window/Det/Avg parameters, ApplyTXAnalyzerSettings + setters - WDSPEngine: full TX chain setters (Filter/Compressor/Leveler/ALC/ PhaseRot/EQ/AMCarrier/FM/CTCSS) + ApplyTXChainSettings - WDSPEngine: ProcessTXBlock now feeds TX analyzer in DISPLAY_BLOCK_SIZE chunks (was passing whole FTXOut → analyzer ignored most of it) - WDSPEngine: ActiveDisplayID switches RX/TX in UpdateSpectrum - WDSPEngine: RX audio muted while TX active to avoid local feedback - WDSPEngine: default EQ frequencies in Create (zero freqs broke TX chain) - WDSPEngine: PushTXMicSampleD + OnPullMicSamples for sound-card path - AudioInput: Available counter for non-blocking pull - MainForm: PullSoundCardMic, BuildMicLineSelectByte, SendDUCSpecific with mic bias/boost/line/PTT bits, OnTXSettingsChange - MainForm: auto-switch MicSource on TX device select, TX diagnostic in StatusBar panel [5] - SettingsForm: new Transmit nav page with Microphone, Filter, Dynamic processing, EQ, AM/FM/CTCSS, TX Display sections NOT YET WORKING: sound-card mic produces ring activity but signal still not visible on TX spectrum/waterfall — needs further investigation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+483
-4
@@ -27,12 +27,14 @@ uses
|
||||
Classes, SysUtils, Math,
|
||||
Forms, Controls, Graphics, Dialogs,
|
||||
StdCtrls, ExtCtrls, Spin,
|
||||
FlatButton, AudioOutput, AudioInput, AppTheme;
|
||||
FlatButton, AudioOutput, AudioInput, AppTheme, Settings;
|
||||
|
||||
type
|
||||
// PA: MaxPower в Вт, BandCal[0..10] — калибровка 38.8..100.0 на диапазон
|
||||
TOnPASettingsChange = procedure(MaxPower: Double;
|
||||
const BandCal: array of Double) of object;
|
||||
// TX-настройки целиком (любая правка → один callback с актуальной структурой)
|
||||
TOnTXSettingsChange = procedure(const T: TTXSettings) of object;
|
||||
|
||||
TOnDisplayParamChange = procedure(FFTSize, WindowType, SpecDetector,
|
||||
SpecAvgMode: Integer; SpecAvgTimeMS: Double) of object;
|
||||
@@ -66,6 +68,7 @@ type
|
||||
FPagePA: TScrollBox;
|
||||
FPageAdvanced: TScrollBox;
|
||||
FPageCAT: TScrollBox;
|
||||
FPageTransmit: TScrollBox;
|
||||
FNavAudio: TFlatButton;
|
||||
FNavDisplay: TFlatButton;
|
||||
FNavSpectrum: TFlatButton;
|
||||
@@ -73,6 +76,7 @@ type
|
||||
FNavPA: TFlatButton;
|
||||
FNavAdvanced: TFlatButton;
|
||||
FNavCAT: TFlatButton;
|
||||
FNavTransmit: TFlatButton;
|
||||
|
||||
// ---- Audio tab controls ----
|
||||
FCmbRXDev: TComboBox;
|
||||
@@ -108,6 +112,62 @@ type
|
||||
FEdMaxPower: TSpinEdit;
|
||||
FEdBandCal: array[0..10] of TFloatSpinEdit;
|
||||
|
||||
// ---- Transmit tab controls ----
|
||||
// Текущее состояние, отдаётся в OnTXChange целиком при любой правке.
|
||||
FTX: TTXSettings;
|
||||
// Mic source / options
|
||||
FCmbTXMicSource: TComboBox;
|
||||
FChkTXMicBoost: TCheckBox;
|
||||
FChkTXMicBias: TCheckBox;
|
||||
FChkTXMicLineIn: TCheckBox;
|
||||
FChkTXMicPTT: TCheckBox;
|
||||
FEdTXMicGain: TFloatSpinEdit;
|
||||
// Filter
|
||||
FEdTXFiltLow: TSpinEdit;
|
||||
FEdTXFiltHigh: TSpinEdit;
|
||||
FCmbTXFiltNC: TComboBox;
|
||||
FCmbTXFiltMP: TComboBox;
|
||||
FCmbTXFiltWindow: TComboBox;
|
||||
// Compressor
|
||||
FChkTXCompOn: TCheckBox;
|
||||
FEdTXCompGain: TFloatSpinEdit;
|
||||
// Leveler
|
||||
FChkTXLevOn: TCheckBox;
|
||||
FEdTXLevTop: TFloatSpinEdit;
|
||||
FEdTXLevDecay: TSpinEdit;
|
||||
// ALC
|
||||
FChkTXALCOn: TCheckBox;
|
||||
FEdTXALCMaxGain: TFloatSpinEdit;
|
||||
FEdTXALCDecay: TSpinEdit;
|
||||
// Phase Rotator
|
||||
FChkTXPHROn: TCheckBox;
|
||||
FEdTXPHRStages: TSpinEdit;
|
||||
FEdTXPHRFreq: TFloatSpinEdit;
|
||||
// EQ
|
||||
FChkTXEQOn: TCheckBox;
|
||||
FCmbTXEQBands: TComboBox;
|
||||
FEdTXEQGain: array[0..10] of TFloatSpinEdit;
|
||||
FEdTXEQFreq: array[0..10] of TFloatSpinEdit;
|
||||
// AM
|
||||
FEdTXAMCarrier: TFloatSpinEdit;
|
||||
// FM
|
||||
FEdTXFMDev: TFloatSpinEdit;
|
||||
FEdTXFMLow: TSpinEdit;
|
||||
FEdTXFMHigh: TSpinEdit;
|
||||
FCmbTXFMEmph: TComboBox;
|
||||
// CTCSS
|
||||
FChkTXCTCSSOn: TCheckBox;
|
||||
FEdTXCTCSSFreq: TFloatSpinEdit;
|
||||
// TX Display (отдельный analyzer)
|
||||
FCmbTXFFT: TComboBox;
|
||||
FCmbTXWindow: TComboBox;
|
||||
FCmbTXSpecDet: TComboBox;
|
||||
FCmbTXSpecAvg: TComboBox;
|
||||
FEdTXSpecAvgTime: TFloatSpinEdit;
|
||||
FCmbTXWfDet: TComboBox;
|
||||
FCmbTXWfAvg: TComboBox;
|
||||
FEdTXWfAvgTime: TFloatSpinEdit;
|
||||
|
||||
// ---- CAT tab controls ----
|
||||
FCATSerialEn: array[0..3] of TCheckBox;
|
||||
FCATSerialPort: array[0..3] of TEdit;
|
||||
@@ -132,6 +192,7 @@ type
|
||||
FOnVisibilityChange: TOnVisibilityChange;
|
||||
FOnFPSChange: TOnFPSChange;
|
||||
FOnThemeChange: TOnThemeChange;
|
||||
FOnTXChange: TOnTXSettingsChange;
|
||||
|
||||
FLoading: Boolean;
|
||||
|
||||
@@ -141,6 +202,10 @@ type
|
||||
procedure BuildRX1Tab;
|
||||
procedure BuildPATab;
|
||||
procedure BuildCATTab;
|
||||
procedure BuildTransmitTab;
|
||||
procedure CollectTXFromUI;
|
||||
procedure FireTXChange;
|
||||
procedure OnTXAnyChange(Sender: TObject);
|
||||
procedure ApplyTheme(const T: TAppTheme);
|
||||
procedure NavClick(Sender: TObject);
|
||||
procedure SelectPage(APage: TWinControl; ANav: TFlatButton);
|
||||
@@ -214,6 +279,7 @@ type
|
||||
const SerPort: array of string;
|
||||
const SerBaud, SerDataBits, SerStopBits, SerParity: array of Integer;
|
||||
TcpEnabled: Boolean; TcpPort: Integer);
|
||||
procedure LoadTXSettings(const T: TTXSettings);
|
||||
|
||||
property OnCATChange: TOnCATChange read FOnCATChange write FOnCATChange;
|
||||
property OnPAChange: TOnPASettingsChange read FOnPAChange write FOnPAChange;
|
||||
@@ -225,6 +291,7 @@ type
|
||||
property OnVisibilityChange: TOnVisibilityChange read FOnVisibilityChange write FOnVisibilityChange;
|
||||
property OnFPSChange: TOnFPSChange read FOnFPSChange write FOnFPSChange;
|
||||
property OnThemeChange: TOnThemeChange read FOnThemeChange write FOnThemeChange;
|
||||
property OnTXChange: TOnTXSettingsChange read FOnTXChange write FOnTXChange;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -429,9 +496,10 @@ begin
|
||||
FNavDisplay := MakeNavButton('Display', 110);
|
||||
FNavSpectrum := MakeNavButton('Spectrum', 146);
|
||||
FNavWaterfall := MakeNavButton('Waterfall', 182);
|
||||
FNavPA := MakeNavButton('Power Amplifier', 218);
|
||||
FNavAdvanced := MakeNavButton('Advanced', 254);
|
||||
FNavCAT := MakeNavButton('CAT', 290);
|
||||
FNavTransmit := MakeNavButton('Transmit', 218);
|
||||
FNavPA := MakeNavButton('Power Amplifier', 254);
|
||||
FNavAdvanced := MakeNavButton('Advanced', 290);
|
||||
FNavCAT := MakeNavButton('CAT', 326);
|
||||
|
||||
FContentPanel := TPanel.Create(Self);
|
||||
FContentPanel.Parent := Self;
|
||||
@@ -443,6 +511,7 @@ begin
|
||||
FPageDisplay := MakeScrollPage;
|
||||
FPageSpectrum := MakeScrollPage;
|
||||
FPageWaterfall := MakeScrollPage;
|
||||
FPageTransmit := MakeScrollPage;
|
||||
FPagePA := MakeScrollPage;
|
||||
FPageAdvanced := MakeScrollPage;
|
||||
FPageCAT := MakeScrollPage;
|
||||
@@ -450,6 +519,7 @@ begin
|
||||
BuildAudioTab;
|
||||
BuildDisplayTab;
|
||||
BuildRX1Tab;
|
||||
BuildTransmitTab;
|
||||
BuildPATab;
|
||||
BuildCATTab;
|
||||
|
||||
@@ -477,6 +547,7 @@ begin
|
||||
else if Sender = FNavDisplay then SelectPage(FPageDisplay, FNavDisplay)
|
||||
else if Sender = FNavSpectrum then SelectPage(FPageSpectrum, FNavSpectrum)
|
||||
else if Sender = FNavWaterfall then SelectPage(FPageWaterfall, FNavWaterfall)
|
||||
else if Sender = FNavTransmit then SelectPage(FPageTransmit, FNavTransmit)
|
||||
else if Sender = FNavPA then SelectPage(FPagePA, FNavPA)
|
||||
else if Sender = FNavAdvanced then SelectPage(FPageAdvanced, FNavAdvanced)
|
||||
else if Sender = FNavCAT then SelectPage(FPageCAT, FNavCAT);
|
||||
@@ -488,6 +559,7 @@ begin
|
||||
FPageDisplay.Visible := APage = FPageDisplay;
|
||||
FPageSpectrum.Visible := APage = FPageSpectrum;
|
||||
FPageWaterfall.Visible := APage = FPageWaterfall;
|
||||
FPageTransmit.Visible := APage = FPageTransmit;
|
||||
FPagePA.Visible := APage = FPagePA;
|
||||
FPageAdvanced.Visible := APage = FPageAdvanced;
|
||||
FPageCAT.Visible := APage = FPageCAT;
|
||||
@@ -496,6 +568,7 @@ begin
|
||||
FNavDisplay.Active := ANav = FNavDisplay;
|
||||
FNavSpectrum.Active := ANav = FNavSpectrum;
|
||||
FNavWaterfall.Active := ANav = FNavWaterfall;
|
||||
FNavTransmit.Active := ANav = FNavTransmit;
|
||||
FNavPA.Active := ANav = FNavPA;
|
||||
FNavAdvanced.Active := ANav = FNavAdvanced;
|
||||
FNavCAT.Active := ANav = FNavCAT;
|
||||
@@ -767,6 +840,412 @@ begin
|
||||
FWfAGCOffset := MkFloat(CX, R1 + 2 * STEP, SPW, 0.0, -40.0, 40.0, 0.5, OnWfThresholdChange);
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// BuildTransmitTab — все настройки TX-тракта (по образцу Thetis Setup→Transmit)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
procedure TSettingsForm.BuildTransmitTab;
|
||||
const
|
||||
MARGIN = 22;
|
||||
PAD = 18;
|
||||
LW = 150;
|
||||
CX = PAD + LW + 12;
|
||||
STEP = 32;
|
||||
R1 = 42;
|
||||
SPW = 96;
|
||||
CMB_W = 200;
|
||||
|
||||
var
|
||||
Grp: TPanel;
|
||||
Y, i: Integer;
|
||||
|
||||
function MkSpin(AParent: TWinControl; AX, AY: Integer; AMin, AMax, AVal: Integer): TSpinEdit;
|
||||
begin
|
||||
Result := TSpinEdit.Create(Self);
|
||||
Result.Parent := AParent;
|
||||
Result.SetBounds(AX, AY, SPW, BTN_H);
|
||||
Result.MinValue := AMin;
|
||||
Result.MaxValue := AMax;
|
||||
Result.Value := AVal;
|
||||
Result.Color := CLR_INPUT;
|
||||
Result.Font.Color := CLR_INPUT_TEXT;
|
||||
Result.Font.Name := UI_FONT;
|
||||
Result.Font.Size := 9;
|
||||
Result.OnChange := OnTXAnyChange;
|
||||
end;
|
||||
|
||||
function MkFloat(AParent: TWinControl; AX, AY: Integer;
|
||||
AVal, AMin, AMax, AInc: Double): TFloatSpinEdit;
|
||||
begin
|
||||
Result := TFloatSpinEdit.Create(Self);
|
||||
Result.Parent := AParent;
|
||||
Result.SetBounds(AX, AY, SPW, BTN_H);
|
||||
Result.MinValue := AMin;
|
||||
Result.MaxValue := AMax;
|
||||
Result.Increment := AInc;
|
||||
Result.Value := AVal;
|
||||
Result.DecimalPlaces := 2;
|
||||
Result.Color := CLR_INPUT;
|
||||
Result.Font.Color := CLR_INPUT_TEXT;
|
||||
Result.Font.Name := UI_FONT;
|
||||
Result.Font.Size := 9;
|
||||
Result.OnChange := OnTXAnyChange;
|
||||
end;
|
||||
|
||||
function MkChk(AParent: TWinControl; AX, AY, AW: Integer; const ACap: string): TCheckBox;
|
||||
begin
|
||||
Result := TCheckBox.Create(Self);
|
||||
Result.Parent := AParent;
|
||||
Result.Caption := ACap;
|
||||
Result.SetBounds(AX, AY, AW, 22);
|
||||
Result.Font.Color := CLR_TEXT;
|
||||
Result.Font.Name := UI_FONT;
|
||||
Result.Font.Size := 9;
|
||||
Result.OnChange := OnTXAnyChange;
|
||||
end;
|
||||
|
||||
function MkCmb(AParent: TWinControl; AX, AY, AW: Integer): TComboBox;
|
||||
begin
|
||||
Result := MakeCombo(AParent, AX, AY, AW, OnTXAnyChange);
|
||||
end;
|
||||
|
||||
begin
|
||||
with TLabel.Create(Self) do
|
||||
begin
|
||||
Parent := FPageTransmit;
|
||||
Caption := 'Transmit';
|
||||
SetBounds(MARGIN, 18, 400, 28);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 16;
|
||||
Font.Style := [fsBold];
|
||||
Font.Color := CLR_TEXT;
|
||||
end;
|
||||
with TLabel.Create(Self) do
|
||||
begin
|
||||
Parent := FPageTransmit;
|
||||
Caption := 'TX-цепь WDSP: микрофон, фильтр, динамическая обработка, модуляция.';
|
||||
SetBounds(MARGIN, 48, 700, 20);
|
||||
Font.Name := UI_FONT;
|
||||
Font.Size := 9;
|
||||
Font.Color := CLR_TEXTDIM;
|
||||
end;
|
||||
|
||||
// ---- Mic source / options ----
|
||||
Y := 86;
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'Microphone', MARGIN, Y, 700, 220);
|
||||
|
||||
MakeLbl(Grp, 'Mic source', PAD, R1 + 5, LW);
|
||||
FCmbTXMicSource := MkCmb(Grp, CX, R1, CMB_W);
|
||||
FCmbTXMicSource.Items.Add('Radio (HW mic)');
|
||||
FCmbTXMicSource.Items.Add('Sound card');
|
||||
FCmbTXMicSource.ItemIndex := 0;
|
||||
|
||||
FChkTXMicBoost := MkChk(Grp, PAD, R1 + STEP, 200, 'Mic boost +20 dB');
|
||||
FChkTXMicBias := MkChk(Grp, PAD + 200, R1 + STEP, 200, 'Mic bias');
|
||||
FChkTXMicLineIn := MkChk(Grp, PAD + 400, R1 + STEP, 160, 'Line in');
|
||||
FChkTXMicPTT := MkChk(Grp, PAD, R1 + 2 * STEP, 220, 'Mic-jack PTT');
|
||||
|
||||
MakeLbl(Grp, 'Mic gain (dB)', PAD, R1 + 3 * STEP + 5, LW);
|
||||
FEdTXMicGain := MkFloat(Grp, CX, R1 + 3 * STEP, 10.0, -20.0, 60.0, 0.5);
|
||||
|
||||
// ---- TX bandpass filter ----
|
||||
Inc(Y, 220 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'TX Filter (bandpass)', MARGIN, Y, 700, 200);
|
||||
|
||||
MakeLbl(Grp, 'Low cut (Hz)', PAD, R1 + 5, LW);
|
||||
FEdTXFiltLow := MkSpin(Grp, CX, R1, 0, 8000, 100);
|
||||
MakeLbl(Grp, 'High cut (Hz)', PAD + 320, R1 + 5, 90);
|
||||
FEdTXFiltHigh := MkSpin(Grp, PAD + 320 + 100, R1, 100, 12000, 2800);
|
||||
|
||||
MakeLbl(Grp, 'FIR length', PAD, R1 + STEP + 5, LW);
|
||||
FCmbTXFiltNC := MkCmb(Grp, CX, R1 + STEP, 140);
|
||||
FCmbTXFiltNC.Items.AddStrings(['256','512','1024','2048','4096']);
|
||||
FCmbTXFiltNC.ItemIndex := 2;
|
||||
|
||||
MakeLbl(Grp, 'Phase mode', PAD, R1 + 2 * STEP + 5, LW);
|
||||
FCmbTXFiltMP := MkCmb(Grp, CX, R1 + 2 * STEP, 200);
|
||||
FCmbTXFiltMP.Items.AddStrings(['Linear Phase','Low Latency']);
|
||||
FCmbTXFiltMP.ItemIndex := 1;
|
||||
|
||||
MakeLbl(Grp, 'Window', PAD, R1 + 3 * STEP + 5, LW);
|
||||
FCmbTXFiltWindow := MkCmb(Grp, CX, R1 + 3 * STEP, 240);
|
||||
for i := 0 to High(WINDOW_NAMES) do
|
||||
FCmbTXFiltWindow.Items.Add(WINDOW_NAMES[i]);
|
||||
FCmbTXFiltWindow.ItemIndex := 1;
|
||||
|
||||
// ---- Compressor / Leveler / ALC / Phase Rotator ----
|
||||
Inc(Y, 200 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'Dynamic processing', MARGIN, Y, 700, 220);
|
||||
|
||||
FChkTXCompOn := MkChk(Grp, PAD, R1, 220, 'Compressor');
|
||||
MakeLbl(Grp, 'Gain (dB)', PAD + 230, R1 + 5, 80);
|
||||
FEdTXCompGain := MkFloat(Grp, PAD + 320, R1, 5.0, 0.0, 20.0, 0.5);
|
||||
|
||||
FChkTXLevOn := MkChk(Grp, PAD, R1 + STEP, 220, 'Leveler');
|
||||
MakeLbl(Grp, 'Top (dB)', PAD + 230, R1 + STEP + 5, 80);
|
||||
FEdTXLevTop := MkFloat(Grp, PAD + 320, R1 + STEP, 5.0, 0.0, 20.0, 0.5);
|
||||
MakeLbl(Grp, 'Decay (ms)', PAD + 430, R1 + STEP + 5, 80);
|
||||
FEdTXLevDecay := MkSpin(Grp, PAD + 520, R1 + STEP, 1, 5000, 500);
|
||||
|
||||
FChkTXALCOn := MkChk(Grp, PAD, R1 + 2 * STEP, 220, 'ALC');
|
||||
MakeLbl(Grp, 'Max gain', PAD + 230, R1 + 2 * STEP + 5, 80);
|
||||
FEdTXALCMaxGain := MkFloat(Grp, PAD + 320, R1 + 2 * STEP, 0.0, -20.0, 20.0, 0.5);
|
||||
MakeLbl(Grp, 'Decay (ms)', PAD + 430, R1 + 2 * STEP + 5, 80);
|
||||
FEdTXALCDecay := MkSpin(Grp, PAD + 520, R1 + 2 * STEP, 1, 5000, 10);
|
||||
|
||||
FChkTXPHROn := MkChk(Grp, PAD, R1 + 3 * STEP, 220, 'Phase Rotator');
|
||||
MakeLbl(Grp, 'Stages', PAD + 230, R1 + 3 * STEP + 5, 80);
|
||||
FEdTXPHRStages := MkSpin(Grp, PAD + 320, R1 + 3 * STEP, 2, 16, 8);
|
||||
MakeLbl(Grp, 'Corner (Hz)', PAD + 430, R1 + 3 * STEP + 5, 80);
|
||||
FEdTXPHRFreq := MkFloat(Grp, PAD + 520, R1 + 3 * STEP, 338.0, 50.0, 3000.0, 1.0);
|
||||
|
||||
// ---- TX EQ ----
|
||||
Inc(Y, 220 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'TX Equalizer', MARGIN, Y, 700, 320);
|
||||
|
||||
FChkTXEQOn := MkChk(Grp, PAD, R1, 200, 'Enable EQ');
|
||||
MakeLbl(Grp, 'Bands', PAD + 230, R1 + 5, 60);
|
||||
FCmbTXEQBands := MkCmb(Grp, PAD + 290, R1, 80);
|
||||
FCmbTXEQBands.Items.AddStrings(['3','10']);
|
||||
FCmbTXEQBands.ItemIndex := 1;
|
||||
|
||||
// 11 строк: [0]=Preamp, [1..10]=полосы. Freq+Gain в одной строке.
|
||||
for i := 0 to 10 do
|
||||
begin
|
||||
if i = 0 then
|
||||
MakeLbl(Grp, 'Preamp (dB)', PAD, R1 + STEP + i * 22 + 3, 100)
|
||||
else
|
||||
MakeLbl(Grp, Format('Band %d', [i]), PAD, R1 + STEP + i * 22 + 3, 80);
|
||||
FEdTXEQFreq[i] := MkFloat(Grp, PAD + 90, R1 + STEP + i * 22, 0.0, 0.0, 20000.0, 10.0);
|
||||
FEdTXEQFreq[i].Width := 100;
|
||||
MakeLbl(Grp, 'gain', PAD + 200, R1 + STEP + i * 22 + 3, 30);
|
||||
FEdTXEQGain[i] := MkFloat(Grp, PAD + 230, R1 + STEP + i * 22, 0.0, -15.0, 15.0, 0.5);
|
||||
FEdTXEQGain[i].Width := 80;
|
||||
end;
|
||||
|
||||
// ---- AM / FM / CTCSS ----
|
||||
Inc(Y, 320 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'AM / FM / CTCSS', MARGIN, Y, 700, 220);
|
||||
|
||||
MakeLbl(Grp, 'AM carrier level', PAD, R1 + 5, LW);
|
||||
FEdTXAMCarrier := MkFloat(Grp, CX, R1, 0.5, 0.0, 1.0, 0.05);
|
||||
|
||||
MakeLbl(Grp, 'FM deviation (Hz)', PAD, R1 + STEP + 5, LW);
|
||||
FEdTXFMDev := MkFloat(Grp, CX, R1 + STEP, 5000.0, 1000.0, 25000.0, 100.0);
|
||||
|
||||
MakeLbl(Grp, 'FM AF low cut', PAD, R1 + 2 * STEP + 5, LW);
|
||||
FEdTXFMLow := MkSpin(Grp, CX, R1 + 2 * STEP, 0, 5000, 300);
|
||||
MakeLbl(Grp, 'FM AF high cut', PAD + 320, R1 + 2 * STEP + 5, 100);
|
||||
FEdTXFMHigh := MkSpin(Grp, PAD + 320 + 110, R1 + 2 * STEP, 100, 8000, 3000);
|
||||
|
||||
MakeLbl(Grp, 'FM emphasis', PAD, R1 + 3 * STEP + 5, LW);
|
||||
FCmbTXFMEmph := MkCmb(Grp, CX, R1 + 3 * STEP, 180);
|
||||
FCmbTXFMEmph.Items.AddStrings(['Pre-EQ','Post-EQ']);
|
||||
FCmbTXFMEmph.ItemIndex := 1;
|
||||
|
||||
FChkTXCTCSSOn := MkChk(Grp, PAD, R1 + 4 * STEP, 220, 'CTCSS tone');
|
||||
MakeLbl(Grp, 'Freq (Hz)', PAD + 230, R1 + 4 * STEP + 5, 80);
|
||||
FEdTXCTCSSFreq := MkFloat(Grp, PAD + 320, R1 + 4 * STEP, 100.0, 50.0, 300.0, 0.1);
|
||||
|
||||
// ---- TX Display (отдельный analyzer для TX-спектра/водопада) ----
|
||||
Inc(Y, 220 + 12);
|
||||
Grp := MakeGroupPanel(FPageTransmit, 'TX Display (Analyzer)', MARGIN, Y, 700, 290);
|
||||
|
||||
MakeLbl(Grp, 'FFT size', PAD, R1 + 5, LW);
|
||||
FCmbTXFFT := MkCmb(Grp, CX, R1, 140);
|
||||
for i := 0 to High(FFT_NAMES) do FCmbTXFFT.Items.Add(FFT_NAMES[i]);
|
||||
FCmbTXFFT.ItemIndex := 2;
|
||||
|
||||
MakeLbl(Grp, 'Window', PAD, R1 + STEP + 5, LW);
|
||||
FCmbTXWindow := MkCmb(Grp, CX, R1 + STEP, 240);
|
||||
for i := 0 to High(WINDOW_NAMES) do FCmbTXWindow.Items.Add(WINDOW_NAMES[i]);
|
||||
FCmbTXWindow.ItemIndex := 2;
|
||||
|
||||
MakeLbl(Grp, 'Spec detector',PAD, R1 + 2 * STEP + 5, LW);
|
||||
FCmbTXSpecDet := MkCmb(Grp, CX, R1 + 2 * STEP, 200);
|
||||
for i := 0 to High(DETECTOR_NAMES) do FCmbTXSpecDet.Items.Add(DETECTOR_NAMES[i]);
|
||||
FCmbTXSpecDet.ItemIndex := 0;
|
||||
|
||||
MakeLbl(Grp, 'Spec average', PAD, R1 + 3 * STEP + 5, LW);
|
||||
FCmbTXSpecAvg := MkCmb(Grp, CX, R1 + 3 * STEP, 200);
|
||||
for i := 0 to High(AVGMODE_NAMES) do FCmbTXSpecAvg.Items.Add(AVGMODE_NAMES[i]);
|
||||
FCmbTXSpecAvg.ItemIndex := 3;
|
||||
MakeLbl(Grp, 'Avg time (ms)', PAD + 430, R1 + 3 * STEP + 5, 100);
|
||||
FEdTXSpecAvgTime := MkFloat(Grp, PAD + 540, R1 + 3 * STEP, 30.0, 1.0, 5000.0, 1.0);
|
||||
|
||||
MakeLbl(Grp, 'WF detector', PAD, R1 + 4 * STEP + 5, LW);
|
||||
FCmbTXWfDet := MkCmb(Grp, CX, R1 + 4 * STEP, 200);
|
||||
for i := 0 to High(DETECTOR_NAMES) do FCmbTXWfDet.Items.Add(DETECTOR_NAMES[i]);
|
||||
FCmbTXWfDet.ItemIndex := 0;
|
||||
|
||||
MakeLbl(Grp, 'WF average', PAD, R1 + 5 * STEP + 5, LW);
|
||||
FCmbTXWfAvg := MkCmb(Grp, CX, R1 + 5 * STEP, 200);
|
||||
for i := 0 to High(WF_AVGMODE_NAMES) do FCmbTXWfAvg.Items.Add(WF_AVGMODE_NAMES[i]);
|
||||
FCmbTXWfAvg.ItemIndex := 3;
|
||||
MakeLbl(Grp, 'Avg time (ms)', PAD + 430, R1 + 5 * STEP + 5, 100);
|
||||
FEdTXWfAvgTime := MkFloat(Grp, PAD + 540, R1 + 5 * STEP, 120.0, 1.0, 5000.0, 1.0);
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.CollectTXFromUI;
|
||||
var i: Integer;
|
||||
begin
|
||||
if FCmbTXMicSource <> nil then
|
||||
FTX.MicSource := Max(0, FCmbTXMicSource.ItemIndex);
|
||||
if FChkTXMicBoost <> nil then FTX.MicBoost := FChkTXMicBoost.Checked;
|
||||
if FChkTXMicBias <> nil then FTX.MicBias := FChkTXMicBias.Checked;
|
||||
if FChkTXMicLineIn <> nil then FTX.MicLineIn := FChkTXMicLineIn.Checked;
|
||||
if FChkTXMicPTT <> nil then FTX.MicPTTEnabled := FChkTXMicPTT.Checked;
|
||||
if FEdTXMicGain <> nil then FTX.MicGainDB := FEdTXMicGain.Value;
|
||||
if FEdTXFiltLow <> nil then FTX.FilterLow := FEdTXFiltLow.Value;
|
||||
if FEdTXFiltHigh <> nil then FTX.FilterHigh := FEdTXFiltHigh.Value;
|
||||
if FCmbTXFiltNC <> nil then
|
||||
FTX.FilterNC := StrToIntDef(FCmbTXFiltNC.Text, 1024);
|
||||
if FCmbTXFiltMP <> nil then FTX.FilterMP := Max(0, FCmbTXFiltMP.ItemIndex);
|
||||
if FCmbTXFiltWindow<> nil then FTX.FilterWindow := Max(0, FCmbTXFiltWindow.ItemIndex);
|
||||
if FChkTXCompOn <> nil then FTX.CompressorOn := FChkTXCompOn.Checked;
|
||||
if FEdTXCompGain <> nil then FTX.CompressorGain := FEdTXCompGain.Value;
|
||||
if FChkTXLevOn <> nil then FTX.LevelerOn := FChkTXLevOn.Checked;
|
||||
if FEdTXLevTop <> nil then FTX.LevelerTop := FEdTXLevTop.Value;
|
||||
if FEdTXLevDecay <> nil then FTX.LevelerDecay := FEdTXLevDecay.Value;
|
||||
if FChkTXALCOn <> nil then FTX.ALCOn := FChkTXALCOn.Checked;
|
||||
if FEdTXALCMaxGain <> nil then FTX.ALCMaxGain := FEdTXALCMaxGain.Value;
|
||||
if FEdTXALCDecay <> nil then FTX.ALCDecay := FEdTXALCDecay.Value;
|
||||
if FChkTXPHROn <> nil then FTX.PhaseRotOn := FChkTXPHROn.Checked;
|
||||
if FEdTXPHRStages <> nil then FTX.PhaseRotStages := FEdTXPHRStages.Value;
|
||||
if FEdTXPHRFreq <> nil then FTX.PhaseRotFreq := FEdTXPHRFreq.Value;
|
||||
if FChkTXEQOn <> nil then FTX.EQOn := FChkTXEQOn.Checked;
|
||||
if FCmbTXEQBands <> nil then
|
||||
if FCmbTXEQBands.ItemIndex = 0 then FTX.EQNumBands := 3 else FTX.EQNumBands := 10;
|
||||
for i := 0 to 10 do
|
||||
begin
|
||||
if FEdTXEQGain[i] <> nil then FTX.EQGains[i] := FEdTXEQGain[i].Value;
|
||||
if FEdTXEQFreq[i] <> nil then FTX.EQFreqs[i] := FEdTXEQFreq[i].Value;
|
||||
end;
|
||||
if FEdTXAMCarrier <> nil then FTX.AMCarrierLevel := FEdTXAMCarrier.Value;
|
||||
if FEdTXFMDev <> nil then FTX.FMDeviation := FEdTXFMDev.Value;
|
||||
if FEdTXFMLow <> nil then FTX.FMLowCut := FEdTXFMLow.Value;
|
||||
if FEdTXFMHigh <> nil then FTX.FMHighCut := FEdTXFMHigh.Value;
|
||||
if FCmbTXFMEmph <> nil then FTX.FMEmphPosition := Max(0, FCmbTXFMEmph.ItemIndex);
|
||||
if FChkTXCTCSSOn <> nil then FTX.CTCSSOn := FChkTXCTCSSOn.Checked;
|
||||
if FEdTXCTCSSFreq <> nil then FTX.CTCSSFreq := FEdTXCTCSSFreq.Value;
|
||||
if (FCmbTXFFT <> nil) and (FCmbTXFFT.ItemIndex >= 0) then
|
||||
FTX.TXFFTSize := FFT_SIZES[FCmbTXFFT.ItemIndex];
|
||||
if FCmbTXWindow <> nil then FTX.TXWindowType := Max(0, FCmbTXWindow.ItemIndex);
|
||||
if FCmbTXSpecDet <> nil then FTX.TXSpecDetector := Max(0, FCmbTXSpecDet.ItemIndex);
|
||||
if (FCmbTXSpecAvg <> nil) and (FCmbTXSpecAvg.ItemIndex >= 0) then
|
||||
FTX.TXSpecAvgMode := AVGMODE_VALUES[FCmbTXSpecAvg.ItemIndex];
|
||||
if FEdTXSpecAvgTime <> nil then FTX.TXSpecAvgTimeMS := FEdTXSpecAvgTime.Value;
|
||||
if FCmbTXWfDet <> nil then FTX.TXWfDetector := Max(0, FCmbTXWfDet.ItemIndex);
|
||||
if (FCmbTXWfAvg <> nil) and (FCmbTXWfAvg.ItemIndex >= 0) then
|
||||
FTX.TXWfAvgMode := WF_AVGMODE_VALUES[FCmbTXWfAvg.ItemIndex];
|
||||
if FEdTXWfAvgTime <> nil then FTX.TXWfAvgTimeMS := FEdTXWfAvgTime.Value;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.FireTXChange;
|
||||
begin
|
||||
if FLoading then Exit;
|
||||
CollectTXFromUI;
|
||||
if Assigned(FOnTXChange) then
|
||||
FOnTXChange(FTX);
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.OnTXAnyChange(Sender: TObject);
|
||||
begin
|
||||
FireTXChange;
|
||||
end;
|
||||
|
||||
procedure TSettingsForm.LoadTXSettings(const T: TTXSettings);
|
||||
var i: Integer;
|
||||
begin
|
||||
FLoading := True;
|
||||
try
|
||||
FTX := T;
|
||||
if FCmbTXMicSource <> nil then
|
||||
FCmbTXMicSource.ItemIndex := EnsureRange(T.MicSource, 0, FCmbTXMicSource.Items.Count - 1);
|
||||
if FChkTXMicBoost <> nil then FChkTXMicBoost.Checked := T.MicBoost;
|
||||
if FChkTXMicBias <> nil then FChkTXMicBias.Checked := T.MicBias;
|
||||
if FChkTXMicLineIn <> nil then FChkTXMicLineIn.Checked := T.MicLineIn;
|
||||
if FChkTXMicPTT <> nil then FChkTXMicPTT.Checked := T.MicPTTEnabled;
|
||||
if FEdTXMicGain <> nil then FEdTXMicGain.Value := T.MicGainDB;
|
||||
if FEdTXFiltLow <> nil then FEdTXFiltLow.Value := T.FilterLow;
|
||||
if FEdTXFiltHigh <> nil then FEdTXFiltHigh.Value := T.FilterHigh;
|
||||
if FCmbTXFiltNC <> nil then FCmbTXFiltNC.Text := IntToStr(T.FilterNC);
|
||||
if FCmbTXFiltMP <> nil then
|
||||
FCmbTXFiltMP.ItemIndex := EnsureRange(T.FilterMP, 0, FCmbTXFiltMP.Items.Count - 1);
|
||||
if FCmbTXFiltWindow<> nil then
|
||||
FCmbTXFiltWindow.ItemIndex := EnsureRange(T.FilterWindow, 0, FCmbTXFiltWindow.Items.Count - 1);
|
||||
if FChkTXCompOn <> nil then FChkTXCompOn.Checked := T.CompressorOn;
|
||||
if FEdTXCompGain <> nil then FEdTXCompGain.Value := T.CompressorGain;
|
||||
if FChkTXLevOn <> nil then FChkTXLevOn.Checked := T.LevelerOn;
|
||||
if FEdTXLevTop <> nil then FEdTXLevTop.Value := T.LevelerTop;
|
||||
if FEdTXLevDecay <> nil then FEdTXLevDecay.Value := T.LevelerDecay;
|
||||
if FChkTXALCOn <> nil then FChkTXALCOn.Checked := T.ALCOn;
|
||||
if FEdTXALCMaxGain <> nil then FEdTXALCMaxGain.Value := T.ALCMaxGain;
|
||||
if FEdTXALCDecay <> nil then FEdTXALCDecay.Value := T.ALCDecay;
|
||||
if FChkTXPHROn <> nil then FChkTXPHROn.Checked := T.PhaseRotOn;
|
||||
if FEdTXPHRStages <> nil then FEdTXPHRStages.Value := T.PhaseRotStages;
|
||||
if FEdTXPHRFreq <> nil then FEdTXPHRFreq.Value := T.PhaseRotFreq;
|
||||
if FChkTXEQOn <> nil then FChkTXEQOn.Checked := T.EQOn;
|
||||
if FCmbTXEQBands <> nil then
|
||||
if T.EQNumBands <= 3 then FCmbTXEQBands.ItemIndex := 0
|
||||
else FCmbTXEQBands.ItemIndex := 1;
|
||||
for i := 0 to 10 do
|
||||
begin
|
||||
if FEdTXEQGain[i] <> nil then FEdTXEQGain[i].Value := T.EQGains[i];
|
||||
if FEdTXEQFreq[i] <> nil then FEdTXEQFreq[i].Value := T.EQFreqs[i];
|
||||
end;
|
||||
if FEdTXAMCarrier <> nil then FEdTXAMCarrier.Value := T.AMCarrierLevel;
|
||||
if FEdTXFMDev <> nil then FEdTXFMDev.Value := T.FMDeviation;
|
||||
if FEdTXFMLow <> nil then FEdTXFMLow.Value := T.FMLowCut;
|
||||
if FEdTXFMHigh <> nil then FEdTXFMHigh.Value := T.FMHighCut;
|
||||
if FCmbTXFMEmph <> nil then
|
||||
FCmbTXFMEmph.ItemIndex := EnsureRange(T.FMEmphPosition, 0, FCmbTXFMEmph.Items.Count - 1);
|
||||
if FChkTXCTCSSOn <> nil then FChkTXCTCSSOn.Checked := T.CTCSSOn;
|
||||
if FEdTXCTCSSFreq <> nil then FEdTXCTCSSFreq.Value := T.CTCSSFreq;
|
||||
|
||||
if FCmbTXFFT <> nil then
|
||||
begin
|
||||
FCmbTXFFT.ItemIndex := 2;
|
||||
for i := 0 to High(FFT_SIZES) do
|
||||
if FFT_SIZES[i] = T.TXFFTSize then
|
||||
begin
|
||||
FCmbTXFFT.ItemIndex := i;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if FCmbTXWindow <> nil then
|
||||
FCmbTXWindow.ItemIndex := EnsureRange(T.TXWindowType, 0, FCmbTXWindow.Items.Count - 1);
|
||||
if FCmbTXSpecDet <> nil then
|
||||
FCmbTXSpecDet.ItemIndex := EnsureRange(T.TXSpecDetector, 0, FCmbTXSpecDet.Items.Count - 1);
|
||||
if FCmbTXSpecAvg <> nil then
|
||||
begin
|
||||
FCmbTXSpecAvg.ItemIndex := 3;
|
||||
for i := 0 to High(AVGMODE_VALUES) do
|
||||
if AVGMODE_VALUES[i] = T.TXSpecAvgMode then
|
||||
begin
|
||||
FCmbTXSpecAvg.ItemIndex := i;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if FEdTXSpecAvgTime <> nil then FEdTXSpecAvgTime.Value := T.TXSpecAvgTimeMS;
|
||||
if FCmbTXWfDet <> nil then
|
||||
FCmbTXWfDet.ItemIndex := EnsureRange(T.TXWfDetector, 0, FCmbTXWfDet.Items.Count - 1);
|
||||
if FCmbTXWfAvg <> nil then
|
||||
begin
|
||||
FCmbTXWfAvg.ItemIndex := 3;
|
||||
for i := 0 to High(WF_AVGMODE_VALUES) do
|
||||
if WF_AVGMODE_VALUES[i] = T.TXWfAvgMode then
|
||||
begin
|
||||
FCmbTXWfAvg.ItemIndex := i;
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if FEdTXWfAvgTime <> nil then FEdTXWfAvgTime.Value := T.TXWfAvgTimeMS;
|
||||
finally
|
||||
FLoading := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// BuildPATab
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user