feat(dmr): add receive frontend and AMBE adapter

This commit is contained in:
2026-07-14 18:38:39 +03:00
parent f33a1fbd0a
commit 53a3681618
20 changed files with 998 additions and 30 deletions
+24 -6
View File
@@ -60,6 +60,7 @@ const
MODE_DIGU = 8;
MODE_DIGL = 9;
MODE_WFM = 10;
MODE_DMR = 11; // DMR receive: WDSP NFM discriminator -> DMRDecoder
// Минимальная длина FIR у WDSP: create_* поднимают fircore с
// nc = max(2048, dsp_size). В firmin.c nfor = nc / size, idxmask = nfor - 1,
@@ -322,6 +323,7 @@ type
FViewHighHz: Double;
FOnAudio: TOnAudioReady;
FOnDemodAudio:TOnAudioReady; // pre-volume/mute tap for digital decoders
FOnSpectrum: TOnSpectrumReady;
FOnWaterfall: TOnWaterfallReady;
FOnTXIQ: TOnTXIQReady;
@@ -682,6 +684,7 @@ type
property WfAvgMode: Integer read FWfAvgMode;
property WfAvgTimeMS: Double read FWfAvgTimeMS;
property OnAudio: TOnAudioReady read FOnAudio write FOnAudio;
property OnDemodAudio: TOnAudioReady read FOnDemodAudio write FOnDemodAudio;
property OnSliceAudio: TOnSliceAudio read FOnSliceAudio write FOnSliceAudio;
property OnSpectrum: TOnSpectrumReady read FOnSpectrum write FOnSpectrum;
property OnWaterfall: TOnWaterfallReady read FOnWaterfall write FOnWaterfall;
@@ -930,6 +933,7 @@ begin
MODE_DIGU: Result := WDSP_DIGU;
MODE_DIGL: Result := WDSP_DIGL;
MODE_WFM: Result := WDSP_RX_WFM;
MODE_DMR: Result := WDSP_FM;
else Result := WDSP_USB;
end;
end;
@@ -1082,6 +1086,7 @@ begin
MODE_DIGU: SetFilter( 0, 3000);
MODE_DIGL: SetFilter(-3000, 0);
MODE_WFM: SetFilter(-80000, 80000);
MODE_DMR: SetFilter(-6250, 6250);
end;
end;
@@ -2087,16 +2092,29 @@ begin
// Full-duplex self-monitor (QO-100): при FMonitorRXDuringTX не глушим RX-аудио
// на TX — слышим свой downlink со спутника. Иначе (по умолчанию) глушим, как
// Thetis/piHPSDR при не-duplex MOX. FPostTXMuteUntil-хвост уважаем в любом случае.
if Assigned(FOnAudio) and not FMuted
and (not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX))
if (not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX))
and (FPostTXMuteUntil = 0) then
begin
for i := 0 to FAudioBufSize - 1 do
// Decoder tap is independent from speaker mute and volume. This is the
// actual demodulator output; digital sync must survive MUTE/volume=0.
if Assigned(FOnDemodAudio) then
begin
FOutL[i] := FRXOut[i * 2] * FVolume;
FOutR[i] := FRXOut[i * 2 + 1] * FVolume;
for i := 0 to FAudioBufSize - 1 do
begin
FOutL[i] := FRXOut[i * 2];
FOutR[i] := FRXOut[i * 2 + 1];
end;
FOnDemodAudio(FOutL, FOutR, FAudioBufSize);
end;
if Assigned(FOnAudio) and not FMuted then
begin
for i := 0 to FAudioBufSize - 1 do
begin
FOutL[i] := FRXOut[i * 2] * FVolume;
FOutR[i] := FRXOut[i * 2 + 1] * FVolume;
end;
FOnAudio(FOutL, FOutR, FAudioBufSize);
end;
FOnAudio(FOutL, FOutR, FAudioBufSize);
end;
// Софтовые слайсы: fan-out того же IQ-блока на доп. WDSP-каналы.