diff --git a/Global/Global.c b/Global/Global.c index 1921810..6940d6f 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -105,7 +105,7 @@ int16_t MIC_VOL_MAP[11]= {-9000,-7000,-5000,-3000,-1000,1000,3000,5000,7000,9000 uint8_t TOUCH_AREA_NUM = (sizeof(Touch_Areas)/sizeof(Touch_AreaTypeDef)); -const uint8_t Version[3] = {0,2,22}; /* major.minor.patch — 0.2.22: 普通/专业模式前奏间奏尾奏断奏即刻切入;万能模式忽略这四键 */ +const uint8_t Version[3] = {0,2,23}; /* major.minor.patch — 0.2.23: 万能拨片先前奏再循环段落1 */ uint8_t Led = 8; bool PressFlag = 0; @@ -114,9 +114,11 @@ uint8_t Band_IsPlaying(void); void Band_AbsorbEatenStart(void); void Band_MarkRealStop(void); void Band_CancelStartFollowup(void); +void Band_NotifyPlayActivity(void); static void Band_StartLocalRetry(uint8_t midi, uint8_t *notes, uint8_t n); static void Band_StartPieceRetry(uint8_t *notes, uint8_t n); static void Band_SyncStartRetry(void); +static void Band_StopBeforeColdStart(void); /* 1=喂 AutoBand 1ms 节拍;停止键软停时清 0,避免库继续出音且不必 Stop */ uint8_t Band_TickGate = 1; @@ -666,12 +668,18 @@ void Accomp_UpdatePlayingChord(void) /* 尾奏期间冻结走向灯:保持全绿,避免 LOOP_LIGHT 按小节刷红 */ static uint8_t s_outro_led_all_green = 0; +/* 万能拨片:前奏播完后再切入 piece 段落1 循环 */ +static uint8_t s_univ_piece_after_preamble = 0; +static uint8_t s_univ_saw_preamble_stage = 0; + /* libAutoBand m_ABSystem:+0x59 舞台,+0x50 小节相位。 - * 前奏挂起舞台 0x0E、尾奏挂起舞台 0x0B 都要等相位对上小节线才真正切入。 */ + * 前奏挂起舞台 0x0E、尾奏挂起舞台 0x0B 都要等相位对上小节线才真正切入。 + * 前奏中舞台 4、前奏结束后进 Run(5)。 */ extern uint8_t m_ABSystem[]; #define AB_STAGE_OFF 0x59u #define AB_BAR_PHASE_OFF 0x50u #define AB_STAGE_PRE_WAIT 0x0Eu +#define AB_STAGE_PRE 0x04u #define AB_STAGE_POST_WAIT 0x0Bu #define AB_STAGE_POST 0x0Cu @@ -704,6 +712,91 @@ static void Accomp_PostambleCutNow(void) *(volatile uint32_t *)(m_ABSystem + AB_BAR_PHASE_OFF) = 0; } +/* 万能拨片起奏:退出 piece → 前奏(不循环) → 待前奏结束后切入 piece 段落1 循环。 */ +static void Univ_StartWithPreamble(uint8_t *notes, uint8_t n) +{ + uint8_t session_was_on = StartFlag ? 1u : 0u; + + (void)notes; + (void)n; + + StartFlag = 1; + s_outro_led_all_green = 0; + mGuiData[GUI_PLAY_SECTION].Current = 0; /* 段落后续固定进段落1 */ + + if (session_was_on) + { + Band_MarkRealStop(); + AutoBandTop1_Stop(); + } + else + Band_StopBeforeColdStart(); + + /* 须先退出 piece,否则 Preamble 舞台切不过去(同尾奏) */ + AutoBandTop1_SetPiecePlayMode(0, 0, 0); + AutoBandTop1_SetRunVar(0); + AutoBandTop1_SetLoopMode(0, 1); /* 循环主段落,不循环前奏 */ + AutoBandTop1_Preamble(0); + MasterVolume_Reapply(); + Band_SyncStartRetry(); + wk_delay_ms(50); + Accomp_FireSectionNotes(); + s_univ_saw_preamble_stage = 0; + s_univ_piece_after_preamble = 1; +} + +/* 前奏舞台结束后切入 piece 段落1 并保持 loop。 */ +static void Univ_PollEnterPieceAfterPreamble(void) +{ + uint8_t st; + uint8_t midi_note_buff[4] = {0,}; + uint8_t note_cnt; + uint8_t chord_id; + + if (!s_univ_piece_after_preamble || !StartFlag) + return; + if (mGuiData[GUI_TAB_INDEX].Current != 0 && + !(mGuiData[GUI_TAB_INDEX].Current == 3 && + mGuiData[GUI_TAB_LAST_INDEX].Current == 0)) + { + s_univ_piece_after_preamble = 0; + s_univ_saw_preamble_stage = 0; + return; + } + + st = m_ABSystem[AB_STAGE_OFF]; + /* 前奏挂起/前奏中:记下已进入前奏,继续等播完 */ + if (st == AB_STAGE_PRE_WAIT || st == AB_STAGE_PRE) + { + s_univ_saw_preamble_stage = 1; + return; + } + /* 尚未见到前奏舞台:若已到 Run(5) 说明空前奏被跳过,可进 piece; + * 其它启动中舞台继续等,避免冷启动抢先切入 piece 砍掉前奏。 */ + if (!s_univ_saw_preamble_stage && st != 5u) + return; + + s_univ_piece_after_preamble = 0; + s_univ_saw_preamble_stage = 0; + AutoBandTop1_SetRunVar(0); + AutoBandTop1_SetPiecePlayMode(1, 0, 480); + AutoBandTop1_SetLoopMode(0, 1); + + chord_id = KEY_ID_1629; + if (chord_id == 0 || chord_id == 22 || chord_id == 23) + { + Accomp_ApplyDefaultIChord(); + chord_id = KEY_ID_1629; + } + note_cnt = GetChordNotesByType(chord_id, chord_type_index_map[chord_id].type, + midi_note_buff); + Band_StartPieceRetry(midi_note_buff, note_cnt); + Band_NotifyPlayActivity(); + LOG_I("pick", "universal after-preamble piece name=%s notes=%u chord=%u", + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)note_cnt, (unsigned)chord_id); +} + /* 尾奏起奏:Postamble(0) + 同步起奏 + 当前和弦 Note_On。 * 供 ADC 独立尾奏键与万能模式第4段落键共用。 * 万能走 piece 循环,须先退出 piece,否则 Postamble 舞台切不过去; @@ -713,6 +806,9 @@ void AutoBand_StartOutro(void) { uint8_t was_playing = StartFlag; + s_univ_piece_after_preamble = 0; + s_univ_saw_preamble_stage = 0; + if (KEY_ID_1629 == 0 || KEY_ID_1629 == 22 || KEY_ID_1629 == 23) Accomp_ApplyDefaultIChord(); @@ -1004,6 +1100,8 @@ void Stop_AutoBand_Soft(void) Band_MarkCleanStopped(); Band_AllNotesOff(); s_outro_led_all_green = 0; + s_univ_piece_after_preamble = 0; + s_univ_saw_preamble_stage = 0; for (uint8_t i = 0; i < 4; i++) key_toggle[i] = 0; } @@ -1019,6 +1117,8 @@ void Stop_AutoBand() AutoBandTop1_Stop(); Band_AllNotesOff(); s_outro_led_all_green = 0; + s_univ_piece_after_preamble = 0; + s_univ_saw_preamble_stage = 0; //tick_ever_positive = false; for(uint8_t i = 0;i < 4;i++) key_toggle[i] = 0; } @@ -1482,11 +1582,11 @@ void Pick_Handle() AutoBandTop1_SetLoopMode(0,1); break; case 0: - /* 设置页内沿用万能:与主路径一致,始终 loop */ - AutoBandTop1_SetPiecePlayMode(1, 0, 480); - Band_StartPieceRetry(midi_note_buff, note_cnt); - AutoBandTop1_SetLoopMode(0, 1); - StartFlag = 1; + /* 设置页内沿用万能:拨片先前奏,再循环段落1 */ + Univ_StartWithPreamble(midi_note_buff, note_cnt); + LOG_I("pick", "settings/universal preamble→sec1 name=%s notes=%u", + AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", + (unsigned)note_cnt); break; } break; @@ -1545,13 +1645,9 @@ void Pick_Handle() Expert_StartWithChord(chord_id, midi_note_buff, note_cnt, "pick"); break; case 0: - /* 万能:和弦走向用 piece 模式;须 SetLoopMode,否则无循环时常听不到伴奏 */ - StartFlag = 1; - s_outro_led_all_green = 0; /* 拨片重开 piece,恢复走向灯 */ - AutoBandTop1_SetPiecePlayMode(1, 0, 480); - Band_StartPieceRetry(midi_note_buff, note_cnt); - AutoBandTop1_SetLoopMode(0, 1); - LOG_I("pick", "universal piece name=%s press=%u notes=%u chord=%u", + /* 万能:拨片先播前奏,结束后进 piece 段落1 并 loop(不循环前奏) */ + Univ_StartWithPreamble(midi_note_buff, note_cnt); + LOG_I("pick", "universal preamble→sec1 name=%s press=%u notes=%u chord=%u", AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?", (unsigned)PressFlag, (unsigned)note_cnt, (unsigned)chord_id); break; @@ -1996,6 +2092,7 @@ void Read_Cur_Measure() Band_TrackPlayTick(); FreeMode_PollEvenBeatStop(); + Univ_PollEnterPieceAfterPreamble(); /* 尾奏中保持全绿,不刷新和弦走向红灯 */ if (loop_light_ok && StartFlag && !s_outro_led_all_green)