fix(band): soft-stop on stop key so immediate pick can start
Stop key no longer calls AutoBandTop1_Stop (library eats the next Start). Soft mute + tick gate runs on MainTask; cold start skips redundant Stop when already clean. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
4b8e676033
commit
d00f570e2f
|
|
@ -315,8 +315,31 @@ uint8_t app_log_try_command(const char *cmd)
|
||||||
"FLASH_BIN3_GO", "FLASH_BIN3_OK\n");
|
"FLASH_BIN3_GO", "FLASH_BIN3_OK\n");
|
||||||
return 1U;
|
return 1U;
|
||||||
}
|
}
|
||||||
if (strncmp(cmd, "tone status", 11) == 0) {
|
/* bp pick:经 MainTask 队列模拟真实拨片(与停止键串行,复现停后立即拨) */
|
||||||
uint8_t hdr[16];
|
if (strncmp(cmd, "bp pick", 7) == 0) {
|
||||||
|
MainTask_Sendmsg(MSG_ID_BP_KEY, 1 /*PICK_STATE_DOWN*/, 0, 0);
|
||||||
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "BP_PICK_OK\n");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
/* band dirty:强制下次冷启动先 Stop(验证 Stop→Start 紧挨是否必被吞) */
|
||||||
|
if (strncmp(cmd, "band dirty", 10) == 0) {
|
||||||
|
Band_ForceStopBeforeStart();
|
||||||
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "BAND_DIRTY_OK\n");
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
/* band state:停/起时序诊断 — StartFlag/PlayTick/是否在播 */
|
||||||
|
if (strncmp(cmd, "band state", 10) == 0) {
|
||||||
|
char line[96];
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"BAND_STATE start=%u playing=%u playtick=%lu ms=%lu\n",
|
||||||
|
(unsigned)StartFlag,
|
||||||
|
(unsigned)Band_IsPlaying(),
|
||||||
|
(unsigned long)AutoBandTop1_GetCurrentPlayTick(),
|
||||||
|
(unsigned long)app_log_ms());
|
||||||
|
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
||||||
|
return 1U;
|
||||||
|
}
|
||||||
|
if (strncmp(cmd, "tone status", 11) == 0) {uint8_t hdr[16];
|
||||||
uint8_t name[40];
|
uint8_t name[40];
|
||||||
uint8_t cur_hdr[16];
|
uint8_t cur_hdr[16];
|
||||||
char *pname;
|
char *pname;
|
||||||
|
|
|
||||||
243
Global/Global.c
243
Global/Global.c
|
|
@ -66,6 +66,10 @@ Fader_t faders[4] = {
|
||||||
|
|
||||||
const Touch_AreaTypeDef Touch_Areas[] =
|
const Touch_AreaTypeDef Touch_Areas[] =
|
||||||
{
|
{
|
||||||
|
/* 状态栏蓝牙:点击开关(热区略大于图标) */
|
||||||
|
{ UI0902_BT_HIT_X0, UI0902_BT_HIT_X1, UI0902_BT_HIT_Y0, UI0902_BT_HIT_Y1,
|
||||||
|
0, 0, GUI_BL_SW, NULL },
|
||||||
|
|
||||||
/* Xmin,Xmax,Ymin,Ymax, Flag, Value, ID, action — 与 UI_Label 网格同步 */
|
/* Xmin,Xmax,Ymin,Ymax, Flag, Value, ID, action — 与 UI_Label 网格同步 */
|
||||||
{ 12, 64, UI0902_CARD_Y, UI0902_CARD_Y + UI0902_CARD_H - 1, -1, 0, GUI_TRANSPOSE, NULL },
|
{ 12, 64, UI0902_CARD_Y, UI0902_CARD_Y + UI0902_CARD_H - 1, -1, 0, GUI_TRANSPOSE, NULL },
|
||||||
{ 65, 116, UI0902_CARD_Y, UI0902_CARD_Y + UI0902_CARD_H - 1, 1, 0, GUI_TRANSPOSE, NULL },
|
{ 65, 116, UI0902_CARD_Y, UI0902_CARD_Y + UI0902_CARD_H - 1, 1, 0, GUI_TRANSPOSE, NULL },
|
||||||
|
|
@ -107,6 +111,14 @@ bool PressFlag = 0;
|
||||||
|
|
||||||
void Return_Light_buff(uint8_t key_id_1629);
|
void Return_Light_buff(uint8_t key_id_1629);
|
||||||
uint8_t Band_IsPlaying(void);
|
uint8_t Band_IsPlaying(void);
|
||||||
|
void Band_AbsorbEatenStart(void);
|
||||||
|
void Band_MarkRealStop(void);
|
||||||
|
void Band_CancelStartFollowup(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);
|
||||||
|
/* 1=喂 AutoBand 1ms 节拍;停止键软停时清 0,避免库继续出音且不必 Stop */
|
||||||
|
uint8_t Band_TickGate = 1;
|
||||||
|
|
||||||
uint8_t AutoCloseTime = 15;
|
uint8_t AutoCloseTime = 15;
|
||||||
uint16_t mAutoPowerOffCount = 15 * 60;
|
uint16_t mAutoPowerOffCount = 15 * 60;
|
||||||
|
|
@ -672,7 +684,7 @@ void AutoBand_StartOutro(void)
|
||||||
app_tm1629_all_on(LED_COLOR_G);
|
app_tm1629_all_on(LED_COLOR_G);
|
||||||
/* 尾奏起奏前补发主音量,保证与图标一致 */
|
/* 尾奏起奏前补发主音量,保证与图标一致 */
|
||||||
MasterVolume_Reapply();
|
MasterVolume_Reapply();
|
||||||
AutoBandTop1_SyncStart();
|
Band_SyncStartRetry();
|
||||||
wk_delay_ms(50);
|
wk_delay_ms(50);
|
||||||
note_cnt = GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff);
|
note_cnt = GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff);
|
||||||
for(uint8_t i = 0;i < note_cnt;i++)
|
for(uint8_t i = 0;i < note_cnt;i++)
|
||||||
|
|
@ -712,7 +724,7 @@ void ADC_IN1_KEY_Handle(uint8_t key,bool on)
|
||||||
/* 前奏/断奏起奏前补发主音量,保证与图标一致 */
|
/* 前奏/断奏起奏前补发主音量,保证与图标一致 */
|
||||||
MasterVolume_Reapply();
|
MasterVolume_Reapply();
|
||||||
//AutoBandTop1_Start();
|
//AutoBandTop1_Start();
|
||||||
AutoBandTop1_SyncStart();
|
Band_SyncStartRetry();
|
||||||
wk_delay_ms(50);
|
wk_delay_ms(50);
|
||||||
note_cnt = GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff);
|
note_cnt = GetChordNotesByType(KEY_ID_1629,chord_type_index_map[KEY_ID_1629].type,midi_note_buff);
|
||||||
for(uint8_t i = 0;i < note_cnt;i++)
|
for(uint8_t i = 0;i < note_cnt;i++)
|
||||||
|
|
@ -888,25 +900,62 @@ void FreeMode_PollEvenBeatStop(void)
|
||||||
if (tick_done || beat_done)
|
if (tick_done || beat_done)
|
||||||
{
|
{
|
||||||
FreeMode_CancelEvenBeatStop();
|
FreeMode_CancelEvenBeatStop();
|
||||||
Stop_AutoBand();
|
Stop_AutoBand_Request();
|
||||||
LOG_I("pick", "free even-stop done beat=%d tick=%u beatDone=%u",
|
LOG_I("pick", "free even-stop done beat=%d tick=%u beatDone=%u",
|
||||||
beat, (unsigned)tick_done, (unsigned)beat_done);
|
beat, (unsigned)tick_done, (unsigned)beat_done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Band_MarkCleanStopped(void);
|
||||||
|
static void Band_StopBeforeColdStart(void);
|
||||||
|
|
||||||
|
/* 扫描线程只投递:真正 Stop 在 MainTask,与拨片 Pick 同队列串行。
|
||||||
|
* 若在扫描线程同步 Stop,会与 MainTask 拨片并发:Stop 期间 StartFlag 仍为 1,
|
||||||
|
* 拨片误判 Band_IsPlaying → 只改和弦不起奏,需再等 ~0.5s 才能拨响。 */
|
||||||
|
void Stop_AutoBand_Request(void)
|
||||||
|
{
|
||||||
|
/* ID=1:停止键软停(静音+停节拍,不调库 Stop,否则随后 Start 被吞) */
|
||||||
|
MainTask_Sendmsg(MSG_ID_STOP_BAND, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_AllNotesOff(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
uint8_t AllNoteOff_buff[3] = {(uint8_t)(0xB0 | i), 0x7B, 0x00};
|
||||||
|
SendMidiDataToDreamDSP(AllNoteOff_buff, sizeof(AllNoteOff_buff));
|
||||||
|
uint8_t AllControlOff_buff[3] = {(uint8_t)(0xB0 | i), 0x79, 0x00};
|
||||||
|
SendMidiDataToDreamDSP(AllControlOff_buff, sizeof(AllControlOff_buff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 停止键/偶拍收束:立刻静音并暂停库 1ms 节拍,不调用 AutoBandTop1_Stop。
|
||||||
|
* 库 Stop 之后第一个 Start 必被吞,立即拨片无声。 */
|
||||||
|
void Stop_AutoBand_Soft(void)
|
||||||
|
{
|
||||||
|
FreeMode_CancelEvenBeatStop();
|
||||||
|
Band_CancelStartFollowup();
|
||||||
|
Band_TickGate = 0;
|
||||||
|
StartFlag = 0;
|
||||||
|
KEY_ID_1629 = 0;
|
||||||
|
Band_MarkCleanStopped();
|
||||||
|
Band_AllNotesOff();
|
||||||
|
s_outro_led_all_green = 0;
|
||||||
|
for (uint8_t i = 0; i < 4; i++) key_toggle[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Stop_AutoBand()
|
void Stop_AutoBand()
|
||||||
{
|
{
|
||||||
FreeMode_CancelEvenBeatStop();
|
FreeMode_CancelEvenBeatStop();
|
||||||
AutoBandTop1_Stop();
|
/* 先清播放态,再 Stop/AllNoteOff,避免处理期间其它路径误判在播 */
|
||||||
for(uint8_t i = 0;i < 16;i++)
|
Band_CancelStartFollowup();
|
||||||
{
|
Band_TickGate = 1;
|
||||||
uint8_t AllNoteOff_buff[3] = {(uint8_t)(0xB0 | i),0x7B,0x00};
|
|
||||||
SendMidiDataToDreamDSP(AllNoteOff_buff,sizeof(AllNoteOff_buff));
|
|
||||||
uint8_t AllControlOff_buff[3] = {(uint8_t)(0xB0 | i),0x79,0x00};
|
|
||||||
SendMidiDataToDreamDSP(AllControlOff_buff,sizeof(AllControlOff_buff));
|
|
||||||
}
|
|
||||||
StartFlag = 0;
|
StartFlag = 0;
|
||||||
KEY_ID_1629 = 0; /* 停奏后再清,避免收束段音区映射突变 */
|
KEY_ID_1629 = 0;
|
||||||
|
Band_MarkCleanStopped();
|
||||||
|
AutoBandTop1_Stop();
|
||||||
|
Band_AllNotesOff();
|
||||||
s_outro_led_all_green = 0;
|
s_outro_led_all_green = 0;
|
||||||
//tick_ever_positive = false;
|
//tick_ever_positive = false;
|
||||||
for(uint8_t i = 0;i < 4;i++) key_toggle[i] = 0;
|
for(uint8_t i = 0;i < 4;i++) key_toggle[i] = 0;
|
||||||
|
|
@ -950,6 +999,135 @@ uint8_t BP_Transpose(uint8_t key_idx)
|
||||||
* 供专业模式指板键区分「播放中换和弦」与「段落结束后续奏重启」。 */
|
* 供专业模式指板键区分「播放中换和弦」与「段落结束后续奏重启」。 */
|
||||||
static uint64_t s_play_tick_last = 0;
|
static uint64_t s_play_tick_last = 0;
|
||||||
static uint32_t s_play_adv_tick = 0; /* 最近一次 PlayTick 前进的系统 tick */
|
static uint32_t s_play_adv_tick = 0; /* 最近一次 PlayTick 前进的系统 tick */
|
||||||
|
/* 1=下次冷启动前需先 Stop 清库残留;0=Stop_AutoBand 已停干净,勿再 Stop。 */
|
||||||
|
static uint8_t s_band_need_stop_before_start = 1;
|
||||||
|
/* 库特性(RTT 实测):真实停播后第一个完整 Start 被吞
|
||||||
|
* (StartFlag=1 但 PlayTick 归 0 且不前进);第二次完整 Start 才起奏。
|
||||||
|
* 哑 Start 不能用来吸收,会占住会话把真正起奏也吃掉。 */
|
||||||
|
static uint8_t s_band_eater_armed = 0;
|
||||||
|
|
||||||
|
static void Band_MarkCleanStopped(void)
|
||||||
|
{
|
||||||
|
s_play_tick_last = 0;
|
||||||
|
s_play_adv_tick = 0;
|
||||||
|
s_band_need_stop_before_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 一切可能真实停播的 Stop 路径调用:武装「停后首启被吞」标记。
|
||||||
|
* 宁可误武装(哑 Start 未被吞也只会被紧随的真实 Start 立刻重触发,无感),
|
||||||
|
* 不可漏武装(漏了用户就要拨两次)。 */
|
||||||
|
void Band_MarkRealStop(void)
|
||||||
|
{
|
||||||
|
s_band_eater_armed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 停后首个完整 Start 会被库吞掉(PlayTick 归 0 且不前进)。
|
||||||
|
* 同一次调用里连发两次会被合成一次,仍然被吞;必须隔一拍再 Start。
|
||||||
|
* 停后再起:先发本次 Start(可能被吞),再 20ms 后由 MainTask 补发一次。 */
|
||||||
|
static uint8_t s_start_followup_pending;
|
||||||
|
static uint8_t s_start_followup_force; /* 1=补发中,禁止走「在播只换和弦」 */
|
||||||
|
static rt_timer_t s_start_followup_timer;
|
||||||
|
|
||||||
|
static uint8_t Band_TakeEaterArmed(void)
|
||||||
|
{
|
||||||
|
uint8_t armed = s_band_eater_armed;
|
||||||
|
s_band_eater_armed = 0;
|
||||||
|
return armed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_StartFollowupTimerCb(void *parameter)
|
||||||
|
{
|
||||||
|
(void)parameter;
|
||||||
|
MainTask_Sendmsg(MSG_ID_START_FOLLOWUP, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Band_CancelStartFollowup(void)
|
||||||
|
{
|
||||||
|
s_start_followup_pending = 0;
|
||||||
|
s_start_followup_force = 0;
|
||||||
|
if (s_start_followup_timer != RT_NULL)
|
||||||
|
rt_timer_stop(s_start_followup_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Band_TakeStartFollowup(void)
|
||||||
|
{
|
||||||
|
uint8_t pending = s_start_followup_pending;
|
||||||
|
s_start_followup_pending = 0;
|
||||||
|
return pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Band_BeginStartFollowup(void)
|
||||||
|
{
|
||||||
|
s_start_followup_force = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Band_EndStartFollowup(void)
|
||||||
|
{
|
||||||
|
s_start_followup_force = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_PostStartFollowup(void)
|
||||||
|
{
|
||||||
|
if (s_start_followup_pending)
|
||||||
|
return;
|
||||||
|
s_start_followup_pending = 1;
|
||||||
|
if (s_start_followup_timer == RT_NULL)
|
||||||
|
{
|
||||||
|
s_start_followup_timer = rt_timer_create("bandFu",
|
||||||
|
Band_StartFollowupTimerCb,
|
||||||
|
RT_NULL,
|
||||||
|
500, /* 库吞掉停后首启;约 0.5s 后再 Start 才生效 */
|
||||||
|
RT_TIMER_FLAG_ONE_SHOT);
|
||||||
|
}
|
||||||
|
if (s_start_followup_timer != RT_NULL)
|
||||||
|
{
|
||||||
|
rt_timer_stop(s_start_followup_timer);
|
||||||
|
rt_timer_start(s_start_followup_timer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MainTask_Sendmsg(MSG_ID_START_FOLLOWUP, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_StartLocalRetry(uint8_t midi, uint8_t *notes, uint8_t n)
|
||||||
|
{
|
||||||
|
Band_TickGate = 1;
|
||||||
|
AutoBandTop1_StartWithNote(midi);
|
||||||
|
AutoBandTop1_StartWithNotes(notes, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_StartPieceRetry(uint8_t *notes, uint8_t n)
|
||||||
|
{
|
||||||
|
Band_TickGate = 1;
|
||||||
|
AutoBandTop1_StartWithNotes(notes, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Band_SyncStartRetry(void)
|
||||||
|
{
|
||||||
|
Band_TickGate = 1;
|
||||||
|
AutoBandTop1_SyncStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Band_AbsorbEatenStart(void)
|
||||||
|
{
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 冷启动前按需 Stop:已由停止键停干净则跳过 */
|
||||||
|
static void Band_StopBeforeColdStart(void)
|
||||||
|
{
|
||||||
|
if (s_band_need_stop_before_start)
|
||||||
|
{
|
||||||
|
Band_MarkRealStop(); /* 若库仍在播,此 Stop 会武装吞噬器,由紧随的吸收处理 */
|
||||||
|
AutoBandTop1_Stop();
|
||||||
|
}
|
||||||
|
s_band_need_stop_before_start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 诊断钩子:强制下次冷启动前先 Stop(RTT `band dirty`) */
|
||||||
|
void Band_ForceStopBeforeStart(void)
|
||||||
|
{
|
||||||
|
s_band_need_stop_before_start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void Band_TrackPlayTick(void)
|
void Band_TrackPlayTick(void)
|
||||||
{
|
{
|
||||||
|
|
@ -997,14 +1175,14 @@ static void Expert_StartWithChord(uint8_t chord_id, uint8_t *midi_note_buff,
|
||||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||||
{
|
{
|
||||||
/* 会话内勿 Stop:段落圆键切变奏后指板续奏若 Stop 会直接关音;
|
/* 会话内勿 Stop:段落圆键切变奏后指板续奏若 Stop 会直接关音;
|
||||||
* 与节奏类型一致,仅换和弦/重进当前段。冷启动仍 Stop 清残留。 */
|
* 与节奏类型一致,仅换和弦/重进当前段。
|
||||||
|
* 冷启动:仅当库可能仍有残留时才 Stop;停止键后已停干净则跳过。 */
|
||||||
if (!session)
|
if (!session)
|
||||||
AutoBandTop1_Stop();
|
Band_StopBeforeColdStart();
|
||||||
AutoBandTop1_SetLoopMode(0, 1);
|
AutoBandTop1_SetLoopMode(0, 1);
|
||||||
AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current);
|
AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current);
|
||||||
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
||||||
AutoBandTop1_StartWithNote(midi);
|
Band_StartLocalRetry(midi, midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
|
||||||
Band_NotifyPlayActivity();
|
Band_NotifyPlayActivity();
|
||||||
LOG_I("pick", "local/expert root=%u name=%s sw=%u tab=%u trigger=%s chord=%u",
|
LOG_I("pick", "local/expert root=%u name=%s sw=%u tab=%u trigger=%s chord=%u",
|
||||||
midi,
|
midi,
|
||||||
|
|
@ -1017,7 +1195,7 @@ static void Expert_StartWithChord(uint8_t chord_id, uint8_t *midi_note_buff,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AutoBandTop1_SetPiecePlayMode(1, 0, 1920);
|
AutoBandTop1_SetPiecePlayMode(1, 0, 1920);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
Band_StartPieceRetry(midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_SetLoopMode(0, 1);
|
AutoBandTop1_SetLoopMode(0, 1);
|
||||||
Band_NotifyPlayActivity();
|
Band_NotifyPlayActivity();
|
||||||
LOG_I("pick", "expert/rhythm piece name=%s trigger=%s chord=%u",
|
LOG_I("pick", "expert/rhythm piece name=%s trigger=%s chord=%u",
|
||||||
|
|
@ -1037,7 +1215,7 @@ void TM1629_Handle(uint8_t key)
|
||||||
if (mGuiData[GUI_TAB_INDEX].Current == 0)
|
if (mGuiData[GUI_TAB_INDEX].Current == 0)
|
||||||
{
|
{
|
||||||
if (key == 22) { Tap_to_Speed(); return; }
|
if (key == 22) { Tap_to_Speed(); return; }
|
||||||
if (key == 23) { Stop_AutoBand(); return; }
|
if (key == 23) { Stop_AutoBand_Request(); return; }
|
||||||
return; /* 忽略 0~21:不改 KEY_ID/USE_MIDI/PressFlag,不启停 OutTime_Stop */
|
return; /* 忽略 0~21:不改 KEY_ID/USE_MIDI/PressFlag,不启停 OutTime_Stop */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1066,7 +1244,7 @@ void TM1629_Handle(uint8_t key)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 22:Tap_to_Speed(); break;
|
case 22:Tap_to_Speed(); break;
|
||||||
case 23:Stop_AutoBand(); break;
|
case 23:Stop_AutoBand_Request(); break;
|
||||||
default: // 1 - 21
|
default: // 1 - 21
|
||||||
if (key >= 1 && key <= 21)
|
if (key >= 1 && key <= 21)
|
||||||
{
|
{
|
||||||
|
|
@ -1229,20 +1407,19 @@ void Pick_Handle()
|
||||||
StartFlag = 1;
|
StartFlag = 1;
|
||||||
AutoBandTop1_SetLoopMode(0,1);
|
AutoBandTop1_SetLoopMode(0,1);
|
||||||
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
||||||
AutoBandTop1_StartWithNote(midi);
|
Band_StartLocalRetry(midi, midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
StartFlag = 1;
|
StartFlag = 1;
|
||||||
AutoBandTop1_SetPiecePlayMode(1,0,1920);
|
AutoBandTop1_SetPiecePlayMode(1,0,1920);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
Band_StartPieceRetry(midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_SetLoopMode(0,1);
|
AutoBandTop1_SetLoopMode(0,1);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
/* 设置页内沿用万能:与主路径一致,始终 loop */
|
/* 设置页内沿用万能:与主路径一致,始终 loop */
|
||||||
AutoBandTop1_SetPiecePlayMode(1, 0, 480);
|
AutoBandTop1_SetPiecePlayMode(1, 0, 480);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
Band_StartPieceRetry(midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_SetLoopMode(0, 1);
|
AutoBandTop1_SetLoopMode(0, 1);
|
||||||
StartFlag = 1;
|
StartFlag = 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1258,35 +1435,43 @@ void Pick_Handle()
|
||||||
(unsigned)PressFlag, (unsigned)chord_id);
|
(unsigned)PressFlag, (unsigned)chord_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
uint8_t session_was_on = StartFlag ? 1u : 0u;
|
||||||
StartFlag = 1;
|
StartFlag = 1;
|
||||||
/* 普通:播放中指板 LED 全绿,关闭走向灯刷新 */
|
/* 普通:播放中指板 LED 全绿,关闭走向灯刷新 */
|
||||||
app_tm1629_all_on(LED_COLOR_G);
|
app_tm1629_all_on(LED_COLOR_G);
|
||||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||||
{
|
{
|
||||||
AutoBandTop1_Stop();
|
/* 播放中再拨:Stop+Start 重启段落;停止键后已停则勿二次 Stop。
|
||||||
|
* 此 Stop 若真实停播会武装库的吞噬器 → 紧随吸收 */
|
||||||
|
if (session_was_on)
|
||||||
|
{ Band_MarkRealStop(); AutoBandTop1_Stop(); }
|
||||||
|
else
|
||||||
|
Band_StopBeforeColdStart();
|
||||||
AutoBandTop1_SetLoopMode(0,1);
|
AutoBandTop1_SetLoopMode(0,1);
|
||||||
AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current);
|
AutoBandTop1_SetRunVar(mGuiData[GUI_PLAY_SECTION].Current);
|
||||||
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
midi = 0x3C + mGuiData[GUI_TRANSPOSE].Current;
|
||||||
AutoBandTop1_StartWithNote(midi);
|
Band_StartLocalRetry(midi, midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
|
||||||
LOG_I("pick", "local/normal root=%u name=%s", midi,
|
LOG_I("pick", "local/normal root=%u name=%s", midi,
|
||||||
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?");
|
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AutoBandTop1_SetPiecePlayMode(1, 0, 1920);
|
AutoBandTop1_SetPiecePlayMode(1, 0, 1920);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
Band_StartPieceRetry(midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_SetLoopMode(0, 1);
|
AutoBandTop1_SetLoopMode(0, 1);
|
||||||
LOG_I("pick", "normal/rhythm piece name=%s notes=%u chord=%u",
|
LOG_I("pick", "normal/rhythm piece name=%s notes=%u chord=%u",
|
||||||
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
|
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
|
||||||
(unsigned)note_cnt, (unsigned)chord_id);
|
(unsigned)note_cnt, (unsigned)chord_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
/* 专业:播放中再拨片不 Stop+Start(库会把未消费的 Start 标志清掉 → 静音);
|
/* 专业:播放中再拨片不 Stop+Start(库会把未消费的 Start 标志清掉 → 静音);
|
||||||
* 本地曲播放中仅换和弦音续播,节奏路径 piece 重启本就安全。 */
|
* 本地曲播放中仅换和弦音续播,节奏路径 piece 重启本就安全。 */
|
||||||
if (Band_IsPlaying() && mGuiData[GUI_AUTOBAND_SW].Current)
|
if (!s_start_followup_force &&
|
||||||
|
Band_IsPlaying() && mGuiData[GUI_AUTOBAND_SW].Current)
|
||||||
{
|
{
|
||||||
Accomp_UpdatePlayingChord();
|
Accomp_UpdatePlayingChord();
|
||||||
LOG_I("pick", "expert/pick skip restart playing chord=%u", (unsigned)chord_id);
|
LOG_I("pick", "expert/pick skip restart playing chord=%u", (unsigned)chord_id);
|
||||||
|
|
@ -1299,7 +1484,7 @@ void Pick_Handle()
|
||||||
StartFlag = 1;
|
StartFlag = 1;
|
||||||
s_outro_led_all_green = 0; /* 拨片重开 piece,恢复走向灯 */
|
s_outro_led_all_green = 0; /* 拨片重开 piece,恢复走向灯 */
|
||||||
AutoBandTop1_SetPiecePlayMode(1, 0, 480);
|
AutoBandTop1_SetPiecePlayMode(1, 0, 480);
|
||||||
AutoBandTop1_StartWithNotes(midi_note_buff, note_cnt);
|
Band_StartPieceRetry(midi_note_buff, note_cnt);
|
||||||
AutoBandTop1_SetLoopMode(0, 1);
|
AutoBandTop1_SetLoopMode(0, 1);
|
||||||
LOG_I("pick", "universal piece name=%s press=%u notes=%u chord=%u",
|
LOG_I("pick", "universal piece name=%s press=%u notes=%u chord=%u",
|
||||||
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
|
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@
|
||||||
#define MSG_ID_BLE_UI_REFRESH 28
|
#define MSG_ID_BLE_UI_REFRESH 28
|
||||||
#define MSG_ID_BLE_STYLE_SET 29
|
#define MSG_ID_BLE_STYLE_SET 29
|
||||||
#define MSG_ID_LOW_BAT_TIP 30
|
#define MSG_ID_LOW_BAT_TIP 30
|
||||||
|
#define MSG_ID_STOP_BAND 31 /* 停止键/收束:MainTask 串行 Stop,避免与拨片起奏竞态 */
|
||||||
|
#define MSG_ID_START_FOLLOWUP 32 /* 停后首启被库吞:下一拍补发真正起奏 */
|
||||||
|
|
||||||
#define GPIO_PIN_RESET false
|
#define GPIO_PIN_RESET false
|
||||||
#define GPIO_PIN_SET true
|
#define GPIO_PIN_SET true
|
||||||
|
|
@ -210,7 +212,6 @@ extern GUI_SWITCH ParamGuiData[];
|
||||||
extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
|
extern void (*CurrUIProcress)(DisplayTaskMessage_Type xEvent);
|
||||||
|
|
||||||
|
|
||||||
void Stop_AutoBand();
|
|
||||||
/* 普通模式:松手后偶拍收束轮询(由 Read_Cur_Measure 调用) */
|
/* 普通模式:松手后偶拍收束轮询(由 Read_Cur_Measure 调用) */
|
||||||
void FreeMode_PollEvenBeatStop(void);
|
void FreeMode_PollEvenBeatStop(void);
|
||||||
/* 当前调一级大和弦(把位1 + maj);开机/进模式/前奏/拨片兜底共用 */
|
/* 当前调一级大和弦(把位1 + maj);开机/进模式/前奏/拨片兜底共用 */
|
||||||
|
|
@ -238,6 +239,17 @@ void TM1617_Handle(uint8_t key);
|
||||||
void TM1629_Handle(uint8_t key);
|
void TM1629_Handle(uint8_t key);
|
||||||
void Pick_Handle();
|
void Pick_Handle();
|
||||||
void Loop_Light_Handle(uint8_t measure);
|
void Loop_Light_Handle(uint8_t measure);
|
||||||
|
void Stop_AutoBand(void);
|
||||||
|
void Stop_AutoBand_Soft(void);
|
||||||
|
extern uint8_t Band_TickGate;
|
||||||
|
void Stop_AutoBand_Request(void);
|
||||||
|
uint8_t Band_IsPlaying(void);
|
||||||
|
void Band_ForceStopBeforeStart(void);
|
||||||
|
void Band_AbsorbEatenStart(void);
|
||||||
|
void Band_MarkRealStop(void);
|
||||||
|
uint8_t Band_TakeStartFollowup(void);
|
||||||
|
void Band_BeginStartFollowup(void);
|
||||||
|
void Band_EndStartFollowup(void);
|
||||||
|
|
||||||
|
|
||||||
void BL_Set_led(uint8_t Led, uint8_t chord_type);
|
void BL_Set_led(uint8_t Led, uint8_t chord_type);
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,8 @@ volatile uint32_t tmr6_ticks;
|
||||||
*/
|
*/
|
||||||
__WEAK void wk_tmr6_1ms_tick(void)
|
__WEAK void wk_tmr6_1ms_tick(void)
|
||||||
{
|
{
|
||||||
AutoBandTop1_Metronome_External_1msTick();
|
if (Band_TickGate)
|
||||||
|
AutoBandTop1_Metronome_External_1msTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,24 @@ void TaskMainThread_entry(void* parameter)
|
||||||
if (!System_LowBat_IsActive())
|
if (!System_LowBat_IsActive())
|
||||||
Pick_Handle();
|
Pick_Handle();
|
||||||
break;
|
break;
|
||||||
|
case MSG_ID_STOP_BAND:
|
||||||
|
if (!System_LowBat_IsActive())
|
||||||
|
{
|
||||||
|
if (xEvent.ID)
|
||||||
|
Stop_AutoBand_Soft();
|
||||||
|
else
|
||||||
|
Stop_AutoBand();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MSG_ID_START_FOLLOWUP:
|
||||||
|
/* 停后补发:强制再 Start,勿因 NotifyPlayActivity 误判「在播」只换和弦 */
|
||||||
|
if (!System_LowBat_IsActive() && Band_TakeStartFollowup())
|
||||||
|
{
|
||||||
|
Band_BeginStartFollowup();
|
||||||
|
Pick_Handle();
|
||||||
|
Band_EndStartFollowup();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case MSG_ID_LOOP_LIGHT:
|
case MSG_ID_LOOP_LIGHT:
|
||||||
if (!System_LowBat_IsActive())
|
if (!System_LowBat_IsActive())
|
||||||
Loop_Light_Handle(xEvent.ID);
|
Loop_Light_Handle(xEvent.ID);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue