Phase 3 (batch 10): route sample-rate/span change through controller

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 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-04 20:03:59 +03:00
co-authored by Claude Opus 4.8
parent 967e7cb7b1
commit 6edcf8bdf4
2 changed files with 56 additions and 45 deletions
+14 -44
View File
@@ -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;
// ===========================================================================