fix(free): stop accompaniment on next even beat after fret release

In normal mode, releasing the fretboard now finishes the current beat-pair (beat 1→end of 2, beat 3→end of 4) instead of cutting immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-09-21 15:23:10 +08:00
parent 8fa5220b82
commit 158c02d27b
2 changed files with 105 additions and 3 deletions

View File

@ -761,8 +761,106 @@ void Tap_to_Speed()
}
/* 普通模式松手:对齐到下一偶拍末再停(拍1→拍2末,拍3→拍4末)。
* piece 窗口 1920=4 拍,每拍 480 tick(与起奏 SetPiecePlayMode(1,0,1920) 一致)。 */
#define FREE_BEAT_TICKS 480u
#define FREE_PIECE_TICKS 1920u
static uint8_t s_free_even_stop_arm = 0;
static uint64_t s_free_even_stop_tick = 0;
static int s_free_even_stop_beat = 2; /* 目标偶拍 2 或 4 */
static uint8_t s_free_even_seen_target = 0;
static void FreeMode_CancelEvenBeatStop(void)
{
s_free_even_stop_arm = 0;
s_free_even_stop_tick = 0;
s_free_even_stop_beat = 2;
s_free_even_seen_target = 0;
}
/* 再次按住指板:取消待停并恢复 piece 循环 */
static void FreeMode_ResumePieceLoop(void)
{
if (!s_free_even_stop_arm)
return;
FreeMode_CancelEvenBeatStop();
if (StartFlag && mGuiData[GUI_TAB_INDEX].Current == 2 &&
!mGuiData[GUI_AUTOBAND_SW].Current)
{
AutoBandTop1_SetPiecePlayMode(1, 0, FREE_PIECE_TICKS);
AutoBandTop1_SetLoopMode(0, 1);
}
}
static void FreeMode_ArmEvenBeatStop(void)
{
uint64_t play;
int beat;
int target;
if (!StartFlag)
{
FreeMode_CancelEvenBeatStop();
return;
}
play = AutoBandTop1_GetCurrentPlayTick();
beat = AutoBandTop1_GetCurrentBeat();
if (beat < 1)
beat = 1;
/* 拍1→2,拍2→2,拍3→4,拍4→4 */
target = ((beat + 1) / 2) * 2;
s_free_even_stop_beat = target;
s_free_even_seen_target = (beat >= target) ? 1u : 0u;
/* ((beat0/2)+1)*2*480 → 拍1/2→960,拍3/4→1920,跨小节同理 */
s_free_even_stop_tick =
((play / FREE_BEAT_TICKS) / 2ull + 1ull) * 2ull * (uint64_t)FREE_BEAT_TICKS;
s_free_even_stop_arm = 1;
/* 禁循环并裁 piece,库播到 stop tick 自停;Poll 作兜底 */
AutoBandTop1_SetLoopMode(0, 0);
if (s_free_even_stop_tick <= 0xFFFFFFFFull)
AutoBandTop1_SetPiecePlayMode(1, 0, (uint32_t)s_free_even_stop_tick);
LOG_I("pick", "free even-stop arm beat=%d target=%d play=%u stop=%u",
beat, target, (unsigned)play, (unsigned)s_free_even_stop_tick);
}
void FreeMode_PollEvenBeatStop(void)
{
int beat;
uint8_t tick_done;
uint8_t beat_done;
if (!s_free_even_stop_arm)
return;
if (PressFlag || mGuiData[GUI_TAB_INDEX].Current != 2 || !StartFlag)
{
FreeMode_CancelEvenBeatStop();
return;
}
beat = AutoBandTop1_GetCurrentBeat();
if (beat == s_free_even_stop_beat)
s_free_even_seen_target = 1;
/* 已到达目标偶拍后离开该拍 = 该拍播完;或 play tick 到点 */
beat_done = (s_free_even_seen_target && beat != s_free_even_stop_beat && beat != 0) ? 1u : 0u;
tick_done = (AutoBandTop1_GetCurrentPlayTick() >= s_free_even_stop_tick) ? 1u : 0u;
if (tick_done || beat_done)
{
FreeMode_CancelEvenBeatStop();
KEY_ID_1629 = 0;
Stop_AutoBand();
LOG_I("pick", "free even-stop done beat=%d tick=%u beatDone=%u",
beat, (unsigned)tick_done, (unsigned)beat_done);
}
}
void Stop_AutoBand()
{
FreeMode_CancelEvenBeatStop();
AutoBandTop1_Stop();
for(uint8_t i = 0;i < 16;i++)
{
@ -914,10 +1012,10 @@ void TM1629_Handle(uint8_t key)
PressFlag = 0;
if(mGuiData[GUI_TAB_INDEX].Current == 2)
{
/* 普通:松手立即结束当前和弦伴奏 */
/* 普通:松手对齐到偶拍末再停(拍1→拍2末,拍3→拍4末) */
KEY_ID_1629 = 0;
if (StartFlag)
Stop_AutoBand();
FreeMode_ArmEvenBeatStop();
}
else if(mGuiData[GUI_TAB_INDEX].Current == 0)
{
@ -940,7 +1038,8 @@ void TM1629_Handle(uint8_t key)
}
else if(mGuiData[GUI_TAB_INDEX].Current == 2)
{
/* 普通:按住指板,等待拨片起奏当前和弦 */
/* 普通:按住指板;若正在偶拍收束则恢复循环续奏 */
FreeMode_ResumePieceLoop();
PressFlag = 1;
}
uint8_t group = (key - 1) / 3; /* 1~3→0, 4~6→1, ..., 19~21→6 */
@ -1637,6 +1736,7 @@ void Read_Cur_Measure()
(tab == 3 && (last == 0 || last == 2));
Band_TrackPlayTick();
FreeMode_PollEvenBeatStop();
/* 尾奏中保持全绿,不刷新和弦走向红灯 */
if (loop_light_ok && StartFlag && !s_outro_led_all_green)

View File

@ -206,6 +206,8 @@ extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
void Stop_AutoBand();
/* 普通模式:松手后偶拍收束轮询(由 Read_Cur_Measure 调用) */
void FreeMode_PollEvenBeatStop(void);
/* 当前调一级大和弦(把位1 + maj);开机/进模式/前奏/拨片兜底共用 */
void Accomp_ApplyDefaultIChord(void);