feat(waterfall): палитры Inferno/Turbo + gamma, разрешение до 4096, HiDPI

- SPECTRUM_PIXELS 1024→4096 + настройка display_pixels (лимит точек
  анализатора, SetDisplayResLimit); web-зеркало остаётся 1024 —
  max-децимация в SnapshotPixels
- палитры водопада Classic/Inferno/Turbo + регулятор gamma (в LUT),
  настройки wf_palette/wf_gamma, страница Waterfall → группа Rendering
- GL-водопад переведён на общий LUT/AGC-уровни базового класса
  (убраны дубли ColorForDB/UpdateLevels)
- явные glViewport в GL-вьюхах умножаются на PixelScale (HiDPI),
  текстура водопада — в физической ширине

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 16:11:58 +03:00
co-authored by Claude Fable 5
parent 4733ddab58
commit 092a202f5f
10 changed files with 397 additions and 263 deletions
+42 -14
View File
@@ -281,6 +281,9 @@ type
FWfManualHigh: Double;
FWfManualLow: Double;
FWfAGCOffset: Double;
FWfPalette: Integer; // 0=Classic, 1=Inferno, 2=Turbo
FWfGamma: Double; // контраст палитры водопада
FDisplayPixels: Integer; // потолок точек анализатора
FSpecRefLevel: Double;
FSpecRange: Double;
FSpecGridStep: Double;
@@ -688,6 +691,7 @@ begin
FPAMaxPower := 100.0;
FPlutoTxMaxAttDb := -10.0; // ADI-дефолт: линейный режим выходных каскадов
FWfAGCEnabled := True; FDitherEnabled := True; FRandomEnabled := True;
FWfPalette := 0; FWfGamma := 1.0; FDisplayPixels := 4096;
FFMStepOn := True;
FLocalAudio := True; // GUI: звук на локальную карту; демон выключит явно
FLastSMeter := -130; FLastSWR := 1; FLastSupplyV := -1; FLastSupplyA := -1;
@@ -709,6 +713,7 @@ begin
// Роутинг аудио слайсов на их звуковухи — внутренний, вешаем сразу (не
// зависит от фронтенда, в отличие от OnAudio/OnSpectrum).
FDSPEngine.OnSliceAudio := OnSliceAudioReady;
FDSPEngine.SetDisplayResLimit(FDisplayPixels);
// QO-100 beacon lock: эталон частоты = декодер (см. ServiceBeaconLock).
FBeaconRefHz := 10489750000.0; // центральный BPSK-маяк NB-транспондера (downlink)
@@ -1256,18 +1261,40 @@ begin
if Result then S := FSlices[idx];
end;
// Снимок кадра для web-зеркала: протокол фиксирован на 1024 точки, поэтому
// при большем разрешении анализатора децимируем max-детектором (не обрезаем).
procedure SnapshotPixels(const Pixels: array of Single; Count: Integer;
var Dst: array of Single; out DstCount: Integer);
var
i, j, S0, S1, N: Integer;
V: Single;
begin
N := Length(Dst);
if Count > Length(Pixels) then Count := Length(Pixels);
if Count <= N then
begin
for i := 0 to Count - 1 do Dst[i] := Pixels[i];
DstCount := Count;
Exit;
end;
for i := 0 to N - 1 do
begin
S0 := Int64(i) * Count div N;
S1 := (Int64(i) + 1) * Count div N - 1;
V := Pixels[S0];
for j := S0 + 1 to S1 do
if Pixels[j] > V then V := Pixels[j];
Dst[i] := V;
end;
DstCount := N;
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;
SnapshotPixels(Pixels, Count, FSpectrumBuf, FSpectrumBufCount);
if Assigned(FOnSpectrumData) then FOnSpectrumData(Pixels, Count);
end;
@@ -1275,14 +1302,8 @@ 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;
SnapshotPixels(Pixels, Count, FWaterfallBuf, FWaterfallBufCount);
if Assigned(FOnWaterfallData) then FOnWaterfallData(Pixels, Count);
end;
@@ -1892,6 +1913,9 @@ begin
Result.WfManualHigh := FWfManualHigh;
Result.WfManualLow := FWfManualLow;
Result.WfAGCOffset := FWfAGCOffset;
Result.WfPalette := FWfPalette;
Result.WfGamma := FWfGamma;
Result.DisplayPixels := FDisplayPixels;
Result.SpecRefLevel := FSpecRefLevel;
Result.SpecRange := FSpecRange;
Result.SpecGridStep := FSpecGridStep;
@@ -3478,6 +3502,10 @@ begin
FWfManualHigh := FLoadedGlobal.WfManualHigh;
FWfManualLow := FLoadedGlobal.WfManualLow;
FWfAGCOffset := FLoadedGlobal.WfAGCOffset;
FWfPalette := EnsureRange(FLoadedGlobal.WfPalette, 0, 2);
FWfGamma := EnsureRange(FLoadedGlobal.WfGamma, 0.3, 3.0);
FDisplayPixels := EnsureRange(FLoadedGlobal.DisplayPixels, 64, 4096);
if FWDSPReady then FDSPEngine.SetDisplayResLimit(FDisplayPixels);
FShowSpectrum := FLoadedGlobal.ShowSpectrum;
FShowWaterfall := FLoadedGlobal.ShowWaterfall;
FShowWideband := FLoadedGlobal.ShowWideband;