Files
ewsdr/ewsdr.lpi
T
ew8bakandClaude Opus 5 de0830fd19 feat(tci): этап 2 — бинарные потоки IQ/аудио, TX-аудио и запись линейного выхода
Реализованы все четыре потока §3.4 и рекордер:

  • RX_AUDIO_STREAM — тап ДО громкости и мьюта (OnDemodAudioReady): скиммеру
    и цифре нужен звук приёмника, а не то, что осталось после ручки;
  • LINEOUT_STREAM — тап ПОСЛЕ (OnAudioReady), то есть что слышно;
  • IQ_STREAM — тап сырого IQ в движке, ОДИН вызов на накопленный блок;
  • TX_AUDIO_STREAM + TX_CHRONO — TRX:0,true,tci берёт модуляцию из потока
    клиента (флаг TCIMicRequested впереди web в SetMOX), маркеры времени идут
    из тика по часам, аудио клиента разворачивается в 48 кГц моно в тот же
    ринг, что и web-микрофон;
  • LINE_OUT_RECORDER_* — кольцо int16 на приёмник, WAV пишет отдельный поток.

Тапы аудио в контроллере многоадресные (AddAudioTap): слушают, ничего не
забирая, в отличие от OnAudioConsume, которым владеет web. Блоки нарезает и
раскладывает по кольцам клиентов сам DSP-поток, в сокет пишет поток клиента —
та же дисциплина, что у команд. Порядок локов везде FSliceLock → FStreamLock.
У очереди команд и кольца блоков разная политика переполнения: команду терять
нельзя, блок потока — можно (теряется самый старый).

Пересчёт частоты многоступенчатый (TCIStreams). Одноступенчатый FIR на верхнем
пресете Pluto (5760 кГц, коэффициент 120) упирался в потолок отводов и давал
завал 1.3 дБ в полосе при подавлении зеркала 16 дБ — то есть поток IQ с
мусором. Теперь коэффициент раскладывается на множители, спецификацию фильтра
каждой ступени задаёт ИТОГОВАЯ полоса, а свёртка идёт со сложением
симметричных пар: −83 дБ на любом коэффициенте, ≈10% ядра на 5.76 МГц.

Согласование частот с железом: из пресетов Pluto 576 и 960 кГц на 384 не
делятся, поэтому отдаём наибольшую ЗАКОННУЮ частоту, делящую источник нацело
(576/960 → 192 кГц). Ответ на IQ_SAMPLERATE называет достижимое, а не просьбу
клиента, и переобъявляется без запроса при смене rate и устройства.

Приёмный буфер соединения 4 → 32 КБ: блок TX-аудио это 64 байта заголовка плюс
data[16384], а кадр крупнее буфера не собирается никогда.

Настройки TCI переехали из Advanced на вкладку CAT, справа от TCP CAT Server:
это такой же канал внешнего управления трансивером.

Стенд (scratchpad, tcitest.pas): 112 проверок, все зелёные — включая сквозной
прогон через живой WDSP (синтетический IQ → блоки RX-аудио и IQ у настоящего
WS-клиента, и обратно TX-аудио клиента → блоки TX-IQ).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 12:36:50 +03:00

