Phase 3 (batch 3): route Volume, AGC-top, WfAGC/WfNF through controller

First sliders through the controller, exercising the FSyncingFromController
re-entrancy guard:
- SetVolume/SetAGCTop clamp, apply to the DSP engine, update band cache,
  and fire OnStateChanged. SetAGCTop reuses ApplyAGCToEngine (the unified
  AGC index->enum mapping), fixing the same bad TWDSPAGCMode(index) cast
  that TrkAGCChange/SyncWebAGCTop used when re-applying AGC on level change.
- OnControllerState updates the slider/label/spectrum (rfAGCTop also
  refreshes the FSpecView AGC line, now consistent for web-initiated
  changes too) and the FSpecView waterfall flags (rfWfAGC/rfWfNF).
- TrkVolumeChange/TrkAGCChange (guarded), SyncWebVolume/AGCTop/WfAGC/WfNF,
  and ApplyWfAGCNF all call the commands.

Builds clean (cocoa).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-04 14:58:03 +03:00
co-authored by Claude Opus 4.8
parent f76533f209
commit b3e4360a5d
2 changed files with 48 additions and 39 deletions
+24 -5
View File
@@ -108,6 +108,7 @@ type
FOnInvoke: TUIInvokeEvent;
FOnStateChanged: TRadioStateEvent;
procedure Changed(Field: TRadioField);
procedure ApplyAGCToEngine; // применяет FAGCMode к WDSP (единый маппинг)
public
// ============================================================
// ПУБЛИЧНЫЕ ПОЛЯ (миграционные — имена совпадают с TMainForm).
@@ -381,27 +382,45 @@ begin FFilter := Idx; Changed(rfFilter); { TODO wiring } end;
procedure TRadioController.SetFilterBW(BWHz: Integer);
begin FFilterBW := BWHz; Changed(rfFilterBW); { TODO wiring } end;
procedure TRadioController.SetAGCMode(M: Integer);
procedure TRadioController.ApplyAGCToEngine;
const
// UI-индекс 0..4 (FAST/MED/SLOW/LONG/OFF) -> WDSP enum. Единый маппинг для
// всех фронтендов (раньше web ошибочно кастовал индекс прямо в enum).
// всех фронтендов (раньше web/слайдер ошибочно кастовали индекс прямо в enum).
AGCModes: array[0..4] of TWDSPAGCMode = (agcFast, agcMedium, agcSlow, agcLong, agcOff);
begin
if FWDSPReady and Assigned(FDSPEngine) and (FAGCMode >= 0) and (FAGCMode <= 4) then
FDSPEngine.SetAGC(AGCModes[FAGCMode], 50.0);
end;
procedure TRadioController.SetAGCMode(M: Integer);
begin
if (M < 0) or (M > 4) then Exit;
FAGCMode := M;
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetAGC(AGCModes[M], 50.0);
ApplyAGCToEngine;
FBandCache[FCurrentBand].AGCMode := FAGCMode;
Changed(rfAGCMode);
end;
procedure TRadioController.SetAGCTop(DB: Integer);
begin FAGCTop := DB; Changed(rfAGCTop); { TODO wiring } end;
begin
if DB < 20 then DB := 20 else if DB > 120 then DB := 120;
FAGCTop := DB;
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetAGCTop(FAGCTop);
ApplyAGCToEngine; // ре-применяем режим с новым уровнем
FBandCache[FCurrentBand].AGCTop := FAGCTop;
Changed(rfAGCTop);
end;
procedure TRadioController.AGCTopBy(Delta: Integer);
begin SetAGCTop(FAGCTop + Delta); end;
procedure TRadioController.SetVolume(V: Integer);
begin FVolume := V; Changed(rfVolume); { TODO wiring: FDSPEngine.SetVolume } end;
begin
if V < 0 then V := 0 else if V > 100 then V := 100;
FVolume := V;
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetVolume(FVolume / 100.0);
Changed(rfVolume);
end;
procedure TRadioController.VolumeBy(Delta: Integer);
begin SetVolume(FVolume + Delta); end;