mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 21:37:32 +00:00
Add flat FM RAW transmit path
This commit is contained in:
+8
-5
@@ -3595,13 +3595,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.UpdateTXControlAvailability;
|
procedure TMainForm.UpdateTXControlAvailability;
|
||||||
var Allowed: Boolean;
|
var MOXAllowed, TuneAllowed: Boolean;
|
||||||
begin
|
begin
|
||||||
if (BtnMOX = nil) or (BtnTUN = nil) or (FController = nil) then Exit;
|
if (BtnMOX = nil) or (BtnTUN = nil) or (FController = nil) then Exit;
|
||||||
Allowed := FController.FRunning and
|
MOXAllowed := FController.FRunning and
|
||||||
not (FController.ActiveTXMode in [MODE_DMR, MODE_FMRAW]);
|
(FController.ActiveTXMode <> MODE_DMR);
|
||||||
BtnMOX.Enabled := Allowed;
|
// FM RAW transmits external PCM only; the speech-path tune generator is not
|
||||||
BtnTUN.Enabled := Allowed;
|
// useful there and remains guarded in the controller as well.
|
||||||
|
TuneAllowed := MOXAllowed and (FController.ActiveTXMode <> MODE_FMRAW);
|
||||||
|
BtnMOX.Enabled := MOXAllowed;
|
||||||
|
BtnTUN.Enabled := TuneAllowed;
|
||||||
UpdatePSButtons;
|
UpdatePSButtons;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
+28
-12
@@ -1923,8 +1923,8 @@ begin
|
|||||||
FSlices[idx].Mode := Mode;
|
FSlices[idx].Mode := Mode;
|
||||||
if Assigned(FDSPEngine) then FDSPEngine.SetSliceMode(Id, Mode);
|
if Assigned(FDSPEngine) then FDSPEngine.SetSliceMode(Id, Mode);
|
||||||
// DMR is receive-only. If this slice used to be the TX source, hand TX back
|
// DMR is receive-only. If this slice used to be the TX source, hand TX back
|
||||||
// to the main receiver as soon as it enters DMR.
|
// to the main receiver as soon as it enters DMR. FM RAW supports flat TX.
|
||||||
if (Mode in [MODE_DMR, MODE_FMRAW]) and (FTxSliceId = Id) then SetTxSlice(0);
|
if (Mode = MODE_DMR) and (FTxSliceId = Id) then SetTxSlice(0);
|
||||||
if (OldMode = MODE_DMR) and (Mode <> MODE_DMR) then
|
if (OldMode = MODE_DMR) and (Mode <> MODE_DMR) then
|
||||||
FreeAndNil(FSlices[idx].DMR);
|
FreeAndNil(FSlices[idx].DMR);
|
||||||
end;
|
end;
|
||||||
@@ -2233,14 +2233,13 @@ begin
|
|||||||
if SliceId > 0 then
|
if SliceId > 0 then
|
||||||
begin
|
begin
|
||||||
if not GetSlice(SliceId, S) then Exit;
|
if not GetSlice(SliceId, S) then Exit;
|
||||||
// EWSDR has no DMR transmitter/AMBE encoder. Do not accidentally use the
|
// EWSDR has no DMR transmitter/AMBE encoder.
|
||||||
// analog WFM transmitter for a receive-only DMR slice.
|
if S.Mode = MODE_DMR then Exit;
|
||||||
if S.Mode in [MODE_DMR, MODE_FMRAW] then Exit;
|
|
||||||
end;
|
end;
|
||||||
if FTxSliceId = SliceId then Exit;
|
if FTxSliceId = SliceId then Exit;
|
||||||
// Selecting main A while it is in DMR is allowed as an RX selection, but it
|
// Selecting main A while it is in DMR is allowed as an RX selection, but it
|
||||||
// cannot inherit an active carrier from a previously selected TX slice.
|
// cannot inherit an active carrier from a previously selected TX slice.
|
||||||
if (SliceId = 0) and (FMode in [MODE_DMR, MODE_FMRAW]) then
|
if (SliceId = 0) and (FMode = MODE_DMR) then
|
||||||
begin
|
begin
|
||||||
if FTuning then SetTune(False)
|
if FTuning then SetTune(False)
|
||||||
else if FTransmitting then SetMOX(False);
|
else if FTransmitting then SetMOX(False);
|
||||||
@@ -3271,7 +3270,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
// Entering receive-only DMR on the selected main TX source immediately
|
// Entering receive-only DMR on the selected main TX source immediately
|
||||||
// releases an existing carrier. SetTune(False) also releases MOX.
|
// releases an existing carrier. SetTune(False) also releases MOX.
|
||||||
if ActiveTXMode in [MODE_DMR, MODE_FMRAW] then
|
if ActiveTXMode = MODE_DMR then
|
||||||
begin
|
begin
|
||||||
if FTuning then SetTune(False)
|
if FTuning then SetTune(False)
|
||||||
else if FTransmitting then SetMOX(False);
|
else if FTransmitting then SetMOX(False);
|
||||||
@@ -3282,6 +3281,17 @@ begin
|
|||||||
if FWDSPReady and Assigned(FDSPEngine) then
|
if FWDSPReady and Assigned(FDSPEngine) then
|
||||||
begin
|
begin
|
||||||
FDSPEngine.SetMode(FMode);
|
FDSPEngine.SetMode(FMode);
|
||||||
|
// SetMode configures the main RX/TX pair; a selected slice may still be
|
||||||
|
// the actual TX source and therefore owns the transmitter mode.
|
||||||
|
FDSPEngine.SetTXMode(ActiveTXMode);
|
||||||
|
// A live mode change must also switch away from web/HW microphone when
|
||||||
|
// entering FM RAW; normally the modem is connected through PortAudio.
|
||||||
|
if FTransmitting and (ActiveTXMode = MODE_FMRAW) then
|
||||||
|
begin
|
||||||
|
FWebMicActive := False;
|
||||||
|
FDSPEngine.SetTXMicSource(DefaultMicSource);
|
||||||
|
if Assigned(FAudioIn) and FAudioIn.IsOpen then FAudioIn.Flush;
|
||||||
|
end;
|
||||||
// Если TUN активен — пересчитываем знак частоты под новый режим
|
// Если TUN активен — пересчитываем знак частоты под новый режим
|
||||||
if FTuning then FDSPEngine.SetTXTone(True, FTXSettings.TUNFreq, TUN_TONE_MAG);
|
if FTuning then FDSPEngine.SetTXTone(True, FTXSettings.TUNFreq, TUN_TONE_MAG);
|
||||||
end;
|
end;
|
||||||
@@ -4165,6 +4175,9 @@ begin
|
|||||||
FDSPEngine.SetTXWaterfallDisplay(FTXSettings.TXWfDetector,
|
FDSPEngine.SetTXWaterfallDisplay(FTXSettings.TXWfDetector,
|
||||||
FTXSettings.TXWfAvgMode,
|
FTXSettings.TXWfAvgMode,
|
||||||
FTXSettings.TXWfAvgTimeMS);
|
FTXSettings.TXWfAvgTimeMS);
|
||||||
|
// Reapply the mode overlay last: FM RAW must stay flat even when the user
|
||||||
|
// edits and saves ordinary voice-chain settings while this mode is active.
|
||||||
|
FDSPEngine.SetTXMode(ActiveTXMode);
|
||||||
// PureSignal-параметры calcc (mox/loop/tx delay, ptol, pin/map/stbl, SetPk)
|
// PureSignal-параметры calcc (mox/loop/tx delay, ptol, pin/map/stbl, SetPk)
|
||||||
ApplyPSSettingsToDSP;
|
ApplyPSSettingsToDSP;
|
||||||
end;
|
end;
|
||||||
@@ -4174,8 +4187,8 @@ var
|
|||||||
WasTransmitting: Boolean;
|
WasTransmitting: Boolean;
|
||||||
begin
|
begin
|
||||||
// DMR support is receive-only. This guard also covers CAT, web and hardware
|
// DMR support is receive-only. This guard also covers CAT, web and hardware
|
||||||
// PTT. A selected non-DMR TX slice remains valid while main A receives DMR.
|
// PTT. FM RAW is a flat external-modem transmit path.
|
||||||
if On_ and (ActiveTXMode in [MODE_DMR, MODE_FMRAW]) then Exit;
|
if On_ and (ActiveTXMode = MODE_DMR) then Exit;
|
||||||
// Safety: блокируем TX на бэндах с DoNotTx (Alex) и на RX-only трансвертере.
|
// Safety: блокируем TX на бэндах с DoNotTx (Alex) и на RX-only трансвертере.
|
||||||
if On_ and FDevConnected and (FCurrentXvtr < 0)
|
if On_ and FDevConnected and (FCurrentXvtr < 0)
|
||||||
and FAlexSettings.DoNotTx[EnsureRange(TxBandIdx, 0, 10)] then
|
and FAlexSettings.DoNotTx[EnsureRange(TxBandIdx, 0, 10)] then
|
||||||
@@ -4222,11 +4235,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
if FWDSPReady and Assigned(FDSPEngine) then
|
if FWDSPReady and Assigned(FDSPEngine) then
|
||||||
begin
|
begin
|
||||||
// Mic source автоматически по источнику TX:
|
// Mic source автоматически по источнику TX. FM RAW always uses the
|
||||||
// Web TX → txmsWeb; HW PTT → txmsRadio; MOX/CAT → DefaultMicSource.
|
// configured default input (normally a virtual PortAudio cable), even if
|
||||||
|
// a web client is connected or hardware PTT keyed the transmitter.
|
||||||
if FTransmitting then
|
if FTransmitting then
|
||||||
begin
|
begin
|
||||||
if FWebClientActive then
|
if ActiveTXMode = MODE_FMRAW then
|
||||||
|
FDSPEngine.SetTXMicSource(DefaultMicSource)
|
||||||
|
else if FWebClientActive then
|
||||||
begin
|
begin
|
||||||
FWebMicActive := True;
|
FWebMicActive := True;
|
||||||
FDSPEngine.SetTXMicSource(txmsWeb);
|
FDSPEngine.SetTXMicSource(txmsWeb);
|
||||||
|
|||||||
+50
-4
@@ -447,6 +447,7 @@ type
|
|||||||
FTXWfAvgTimeMS: Double;
|
FTXWfAvgTimeMS: Double;
|
||||||
|
|
||||||
FMode: Integer;
|
FMode: Integer;
|
||||||
|
FTXMode: Integer; // may differ from RX when a slice is TX source
|
||||||
FRawFMDeviation: Double;
|
FRawFMDeviation: Double;
|
||||||
FSMeter: Double;
|
FSMeter: Double;
|
||||||
FFilterLow: Integer;
|
FFilterLow: Integer;
|
||||||
@@ -486,6 +487,9 @@ type
|
|||||||
procedure ApplyRXDMRToChan(Chan: Integer);
|
procedure ApplyRXDMRToChan(Chan: Integer);
|
||||||
procedure ApplyRXRawToChan(Chan: Integer);
|
procedure ApplyRXRawToChan(Chan: Integer);
|
||||||
procedure ApplyWFMSettings;
|
procedure ApplyWFMSettings;
|
||||||
|
// Mode-dependent TX overlay. FM RAW uses the flat WFM modulator and
|
||||||
|
// bypasses every speech processor without overwriting the saved TX setup.
|
||||||
|
procedure ApplyTXModeSettings(Mode: Integer);
|
||||||
// --- Мультислайсы ---
|
// --- Мультислайсы ---
|
||||||
function FindSliceIdx(Id: Integer): Integer; // -1 если нет
|
function FindSliceIdx(Id: Integer): Integer; // -1 если нет
|
||||||
function SliceInRate(Idx: Integer): Integer; // входной rate слайса (его пан)
|
function SliceInRate(Idx: Integer): Integer; // входной rate слайса (его пан)
|
||||||
@@ -1006,8 +1010,10 @@ end;
|
|||||||
function TWDSPEngine.ModeToWDSPTX(Mode: Integer): Integer;
|
function TWDSPEngine.ModeToWDSPTX(Mode: Integer): Integer;
|
||||||
// txaMode расходится с rxaMode после DRM — отдельный маппинг только для WFM.
|
// txaMode расходится с rxaMode после DRM — отдельный маппинг только для WFM.
|
||||||
begin
|
begin
|
||||||
if Mode = MODE_WFM then Result := WDSP_TX_WFM
|
// The narrow FM modulator has mandatory speech pre-emphasis. FM RAW uses
|
||||||
else if Mode in [MODE_DMR, MODE_FMRAW] then Result := WDSP_FM
|
// wfmmod even at NFM deviation because that path has an explicit flat mode.
|
||||||
|
if Mode in [MODE_WFM, MODE_FMRAW] then Result := WDSP_TX_WFM
|
||||||
|
else if Mode = MODE_DMR then Result := WDSP_FM
|
||||||
else Result := ModeToWDSP(Mode);
|
else Result := ModeToWDSP(Mode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -1148,6 +1154,36 @@ begin
|
|||||||
SetTXAWFMPreEmphTau (TXA_CHAN, WFM_TAU_DE_US);
|
SetTXAWFMPreEmphTau (TXA_CHAN, WFM_TAU_DE_US);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWDSPEngine.ApplyTXModeSettings(Mode: Integer);
|
||||||
|
begin
|
||||||
|
if not FInitialized then Exit;
|
||||||
|
if Mode = MODE_FMRAW then
|
||||||
|
begin
|
||||||
|
// Decoder/modem-grade FM input. A full-scale PCM peak produces the
|
||||||
|
// selected peak deviation. Keep only a broad linear-phase AF bandpass;
|
||||||
|
// APRS and other external modems must not see voice EQ, dynamics or emphasis.
|
||||||
|
SetTXAWFMDeviation (TXA_CHAN, FRawFMDeviation);
|
||||||
|
SetTXAWFMAFFreqs (TXA_CHAN, 20.0, 7000.0);
|
||||||
|
SetTXAWFMPreEmphRun (TXA_CHAN, 0);
|
||||||
|
SetTXABandpassFreqs (TXA_CHAN, 20.0, 7000.0);
|
||||||
|
SetTXABandpassRun (TXA_CHAN, 1);
|
||||||
|
SetTXAPanelGain1 (TXA_CHAN, 1.0);
|
||||||
|
SetTXACompressorRun (TXA_CHAN, 0);
|
||||||
|
SetTXALevelerSt (TXA_CHAN, 0);
|
||||||
|
SetTXAALCSt (TXA_CHAN, 0);
|
||||||
|
SetTXAPHROTRun (TXA_CHAN, 0);
|
||||||
|
SetTXAEQRun (TXA_CHAN, 0);
|
||||||
|
SetTXACTCSSRun (TXA_CHAN, 0);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
// Restore the user's normal voice/data chain after leaving FM RAW.
|
||||||
|
SetTXABandpassRun(TXA_CHAN, 1);
|
||||||
|
ApplyTXChainSettings;
|
||||||
|
if Mode = MODE_WFM then ApplyWFMSettings;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TWDSPEngine.ClampToNyquist(Hz, Rate: Integer): Integer;
|
function TWDSPEngine.ClampToNyquist(Hz, Rate: Integer): Integer;
|
||||||
var Limit: Integer;
|
var Limit: Integer;
|
||||||
begin
|
begin
|
||||||
@@ -1196,6 +1232,7 @@ begin
|
|||||||
FInitialized := False;
|
FInitialized := False;
|
||||||
FAnalyzerOpen := False;
|
FAnalyzerOpen := False;
|
||||||
FMode := MODE_USB;
|
FMode := MODE_USB;
|
||||||
|
FTXMode := MODE_USB;
|
||||||
FFilterLow := 100;
|
FFilterLow := 100;
|
||||||
FFilterHigh := 2400;
|
FFilterHigh := 2400;
|
||||||
FAGCMode := agcMedium;
|
FAGCMode := agcMedium;
|
||||||
@@ -1688,7 +1725,8 @@ begin
|
|||||||
// изредка фазовый разрыв PostGen-тона (всплеск на водопаде + щелчок).
|
// изредка фазовый разрыв PostGen-тона (всплеск на водопаде + щелчок).
|
||||||
);
|
);
|
||||||
|
|
||||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(FMode));
|
FTXMode := FMode;
|
||||||
|
SetTXAMode(TXA_CHAN, ModeToWDSPTX(FTXMode));
|
||||||
SetTXAPanelRun(TXA_CHAN, 1);
|
SetTXAPanelRun(TXA_CHAN, 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(TXA_CHAN, 2);
|
||||||
@@ -2819,6 +2857,7 @@ end;
|
|||||||
procedure TWDSPEngine.SetMode(Mode: Integer);
|
procedure TWDSPEngine.SetMode(Mode: Integer);
|
||||||
begin
|
begin
|
||||||
FMode := Mode;
|
FMode := Mode;
|
||||||
|
FTXMode := Mode;
|
||||||
if not FInitialized then Exit;
|
if not FInitialized then Exit;
|
||||||
// Rate — до режима: setDSPSamplerate_rxa перестраивает всю цепь (в т.ч. wfmd),
|
// Rate — до режима: setDSPSamplerate_rxa перестраивает всю цепь (в т.ч. wfmd),
|
||||||
// а SetRXAMode затем пересчитает bpsnba под уже актуальный dsp_rate.
|
// а SetRXAMode затем пересчитает bpsnba под уже актуальный dsp_rate.
|
||||||
@@ -2833,6 +2872,7 @@ begin
|
|||||||
SetRXAWFMDeemphRun (RXA_CHAN, 0);
|
SetRXAWFMDeemphRun (RXA_CHAN, 0);
|
||||||
end
|
end
|
||||||
else if Mode = MODE_FMRAW then ApplyRXRawToChan(RXA_CHAN);
|
else if Mode = MODE_FMRAW then ApplyRXRawToChan(RXA_CHAN);
|
||||||
|
ApplyTXModeSettings(FTXMode);
|
||||||
// НЕ вызываем ApplyDefaultFilter — фильтр устанавливается явно из UI
|
// НЕ вызываем ApplyDefaultFilter — фильтр устанавливается явно из UI
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -3081,6 +3121,7 @@ begin
|
|||||||
FRawFMDeviation := EnsureRange(Deviation, 500.0, 10000.0);
|
FRawFMDeviation := EnsureRange(Deviation, 500.0, 10000.0);
|
||||||
if not FInitialized then Exit;
|
if not FInitialized then Exit;
|
||||||
if FMode = MODE_FMRAW then SetRXAWFMDeviation(RXA_CHAN, FRawFMDeviation);
|
if FMode = MODE_FMRAW then SetRXAWFMDeviation(RXA_CHAN, FRawFMDeviation);
|
||||||
|
if FTXMode = MODE_FMRAW then SetTXAWFMDeviation(TXA_CHAN, FRawFMDeviation);
|
||||||
// One calibration value applies to every active FM RAW decoder output.
|
// One calibration value applies to every active FM RAW decoder output.
|
||||||
FSliceLock.Enter;
|
FSliceLock.Enter;
|
||||||
try
|
try
|
||||||
@@ -3127,13 +3168,18 @@ end;
|
|||||||
|
|
||||||
procedure TWDSPEngine.SetTXMode(Mode: Integer);
|
procedure TWDSPEngine.SetTXMode(Mode: Integer);
|
||||||
begin
|
begin
|
||||||
|
FTXMode := Mode;
|
||||||
if not FInitialized then Exit;
|
if not FInitialized then Exit;
|
||||||
SetTXAMode(TXA_CHAN, ModeToWDSPTX(Mode));
|
SetTXAMode(TXA_CHAN, ModeToWDSPTX(FTXMode));
|
||||||
|
ApplyTXModeSettings(FTXMode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TWDSPEngine.SetTXFilter(Low, High: Integer);
|
procedure TWDSPEngine.SetTXFilter(Low, High: Integer);
|
||||||
begin
|
begin
|
||||||
if not FInitialized then Exit;
|
if not FInitialized then Exit;
|
||||||
|
// In FM RAW this is an RF-channel-width update mirrored from the RX UI,
|
||||||
|
// not an audio passband request. The flat modem AF passband is fixed above.
|
||||||
|
if FTXMode = MODE_FMRAW then Exit;
|
||||||
SetTXABandpassFreqs(TXA_CHAN, Low, High);
|
SetTXABandpassFreqs(TXA_CHAN, Low, High);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user