mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Phase 5 (D2): move spectrum/waterfall raw frames into the controller
OnSpectrumReady/OnWaterfallReady move into TRadioController. The controller now owns the last spectrum/waterfall frame (FSpectrumBuf/FWaterfallBuf) for the web mirror and emits raw pixels via OnSpectrumData/OnWaterfallData. MainForm subscribes for FSpecView rendering (+ waterfall scroll decimation, a UI concern). TWebAdapter.PushState now reads the frame from the controller (no buffer params). Behavior-preserving; removes the last spectrum/waterfall data-path coupling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7c8fd298ae
commit
f122079b83
@@ -85,6 +85,9 @@ type
|
||||
TAudioConsumeEvent = function(const Left, Right: array of Single;
|
||||
Count: Integer): Boolean of object;
|
||||
|
||||
// Сырьё спектра/водопада наружу (фронтенды рисуют). Вызывается из DSP-потока.
|
||||
TPixelDataEvent = procedure(const Pixels: array of Single; Count: Integer) of object;
|
||||
|
||||
// Снимок состояния для синхронизации нового фронтенда (Arduino/Web на connect).
|
||||
TRadioSnapshot = record
|
||||
VfoA, VfoB, CenterFreq, SpanHz: Double;
|
||||
@@ -117,6 +120,8 @@ type
|
||||
FOnStateChanged: TRadioStateEvent;
|
||||
FOnAfterTune: TThreadMethod; // пост-тюн хук: канал-оркестрация после SetVfoA
|
||||
FOnAudioConsume: TAudioConsumeEvent; // web-перехват RX-аудио (если активен клиент)
|
||||
FOnSpectrumData: TPixelDataEvent; // сырьё спектра наружу (UI рисует FSpecView)
|
||||
FOnWaterfallData: TPixelDataEvent; // сырьё водопада наружу (UI: децимация+рендер)
|
||||
procedure Changed(Field: TRadioField);
|
||||
procedure ApplyAGCToEngine; // применяет FAGCMode к WDSP (единый маппинг)
|
||||
procedure ApplyModeDefaults; // дефолтный фильтр/девиация под текущий FMode
|
||||
@@ -130,6 +135,15 @@ type
|
||||
// OnStateChanged. Прямая запись извне — временная мера на время Фазы 1.
|
||||
// ============================================================
|
||||
|
||||
// ---- Последний кадр спектра/водопада (пиксели от WDSP) ----
|
||||
// Снимок для исходящего web-зеркала (PushState читает напрямую). Пишется из
|
||||
// DSP-потока в OnSpectrumReady/OnWaterfallReady; читается из GUI-таймера —
|
||||
// та же толерантная гонка, что и раньше (косметика пикселей).
|
||||
FSpectrumBuf: array[0..1023] of Single;
|
||||
FWaterfallBuf: array[0..1023] of Single;
|
||||
FSpectrumBufCount: Integer;
|
||||
FWaterfallBufCount: Integer;
|
||||
|
||||
// ---- Движки (владение: см. шапку юнита) ----
|
||||
FNetwork: THPSDRNetwork;
|
||||
FDSPEngine: TWDSPEngine;
|
||||
@@ -273,6 +287,8 @@ type
|
||||
// Чистая обработка данных без UI; навешиваются на FNetwork/FDSPEngine
|
||||
// вызывающим (GUI или демон) после CreateEngines.
|
||||
procedure OnAudioReady(const Left, Right: array of Single; Count: Integer);
|
||||
procedure OnSpectrumReady(const Pixels: array of Single; Count: Integer);
|
||||
procedure OnWaterfallReady(const Pixels: array of Single; Count: Integer);
|
||||
procedure OnMicPacket(const Data: TMicDataPacket);
|
||||
function PullSoundCardMic(MaxN: Integer): Integer;
|
||||
procedure OnDDCIQ(DDCIndex: Integer; const Data: TDDCIQPacket);
|
||||
@@ -438,6 +454,8 @@ type
|
||||
// чтобы любой путь тюнинга (desktop/web/CAT/энкодер) был канал-aware headless.
|
||||
property OnAfterTune: TThreadMethod read FOnAfterTune write FOnAfterTune;
|
||||
property OnAudioConsume: TAudioConsumeEvent read FOnAudioConsume write FOnAudioConsume;
|
||||
property OnSpectrumData: TPixelDataEvent read FOnSpectrumData write FOnSpectrumData;
|
||||
property OnWaterfallData: TPixelDataEvent read FOnWaterfallData write FOnWaterfallData;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -454,6 +472,7 @@ begin
|
||||
FVolume := 70; FDrivePercent := 50; FDriveLevel := 0; FAtten := 0;
|
||||
FCenterFreq := FVfoA; FSpanHz := 192000; FSampleRate := 192000;
|
||||
FCurrentBand := 5; FCurrentXvtr := -1;
|
||||
FSpectrumBufCount := 1024; FWaterfallBufCount := 1024;
|
||||
FPAMaxPower := 100.0;
|
||||
FWfAGCEnabled := True; FDitherEnabled := True; FRandomEnabled := True;
|
||||
FFMStepOn := True;
|
||||
@@ -754,6 +773,36 @@ begin
|
||||
FAudioOut.Write(Left, Right, Count);
|
||||
end;
|
||||
|
||||
procedure TRadioController.OnSpectrumReady(const Pixels: array of Single;
|
||||
Count: Integer);
|
||||
// DSP-поток: сохраняем последний кадр для web-зеркала и отдаём сырьё наружу
|
||||
// (UI рисует FSpecView). Децимации у спектра нет.
|
||||
var
|
||||
i, N: Integer;
|
||||
begin
|
||||
N := Count;
|
||||
if N > Length(FSpectrumBuf) then N := Length(FSpectrumBuf);
|
||||
for i := 0 to N - 1 do
|
||||
FSpectrumBuf[i] := Pixels[i];
|
||||
FSpectrumBufCount := N;
|
||||
if Assigned(FOnSpectrumData) then FOnSpectrumData(Pixels, Count);
|
||||
end;
|
||||
|
||||
procedure TRadioController.OnWaterfallReady(const Pixels: array of Single;
|
||||
Count: Integer);
|
||||
// DSP-поток: web-зеркало получает КАЖДЫЙ кадр; децимация рендера водопада —
|
||||
// забота фронтенда (OnWaterfallData).
|
||||
var
|
||||
i, N: Integer;
|
||||
begin
|
||||
N := Count;
|
||||
if N > Length(FWaterfallBuf) then N := Length(FWaterfallBuf);
|
||||
for i := 0 to N - 1 do
|
||||
FWaterfallBuf[i] := Pixels[i];
|
||||
FWaterfallBufCount := N;
|
||||
if Assigned(FOnWaterfallData) then FOnWaterfallData(Pixels, Count);
|
||||
end;
|
||||
|
||||
procedure TRadioController.OnMicPacket(const Data: TMicDataPacket);
|
||||
// HW mic-стрим уходит в WDSP только если выбран источник Radio; иначе сэмплы
|
||||
// игнорируются (mic берётся со звуковой карты).
|
||||
|
||||
Reference in New Issue
Block a user