feat(tx): привязка профиля к паре «флаг + модуляция»

Одного значения на флаг мало: на слайсе с FT8 и на нём же голосом нужен разный
звук, а слайс/главный меняют модуляцию на лету. Привязка стала таблицей
TTXProfModeTable (режим → индекс профиля, -1 = не переключать), своя у каждого
флага: MainByMode у главного (одна на устройство, общая для КВ и трансвертера)
и TXProfByMode у слайса (сама разъезжается по контекстам — записи слайсов
хранятся отдельно для КВ и трансвертера).

Ключ — режим САМОГО ФЛАГА (FlagMode): у главного FMode, у слайса свой. Выбор в
пилюле пишется в ячейку текущего режима, поэтому смена модуляции достаёт
профиль, с которым в этом виде работали в прошлый раз.

Применение — в трёх точках, все ДО пуша режима в WDSP (ApplyTXChainSettings
внутри SetTXMode перешьёт цепь уже новыми значениями): SetTxSlice, SetMode
(если передаём с главного) и SetSliceMode (если источник — этот слайс).

Персист: tx_prof_modes в записи слайса, main_prof_modes в секции tx_profiles.
Чтение защитное — индекс вне текущего списка профилей читается как -1.
Round-trip проверен прогоном: обе таблицы переживают запись/чтение, незаданные
режимы -1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 17:58:46 +03:00
co-authored by Claude Opus 5
parent 013d0406ac
commit 36af031767
3 changed files with 143 additions and 30 deletions
+8 -2
View File
@@ -1570,6 +1570,10 @@ begin
SyncSpecViewFreq; // иначе полоса фильтра рисуется под старый режим
UpdateTXControlAvailability;
UpdateDMRStatus;
// Пилюля профиля во флаге A: привязка ключуется режимом, значит на
// смене модуляции она показывает уже другой профиль. Флаг главного
// приёмника живёт только на пане 0 — как в RefreshTxIndicators.
FPan.PushMainFlagExtState;
end;
rfFilter:
begin
@@ -7176,7 +7180,7 @@ begin
Cfg.Pans[i].Slices[n].FMSQLevel := FController.FSlices[s].FMSQLevel;
Cfg.Pans[i].Slices[n].DevName := FController.FSlices[s].DevName;
Cfg.Pans[i].Slices[n].InDevName := FController.FSlices[s].InDevName;
Cfg.Pans[i].Slices[n].TXProfile := FController.FSlices[s].TXProfile;
Cfg.Pans[i].Slices[n].TXProfByMode := FController.FSlices[s].TXProfByMode;
Inc(n);
end;
end;
@@ -7203,7 +7207,9 @@ begin
FController.FAudioIn.FindDeviceByName(SC.InDevName), SC.InDevName);
if SC.Muted then FController.SetSliceMute(Id, True);
FController.SetSliceRxMuteOnTx(Id, SC.RxMuteOnTx);
FController.SetSliceTXProfile(Id, SC.TXProfile); // «этот слайс звучит вот так»
// Таблица «режим → профиль» этого слайса целиком (не через SetSliceTXProfile:
// тот пишет только ячейку текущего режима).
FController.SetSliceTXProfileTable(Id, SC.TXProfByMode);
if SC.FMSQOn then FController.SetSliceFMSquelch(Id, True, SC.FMSQLevel);
P.CreateSliceFlag(Id);
FActiveSliceId := Id;