mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(fm): add universal FM RAW decoder output
This commit is contained in:
+26
-7
@@ -6,13 +6,15 @@ unit Settings;
|
||||
}
|
||||
{$mode objfpc}{$H+}
|
||||
interface
|
||||
uses SysUtils, Classes, Math, fpJSON, jsonparser, jsonscanner, PlatformUtils;
|
||||
uses SysUtils, Classes, Math, fpJSON, jsonparser, jsonscanner, PlatformUtils,
|
||||
RadioModes;
|
||||
|
||||
const
|
||||
SETTINGS_FILE = 'hpsdr_settings.json';
|
||||
CFG_BAND_COUNT = 12;
|
||||
CFG_XVTR_COUNT = 8; // количество XVTR-слотов (трансверторов)
|
||||
CFG_MODE_MAX = 11; // LSB..DMR; keep persisted-mode validation current
|
||||
CFG_MODE_MIN = RadioModes.MODE_MIN;
|
||||
CFG_MODE_MAX = RadioModes.MODE_MAX;
|
||||
CFG_PANS_MAX = 4; // потолок панадаптеров (пан 0 + доп.) — = WDSPEngine.MAX_PANS
|
||||
QO100_SLOT = CFG_XVTR_COUNT - 1; // последний слот зарезервирован под QO-100
|
||||
// (split-LO транспондер; настраивается на
|
||||
@@ -61,6 +63,16 @@ const
|
||||
FILT_WFM_BW: array[0..2] of Integer = (200000, 160000, 120000);
|
||||
FILT_WFM_DEF = 1; // 160k — влезает и в 192k
|
||||
|
||||
// FM RAW: narrow, flat discriminator output for external digital decoders.
|
||||
// These are RF channel widths; baseband stays flat at 20..7000 Hz.
|
||||
FILT_RAW_COUNT = 5;
|
||||
FILT_RAW_BW: array[0..FILT_RAW_COUNT-1] of Integer =
|
||||
(6250, 10000, 12500, 20000, 25000);
|
||||
FILT_RAW_DEF = 2; // 12.5 kHz
|
||||
RAW_FM_DEV_DEFAULT = 2500;
|
||||
RAW_FM_DEV_MIN = 500;
|
||||
RAW_FM_DEV_MAX = 10000;
|
||||
|
||||
// DMR Tier II: 12.5 kHz RF channel, 4FSK nominal deviation +/-1.944 kHz.
|
||||
FILT_DMR_BW = 12500;
|
||||
DMR_FM_DEV = 2500;
|
||||
@@ -359,6 +371,7 @@ type
|
||||
AudioSampleRate: Integer; // PortAudio stream sample rate (e.g. 48000)
|
||||
AudioInDevice: string; // PortAudio input device name for TX mic ('' = none)
|
||||
SendAudioToRadio: Boolean; // True = send RX audio stream to radio (built-in speaker)
|
||||
RawFMDeviation: Integer; // Hz, flat RAW FM discriminator scale
|
||||
// --- Visibility settings ---
|
||||
ShowSpectrum: Boolean; // True = draw spectrum on main form
|
||||
ShowWaterfall: Boolean; // True = draw waterfall on main form
|
||||
@@ -566,6 +579,7 @@ begin
|
||||
G.AudioSampleRate := 48000;
|
||||
G.AudioInDevice := '';
|
||||
G.SendAudioToRadio := False;
|
||||
G.RawFMDeviation := RAW_FM_DEV_DEFAULT;
|
||||
G.ShowSpectrum := True;
|
||||
G.ShowWaterfall := True;
|
||||
G.ShowWideband := False;
|
||||
@@ -796,6 +810,9 @@ begin
|
||||
G.AudioSampleRate := JI(GObj,'audio_sample_rate',48000);
|
||||
G.AudioInDevice := JS(GObj,'audio_in_device','');
|
||||
G.SendAudioToRadio := JB(GObj,'send_audio_to_radio',False);
|
||||
G.RawFMDeviation := EnsureRange(
|
||||
JI(GObj,'raw_fm_deviation',RAW_FM_DEV_DEFAULT),
|
||||
RAW_FM_DEV_MIN, RAW_FM_DEV_MAX);
|
||||
// Visibility settings
|
||||
G.ShowSpectrum := JB(GObj,'show_spectrum',True);
|
||||
G.ShowWaterfall := JB(GObj,'show_waterfall',True);
|
||||
@@ -840,7 +857,7 @@ begin
|
||||
BObj := GetBandObj(DevObj, i);
|
||||
Bands[i].VfoA := JD(BObj,'vfo_a', Bands[i].VfoA);
|
||||
Bands[i].VfoB := JD(BObj,'vfo_b', Bands[i].VfoB);
|
||||
Bands[i].Mode := JI(BObj,'mode', Bands[i].Mode);
|
||||
Bands[i].Mode := EnsureRange(JI(BObj,'mode', Bands[i].Mode), CFG_MODE_MIN, CFG_MODE_MAX);
|
||||
Bands[i].FilterIdx := JI(BObj,'filter_idx', Bands[i].FilterIdx);
|
||||
Bands[i].FilterBW := JI(BObj,'filter_bw', Bands[i].FilterBW);
|
||||
Bands[i].AGCMode := JI(BObj,'agc_mode', Bands[i].AGCMode);
|
||||
@@ -908,6 +925,7 @@ begin
|
||||
JW(O,'audio_sample_rate',G.AudioSampleRate);
|
||||
JWS(O,'audio_in_device',G.AudioInDevice);
|
||||
JW(O,'send_audio_to_radio',G.SendAudioToRadio);
|
||||
JW(O,'raw_fm_deviation',G.RawFMDeviation);
|
||||
// Visibility settings
|
||||
JW(O,'show_spectrum',G.ShowSpectrum);
|
||||
JW(O,'show_waterfall',G.ShowWaterfall);
|
||||
@@ -973,7 +991,7 @@ begin
|
||||
O := GetBandObj(GetDevObj(MacStr), BandIdx);
|
||||
B.VfoA := JD(O,'vfo_a', B.VfoA);
|
||||
B.VfoB := JD(O,'vfo_b', B.VfoB);
|
||||
B.Mode := JI(O,'mode', B.Mode);
|
||||
B.Mode := EnsureRange(JI(O,'mode', B.Mode), CFG_MODE_MIN, CFG_MODE_MAX);
|
||||
B.FilterIdx := JI(O,'filter_idx', B.FilterIdx);
|
||||
B.FilterBW := JI(O,'filter_bw', B.FilterBW);
|
||||
B.AGCMode := JI(O,'agc_mode', B.AGCMode);
|
||||
@@ -1491,7 +1509,7 @@ begin
|
||||
X.Entries[i].RXAntenna := 0;
|
||||
X.Entries[i].LastFreq := 0.0;
|
||||
X.Entries[i].LastFreqB := 0.0;
|
||||
X.Entries[i].LastMode := 1; // USB — VHF SSB calling default
|
||||
X.Entries[i].LastMode := MODE_USB; // VHF SSB calling default
|
||||
X.Entries[i].LastFilterIdx := 0; // NFM
|
||||
X.Entries[i].LastFMSQOn := False;
|
||||
X.Entries[i].LastFMSQLevel := 30;
|
||||
@@ -1572,7 +1590,7 @@ begin
|
||||
X.Entries[i].RXAntenna := EnsureRange(JI(EObj, 'rx_ant', X.Entries[i].RXAntenna), 0, 3);
|
||||
X.Entries[i].LastFreq := JD(EObj, 'last_freq', X.Entries[i].LastFreq);
|
||||
X.Entries[i].LastFreqB := JD(EObj, 'last_freq_b', X.Entries[i].LastFreqB);
|
||||
X.Entries[i].LastMode := EnsureRange(JI(EObj, 'last_mode', X.Entries[i].LastMode), 0, CFG_MODE_MAX);
|
||||
X.Entries[i].LastMode := EnsureRange(JI(EObj, 'last_mode', X.Entries[i].LastMode), CFG_MODE_MIN, CFG_MODE_MAX);
|
||||
X.Entries[i].LastFilterIdx := EnsureRange(JI(EObj, 'last_filt', X.Entries[i].LastFilterIdx), 0, 9);
|
||||
X.Entries[i].LastFMSQOn := JB(EObj, 'last_fmsq_on', X.Entries[i].LastFMSQOn);
|
||||
X.Entries[i].LastFMSQLevel := EnsureRange(JI(EObj, 'last_fmsq_lvl', X.Entries[i].LastFMSQLevel), 0, 100);
|
||||
@@ -1908,7 +1926,8 @@ begin
|
||||
n := Length(P.Pans[id].Slices);
|
||||
SetLength(P.Pans[id].Slices, n+1);
|
||||
P.Pans[id].Slices[n].TargetHz := JD(SliceObj, 'target_hz', 0.0);
|
||||
P.Pans[id].Slices[n].Mode := JI(SliceObj, 'mode', 0);
|
||||
P.Pans[id].Slices[n].Mode := EnsureRange(
|
||||
JI(SliceObj, 'mode', MODE_LSB), CFG_MODE_MIN, CFG_MODE_MAX);
|
||||
P.Pans[id].Slices[n].FilterLo := JI(SliceObj, 'filter_lo', -1500);
|
||||
P.Pans[id].Slices[n].FilterHi := JI(SliceObj, 'filter_hi', 1500);
|
||||
P.Pans[id].Slices[n].AGC := JI(SliceObj, 'agc', 1);
|
||||
|
||||
Reference in New Issue
Block a user