diff --git a/AudioOutput.pas b/AudioOutput.pas index b6b9df2..da264de 100644 --- a/AudioOutput.pas +++ b/AudioOutput.pas @@ -189,6 +189,7 @@ const ); {$ENDIF} {$ENDIF} +const PA_NO_ERROR = 0; PA_FLOAT32 = LongWord(1); PA_NO_FLAG = LongWord(0); diff --git a/MainForm.pas b/MainForm.pas index cf29837..513e05f 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -1155,18 +1155,16 @@ begin rfVfoA: begin FreqDispA.Frequency := Round(FController.FVfoA); - // Не рисуем синхронно из wheel/drag: частые события забивают UI-поток. - // Invalidate лишь планирует; DrawSpectrum откладываем (FSpectrumDirty). - // Линейку дёргаем сразу — её рендер дешёвый, иначе отстаёт от спектра. + // Не рисуем синхронно из wheel/drag: частые события забивают UI-поток, + // а мгновенный Invalidate давал GL-кадр на КАЖДОЕ событие мыши (при + // драге рендер упирался в vsync и обходил FPS-гейт — на AMD APU это + // трещало в HDMI-звуке того же GPU). Кадр отрисует ближайший тик + // FSpectrumTimer по FSpectrumDirty. Линейка дешёвая — её сразу. SyncSpecViewFreq; FSpectrumDirty := True; - PbSpectrum.Invalidate; if PbRuler <> nil then PbRuler.Invalidate; if FController.FLastVfoScrolled then - begin FWaterfallDirty := True; - if PbWaterfall <> nil then PbWaterfall.Invalidate; - end; end; rfActiveVfo: begin @@ -1182,11 +1180,11 @@ begin rfCenterFreq: begin // CTUN-скролл центра (drag/web): ruler-метки сдвинулись → инвалидируем - // кэш; спектр откладываем (FSpectrumDirty) — drag шлёт много событий. + // кэш; спектр откладываем (FSpectrumDirty) — drag шлёт много событий, + // кадр отрисует таймер (FPS-гейт, см. rfVfoA). FSpecView.InvalidateRulerCache; SyncSpecViewFreq; FSpectrumDirty := True; - PbSpectrum.Invalidate; if PbRuler <> nil then PbRuler.Invalidate; end; rfVfoB: @@ -1196,8 +1194,7 @@ begin begin FSpecView.InvalidateRulerCache; SyncSpecViewFreq; - FSpectrumDirty := True; - PbSpectrum.Invalidate; + FSpectrumDirty := True; // кадр — по таймеру (FPS-гейт, см. rfVfoA) if PbRuler <> nil then PbRuler.Invalidate; end; end; @@ -4568,8 +4565,7 @@ begin FController.SetSliceTarget(FSliceDragId, NewHz); PushSliceFlagState(FSliceDragId); // обновить частоту во флаге PositionSliceFlags; - FSpectrumDirty := True; - PbSpectrum.Invalidate; + FSpectrumDirty := True; // кадр — по таймеру (FPS-гейт, как при drag VFO) end; Exit; end; diff --git a/WDSPEngine.pas b/WDSPEngine.pas index 633027c..dbaa360 100644 --- a/WDSPEngine.pas +++ b/WDSPEngine.pas @@ -1259,6 +1259,17 @@ begin FreeAndNil(FDSPThread); end; + // TX-DSP поток живёт весь сеанс (не пересоздаётся на T/R) — гасим его здесь, + // до закрытия WDSP-каналов (он зовёт fexchange0 на TXA_CHAN). + FTXActive := False; + if Assigned(FTXThread) then + begin + FTXThread.Terminate; + RTLEventSetEvent(FTXMicSem); + FTXThread.WaitFor; + FreeAndNil(FTXThread); + end; + // Закрываем WDSP-каналы слайсов (записи FSlices сохраняем — переоткроются в Open). FSliceLock.Enter; try @@ -2130,37 +2141,30 @@ end; procedure TWDSPEngine.SetTXRun(Run: Boolean); begin - FTXActive := Run; FDispPos := 0; FTXDispPos := 0; - if Run then - FActiveDisplayID := TX_DISP_ID - else - FActiveDisplayID := RX_DISP_ID; - if Run then begin - if FInitialized then - SetChannelState(TXA_CHAN, 1, 0); // run, no delay - // Сброс mic ring buffer и запуск TX потока + FActiveDisplayID := TX_DISP_ID; + // Сброс mic ring ДО активации, чтобы простаивавший поток не прочитал старое. FTXMicHead := 0; FTXMicTail := 0; + if FInitialized then + SetChannelState(TXA_CHAN, 1, 0); // run, no delay + // TX-DSP поток создаётся ОДИН раз и живёт весь сеанс. НЕ пересоздаём на каждом + // T/R: join (WaitFor) давал фиксированные ~100 мс фриза GUI на отпускании PTT. + // При FTXActive=False поток простаивает (см. TTXDSPThread.Execute: Continue). if not Assigned(FTXThread) then begin FTXThread := TTXDSPThread.Create(Self); FTXThread.Priority := tpHighest; end; + FTXActive := True; // активируем последним end else begin + FTXActive := False; // поток уходит в простой (не трогает канал/ring) + FActiveDisplayID := RX_DISP_ID; if FInitialized then - SetChannelState(TXA_CHAN, 0, 1); // stop, with slew - // Останавливаем TX поток - if Assigned(FTXThread) then - begin - FTXThread.Terminate; - RTLEventSetEvent(FTXMicSem); - FTXThread.WaitFor; - FreeAndNil(FTXThread); - end; + SetChannelState(TXA_CHAN, 0, 1); // stop, with slew (поток уже idle) FTXMicHead := 0; FTXMicTail := 0; end; diff --git a/ewsdr.lpi b/ewsdr.lpi index 4a338f8..3b6971b 100644 --- a/ewsdr.lpi +++ b/ewsdr.lpi @@ -17,9 +17,9 @@ - + - + @@ -83,6 +83,7 @@ +