diff --git a/MainForm.pas b/MainForm.pas index 334d0a4..80682d6 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -62,43 +62,18 @@ const BAND_COUNT = 11; MODE_COUNT = 8; - FILT_COUNT = 10; - - // Группы фильтров по типу модуляции - // SSB: LSB/USB + // Полосы/дефолты фильтров (FILT_COUNT, FILT_*_BW, FILT_*_DEF, FILT_FM_*) + // перенесены в Settings.pas — нужны TRadioController. Здесь остаются только + // UI-подписи кнопок (NAMES). FILT_SSB_NAMES: array[0..FILT_COUNT-1] of string = ('5.0k','4.4k','3.8k','3.3k','2.9k','2.7k','2.4k','2.1k','1.8k','1.0k'); - FILT_SSB_BW: array[0..FILT_COUNT-1] of Integer = - (5000, 4400, 3800, 3300, 2900, 2700, 2400, 2100, 1800, 1000); - FILT_SSB_DEF = 5; // 2.7k - - // CW: CWL/CWU FILT_CW_NAMES: array[0..FILT_COUNT-1] of string = ('1.0k','800','600','500','400','250','150','100','50','25'); - FILT_CW_BW: array[0..FILT_COUNT-1] of Integer = - (1000, 800, 600, 500, 400, 250, 150, 100, 50, 25); - FILT_CW_DEF = 3; // 500 - - // DSB FILT_DSB_NAMES: array[0..FILT_COUNT-1] of string = ('16k','12k','10k','8.0k','6.6k','5.2k','4.0k','3.1k','2.9k','2.4k'); - FILT_DSB_BW: array[0..FILT_COUNT-1] of Integer = - (16000, 12000, 10000, 8000, 6600, 5200, 4000, 3100, 2900, 2400); - FILT_DSB_DEF = 3; // 8.0k - - // AM/SAM FILT_AM_NAMES: array[0..FILT_COUNT-1] of string = ('20k','18k','16k','12k','10k','9.0k','8.0k','7.0k','6.0k','5.0k'); - FILT_AM_BW: array[0..FILT_COUNT-1] of Integer = - (20000, 18000, 16000, 12000, 10000, 9000, 8000, 7000, 6000, 5000); - FILT_AM_DEF = 4; // 10k - - // FM: NFM (2.5 kHz deviation / 11 kHz BW) and FM (5.0 kHz deviation / 16 kHz BW) - FILT_FM_COUNT = 2; FILT_FM_NAMES: array[0..1] of string = ('NFM', 'FM'); - FILT_FM_BW: array[0..1] of Integer = (11000, 16000); - FILT_FM_DEV: array[0..1] of Double = (2500.0, 5000.0); - FILT_FM_DEF = 0; // NFM // CTCSS tones (38 standard tones, no None — toggle via CTCSS button) // CTCSS_COUNT и CTCSS_TONES перенесены в FMRepeater (нужны TRadioController). @@ -440,7 +415,6 @@ type function MakeBandSettings: TBandSettings; procedure FreqDispBChanged(Sender: TObject; NewFreq: Int64); procedure BtnBandClick(Sender: TObject); - procedure ApplyModeFilter; procedure BtnModeClick(Sender: TObject); procedure BtnFilterClick(Sender: TObject); procedure BtnCTunClick(Sender: TObject); @@ -978,7 +952,7 @@ begin FController.FFilter := B.FilterIdx; FController.FFilterBW := B.FilterBW; UpdateFilterButtons; // обновляет кнопки фильтра - ApplyModeFilter; // применяет Lo/Hi в WDSP с учётом нового FController.FMode + FController.ApplyModeFilter; // применяет Lo/Hi в WDSP с учётом нового FController.FMode // --- AGC --- FController.FAGCMode := B.AGCMode; @@ -1432,6 +1406,17 @@ begin rfNB: UpdateNBButton; rfSNB: UpdateSNBButton; rfANF: UpdateANFButton; + rfMode: + begin + for i := 0 to MODE_COUNT - 1 do StyleButton(BtnMode[i], i = FController.FMode); + UpdateFilterButtons; // подписи/дефолт фильтра + FM-панели под режим + SyncSpecViewFreq; // иначе полоса фильтра рисуется под старый режим + end; + rfFilter: + begin + for i := 0 to FILT_COUNT - 1 do StyleButton(BtnFilter[i], i = FController.FFilter); + SyncSpecViewFreq; + end; rfAGCMode: for i := 0 to 4 do StyleButton(BtnAGCMode[i], i = FController.FAGCMode); rfVolume: @@ -4249,7 +4234,7 @@ begin begin FController.FDSPEngine.SetMode(FController.FMode); FController.FDSPEngine.SetVolume(FController.FVolume / 100.0); - ApplyModeFilter; + FController.ApplyModeFilter; ApplyNoiseFilterButtonsToDSP; // ChangeSampleRate пересоздаёт WDSP-канал — восстанавливаем все настройки FController.FDSPEngine.SetAGCTop(FController.FAGCTop); @@ -4282,7 +4267,7 @@ begin SendDUCSpecificFromSettings; // Применяем TX-цепь (фильтр, mic gain, EQ, leveler, ALC, comp, ...). ApplyTXSettingsToDSP; - ApplyModeFilter; + FController.ApplyModeFilter; // Принудительно обновляем AGC линии — гарантированно после всех SetAGC вызовов if FController.FWDSPReady then @@ -5209,76 +5194,18 @@ begin RestoreBand(FController.FCurrentBand); end; -procedure TMainForm.ApplyModeFilter; -var - Lo, Hi, Half: Integer; -begin - Half := FController.FFilterBW div 2; - case FController.FMode of - 0: begin Lo := -FController.FFilterBW; Hi := -100; end; // LSB - 1: begin Lo := 100; Hi := FController.FFilterBW; end; // USB - 2: begin Lo := -Half; Hi := Half; end; // DSB - 3: begin Lo := -Half; Hi := Half; end; // CWL - 4: begin Lo := -Half; Hi := Half; end; // CWU - 5: begin Lo := -Half; Hi := Half; end; // FM - 6: begin Lo := -Half; Hi := Half; end; // AM - 7: begin Lo := -Half; Hi := Half; end; // SAM - else Lo := -Half; Hi := Half; - end; - if FController.FWDSPReady then - begin - FController.FDSPEngine.SetFilter(Lo, Hi); - FController.FDSPEngine.SetTXFilter(Lo, Hi); - if FController.FMode = MODE_FM then - begin - FController.FDSPEngine.SetRXFMDeviation(FController.FFMDeviation); - FController.FDSPEngine.SetTXFMParams(FController.FFMDeviation, FController.FTXSettings.FMLowCut, - FController.FTXSettings.FMHighCut, FController.FTXSettings.FMEmphPosition); - FController.FDSPEngine.SetFMSquelch(FController.FFMSQOn, FController.FFMSQLevel); - end - else - FController.FDSPEngine.SetFMSquelch(False, 0); - end; -end; - procedure TMainForm.BtnModeClick(Sender: TObject); -var - i, N: Integer; begin - N := (Sender as TFlatButton).Tag; - FController.FMode := N; - for i := 0 to MODE_COUNT - 1 do StyleButton(BtnMode[i], i = FController.FMode); - if FController.FWDSPReady then - begin - FController.FDSPEngine.SetMode(N); - // Если TUN активен — пересчитываем знак частоты под новый режим - if FController.FTuning then - FController.FDSPEngine.SetTXTone(True, FController.FTXSettings.TUNFreq, 1.0); - end; - UpdateFilterButtons; // обновляем подписи и дефолт фильтра под новый режим - ApplyModeFilter; - SyncSpecViewFreq; // FSpecView.Mode/FilterBW — иначе полоса рисуется под старый режим + // Логика (FMode, дефолтный фильтр, DSP SetMode/TUN/ApplyModeFilter, band cache) + // — в контроллере; рендер кнопок/фильтра/спектра — в OnControllerState(rfMode). + FController.SetMode((Sender as TFlatButton).Tag); end; procedure TMainForm.BtnFilterClick(Sender: TObject); -var - i, N: Integer; begin - N := (Sender as TFlatButton).Tag; - FController.FFilter := N; - case FController.FMode of - 0, 1: FController.FFilterBW := FILT_SSB_BW[N]; - 2: FController.FFilterBW := FILT_DSB_BW[N]; - 3, 4: FController.FFilterBW := FILT_CW_BW[N]; - 5: begin - FController.FFilterBW := FILT_FM_BW[N]; - FController.FFMDeviation := FILT_FM_DEV[N]; - end; - else FController.FFilterBW := FILT_AM_BW[N]; - end; - for i := 0 to FILT_COUNT - 1 do StyleButton(BtnFilter[i], i = FController.FFilter); - ApplyModeFilter; - SyncSpecViewFreq; + // Логика (FFilter/FFilterBW по таблицам режима, ApplyModeFilter, band cache) + // — в контроллере; рендер — в OnControllerState(rfFilter). + FController.SetFilterIdx((Sender as TFlatButton).Tag); end; // --------------------------------------------------------------------------- @@ -5558,7 +5485,7 @@ begin if FController.FTuning then FController.FDSPEngine.SetTXTone(True, FController.FTXSettings.TUNFreq, 1.0); end; UpdateFilterButtons; - ApplyModeFilter; + FController.ApplyModeFilter; SyncSpecViewFreq; end; @@ -6079,7 +6006,7 @@ begin if FController.FWDSPReady then begin FController.FDSPEngine.SetMode(FController.FMode); - ApplyModeFilter; + FController.ApplyModeFilter; end; SyncSpecViewFreq; if Assigned(FVfoOverlay) and FVfoOverlay.Visible then @@ -6154,7 +6081,7 @@ begin begin FController.FDSPEngine.SetMode(FController.FMode); FController.FDSPEngine.SetVolume(FController.FVolume / 100.0); - ApplyModeFilter; + FController.ApplyModeFilter; ApplyNoiseFilterButtonsToDSP; // ChangeSampleRate пересоздаёт WDSP-канал — восстанавливаем AGC FController.FDSPEngine.SetAGCTop(FController.FAGCTop); @@ -6222,7 +6149,7 @@ begin for i := 0 to MODE_COUNT - 1 do StyleButton(BtnMode[i], i = FController.FMode); if FController.FWDSPReady then FController.FDSPEngine.SetMode(FController.FMode); UpdateFilterButtons; - ApplyModeFilter; + FController.ApplyModeFilter; SyncSpecViewFreq; FController.FBandCache[FController.FCurrentBand].Mode := FController.FMode; end; @@ -6259,7 +6186,7 @@ begin else FController.FFilterBW := FILT_AM_BW[Idx]; end; for j := 0 to FILT_COUNT-1 do StyleButton(BtnFilter[j], j = FController.FFilter); - ApplyModeFilter; + FController.ApplyModeFilter; SyncSpecViewFreq; FController.FBandCache[FController.FCurrentBand].FilterBW := FController.FFilterBW; end; @@ -6285,7 +6212,7 @@ begin FController.FFilter := best; if FController.FMode = 5 then FController.FFMDeviation := FILT_FM_DEV[best]; for j := 0 to FILT_COUNT-1 do StyleButton(BtnFilter[j], j = FController.FFilter); - ApplyModeFilter; + FController.ApplyModeFilter; SyncSpecViewFreq; FController.FBandCache[FController.FCurrentBand].FilterBW := FController.FFilterBW; end; @@ -7069,7 +6996,7 @@ begin for i := 0 to MODE_COUNT - 1 do StyleButton(BtnMode[i], i = FController.FMode); if FController.FWDSPReady then FController.FDSPEngine.SetMode(FController.FMode); UpdateFilterButtons; // показывает/скрывает FM-панели, обновляет SQL UI - ApplyModeFilter; + FController.ApplyModeFilter; FController.FFMCTCSSOn := E.LastCTCSSOn; FController.FFMCTCSSAutoActive := E.LastCTCSSAutoActive; if BtnFMCTCSS <> nil then StyleButton(BtnFMCTCSS, FController.FFMCTCSSOn); diff --git a/RadioController.pas b/RadioController.pas index cb66eca..2a812d9 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -109,6 +109,7 @@ type FOnStateChanged: TRadioStateEvent; procedure Changed(Field: TRadioField); procedure ApplyAGCToEngine; // применяет FAGCMode к WDSP (единый маппинг) + procedure ApplyModeDefaults; // дефолтный фильтр/девиация под текущий FMode public // ============================================================ // ПУБЛИЧНЫЕ ПОЛЯ (миграционные — имена совпадают с TMainForm). @@ -210,6 +211,10 @@ type function XvtrTranslate(VisibleHz: Double): Double; function ActiveTXFreqHz: Double; + // Применяет текущие FMode/FFilterBW/FM-параметры к DSP (RX/TX фильтр, + // FM-девиация, squelch). Вызывается командами и UI-путями смены режима. + procedure ApplyModeFilter; + // ==================================================================== // КОМАНДЫ — единый API для GUI / Web / CAT / Arduino. // Фаза 1: обновляют поле + шлют событие; логика движка — TODO-wiring. @@ -372,6 +377,51 @@ begin end; end; +procedure TRadioController.ApplyModeFilter; +var + Lo, Hi, Half: Integer; +begin + Half := FFilterBW div 2; + case FMode of + 0: begin Lo := -FFilterBW; Hi := -100; end; // LSB + 1: begin Lo := 100; Hi := FFilterBW; end; // USB + else Lo := -Half; Hi := Half; // DSB/CW/FM/AM/SAM + end; + if FWDSPReady and Assigned(FDSPEngine) then + begin + FDSPEngine.SetFilter(Lo, Hi); + FDSPEngine.SetTXFilter(Lo, Hi); + if FMode = MODE_FM then + begin + FDSPEngine.SetRXFMDeviation(FFMDeviation); + FDSPEngine.SetTXFMParams(FFMDeviation, FTXSettings.FMLowCut, + FTXSettings.FMHighCut, FTXSettings.FMEmphPosition); + FDSPEngine.SetFMSquelch(FFMSQOn, FFMSQLevel); + end + else + FDSPEngine.SetFMSquelch(False, 0); + end; +end; + +// Выбирает дефолтный фильтр (индекс + полоса + FM-девиация) под текущий FMode. +// Зеркалит state-часть UI UpdateFilterButtons, чтобы смена режима была +// корректной и без UI (headless). FM сохраняет текущий NFM/WFM, прочие — дефолт. +procedure TRadioController.ApplyModeDefaults; +begin + case FMode of + MODE_FM: + begin + if FFilter > 1 then FFilter := FILT_FM_DEF; + FFilterBW := FILT_FM_BW[FFilter]; + FFMDeviation := FILT_FM_DEV[FFilter]; + end; + 0, 1: begin FFilter := FILT_SSB_DEF; FFilterBW := FILT_SSB_BW[FFilter]; end; + 2: begin FFilter := FILT_DSB_DEF; FFilterBW := FILT_DSB_BW[FFilter]; end; + 3, 4: begin FFilter := FILT_CW_DEF; FFilterBW := FILT_CW_BW[FFilter]; end; + else begin FFilter := FILT_AM_DEF; FFilterBW := FILT_AM_BW[FFilter]; end; + end; +end; + // ===================================================================== // Команды (Фаза 1 — каркас). Полная логика переносится из TMainForm. // ===================================================================== @@ -405,10 +455,38 @@ procedure TRadioController.VfoBCopyA; begin FVfoB := FVfoA; Changed(rfVfoB); { TODO wiring } end; procedure TRadioController.SetMode(M: Integer); -begin FMode := M; Changed(rfMode); { TODO wiring: ApplyModeFilter } end; +begin + FMode := M; + ApplyModeDefaults; // дефолтный фильтр/девиация под режим + FBandCache[FCurrentBand].Mode := FMode; + if FWDSPReady and Assigned(FDSPEngine) then + begin + FDSPEngine.SetMode(FMode); + // Если TUN активен — пересчитываем знак частоты под новый режим + if FTuning then FDSPEngine.SetTXTone(True, FTXSettings.TUNFreq, 1.0); + end; + ApplyModeFilter; + Changed(rfMode); +end; procedure TRadioController.SetFilterIdx(Idx: Integer); -begin FFilter := Idx; Changed(rfFilter); { TODO wiring } end; +begin + FFilter := Idx; + case FMode of + 0, 1: FFilterBW := FILT_SSB_BW[Idx]; + 2: FFilterBW := FILT_DSB_BW[Idx]; + 3, 4: FFilterBW := FILT_CW_BW[Idx]; + MODE_FM: + begin + FFilterBW := FILT_FM_BW[Idx]; + FFMDeviation := FILT_FM_DEV[Idx]; + end; + else FFilterBW := FILT_AM_BW[Idx]; + end; + FBandCache[FCurrentBand].FilterBW := FFilterBW; + ApplyModeFilter; + Changed(rfFilter); +end; procedure TRadioController.SetFilterBW(BWHz: Integer); begin FFilterBW := BWHz; Changed(rfFilterBW); { TODO wiring } end; diff --git a/Settings.pas b/Settings.pas index ff35110..c724984 100644 --- a/Settings.pas +++ b/Settings.pas @@ -23,6 +23,27 @@ const CFG_BAND_DEFAULT_MODE: array[0..CFG_BAND_COUNT-1] of Integer = ( 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1); + // Полосы фильтров по типу модуляции (Гц) + дефолтные индексы. Нужны + // TRadioController для headless-выбора фильтра при смене режима; UI-подписи + // (FILT_*_NAMES) остаются в MainForm. NAMES-массивы там используют FILT_COUNT. + FILT_COUNT = 10; + FILT_SSB_BW: array[0..FILT_COUNT-1] of Integer = + (5000, 4400, 3800, 3300, 2900, 2700, 2400, 2100, 1800, 1000); + FILT_SSB_DEF = 5; // 2.7k + FILT_CW_BW: array[0..FILT_COUNT-1] of Integer = + (1000, 800, 600, 500, 400, 250, 150, 100, 50, 25); + FILT_CW_DEF = 3; // 500 + FILT_DSB_BW: array[0..FILT_COUNT-1] of Integer = + (16000, 12000, 10000, 8000, 6600, 5200, 4000, 3100, 2900, 2400); + FILT_DSB_DEF = 3; // 8.0k + FILT_AM_BW: array[0..FILT_COUNT-1] of Integer = + (20000, 18000, 16000, 12000, 10000, 9000, 8000, 7000, 6000, 5000); + FILT_AM_DEF = 4; // 10k + FILT_FM_COUNT = 2; + FILT_FM_BW: array[0..1] of Integer = (11000, 16000); + FILT_FM_DEV: array[0..1] of Double = (2500.0, 5000.0); + FILT_FM_DEF = 0; // NFM + type TBandSettings = record VfoA: Double;