refactoring SettingsForm

This commit is contained in:
2026-04-25 14:50:52 +03:00
parent 4c48f22447
commit 537d288e1e
6 changed files with 710 additions and 512 deletions
+42 -6
View File
@@ -15,6 +15,7 @@ unit AudioInput;
{$IFDEF FPC} {$IFDEF FPC}
{$MODE Delphi} {$MODE Delphi}
{$PACKRECORDS C}
{$ENDIF} {$ENDIF}
interface interface
@@ -156,9 +157,13 @@ const
'libportaudio.so.0' 'libportaudio.so.0'
); );
{$ELSE} {$ELSE}
PA_IN_LIBS: array[0..1] of AnsiString = ( PA_IN_LIBS: array[0..5] of AnsiString = (
'portaudio_x64.dll', 'portaudio_x64.dll',
'portaudio.dll' 'portaudio_x86.dll',
'portaudio.dll',
'libportaudio-2.dll',
'libportaudio.dll',
'libportaudio64.dll'
); );
{$ENDIF} {$ENDIF}
PA_NO_ERROR = 0; PA_NO_ERROR = 0;
@@ -265,7 +270,11 @@ begin
if FLibHandle = NilHandle then if FLibHandle = NilHandle then
begin begin
{$IFDEF WINDOWS}
FLastError := 'PortAudio DLL not found. Put portaudio_x64.dll, portaudio.dll, or libportaudio-2.dll next to ewsdr.exe';
{$ELSE}
FLastError := 'libportaudio not found'; FLastError := 'libportaudio not found';
{$ENDIF}
Exit; Exit;
end; end;
@@ -279,7 +288,15 @@ begin
FPa_CloseStream := TPaMic_CloseStream (GetProcAddress(FLibHandle, 'Pa_CloseStream')); FPa_CloseStream := TPaMic_CloseStream (GetProcAddress(FLibHandle, 'Pa_CloseStream'));
FPa_GetErrorText := TPaMic_GetErrorText(GetProcAddress(FLibHandle, 'Pa_GetErrorText')); FPa_GetErrorText := TPaMic_GetErrorText(GetProcAddress(FLibHandle, 'Pa_GetErrorText'));
if not Assigned(FPa_Initialize) or not Assigned(FPa_OpenStream) then if not Assigned(FPa_Initialize) or
not Assigned(FPa_Terminate) or
not Assigned(FPa_GetDeviceCount) or
not Assigned(FPa_GetDeviceInfo) or
not Assigned(FPa_OpenStream) or
not Assigned(FPa_StartStream) or
not Assigned(FPa_StopStream) or
not Assigned(FPa_CloseStream) or
not Assigned(FPa_GetErrorText) then
begin begin
FLastError := 'libportaudio: symbols not found'; FLastError := 'libportaudio: symbols not found';
FreeLibrary(FLibHandle); FreeLibrary(FLibHandle);
@@ -329,10 +346,27 @@ begin
Count := 0; Count := 0;
Result := False; Result := False;
if not Initialize then Exit; if not Initialize then Exit;
if not Assigned(FPa_GetDeviceCount) or not Assigned(FPa_GetDeviceInfo) then Exit; if not Assigned(FPa_GetDeviceCount) or not Assigned(FPa_GetDeviceInfo) then
begin
FLastError := 'PortAudio device enumeration is not available';
Exit;
end;
N := FPa_GetDeviceCount(); N := FPa_GetDeviceCount();
if N <= 0 then Exit; if N < 0 then
begin
FLastError := 'Pa_GetDeviceCount: ';
if Assigned(FPa_GetErrorText) then
FLastError := FLastError + string(FPa_GetErrorText(N))
else
FLastError := FLastError + IntToStr(N);
Exit;
end;
if N = 0 then
begin
FLastError := 'No PortAudio devices found';
Exit;
end;
for I := 0 to N - 1 do for I := 0 to N - 1 do
begin begin
@@ -410,8 +444,10 @@ begin
InParam.device := FDeviceIndex; InParam.device := FDeviceIndex;
InParam.sampleFormat := PA_FLOAT32; InParam.sampleFormat := PA_FLOAT32;
// suggestedLatency = defaultLowInputLatency устройства (как в piHPSDR)
Info := FPa_GetDeviceInfo(FDeviceIndex); Info := FPa_GetDeviceInfo(FDeviceIndex);
{$IFDEF WINDOWS}
// На Windows latency=0 часто ломает WASAPI/MME; берём значение от устройства.
{$ENDIF}
if Info <> nil then if Info <> nil then
InParam.suggestedLatency := Info^.defaultLowInputLatency InParam.suggestedLatency := Info^.defaultLowInputLatency
else else
+47 -7
View File
@@ -15,6 +15,7 @@ unit AudioOutput;
{$IFDEF FPC} {$IFDEF FPC}
{$MODE Delphi} {$MODE Delphi}
{$PACKRECORDS C}
{$ENDIF} {$ENDIF}
interface interface
@@ -166,9 +167,13 @@ const
'libportaudio.so.0' 'libportaudio.so.0'
); );
{$ELSE} {$ELSE}
PA_LIBS: array[0..1] of AnsiString = ( PA_LIBS: array[0..5] of AnsiString = (
'portaudio_x64.dll', 'portaudio_x64.dll',
'portaudio.dll' 'portaudio_x86.dll',
'portaudio.dll',
'libportaudio-2.dll',
'libportaudio.dll',
'libportaudio64.dll'
); );
{$ENDIF} {$ENDIF}
PA_NO_ERROR = 0; PA_NO_ERROR = 0;
@@ -282,7 +287,11 @@ begin
if FLibHandle = NilHandle then if FLibHandle = NilHandle then
begin begin
{$IFDEF WINDOWS}
FLastError := 'PortAudio DLL not found. Put portaudio_x64.dll, portaudio.dll, or libportaudio-2.dll next to ewsdr.exe';
{$ELSE}
FLastError := 'libportaudio not found. sudo apt install libportaudio2'; FLastError := 'libportaudio not found. sudo apt install libportaudio2';
{$ENDIF}
Exit; Exit;
end; end;
@@ -297,7 +306,16 @@ begin
FPa_CloseStream := TPa_CloseStream(GetProcAddress(FLibHandle, 'Pa_CloseStream')); FPa_CloseStream := TPa_CloseStream(GetProcAddress(FLibHandle, 'Pa_CloseStream'));
FPa_GetErrorText := TPa_GetErrorText(GetProcAddress(FLibHandle, 'Pa_GetErrorText')); FPa_GetErrorText := TPa_GetErrorText(GetProcAddress(FLibHandle, 'Pa_GetErrorText'));
if not Assigned(FPa_Initialize) or not Assigned(FPa_OpenStream) then if not Assigned(FPa_Initialize) or
not Assigned(FPa_Terminate) or
not Assigned(FPa_GetDefaultOutputDevice) or
not Assigned(FPa_GetDeviceCount) or
not Assigned(FPa_GetDeviceInfo) or
not Assigned(FPa_OpenStream) or
not Assigned(FPa_StartStream) or
not Assigned(FPa_StopStream) or
not Assigned(FPa_CloseStream) or
not Assigned(FPa_GetErrorText) then
begin begin
FLastError := 'libportaudio: symbols not found'; FLastError := 'libportaudio: symbols not found';
FreeLibrary(FLibHandle); FreeLibrary(FLibHandle);
@@ -350,10 +368,27 @@ begin
Count := 0; Count := 0;
Result := False; Result := False;
if not Initialize then Exit; if not Initialize then Exit;
if not Assigned(FPa_GetDeviceCount) or not Assigned(FPa_GetDeviceInfo) then Exit; if not Assigned(FPa_GetDeviceCount) or not Assigned(FPa_GetDeviceInfo) then
begin
FLastError := 'PortAudio device enumeration is not available';
Exit;
end;
N := FPa_GetDeviceCount(); N := FPa_GetDeviceCount();
if N <= 0 then Exit; if N < 0 then
begin
FLastError := 'Pa_GetDeviceCount: ';
if Assigned(FPa_GetErrorText) then
FLastError := FLastError + string(FPa_GetErrorText(N))
else
FLastError := FLastError + IntToStr(N);
Exit;
end;
if N = 0 then
begin
FLastError := 'No PortAudio devices found';
Exit;
end;
for I := 0 to N - 1 do for I := 0 to N - 1 do
begin begin
@@ -416,6 +451,7 @@ var
OutParam: TPaStreamParameters; OutParam: TPaStreamParameters;
Err: TPaError; Err: TPaError;
Dev: TPaDeviceIndex; Dev: TPaDeviceIndex;
Info: PPaDeviceInfo;
begin begin
Result := False; Result := False;
if FOpen then begin Result := True; Exit; end; if FOpen then begin Result := True; Exit; end;
@@ -441,8 +477,12 @@ begin
OutParam.hostApiSpecificStreamInfo := nil; OutParam.hostApiSpecificStreamInfo := nil;
OutParam.sampleFormat := PA_FLOAT32; OutParam.sampleFormat := PA_FLOAT32;
{$IFDEF WINDOWS} {$IFDEF WINDOWS}
// На Windows latency=0 вызывает фризы — используем разумный минимум // На Windows latency=0 часто ломает WASAPI/MME; берём значение от устройства.
OutParam.suggestedLatency := 0.050; // 50ms — стабильно на Windows WASAPI/MME Info := FPa_GetDeviceInfo(Dev);
if (Info <> nil) and (Info^.defaultLowOutputLatency > 0.0) then
OutParam.suggestedLatency := Info^.defaultLowOutputLatency
else
OutParam.suggestedLatency := 0.050;
{$ELSE} {$ELSE}
OutParam.suggestedLatency := 0.0; // на Linux ALSA справляется с минимумом OutParam.suggestedLatency := 0.0; // на Linux ALSA справляется с минимумом
{$ENDIF} {$ENDIF}
+3 -3
View File
@@ -952,7 +952,7 @@ begin
end end
else else
begin begin
Result.FFTSize := 4096; Result.FFTSize := 131072;
Result.WindowType := 2; Result.WindowType := 2;
Result.SpecDetector := 0; Result.SpecDetector := 0;
Result.SpecAvgMode := 3; Result.SpecAvgMode := 3;
@@ -1177,7 +1177,7 @@ begin
FPanelHidden := False; FPanelHidden := False;
FShowSpectrum := True; FShowSpectrum := True;
FShowWaterfall := True; FShowWaterfall := True;
FDisplayFPS := 20; FDisplayFPS := 60;
FWaterfallDirty := True; FWaterfallDirty := True;
FSplitterRatio := 0.40; // 40% спектр, 60% водопад по умолчанию FSplitterRatio := 0.40; // 40% спектр, 60% водопад по умолчанию
FSplitterDrag := False; FSplitterDrag := False;
@@ -5815,7 +5815,7 @@ begin
FAudioOutDevName, FAudioInDevName) FAudioOutDevName, FAudioInDevName)
else else
SF.LoadValues( SF.LoadValues(
4096, 2, 0, 3, 30.0, 131072, 2, 0, 3, 30.0,
0, 3, 120.0, FWfManualHigh, FWfManualLow, FWfAGCOffset, 0, 3, 120.0, FWfManualHigh, FWfManualLow, FWfAGCOffset,
FSpecRefLevel, FSpecRange, FSpecGridStep, FSpecRefLevel, FSpecRange, FSpecGridStep,
FAudioOutDevName, FAudioInDevName); FAudioOutDevName, FAudioInDevName);
+25 -15
View File
@@ -49,7 +49,7 @@ type
WindowWidth: Integer; WindowWidth: Integer;
WindowHeight: Integer; WindowHeight: Integer;
// --- Display settings --- // --- Display settings ---
FFTSize: Integer; // 1024,2048,4096,8192,16384 FFTSize: Integer; // 4096..262144
WindowType: Integer; // 0=Rect,1=BH4,2=Hann,3=FlatTop,4=Hamming,5=Kaiser,6=BH7 WindowType: Integer; // 0=Rect,1=BH4,2=Hann,3=FlatTop,4=Hamming,5=Kaiser,6=BH7
SpecDetector: Integer; // 0=Peak,1=Rosenfell,2=Average,3=Sample,4=RMS SpecDetector: Integer; // 0=Peak,1=Rosenfell,2=Average,3=Sample,4=RMS
SpecAvgMode: Integer; // 0=None,1=Recursive,2=TimeWindow,3=LogRecursive SpecAvgMode: Integer; // 0=None,1=Recursive,2=TimeWindow,3=LogRecursive
@@ -171,7 +171,7 @@ begin
G.PAMaxPower := 100.0; G.PAMaxPower := 100.0;
for i := 0 to CFG_BAND_COUNT-1 do G.PABandCal[i] := 100.0; for i := 0 to CFG_BAND_COUNT-1 do G.PABandCal[i] := 100.0;
// Display defaults // Display defaults
G.FFTSize := 4096; G.FFTSize := 131072;
G.WindowType := 2; // Hann G.WindowType := 2; // Hann
G.SpecDetector := 0; // Peak G.SpecDetector := 0; // Peak
G.SpecAvgMode := 3; // Log Recursive G.SpecAvgMode := 3; // Log Recursive
@@ -190,7 +190,7 @@ begin
G.AudioInDevice := ''; G.AudioInDevice := '';
G.ShowSpectrum := True; G.ShowSpectrum := True;
G.ShowWaterfall := True; G.ShowWaterfall := True;
G.DisplayFPS := 20; G.DisplayFPS := 60;
end; end;
constructor TSettingsManager.Create(const FilePath: string); constructor TSettingsManager.Create(const FilePath: string);
@@ -336,30 +336,40 @@ begin
G.LastBand := JI(GObj,'last_band',5); G.LastBand := JI(GObj,'last_band',5);
G.SampleRate := JI(GObj,'sample_rate',192000); G.SampleRate := JI(GObj,'sample_rate',192000);
// Display settings // Display settings
G.FFTSize := JI(GObj,'fft_size',4096); G.FFTSize := JI(GObj,'fft_size',131072);
G.WindowType := JI(GObj,'win_type',5); G.WindowType := JI(GObj,'win_type',2);
G.SpecDetector := JI(GObj,'spec_detector',0); G.SpecDetector := JI(GObj,'spec_detector',0);
G.SpecAvgMode := JI(GObj,'spec_avg_mode',0); G.SpecAvgMode := JI(GObj,'spec_avg_mode',3);
if GObj.Find('spec_avg_time_ms') <> nil then if GObj.Find('spec_avg_time_ms') <> nil then
G.SpecAvgTimeMS := JD(GObj,'spec_avg_time_ms',120.0) G.SpecAvgTimeMS := JD(GObj,'spec_avg_time_ms',30.0)
else else if (GObj.Find('spec_avg_count') <> nil) or
(GObj.Find('spec_backmult') <> nil) then
begin
G.SpecAvgTimeMS := LegacyAverageTimeMS( G.SpecAvgTimeMS := LegacyAverageTimeMS(
JI(GObj,'display_fps',20), JI(GObj,'display_fps',60),
G.SpecAvgMode, G.SpecAvgMode,
JI(GObj,'spec_avg_count',1), JI(GObj,'spec_avg_count',1),
JD(GObj,'spec_backmult',0.0), JD(GObj,'spec_backmult',0.0),
120.0); 30.0);
G.WfDetector := JI(GObj,'wf_detector',2); end
G.WfAvgMode := JI(GObj,'wf_avg_mode',1); else
G.SpecAvgTimeMS := 30.0;
G.WfDetector := JI(GObj,'wf_detector',0);
G.WfAvgMode := JI(GObj,'wf_avg_mode',3);
if GObj.Find('wf_avg_time_ms') <> nil then if GObj.Find('wf_avg_time_ms') <> nil then
G.WfAvgTimeMS := JD(GObj,'wf_avg_time_ms',120.0) G.WfAvgTimeMS := JD(GObj,'wf_avg_time_ms',120.0)
else else if (GObj.Find('wf_avg_count') <> nil) or
(GObj.Find('wf_backmult') <> nil) then
begin
G.WfAvgTimeMS := LegacyAverageTimeMS( G.WfAvgTimeMS := LegacyAverageTimeMS(
JI(GObj,'display_fps',20), JI(GObj,'display_fps',60),
G.WfAvgMode, G.WfAvgMode,
JI(GObj,'wf_avg_count',2), JI(GObj,'wf_avg_count',2),
JD(GObj,'wf_backmult',0.25), JD(GObj,'wf_backmult',0.25),
120.0); 120.0);
end
else
G.WfAvgTimeMS := 120.0;
G.WfManualHigh := JD(GObj,'wf_manual_high',-80.0); G.WfManualHigh := JD(GObj,'wf_manual_high',-80.0);
G.WfManualLow := JD(GObj,'wf_manual_low',-130.0); G.WfManualLow := JD(GObj,'wf_manual_low',-130.0);
G.WfAGCOffset := JD(GObj,'wf_agc_offset',0.0); G.WfAGCOffset := JD(GObj,'wf_agc_offset',0.0);
@@ -373,7 +383,7 @@ begin
// Visibility settings // Visibility settings
G.ShowSpectrum := JB(GObj,'show_spectrum',True); G.ShowSpectrum := JB(GObj,'show_spectrum',True);
G.ShowWaterfall := JB(GObj,'show_waterfall',True); G.ShowWaterfall := JB(GObj,'show_waterfall',True);
G.DisplayFPS := JI(GObj,'display_fps',20); G.DisplayFPS := JI(GObj,'display_fps',60);
// PA settings // PA settings
G.PAMaxPower := JD(GObj,'pa_max_power',100.0); G.PAMaxPower := JD(GObj,'pa_max_power',100.0);
for i := 0 to CFG_BAND_COUNT-1 do for i := 0 to CFG_BAND_COUNT-1 do
+590 -478
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -551,10 +551,10 @@ begin
FANFEnabled := False; FANFEnabled := False;
FRXAccPos := 0; FRXAccPos := 0;
// Analyzer defaults // Analyzer defaults
FFFTSize := 4096; FFFTSize := 131072;
FWindowType := 2; // Hann FWindowType := 2; // Hann
FDisplayFPS := 20; FDisplayFPS := 60;
FEffectiveDisplayFPS := 20.0; FEffectiveDisplayFPS := 60.0;
FDisplayPixelCount := SPECTRUM_PIXELS; FDisplayPixelCount := SPECTRUM_PIXELS;
FSpecDetector := 0; // Peak FSpecDetector := 0; // Peak
FSpecAvgMode := 3; // Log Recursive FSpecAvgMode := 3; // Log Recursive