Render wideband spectrum with OpenGL primitives

This commit is contained in:
2026-05-26 18:01:58 +03:00
parent ae1a7d9a6d
commit daa8043a23
+142 -28
View File
@@ -30,6 +30,7 @@ type
FPoints: array of TPoint;
FGLTex: GLuint;
FDirty: Boolean;
FGLBackgroundDirty: Boolean;
FSampleRateHz: Double;
FRefLevel: Double;
FRange: Double;
@@ -51,10 +52,14 @@ type
function ComputeSpectrumWDSP(const Samples: array of SmallInt;
Count: Integer): Boolean;
procedure CloseWDSPAnalyzer;
procedure DrawCPU(W, H: Integer);
function BuildSpectrumPoints(PlotW, H: Integer): Boolean;
procedure DrawCPU(W, H: Integer; IncludeSpectrum: Boolean = True);
procedure PaintCPU(C: TCanvas);
procedure PaintGL(C: TOpenGLControl);
procedure ColorToGL(AColor: TColor; out R, G, B: GLFloat);
procedure DrawSpectrumGL(PlotW, H: Integer);
procedure DrawHamBandGL(PlotW, H: Integer; F1, F2: Double; AColor: TColor);
procedure DrawHamBandsGL(PlotW, H: Integer);
function SourceFreqToBin(FreqHz: Double; BinCount: Integer): Integer;
function FreqToX(FreqHz: Double; W: Integer): Integer;
function GridStepHz(W: Integer): Double;
@@ -123,6 +128,7 @@ begin
SetLength(FWDSPPixels, WB_WDSP_PIXELS);
FGLTex := 0;
FDirty := True;
FGLBackgroundDirty := True;
end;
destructor TWidebandView.Destroy;
@@ -139,6 +145,7 @@ procedure TWidebandView.SetTheme(const T: TAppTheme);
begin
FTheme := T;
FDirty := True;
FGLBackgroundDirty := True;
end;
procedure TWidebandView.SetSampleRateHz(AHz: Double);
@@ -180,6 +187,7 @@ begin
FSourceStartHz := SourceStartHz;
FSourceEndHz := SourceEndHz;
FDirty := True;
FGLBackgroundDirty := True;
Result := True;
end;
@@ -218,7 +226,10 @@ begin
W := Max(1, W);
H := Max(1, H);
if (FBitmap.Width <> W) or (FBitmap.Height <> H) then
begin
FBitmap.SetSize(W, H);
FGLBackgroundDirty := True;
end;
end;
procedure TWidebandView.SetBitmapSize(W, H: Integer);
@@ -560,11 +571,42 @@ begin
end;
end;
procedure TWidebandView.DrawCPU(W, H: Integer);
function TWidebandView.BuildSpectrumPoints(PlotW, H: Integer): Boolean;
var
X, Y, Bin, N, TopH: Integer;
DB, InvRange, SrcHz, Nyq: Double;
begin
Result := False;
N := Length(FData);
if (N <= 1) or (PlotW <= 0) or (H <= 0) then Exit;
TopH := Max(1, H - 1);
InvRange := 1.0 / Max(1.0, FRange);
SetLength(FPoints, PlotW);
Nyq := FSampleRateHz * 0.5;
if Nyq <= 0.0 then Nyq := 61440000.0;
for X := 0 to PlotW - 1 do
begin
SrcHz := FSourceStartHz +
X / Max(1, PlotW - 1) * (FSourceEndHz - FSourceStartHz);
if (SrcHz < 0.0) or (SrcHz > Nyq) then
DB := -200.0
else
begin
Bin := SourceFreqToBin(SrcHz, N);
DB := FData[Bin];
end;
Y := Round((FRefLevel - DB) * InvRange * TopH);
Y := EnsureRange(Y, 1, TopH);
FPoints[X] := Point(X, Y);
end;
Result := True;
end;
procedure TWidebandView.DrawCPU(W, H: Integer; IncludeSpectrum: Boolean);
var
C: TCanvas;
X, Y, Bin, N, TopH, PlotW, ScaleX: Integer;
DB, DBMin, InvRange, StepHz, FreqHz, SrcHz, Nyq: Double;
X, Y, TopH, PlotW, ScaleX: Integer;
DB, DBMin, InvRange, StepHz, FreqHz: Double;
begin
EnsureBitmap(W, H);
C := FBitmap.Canvas;
@@ -614,27 +656,8 @@ begin
DB := DB - 20.0;
end;
N := Length(FData);
if N > 1 then
if IncludeSpectrum and BuildSpectrumPoints(PlotW, H) then
begin
SetLength(FPoints, PlotW);
Nyq := FSampleRateHz * 0.5;
if Nyq <= 0.0 then Nyq := 61440000.0;
for X := 0 to PlotW - 1 do
begin
SrcHz := FSourceStartHz +
X / Max(1, PlotW - 1) * (FSourceEndHz - FSourceStartHz);
if (SrcHz < 0.0) or (SrcHz > Nyq) then
DB := -200.0
else
begin
Bin := SourceFreqToBin(SrcHz, N);
DB := FData[Bin];
end;
Y := Round((FRefLevel - DB) * InvRange * TopH);
Y := EnsureRange(Y, 1, TopH);
FPoints[X] := Point(X, Y);
end;
if FFillSpectrum then
DrawSpectrumGradient(FPoints, PlotW, H);
C.Pen.Color := TColor($0040FF80);
@@ -645,7 +668,10 @@ begin
C.Font.Color := FTheme.Text;
C.TextOut(6, 4, 'Wideband');
FDirty := False;
if IncludeSpectrum then
FDirty := False
else
FGLBackgroundDirty := False;
end;
procedure TWidebandView.DrawRuler;
@@ -716,6 +742,90 @@ begin
B := ((AColor shr 16) and $FF) / 255.0;
end;
procedure TWidebandView.DrawSpectrumGL(PlotW, H: Integer);
var
I: Integer;
R, G, B: GLFloat;
ATop, ABot: GLFloat;
begin
if not BuildSpectrumPoints(PlotW, H) then Exit;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if FFillSpectrum then
begin
R := FTheme.SpecGradR / 255.0;
G := FTheme.SpecGradG / 255.0;
B := FTheme.SpecGradB / 255.0;
glBegin(GL_TRIANGLE_STRIP);
for I := 0 to PlotW - 1 do
begin
ATop := 0.44;
ABot := 0.02;
glColor4f(R, G, B, ATop);
glVertex2f(FPoints[I].X, H - FPoints[I].Y);
glColor4f(R, G, B, ABot);
glVertex2f(FPoints[I].X, 0);
end;
glEnd;
end;
glColor4f(0.25, 1.0, 0.50, 1.0);
glBegin(GL_LINE_STRIP);
for I := 0 to PlotW - 1 do
glVertex2f(FPoints[I].X, H - FPoints[I].Y);
glEnd;
glDisable(GL_BLEND);
end;
procedure TWidebandView.DrawHamBandGL(PlotW, H: Integer; F1, F2: Double;
AColor: TColor);
var
X1, X2: Integer;
R, G, B: GLFloat;
begin
X1 := FreqToX(F1, PlotW);
X2 := FreqToX(F2, PlotW);
if (X2 <= 0) or (X1 >= PlotW) then Exit;
X1 := EnsureRange(X1, 0, PlotW - 1);
X2 := EnsureRange(X2, 0, PlotW - 1);
if X2 <= X1 then Exit;
ColorToGL(AColor, R, G, B);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(R, G, B, 0.34);
glBegin(GL_QUADS);
glVertex2f(X1, 0);
glVertex2f(X2 + 1, 0);
glVertex2f(X2 + 1, H);
glVertex2f(X1, H);
glEnd;
glColor4f(R, G, B, 0.46);
glBegin(GL_QUADS);
glVertex2f(X1, H - Min(H, 15));
glVertex2f(X2 + 1, H - Min(H, 15));
glVertex2f(X2 + 1, H);
glVertex2f(X1, H);
glEnd;
glDisable(GL_BLEND);
end;
procedure TWidebandView.DrawHamBandsGL(PlotW, H: Integer);
begin
DrawHamBandGL(PlotW, H, 1810000, 2000000, TColor($003B8F5A));
DrawHamBandGL(PlotW, H, 3500000, 3800000, TColor($004D8F3B));
DrawHamBandGL(PlotW, H, 5258500, 5403500, TColor($00688F3B));
DrawHamBandGL(PlotW, H, 7000000, 7300000, TColor($00808D34));
DrawHamBandGL(PlotW, H, 10100000, 10150000, TColor($008F7834));
DrawHamBandGL(PlotW, H, 14000000, 14350000, TColor($008F5D34));
DrawHamBandGL(PlotW, H, 18068000, 18168000, TColor($008F4934));
DrawHamBandGL(PlotW, H, 21000000, 21450000, TColor($008C3E58));
DrawHamBandGL(PlotW, H, 24890000, 24990000, TColor($007A3E8C));
DrawHamBandGL(PlotW, H, 28000000, 29700000, TColor($005B4B9A));
DrawHamBandGL(PlotW, H, 50000000, 51990000, TColor($003C729A));
end;
procedure TWidebandView.UploadBitmapToGL;
var
X, Y, I: Integer;
@@ -767,9 +877,9 @@ begin
SetBitmapSize(W, H);
NeedUpload := True;
end;
if FDirty then
if FGLBackgroundDirty then
begin
DrawCPU(W, H);
DrawCPU(W, H, False);
NeedUpload := True;
end;
if FGLTex = 0 then
@@ -797,9 +907,13 @@ begin
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
PlotW := Max(1, W - WB_DB_SCALE_W);
DrawSpectrumGL(PlotW, H);
DrawHamBandsGL(PlotW, H);
FDirty := False;
if (FMarkerHz >= FViewStartHz) and (FMarkerHz <= FViewEndHz) then
begin
PlotW := Max(1, W - WB_DB_SCALE_W);
X := EnsureRange(FreqToX(FMarkerHz, PlotW), 0, PlotW - 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);