From 6edcf8bdf442d1b5ed5d2567c7f4977a455f0a4e Mon Sep 17 00:00:00 2001 From: Uladzimir Karpenka Date: Thu, 4 Jun 2026 20:03:59 +0300 Subject: [PATCH] Phase 3 (batch 10): route sample-rate/span change through controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Span ≡ sample rate in this app; OnSampleRateSelect (overlay dropdown) is a fairly self-contained heavy-class item. - TRadioController.SetSampleRate(Hz): sets FSampleRate/FSpanHz + band cache, recreates the WDSP channel (ChangeSampleRate = Close+FlushQueue+Open), pushes the new DDC rate to the radio, and restores full DSP state (mode/volume/filter/NR/NB/SNB/ANF/AGC-top/AGC/shift). - Fixes the same latent AGC cast bug as earlier batches: the inline restore used SetAGC(TWDSPAGCMode(FAGCMode)) (index cast); now goes through the shared ApplyAGCToEngine mapping. MainForm: OnSampleRateSelect is a thin wrapper (global-settings SaveGlobal stays in UI). OnControllerState(rfSampleRate) renders the rate overlay and recomputes AGC display lines (UpdateAGCLines needs UI spectrum width). Dropped the cosmetic ProcessMessages pre-paint. Startup paths that set FSampleRate directly + RecreateDSPEngine left as-is. Builds clean, links. Co-Authored-By: Claude Opus 4.8 --- MainForm.pas | 58 +++++++++++---------------------------------- RadioController.pas | 43 ++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 45 deletions(-) diff --git a/MainForm.pas b/MainForm.pas index 008abea..6d3580b 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -1467,6 +1467,15 @@ begin end; rfFMCTCSSTone: if FCTCSSDropDown <> nil then FCTCSSDropDown.SetItemIndex(FController.FFMCTCSSToneIdx); + rfSampleRate: + begin + if Assigned(FSampleRateOverlay) then + FSampleRateOverlay.SetCurrentRate(FController.FSampleRate); + // ChangeSampleRate пересоздал WDSP-канал — пересчёт AGC-линий под + // актуальную ширину спектра (UI-зависимая величина). + if FController.FWDSPReady then + FController.FDSPEngine.UpdateAGCLines(FSpectrumWidth); + end; rfFMRpt: begin if BtnFMRptMinus <> nil then @@ -6008,53 +6017,14 @@ begin end; procedure TMainForm.OnSampleRateSelect(SampleRate: Integer); -var - NewRate: Integer; - DDCRate: Word; begin - NewRate := SampleRate; - if NewRate = FController.FSampleRate then Exit; - - FController.FSampleRate := NewRate; - FController.FSpanHz := NewRate; - DDCRate := NewRate div 1000; - - if Assigned(FSampleRateOverlay) then - FSampleRateOverlay.SetCurrentRate(NewRate); - Application.ProcessMessages; - - FController.FBandCache[FController.FCurrentBand].SpanHz := FController.FSpanHz; // для обратной совместимости - // SampleRate — глобальный: сохраняем в global settings + if SampleRate = FController.FSampleRate then Exit; + // Движок (пересоздание WDSP-канала, DDC-rate, восстановление DSP) — в + // контроллере; рендер overlay + AGC-линий — в OnControllerState(rfSampleRate). + FController.SetSampleRate(SampleRate); + // SampleRate глобальный — сохраняем в global settings. if FController.FDevConnected then FController.FSettings.SaveGlobal(FController.FDevMAC, MakeGlobalSettings); - - // 1. Останавливаем WDSP и сбрасываем очередь старых пакетов - if FController.FWDSPReady then - begin - FController.FWDSPReady := False; - FController.FDSPEngine.ChangeSampleRate(NewRate); // Close + FlushQueue + Open - end; - - // 2. Отправляем новый rate трансиверу - // (после остановки DSP — новые пакеты сразу идут с правильным rate) - if FController.FNetwork.Connected then - FController.FNetwork.ConfigureDDCs(1, DDCRate, 0, FController.FDitherEnabled, FController.FRandomEnabled); - - // 3. Восстанавливаем настройки DSP - FController.FWDSPReady := FController.FDSPEngine.Initialized; - if FController.FWDSPReady then - begin - FController.FDSPEngine.SetMode(FController.FMode); - FController.FDSPEngine.SetVolume(FController.FVolume / 100.0); - FController.ApplyModeFilter; - ApplyNoiseFilterButtonsToDSP; - // ChangeSampleRate пересоздаёт WDSP-канал — восстанавливаем AGC - FController.FDSPEngine.SetAGCTop(FController.FAGCTop); - FController.FDSPEngine.SetAGC(TWDSPAGCMode(FController.FAGCMode), 50.0); - FController.FDSPEngine.UpdateAGCLines(FSpectrumWidth); - if FController.FNetwork.Connected then - FController.FDSPEngine.SetShift(FController.FVfoA - FController.FCenterFreq); - end; end; // =========================================================================== diff --git a/RadioController.pas b/RadioController.pas index ebc0ba1..48f55d3 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -589,7 +589,48 @@ procedure TRadioController.SetSpan(Hz: Integer); begin FSpanHz := Hz; Changed(rfSpan); { TODO wiring } end; procedure TRadioController.SetSampleRate(Hz: Integer); -begin FSampleRate := Hz; Changed(rfSampleRate); { TODO wiring: RecreateDSPEngine } end; +// Смена частоты дискретизации DDC. В этом приложении span ≡ sample rate. +// Несёт: пересоздание WDSP-канала (Close+FlushQueue+Open), новый rate в +// трансивер и полное восстановление DSP-состояния. Сохранение в global +// settings + рендер overlay/AGC-линий остаются в UI (OnControllerState). +begin + if (Hz <= 0) or (Hz = FSampleRate) then Exit; + FSampleRate := Hz; + FSpanHz := Hz; + FBandCache[FCurrentBand].SpanHz := FSpanHz; // для обратной совместимости + + // 1. Останавливаем WDSP и меняем rate (Close + FlushQueue + Open). + if FWDSPReady and Assigned(FDSPEngine) then + begin + FWDSPReady := False; + FDSPEngine.ChangeSampleRate(Hz); + end; + + // 2. Новый rate трансиверу (после остановки DSP — пакеты сразу с верным rate). + if Assigned(FNetwork) and FNetwork.Connected then + FNetwork.ConfigureDDCs(1, Hz div 1000, 0, FDitherEnabled, FRandomEnabled); + + // 3. Восстанавливаем DSP-состояние (ChangeSampleRate пересоздал канал). + if Assigned(FDSPEngine) then + begin + FWDSPReady := FDSPEngine.Initialized; + if FWDSPReady then + begin + FDSPEngine.SetMode(FMode); + FDSPEngine.SetVolume(FVolume / 100.0); + ApplyModeFilter; + FDSPEngine.SetNRMode(FNRMode); + FDSPEngine.SetNBMode(FNBMode); + FDSPEngine.SetSNB(FSNB); + FDSPEngine.SetANF(FANF); + FDSPEngine.SetAGCTop(FAGCTop); + ApplyAGCToEngine; // единый маппинг (раньше здесь был ошибочный каст индекса) + if Assigned(FNetwork) and FNetwork.Connected then + FDSPEngine.SetShift(FVfoA - FCenterFreq); + end; + end; + Changed(rfSampleRate); +end; procedure TRadioController.SetCTun(On_: Boolean); begin