diff --git a/WDSPEngine.pas b/WDSPEngine.pas index f58d295..bdc5344 100644 --- a/WDSPEngine.pas +++ b/WDSPEngine.pas @@ -26,7 +26,6 @@ interface uses Classes, SysUtils, Math, SyncObjs, BeaconDecoder, - PerfLog, // ВРЕМЕННО (perf/cpu-profiling): зонные CPU-таймеры WDSP; const @@ -365,7 +364,6 @@ type procedure ApplyAGCToChan(Chan: Integer; Mode: TWDSPAGCMode; FixedGain: Double); procedure ProcessSlices; // fan-out в ProcessRXBlock procedure AllocSliceBuffers; // (пере)аллокация буферов - procedure FeedDisplaySample(const I, Q: Double); procedure ProcessRXBlock; procedure PushIQItemToDSP(const Item: TIQQueueItem); procedure OpenAnalyzer; @@ -1366,12 +1364,14 @@ procedure TWDSPEngine.PushIQItemToDSP(const Item: TIQQueueItem); var i, Pos: Integer; IR, QR: LongInt; - T0: Int64; // PERF + DI, DQ: Double; // сэмпл во float — считаем ОДИН раз на всех трёх потребителей + AnOpen: Boolean; // FAnalyzerOpen и FBeaconDec внутри цикла не меняются: + Bec: TBeaconDecoder; // держим локально, не перечитываем поле на каждый сэмпл + P: PByte; // бегущий указатель вместо Pos := i * 6 const SCALE = 1.0 / 8388608.0; begin if FTXActive and not FKeepRXDuringTX then Exit; - T0 := PerfNow; // PERF // Post-TX hold: дропаем входящие RX-IQ пакеты пока активно окно мьюта. // Это закрывает ОБА канала сразу — и водопад/спектр (анализатор не // кормится), и аудио (RXA не запускается, FOnAudio не вызывается). @@ -1379,51 +1379,48 @@ begin // ~50–200мс после MOX-off; этот хвост попадает в RX1 как leak. Дропаем // его на входе — single-source-of-truth. if (FPostTXMuteUntil <> 0) and (GetTickCount64 < FPostTXMuteUntil) then Exit; + AnOpen := FAnalyzerOpen; + Bec := FBeaconDec; + Pos := 0; + P := @Item.Data[0]; for i := 0 to Item.IQPairs - 1 do begin - Pos := i * 6; if Pos + 5 >= Item.DataLen then Break; - IR := (LongInt(Item.Data[Pos]) shl 16) or - (LongInt(Item.Data[Pos+1]) shl 8) or - LongInt(Item.Data[Pos+2]); - QR := (LongInt(Item.Data[Pos+3]) shl 16) or - (LongInt(Item.Data[Pos+4]) shl 8) or - LongInt(Item.Data[Pos+5]); + IR := (LongInt(P[0]) shl 16) or (LongInt(P[1]) shl 8) or LongInt(P[2]); + QR := (LongInt(P[3]) shl 16) or (LongInt(P[4]) shl 8) or LongInt(P[5]); + Inc(P, 6); + Inc(Pos, 6); if (IR and $800000) <> 0 then IR := IR or LongInt($FF000000); if (QR and $800000) <> 0 then QR := QR or LongInt($FF000000); - FeedDisplaySample(IR * SCALE, QR * SCALE); + DI := IR * SCALE; + DQ := QR * SCALE; - if FBeaconDec <> nil then FBeaconDec.Feed(IR * SCALE, QR * SCALE); + // FeedDisplaySample развёрнут сюда: вызов метода на каждый сэмпл (576к/с) + // стоил дороже самой работы — двух записей в буфер. + if AnOpen then + begin + FDispBuf[FDispPos * 2] := DI; + FDispBuf[FDispPos * 2 + 1] := DQ; + Inc(FDispPos); + if FDispPos >= DISPLAY_BLOCK_SIZE then + begin + Spectrum0(1, RX_DISP_ID, 0, 0, @FDispBuf[0]); + FDispPos := 0; + end; + end; - FRXAccI[FRXAccPos] := IR * SCALE; - FRXAccQ[FRXAccPos] := QR * SCALE; + if Bec <> nil then Bec.Feed(DI, DQ); + + FRXAccI[FRXAccPos] := DI; + FRXAccQ[FRXAccPos] := DQ; Inc(FRXAccPos); if FRXAccPos >= FBufSize then ProcessRXBlock; end; - PerfAdd(pzDspPushIQ, T0); // PERF: весь путь пакета через DSP-поток -end; - -procedure TWDSPEngine.FeedDisplaySample(const I, Q: Double); -var T0: Int64; // PERF -begin - if not FAnalyzerOpen then Exit; - - FDispBuf[FDispPos * 2] := I; - FDispBuf[FDispPos * 2 + 1] := Q; - Inc(FDispPos); - - if FDispPos >= DISPLAY_BLOCK_SIZE then - begin - T0 := PerfNow; // PERF - Spectrum0(1, RX_DISP_ID, 0, 0, @FDispBuf[0]); - PerfAdd(pzDspSpectrum0, T0); // PERF: скармливание блока анализатору - FDispPos := 0; - end; end; procedure TWDSPEngine.FeedTXDisplaySample(const I, Q: Double); @@ -1445,14 +1442,12 @@ procedure TWDSPEngine.ProcessRXBlock; var i: Integer; Err: Integer; - T0: Int64; // PERF // OutL/OutR теперь поля класса — не аллоцируем каждый раз begin FRXAccPos := 0; if not FInitialized then Exit; try - T0 := PerfNow; // PERF // Упаковываем в interleaved буфер для fexchange0 for i := 0 to FBufSize - 1 do begin @@ -1463,7 +1458,6 @@ begin // DSP обработка Err := 0; fexchange0(RXA_CHAN, @FRXIn[0], @FRXOut[0], @Err); - PerfAdd(pzDspFexMain, T0); // PERF: главный RX-канал WDSP // S-meter: читаем ОДИН раз в DSP-колбэке и кешируем в FSMeter. // GetRXAMeter сбрасывает аккумулятор после вызова, поэтому второй @@ -1485,14 +1479,12 @@ begin and (not FTXActive or (FKeepRXDuringTX and FMonitorRXDuringTX)) and (FPostTXMuteUntil = 0) then begin - T0 := PerfNow; // PERF for i := 0 to FAudioBufSize - 1 do begin FOutL[i] := FRXOut[i * 2] * FVolume; FOutR[i] := FRXOut[i * 2 + 1] * FVolume; end; FOnAudio(FOutL, FOutR, FAudioBufSize); - PerfAdd(pzDspAudioCb, T0); // PERF: маршрут RX-аудио (web/радио/звуковуха) end; // Софтовые слайсы: fan-out того же IQ-блока на доп. WDSP-каналы. @@ -1600,10 +1592,8 @@ procedure TWDSPEngine.ProcessSlices; var s, i, k, Err: Integer; V: Double; - T0, TS: Int64; // PERF begin if not Assigned(FOnSliceAudio) then Exit; - T0 := PerfNow; // PERF FSliceLock.Enter; try for s := 0 to MAX_SLICES - 1 do @@ -1617,9 +1607,7 @@ begin FSliceIn[i * 2 + 1] := FRXAccQ[i]; end; Err := 0; - TS := PerfNow; // PERF fexchange0(FSlices[s].Chan, @FSliceIn[0], @FSliceOut[0], @Err); - PerfAdd(pzDspSliceFex, TS); // PERF: fexchange0 одного слайса // S-метр канала читаем здесь (DSP-поток) — GetRXAMeter сбрасывает аккумулятор. FSlices[s].SMeter := GetRXAMeter(FSlices[s].Chan, RXA_S_AV); V := FSlices[s].Volume; @@ -1633,7 +1621,6 @@ begin finally FSliceLock.Leave; end; - PerfAdd(pzDspSlices, T0); // PERF: fan-out всех слайсов целиком end; function TWDSPEngine.AddSlice(Id, Mode, FilterLo, FilterHi: Integer; @@ -2290,10 +2277,8 @@ var i, tail: Integer; Err: Integer; Avail: Integer; - T0: Int64; // PERF begin if not FInitialized then Exit; - T0 := PerfNow; // PERF Avail := (FTXMicHead - FTXMicTail + TX_MIC_RING) and (TX_MIC_RING - 1); @@ -2333,7 +2318,6 @@ begin // FTXOut содержит FTXOutBufSize IQ пар @ FTXSampleRate (interleaved double) if Assigned(FOnTXIQ) then FOnTXIQ(FTXOut, FTXOutBufSize); - PerfAdd(pzDspTxBlock, T0); // PERF: TX-блок целиком (fexchange0 + analyzer + IQ out) end; procedure TWDSPEngine.PushTXMicSamples16(const Src: array of SmallInt; N: Integer); @@ -2631,10 +2615,8 @@ var Flag: Integer; i, N: Integer; DispID: Integer; - T0: Int64; // PERF begin if not FInitialized or not FAnalyzerOpen then Exit; - T0 := PerfNow; // PERF N := EnsureRange(FDisplayPixelCount, 1, SPECTRUM_PIXELS); DispID := FActiveDisplayID; // RX_DISP_ID или TX_DISP_ID, зависит от FTXActive @@ -2657,7 +2639,6 @@ begin if Assigned(FOnWaterfall) then FOnWaterfall(FWaterfallPixels, N); end; - PerfAdd(pzDispGetPixels, T0); // PERF: GetPixels + колбэки спектр/водопад end; procedure TWDSPEngine.GetSpectrumData(var Pixels: array of Single;