490 lines
16 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<SessionStorage Value="InProjectDir"/>
<Title Value="EWSDR"/>
<Scaled Value="True"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<DpiAware Value="True/PM_V2"/>
</XPManifest>
<Icon Value="0"/>
</General>
<VersionInfo>
<UseVersionInfo Value="True"/>
<AutoIncrementBuild Value="True"/>
<MinorVersionNr Value="9"/>
<BuildNr Value="300"/>
</VersionInfo>
<MacroValues Count="148">
<Macro1 Name="LCLWidgetType" Value="qt6"/>
<Macro2 Name="LCLWidgetType" Value="qt6"/>
<Macro3 Name="LCLWidgetType" Value="qt6"/>
<Macro4 Name="LCLWidgetType" Value="qt6"/>
<Macro5 Name="LCLWidgetType" Value="qt6"/>
<Macro6 Name="LCLWidgetType" Value="qt6"/>
<Macro7 Name="LCLWidgetType" Value="qt6"/>
<Macro8 Name="LCLWidgetType" Value="qt6"/>
<Macro9 Name="LCLWidgetType" Value="qt6"/>
<Macro10 Name="LCLWidgetType" Value="qt6"/>
<Macro11 Name="LCLWidgetType" Value="qt6"/>
<Macro12 Name="LCLWidgetType" Value="qt6"/>
<Macro13 Name="LCLWidgetType" Value="qt6"/>
<Macro14 Name="LCLWidgetType" Value="qt6"/>
<Macro15 Name="LCLWidgetType" Value="qt6"/>
<Macro16 Name="LCLWidgetType" Value="qt6"/>
<Macro17 Name="LCLWidgetType" Value="qt6"/>
<Macro18 Name="LCLWidgetType" Value="qt6"/>
<Macro19 Name="LCLWidgetType" Value="qt6"/>
<Macro20 Name="LCLWidgetType" Value="qt6"/>
<Macro21 Name="LCLWidgetType" Value="qt6"/>
<Macro22 Name="LCLWidgetType" Value="qt6"/>
<Macro23 Name="LCLWidgetType" Value="qt6"/>
<Macro24 Name="LCLWidgetType" Value="qt6"/>
<Macro25 Name="LCLWidgetType" Value="qt6"/>
<Macro26 Name="LCLWidgetType" Value="qt6"/>
<Macro27 Name="LCLWidgetType" Value="qt6"/>
<Macro28 Name="LCLWidgetType" Value="qt6"/>
<Macro29 Name="LCLWidgetType" Value="qt6"/>
<Macro30 Name="LCLWidgetType" Value="qt6"/>
<Macro31 Name="LCLWidgetType" Value="qt6"/>
<Macro32 Name="LCLWidgetType" Value="qt6"/>
<Macro33 Name="LCLWidgetType" Value="qt6"/>
<Macro34 Name="LCLWidgetType" Value="qt6"/>
<Macro35 Name="LCLWidgetType" Value="qt6"/>
<Macro36 Name="LCLWidgetType" Value="qt6"/>
<Macro37 Name="LCLWidgetType" Value="qt6"/>
<Macro38 Name="LCLWidgetType" Value="qt6"/>
<Macro39 Name="LCLWidgetType" Value="qt6"/>
<Macro40 Name="LCLWidgetType" Value="qt6"/>
<Macro41 Name="LCLWidgetType" Value="qt6"/>
<Macro42 Name="LCLWidgetType" Value="qt6"/>
<Macro43 Name="LCLWidgetType" Value="qt6"/>
<Macro44 Name="LCLWidgetType" Value="qt6"/>
<Macro45 Name="LCLWidgetType" Value="qt6"/>
<Macro46 Name="LCLWidgetType" Value="qt6"/>
<Macro47 Name="LCLWidgetType" Value="qt6"/>
<Macro48 Name="LCLWidgetType" Value="qt6"/>
<Macro49 Name="LCLWidgetType" Value="qt6"/>
<Macro50 Name="LCLWidgetType" Value="qt6"/>
<Macro51 Name="LCLWidgetType" Value="qt6"/>
<Macro52 Name="LCLWidgetType" Value="qt6"/>
<Macro53 Name="LCLWidgetType" Value="qt6"/>
<Macro54 Name="LCLWidgetType" Value="qt6"/>
<Macro55 Name="LCLWidgetType" Value="qt6"/>
<Macro56 Name="LCLWidgetType" Value="qt6"/>
<Macro57 Name="LCLWidgetType" Value="qt6"/>
<Macro58 Name="LCLWidgetType" Value="qt6"/>
<Macro59 Name="LCLWidgetType" Value="qt6"/>
<Macro60 Name="LCLWidgetType" Value="qt6"/>
<Macro61 Name="LCLWidgetType" Value="qt6"/>
<Macro62 Name="LCLWidgetType" Value="qt6"/>
<Macro63 Name="LCLWidgetType" Value="qt6"/>
<Macro64 Name="LCLWidgetType" Value="qt6"/>
<Macro65 Name="LCLWidgetType" Value="qt6"/>
<Macro66 Name="LCLWidgetType" Value="qt6"/>
<Macro67 Name="LCLWidgetType" Value="qt6"/>
<Macro68 Name="LCLWidgetType" Value="qt6"/>
<Macro69 Name="LCLWidgetType" Value="qt6"/>
<Macro70 Name="LCLWidgetType" Value="qt6"/>
<Macro71 Name="LCLWidgetType" Value="qt6"/>
<Macro72 Name="LCLWidgetType" Value="qt6"/>
<Macro73 Name="LCLWidgetType" Value="qt6"/>
<Macro74 Name="LCLWidgetType" Value="qt6"/>
<Macro75 Name="LCLWidgetType" Value="qt6"/>
<Macro76 Name="LCLWidgetType" Value="qt6"/>
<Macro77 Name="LCLWidgetType" Value="qt6"/>
<Macro78 Name="LCLWidgetType" Value="qt6"/>
<Macro79 Name="LCLWidgetType" Value="qt6"/>
<Macro80 Name="LCLWidgetType" Value="qt6"/>
<Macro81 Name="LCLWidgetType" Value="qt6"/>
<Macro82 Name="LCLWidgetType" Value="qt6"/>
<Macro83 Name="LCLWidgetType" Value="qt6"/>
<Macro84 Name="LCLWidgetType" Value="qt6"/>
<Macro85 Name="LCLWidgetType" Value="qt6"/>
<Macro86 Name="LCLWidgetType" Value="qt6"/>
<Macro87 Name="LCLWidgetType" Value="qt6"/>
<Macro88 Name="LCLWidgetType" Value="qt6"/>
<Macro89 Name="LCLWidgetType" Value="qt6"/>
<Macro90 Name="LCLWidgetType" Value="qt6"/>
<Macro91 Name="LCLWidgetType" Value="qt6"/>
<Macro92 Name="LCLWidgetType" Value="qt6"/>
<Macro93 Name="LCLWidgetType" Value="qt6"/>
<Macro94 Name="LCLWidgetType" Value="qt6"/>
<Macro95 Name="LCLWidgetType" Value="qt6"/>
<Macro96 Name="LCLWidgetType" Value="qt6"/>
<Macro97 Name="LCLWidgetType" Value="qt6"/>
<Macro98 Name="LCLWidgetType" Value="qt6"/>
<Macro99 Name="LCLWidgetType" Value="qt6"/>
<Macro100 Name="LCLWidgetType" Value="qt6"/>
<Macro101 Name="LCLWidgetType" Value="qt6"/>
<Macro102 Name="LCLWidgetType" Value="qt6"/>
<Macro103 Name="LCLWidgetType" Value="qt6"/>
<Macro104 Name="LCLWidgetType" Value="qt6"/>
<Macro105 Name="LCLWidgetType" Value="qt6"/>
<Macro106 Name="LCLWidgetType" Value="qt6"/>
<Macro107 Name="LCLWidgetType" Value="qt6"/>
<Macro108 Name="LCLWidgetType" Value="qt6"/>
<Macro109 Name="LCLWidgetType" Value="qt6"/>
<Macro110 Name="LCLWidgetType" Value="qt6"/>
<Macro111 Name="LCLWidgetType" Value="qt6"/>
<Macro112 Name="LCLWidgetType" Value="qt6"/>
<Macro113 Name="LCLWidgetType" Value="qt6"/>
<Macro114 Name="LCLWidgetType" Value="qt6"/>
<Macro115 Name="LCLWidgetType" Value="qt6"/>
<Macro116 Name="LCLWidgetType" Value="qt6"/>
<Macro117 Name="LCLWidgetType" Value="qt6"/>
<Macro118 Name="LCLWidgetType" Value="qt6"/>
<Macro119 Name="LCLWidgetType" Value="qt6"/>
<Macro120 Name="LCLWidgetType" Value="qt6"/>
<Macro121 Name="LCLWidgetType" Value="qt6"/>
<Macro122 Name="LCLWidgetType" Value="qt6"/>
<Macro123 Name="LCLWidgetType" Value="qt6"/>
<Macro124 Name="LCLWidgetType" Value="qt6"/>
<Macro125 Name="LCLWidgetType" Value="qt6"/>
<Macro126 Name="LCLWidgetType" Value="qt6"/>
<Macro127 Name="LCLWidgetType" Value="qt6"/>
<Macro128 Name="LCLWidgetType" Value="qt6"/>
<Macro129 Name="LCLWidgetType" Value="qt6"/>
<Macro130 Name="LCLWidgetType" Value="qt6"/>
<Macro131 Name="LCLWidgetType" Value="qt6"/>
<Macro132 Name="LCLWidgetType" Value="qt6"/>
<Macro133 Name="LCLWidgetType" Value="qt6"/>
<Macro134 Name="LCLWidgetType" Value="qt6"/>
<Macro135 Name="LCLWidgetType" Value="qt6"/>
<Macro136 Name="LCLWidgetType" Value="qt6"/>
<Macro137 Name="LCLWidgetType" Value="qt6"/>
<Macro138 Name="LCLWidgetType" Value="qt6"/>
<Macro139 Name="LCLWidgetType" Value="qt6"/>
<Macro140 Name="LCLWidgetType" Value="qt6"/>
<Macro141 Name="LCLWidgetType" Value="qt6"/>
<Macro142 Name="LCLWidgetType" Value="qt6"/>
<Macro143 Name="LCLWidgetType" Value="qt6"/>
<Macro144 Name="LCLWidgetType" Value="qt6"/>
<Macro145 Name="LCLWidgetType" Value="qt6"/>
<Macro146 Name="LCLWidgetType" Value="qt6"/>
<Macro147 Name="LCLWidgetType" Value="qt6"/>
<Macro148 Name="LCLWidgetType" Value="qt6"/>
</MacroValues>
<BuildModes>
<Item Name="Debug" Default="True"/>
<Item Name="Release">
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="bin/$(TargetCPU)-$(TargetOS)/ewsdr"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
<RunWithoutDebug Value="True"/>
<StripSymbols Value="True"/>
</Debugging>
<LinkSmart Value="True"/>
</Linking>
<Other>
<CustomOptions Value="-k-L/usr/local/lib"/>
</Other>
</CompilerOptions>
</Item>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<RequiredPackages>
<Item>
<PackageName Value="LazOpenGLContextEx"/>
</Item>
<Item>
<PackageName Value="LCL"/>
</Item>
</RequiredPackages>
<Units>
<Unit>
<Filename Value="ewsdr.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="MainForm.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="MainForm"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit>
<Unit>
<Filename Value="HPSDRProtocol.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="HPSDRNetwork.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WebServer.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WebPageHtml.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WDSPEngine.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="BeaconDecoder.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="BeaconFEC.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="BeaconScopeForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="VfoOverlay.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="SampleRateOverlay.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="AudioOutput.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="AudioInput.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="DeviceForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="SettingsForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatButton.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatDropDown.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="AppTheme.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatSlider.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatCheckBox.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatComboBox.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatEdit.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FMRepeater.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="ChannelStore.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="ChannelsForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CWMorse.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CWKeyer.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CWDecoder.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CWTerminalForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CWMessagesForm.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatSpinEdit.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatFloatSpinEdit.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatListBox.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatRadioButton.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FlatProgressBar.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="EqualizerControl.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="FreqDisplay.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WDSP.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WebUtils.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WinFirewall.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WsClient.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="Settings.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CATEngine.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CATSerial.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CATTcp.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="CATSliceEndpoint.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="SpectrumView.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="PlatformUtils.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="PowerInhibit.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="BoardUtils.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WisdomBuilder.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="UISync.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="SpectrumViewOpengl.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="AlertOverlay.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WaterfallView.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="WaterfallViewOpengl.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="SMeterView.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="RulerView.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="bin/$(TargetCPU)-$(TargetOS)/ewsdr-debug"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf3"/>
</Debugging>
</Linking>
<Other>
<CustomOptions Value="-k-L/usr/local/lib"/>
</Other>
</CompilerOptions>
</CONFIG>