Phase 5 (batch 22): move engine lifecycle into the controller

TRadioController now owns its engines: CreateEngines(ASampleRate) builds
FNetwork/FDSPEngine/FAudioOut/FAudioIn (and the constructor now owns
FSettings), FreeEngines closes and frees them, and Destroy calls
FreeEngines + frees FSettings. FormCreate replaces the four inline
T...Create calls with a single FController.CreateEngines (after the
startup sample rate is loaded, so FDSPEngine is still born at the right
rate) and keeps wiring the MainForm callbacks. FormDestroy keeps the
graceful Run=0 stop + Disconnect but drops the per-engine Close/Free and
FSettings.Free, which now happen in the controller's destructor. This is
a behaviour-preserving ownership move toward headless/daemon operation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-05 17:20:17 +03:00
co-authored by Claude Opus 4.8
parent 33c433ce5e
commit 8be98b72e1
2 changed files with 49 additions and 26 deletions
+39 -1
View File
@@ -203,6 +203,13 @@ type
constructor Create;
destructor Destroy; override;
// Lifecycle движков: создаёт FNetwork/FDSPEngine/FAudioOut/FAudioIn с
// заданным sample rate (вызывающий уже определил его из настроек). Колбэки
// движков навешивает вызывающий (GUI: методы MainForm; демон: свои). Парный
// FreeEngines закрывает и освобождает их; вызывается из Destroy.
procedure CreateEngines(ASampleRate: Integer);
procedure FreeEngines;
// Маршалинг команды в поток контроллера (GUI: TThread.Synchronize).
procedure Invoke(M: TThreadMethod);
@@ -343,6 +350,7 @@ implementation
constructor TRadioController.Create;
begin
inherited Create;
FSettings := TSettingsManager.Create; // владелец настроек (GUI и демон)
// Дефолты (дублируют TMainForm.FormCreate; в GUI перезапишутся, в демоне нужны).
FVfoA := 14200000; FVfoB := 7100000; FActiveVfo := 0;
FMode := 1; FFilter := 5; FFilterBW := 2700;
@@ -357,9 +365,39 @@ begin
FillChar(FDevMAC, SizeOf(FDevMAC), 0);
end;
procedure TRadioController.CreateEngines(ASampleRate: Integer);
// Создаёт движки в полях контроллера. Колбэки (OnAudio/OnSpectrum/OnHPStatus…)
// навешивает вызывающий после возврата — они указывают на UI/демон.
begin
FNetwork := THPSDRNetwork.Create;
// BufSize=512: латентность 512/48000 ≈ 10.7мс — допустимо для SDR; меньший
// буфер вдвое сокращает построение downsampler в OpenChannel RXA.
FDSPEngine := TWDSPEngine.Create(ASampleRate, 48000, 512);
// Audio out/in — объекты создаём сейчас, Open вызывается позже (после показа
// формы / при подключении устройства).
FAudioOut := TAudioOutput.Create(48000);
FAudioOut.OutputBufferSize := FSettings.LoadAudioBufferSize;
FAudioIn := TAudioInput.Create(48000);
end;
procedure TRadioController.FreeEngines;
begin
if Assigned(FNetwork) then
begin
if FNetwork.Connected then FNetwork.Disconnect;
FreeAndNil(FNetwork);
end;
if Assigned(FAudioOut) then begin FAudioOut.Close; FreeAndNil(FAudioOut); end;
if Assigned(FAudioIn) then begin FAudioIn.Close; FreeAndNil(FAudioIn); end;
if Assigned(FDSPEngine) then begin FDSPEngine.Close; FreeAndNil(FDSPEngine); end;
end;
destructor TRadioController.Destroy;
begin
// Фаза 1: движки освобождает MainForm. Здесь ничего не освобождаем.
FreeEngines;
FreeAndNil(FSettings);
inherited Destroy;
end;