fix(univ): finish the universal outro so the pick can start again

Keep the last 1/2/3 fill on screen, and leave neck lights all green in normal and expert unless the app is guiding them.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-10-14 11:20:51 +08:00
parent ccad4570d8
commit a68b978c08
5 changed files with 74 additions and 18 deletions

View File

@ -123,7 +123,12 @@ void AppNeckLed_NoteGuide(void)
void AppNeckLed_ClearGuide(void)
{
uint8_t tab;
s_app_neck_led = 0;
/* 断开 App 后,普通/专业回到一直全绿 */
tab = (uint8_t)mGuiData[GUI_TAB_INDEX].Current;
if (tab == 1u || tab == 2u)
app_tm1629_all_on(LED_COLOR_G);
}
uint8_t AppNeckLed_IsGuide(void)
@ -944,6 +949,10 @@ void Accomp_UpdatePlayingChord(void)
/* 尾奏期间冻结走向灯:保持全绿,避免 LOOP_LIGHT 按小节刷红 */
static uint8_t s_outro_led_all_green = 0;
/* bit0=等尾奏播完再停,bit1=已见到尾奏舞台 */
static uint8_t s_outro_wait_end = 0;
#define OUTRO_WAIT_END 0x01u
#define OUTRO_SAW_STAGE 0x02u
/* 万能拨片:bit0=等前奏后进 piece,bit1=已见前奏舞台(省 RAM) */
static uint8_t s_univ_preamble_flags = 0;
@ -991,7 +1000,14 @@ static void Accomp_PostambleCutNow(void)
*(volatile uint32_t *)(m_ABSystem + AB_BAR_PHASE_OFF) = 0;
}
/* 万能拨片起奏:退出 piece → 前奏(不循环) → 待前奏结束后切入 piece 段落1 循环。 */
/* 万能 1/2/3 才是加花;4 号是尾奏,不占用屏幕焦点 */
static uint8_t Univ_FillSection(void)
{
uint8_t sec = (uint8_t)mGuiData[GUI_PLAY_SECTION].Current;
if (sec > 2u)
sec = 2u;
return sec;
}
static void Univ_StartWithPreamble(uint8_t *notes, uint8_t n)
{
uint8_t session_was_on = StartFlag ? 1u : 0u;
@ -1001,7 +1017,8 @@ static void Univ_StartWithPreamble(uint8_t *notes, uint8_t n)
StartFlag = 1;
s_outro_led_all_green = 0;
mGuiData[GUI_PLAY_SECTION].Current = 0; /* 段落后续固定进段落1 */
s_outro_wait_end = 0;
/* 再拨片按屏幕上仍选中的 1/2/3 加花,不改回段落 1 */
if (session_was_on)
AutoBandTop1_Stop();
@ -1010,7 +1027,7 @@ static void Univ_StartWithPreamble(uint8_t *notes, uint8_t n)
/* 须先退出 piece,否则 Preamble 舞台切不过去(同尾奏) */
AutoBandTop1_SetPiecePlayMode(0, 0, 0);
AutoBandTop1_SetRunVar(0);
AutoBandTop1_SetRunVar(Univ_FillSection());
AutoBandTop1_SetLoopMode(0, 1); /* 循环主段落,不循环前奏 */
AutoBandTop1_Preamble(0);
MasterVolume_Reapply();
@ -1051,7 +1068,7 @@ static void Univ_PollEnterPieceAfterPreamble(void)
return;
s_univ_preamble_flags = 0;
AutoBandTop1_SetRunVar(0);
AutoBandTop1_SetRunVar(Univ_FillSection());
AutoBandTop1_SetPiecePlayMode(1, 0, 480);
AutoBandTop1_SetLoopMode(0, 1);
@ -1070,6 +1087,35 @@ static void Univ_PollEnterPieceAfterPreamble(void)
(unsigned)note_cnt, (unsigned)chord_id);
}
/* 万能 4 号尾奏播完后硬停,状态与止音键一致,拨片才能再启动 */
static void Univ_PollOutroEnd(void)
{
uint8_t st;
uint8_t tab;
uint8_t last;
if (!(s_outro_wait_end & OUTRO_WAIT_END) || !StartFlag)
return;
tab = (uint8_t)mGuiData[GUI_TAB_INDEX].Current;
last = (uint8_t)mGuiData[GUI_TAB_LAST_INDEX].Current;
if (tab != 0u && !(tab == 3u && last == 0u))
{
s_outro_wait_end = 0;
return;
}
st = m_ABSystem[AB_STAGE_OFF];
if (st == AB_STAGE_POST_WAIT || st == AB_STAGE_POST)
{
s_outro_wait_end |= OUTRO_SAW_STAGE;
return;
}
if (s_outro_wait_end & OUTRO_SAW_STAGE)
{
s_outro_wait_end = 0;
Stop_AutoBand_Request();
}
}
/* 尾奏起奏:Postamble(0) + 同步起奏 + 当前和弦 Note_On。
* 供 ADC 独立尾奏键与万能模式第4段落键共用。
* 万能走 piece 循环,须先退出 piece,否则 Postamble 舞台切不过去;
@ -1087,9 +1133,11 @@ void AutoBand_StartOutro(void)
/* 退出和弦走向 piece,再进风格尾奏舞台 */
AutoBandTop1_SetPiecePlayMode(0, 0, 0);
AutoBandTop1_Postamble(0);
/* 尾奏:指板 LED 全绿(停走 LOOP 走向红灯) */
/* 尾奏:未连 App 时指板全绿。播完后 Univ_PollOutroEnd 硬停。 */
s_outro_led_all_green = 1;
app_tm1629_all_on(LED_COLOR_G);
s_outro_wait_end = OUTRO_WAIT_END;
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
/* 尾奏起奏前补发主音量,保证与图标一致 */
MasterVolume_Reapply();
if (was_playing)
@ -1392,6 +1440,7 @@ void Stop_AutoBand(void)
AutoBandTop1_Stop();
Band_AllNotesOff();
s_outro_led_all_green = 0;
s_outro_wait_end = 0;
s_univ_preamble_flags = 0;
for (uint8_t i = 0; i < 4; i++) key_toggle[i] = 0;
}
@ -1889,8 +1938,11 @@ void Pick_Handle()
break;
case 1:
/* 专业:播放中再拨片不 Stop+Start(库会把未消费的 Start 标志清掉 → 静音);
/* 专业:未连 App 时把位灯一直全绿。App 引导中不改灯。
* 播放中再拨片不 Stop+Start(库会把未消费的 Start 标志清掉 → 静音);
* 本地曲播放中仅换和弦音续播,节奏路径 piece 重启本就安全。 */
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
if (Band_IsPlaying() && mGuiData[GUI_AUTOBAND_SW].Current)
{
Accomp_UpdatePlayingChord();
@ -2350,9 +2402,10 @@ void Read_Cur_Measure()
Band_TrackPlayTick();
FreeMode_PollEvenBeatStop();
Univ_PollEnterPieceAfterPreamble();
Univ_PollOutroEnd();
/* 尾奏中保持全绿,不刷新和弦走向红灯 */
if (loop_light_ok && StartFlag && !s_outro_led_all_green)
/* 尾奏中保持全绿。App 弹唱只显示下发灯,不走本地走向灯。 */
if (loop_light_ok && StartFlag && !s_outro_led_all_green && !AppNeckLed_IsGuide())
{
if(now - last_tick_i >= 10)
{

View File

@ -6,6 +6,9 @@ void UI_ExpertMode_Init(void)
mGuiData[GUI_TAB_LAST_INDEX].Current = mGuiData[GUI_TAB_INDEX].Current;
//mGuiData[GUI_AUTOBAND_SW].Current = 1;
UI_ReloadTonePreset(); /* 必须在 TAB=专业 之后换库,否则仍是万能 3.bin */
/* 未连 App 弹唱:专业把位灯一直全绿。App 引导中不改灯。 */
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
if (CurrUIProcress == UI_SongMode_Process)
Show_home_UI_Diff();
else

View File

@ -7,7 +7,9 @@ void UI_FreeMode_Init(void)
mGuiData[GUI_TAB_LAST_INDEX].Current = mGuiData[GUI_TAB_INDEX].Current;
//mGuiData[GUI_AUTOBAND_SW].Current = 1;
UI_ReloadTonePreset(); /* TAB=普通 后再加载 1.bin */
app_tm1629_all_on(LED_COLOR_G); /* 普通模式:全绿,不跟节奏走向灯 */
/* 未连 App:普通一直全绿。App 引导中不改灯。 */
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
if (CurrUIProcress == UI_SongMode_Process)
Show_home_UI_Diff();
else

View File

@ -262,14 +262,10 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
}
else if(ID==GUI_PLAY_SECTION)
{
/* 万能模式第4键:改为尾奏播放(与独立尾奏键同路径),不走 main4 */
/* 万能模式第4键是尾奏,不是第4加花:不改 1/2/3 焦点 */
if (mGuiData[GUI_TAB_INDEX].Current == 0 && value == 3)
{
last_value = mGuiData[ID].Current;
mGuiData[ID].Current = value;
AutoBand_StartOutro();
if (!UI_SetFocus(GUI_PLAY_SECTION))
Refresh_SectionSelect(last_value, &UI_Label[ID], &mGuiData[ID]);
return;
}
if(mGuiData[ID].Current != value)
@ -305,7 +301,8 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
Accomp_RememberPlayContext();
mGuiData[ID].Current = value;
app_tm1629_all_on(LED_COLOR_G);
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
switch(mGuiData[ID].Current)
{
case 0: /* 万能 → 3.bin / 本地→2.bin */

View File

@ -1132,8 +1132,9 @@ void Draw_Bottom_Bar(uint8_t sel, uint8_t first_back)
void UI_NavBar_Action(uint8_t value)
{
/* 离开万能后 LOOP_LIGHT 停更,须显式恢复全绿(旧 GUI_TAB_INDEX 路径曾做) */
app_tm1629_all_on(LED_COLOR_G);
/* 离开万能后 LOOP_LIGHT 停更。未连 App 时普通/专业保持全绿;App 引导中不改灯。 */
if (!AppNeckLed_IsGuide())
app_tm1629_all_on(LED_COLOR_G);
/* 先记住当前专业/普通的指板与移调,再停;勿再强制一级(会盖掉记忆供普通无指板拨片) */
Accomp_RememberPlayContext();
Stop_AutoBand();