mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feat(slices): пан-зум панов N — свой бар/кнопки, span-clip анализатора пана
Движок: TPanChan.ZoomFactor/PanSlider, span-clip в ApplyPanAnalyzerSettings (математика главного, ZOOM_LIMIT 100), SetPanZoomPan с no-op guard (SetAnalyzer сбрасывает FFT-историю). Зум переживает смену rate/ADC пана. Контроллер: формула окна вынесена в ViewWindowFor (главный GetViewWindow тоже через неё), GetPanViewWindow (PanId=0 делегирует), PanZoomIn/Out по лестнице кратностей с якорем на центре окна, PanZoomDefault, геттеры. UI: TPanZoomEvent получил Sender; у панов N включён ряд зума, бар диспетчеризуется по объекту, кнопки −/⌂/+ общие через PanOfZoomButton (матч по идентичности — MakeFlatBtn создаёт кнопки с Owner=контейнер, PanFromSender их не видит); SyncPanZoomUI/RefreshPanZoom, вся мышь панов зум-корректна через GetPanViewWindow. Темизация баров панов N. Смоук panzoomtest ALL PASS (пик тона совпадает с формулой окна ±0.6%), подтверждено на экране. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+43
-3
@@ -235,6 +235,8 @@ type
|
||||
DispBuf: array of Double; // feed анализатора (DISPLAY_BLOCK_SIZE пар)
|
||||
DispPos: Integer;
|
||||
DispOpen: Boolean; // XCreateAnalyzer(PAN_DISP_BASE+PanId) жив
|
||||
ZoomFactor: Double; // зум пана 0..1 (0 = весь span), как FZoomFactor
|
||||
PanSlider: Double; // положение окна 0..1
|
||||
end;
|
||||
|
||||
{ TWDSPEngine }
|
||||
@@ -646,6 +648,9 @@ type
|
||||
// Zoom/pan: задать коэффициент зума и положение пана и переармировать
|
||||
// RX-анализатор. View* — границы видимого окна (Гц отн. DDC-центра).
|
||||
procedure SetZoomPan(AZoom, APan: Double);
|
||||
// Зум/пан доп. пана (span-clip его анализатора). Видимое окно считает
|
||||
// контроллер той же формулой (GetPanViewWindow).
|
||||
procedure SetPanZoomPan(PanId: Integer; AZoom, APan: Double);
|
||||
property ZoomFactor: Double read FZoomFactor;
|
||||
property PanSlider: Double read FPanSlider;
|
||||
property ViewLowHz: Double read FViewLowHz;
|
||||
@@ -1383,14 +1388,17 @@ end;
|
||||
|
||||
procedure TWDSPEngine.ApplyPanAnalyzerSettings(PanId: Integer);
|
||||
// Параметризованная копия ApplyRXAnalyzerSettings для analyzer'а доп. пана:
|
||||
// rate пана, БЕЗ span-clip/zoom (пан-зум — этап 3.3+), FFT/детектор/усреднение
|
||||
// пока общие с главным. Вызывать под FSliceLock.
|
||||
// rate пана + СВОЙ span-clip/zoom (ZoomFactor/PanSlider записи пана);
|
||||
// FFT/детектор/усреднение пока общие с главным. Вызывать под FSliceLock.
|
||||
var
|
||||
AnalyzerFFT, AvgCount, WfAvgCount, MaxW, Overlap, DisplayPixels, Disp: Integer;
|
||||
Backmult, WfBackmult: Double;
|
||||
EffFPS: Double;
|
||||
Bins, SpanClipL, SpanClipH, ZWidth: Integer;
|
||||
ZoomSlider: Double;
|
||||
const
|
||||
KEEP_TIME_SEC = 0.10;
|
||||
ZOOM_LIMIT = 100.0; // как у главного (ApplyRXAnalyzerSettings)
|
||||
begin
|
||||
if not FPans[PanId].DispOpen then Exit;
|
||||
Disp := PAN_DISP_BASE + PanId;
|
||||
@@ -1405,8 +1413,17 @@ begin
|
||||
AverageTimeToParams(FSpecAvgMode, FSpecAvgTimeMS, AvgCount, Backmult);
|
||||
AverageTimeToParams(FWfAvgMode, FWfAvgTimeMS, WfAvgCount, WfBackmult);
|
||||
|
||||
// Span-clip зума пана — та же математика, что у главного (clp=0, зум только
|
||||
// клипует края FFT). Контроллер считает видимое окно той же формулой.
|
||||
Bins := AnalyzerFFT;
|
||||
ZoomSlider := Log10(9.0 * EnsureRange(FPans[PanId].ZoomFactor, 0.0, 1.0) + 1.0);
|
||||
ZWidth := Round(Bins * (1.0 - (1.0 - 1.0 / ZOOM_LIMIT) * ZoomSlider));
|
||||
ZWidth := EnsureRange(ZWidth, 1, Bins);
|
||||
SpanClipL := Floor(EnsureRange(FPans[PanId].PanSlider, 0.0, 1.0) * (Bins - ZWidth));
|
||||
SpanClipH := Bins - ZWidth - SpanClipL;
|
||||
|
||||
SetAnalyzer(Disp, 2, 1, 1, @FFlp[0], AnalyzerFFT, DISPLAY_BLOCK_SIZE,
|
||||
FWindowType, 14.0, Overlap, 0, 0, 0, DisplayPixels,
|
||||
FWindowType, 14.0, Overlap, 0, SpanClipL, SpanClipH, DisplayPixels,
|
||||
1, 0, 0.0, 0.0, MaxW);
|
||||
SetDisplayDetectorMode(Disp, 0, FSpecDetector);
|
||||
SetDisplayAverageMode (Disp, 0, FSpecAvgMode);
|
||||
@@ -2292,6 +2309,8 @@ begin
|
||||
FPans[PanId].AccPos := 0;
|
||||
FPans[PanId].DispPos := 0;
|
||||
FPans[PanId].DispOpen := False;
|
||||
FPans[PanId].ZoomFactor := 0.0; // без зума
|
||||
FPans[PanId].PanSlider := 0.5;
|
||||
FPans[PanId].Active := True;
|
||||
AllocSliceBuffers; // FSliceIn/Out под новый макс. блок
|
||||
if FAnalyzerOpen then CreatePanAnalyzer(PanId);
|
||||
@@ -2361,6 +2380,27 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TWDSPEngine.SetPanZoomPan(PanId: Integer; AZoom, APan: Double);
|
||||
// Переармирует анализатор пана под новый span-clip. No-op guard обязателен:
|
||||
// SetAnalyzer сбрасывает FFT-историю (урок SetZoomPan главного, dae0c19).
|
||||
var NZ, NP: Double;
|
||||
begin
|
||||
if (PanId < 1) or (PanId >= MAX_PANS) then Exit;
|
||||
NZ := EnsureRange(AZoom, 0.0, 1.0);
|
||||
NP := EnsureRange(APan, 0.0, 1.0);
|
||||
FSliceLock.Enter;
|
||||
try
|
||||
if not FPans[PanId].Active then Exit;
|
||||
if (Abs(NZ - FPans[PanId].ZoomFactor) < 1E-9) and
|
||||
(Abs(NP - FPans[PanId].PanSlider) < 1E-9) then Exit;
|
||||
FPans[PanId].ZoomFactor := NZ;
|
||||
FPans[PanId].PanSlider := NP;
|
||||
ApplyPanAnalyzerSettings(PanId); // внутри гейт по DispOpen
|
||||
finally
|
||||
FSliceLock.Leave;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TWDSPEngine.PanActive(PanId: Integer): Boolean;
|
||||
begin
|
||||
Result := (PanId >= 1) and (PanId < MAX_PANS) and FPans[PanId].Active;
|
||||
|
||||
Reference in New Issue
Block a user