feat(slices): этап 3.4 ADC-селектор панов + этап 3.5 pop-out в отдельное окно

3.4 ADC-селектор:
- Caps.NumADCs (HPSDR: 2 для ORION/ORION2/SATURN, как Pkt.NumADCs; Pluto: 1)
- controller.PanADC/SetPanADC: пан 0 = FMainADCSrc + ConfigureDDCs (ADC
  прокинут и в штатные вызовы — смена rate не сбрасывает выбор), паны N =
  FPanADC[] + SetPanDDC (RebuildDDCSpecific)
- Бейдж «A1/A2» в шапке каждого пана (виден при NumADCs>1), клик = тумблер;
  пан 0 на ADC2 закрывает сценарий rx2-support

3.5 Pop-out:
- «⧉» в шапке панов N → PopOutPan: TForm.CreateNew + ReparentTo (перенос
  всех контролов панели), [×] окна = DockBackPan (возврат в стек), «×»
  шапки = закрыть пан; LayoutPanStack скипает плавающих; колесо окна =
  FormMouseWheel
- GL: reparent пересоздаёт контексты → ResetGLCache обеих канв без glDelete
  (по прецеденту MSAA); TWaterfallViewOpenGL.ResetGLCache новый, история
  водопада перезаливается из CPU-буфера

Проверено юзером на экране (беглый тест: селектор и pop-out работают).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 23:54:09 +03:00
co-authored by Claude Fable 5
parent e5921b8196
commit 8bf8bcfc76
9 changed files with 348 additions and 9 deletions
+38 -2
View File
@@ -353,6 +353,7 @@ type
FPanFreqHz: array[1..MAX_PANS-1] of Double;
FPanRateKHz: array[1..MAX_PANS-1] of Word;
FPanADC: array[1..MAX_PANS-1] of Byte; // ADC-источник пана (3.4)
FMainADCSrc: Byte; // ADC главного DDC (пан 0)
FDDCPanMap: array[0..MAX_DDCS-1] of Integer;
FLastDDCSeq: LongWord; // последний seq (из сетевого потока)
FLastDDCIndex: Integer; // последний DDC index
@@ -576,6 +577,10 @@ type
function PanDDCActive(PanId: Integer): Boolean;
function PanDDCFreq(PanId: Integer): Double;
function PanDDCRateKHz(PanId: Integer): Word;
// ADC-источник пана (3.4). PanId=0 = главный DDC (реконфиг ConfigureDDCs),
// N>0 = его пан-DDC (SetPanDDC). ADC ∈ [0..Caps.NumADCs-1].
function PanADC(PanId: Integer): Byte;
function SetPanADC(PanId: Integer; ADC: Byte): Boolean;
// Pluto TX-мощность через аттенюацию: drive% → дБ (потолок FPlutoTxMaxAttDb на
// 100%, выкл на приёме). Логика/маппинг здесь; бэкенд лишь пишет hardwaregain.
@@ -1317,6 +1322,35 @@ begin
else Result := 0;
end;
function TRadioController.PanADC(PanId: Integer): Byte;
begin
if PanId = 0 then Result := FMainADCSrc
else if PanDDCActive(PanId) then Result := FPanADC[PanId]
else Result := 0;
end;
function TRadioController.SetPanADC(PanId: Integer; ADC: Byte): Boolean;
begin
Result := False;
if not (Assigned(FNetwork) and FRunning) then Exit;
if ADC >= FNetwork.Caps.NumADCs then Exit;
if PanId = 0 then
begin
// Главный DDC: тот же ConfigureDDCs, что при смене rate (кэш+RebuildDDCSpecific).
if FMainADCSrc = ADC then Exit(True);
FMainADCSrc := ADC;
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, ADC,
FDitherEnabled, FRandomEnabled);
Exit(True);
end;
if not PanDDCActive(PanId) then Exit;
if FPanADC[PanId] = ADC then Exit(True);
FPanADC[PanId] := ADC;
FNetwork.SetPanDDC(FPanDDCIdx[PanId], True, FPanFreqHz[PanId],
FPanRateKHz[PanId], ADC);
Result := True;
end;
function TRadioController.AddSlice(TargetHz: Double;
Mode, FilterLo, FilterHi: Integer; AGC: TWDSPAGCMode; Vol: Double;
DevIndex: Integer; const DevName: string; APanId: Integer): Integer;
@@ -3142,7 +3176,8 @@ begin
// 2. Новый rate трансиверу (после остановки DSP — пакеты сразу с верным rate).
if Assigned(FNetwork) and FNetwork.Connected then
FNetwork.ConfigureDDCs(1, Hz div 1000, 0, FDitherEnabled, FRandomEnabled);
FNetwork.ConfigureDDCs(1, Hz div 1000, FMainADCSrc,
FDitherEnabled, FRandomEnabled);
// 3. Восстанавливаем DSP-состояние (ChangeSampleRate пересоздал канал).
if Assigned(FDSPEngine) then
@@ -3657,7 +3692,8 @@ begin
// DDC и DUC Specific — теперь потоки эмулятора слушают на своих портах.
// DUC Specific содержит mic-конфигурацию (boost/bias/line/PTT) из FTXSettings.
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, 0, FDitherEnabled, FRandomEnabled);
FNetwork.ConfigureDDCs(1, FSampleRate div 1000, FMainADCSrc,
FDitherEnabled, FRandomEnabled);
// Применяем сохранённое состояние динамика/отправки аудио (мьют byte 1400 bit1).
FNetwork.SetSpeakerAudio(FSendAudioToRadio);
// RX hw-gain в бэкенд (Pluto). HPSDR — no-op.