diff --git a/APP/app_log.c b/APP/app_log.c index 12a56c3..b569469 100644 --- a/APP/app_log.c +++ b/APP/app_log.c @@ -532,6 +532,18 @@ uint8_t app_log_try_command(const char *cmd) SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line); return 1U; } + /* mode N:进入模式选择页的第 N 项(0 万能 / 1 专业 / 2 普通),供 RTT 起奏 */ + if (strncmp(cmd, "mode ", 5) == 0 && cmd[5] != '\0') { + unsigned id = (unsigned)strtoul(cmd + 5, NULL, 10); + extern void Touch_Mode_Select_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex); + if (id > 2u) { + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MODE_BAD\n"); + return 1U; + } + Touch_Mode_Select_Action(0, (uint8_t)id, 0); + SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "MODE_OK\n"); + return 1U; + } /* tone start:在当前已加载音色上拨片起奏(不改 TAB/库) */ if (strncmp(cmd, "tone start", 10) == 0) { StartFlag = 0; diff --git a/MyCode/App_Auto.c b/MyCode/App_Auto.c index 560ee09..245f85c 100644 --- a/MyCode/App_Auto.c +++ b/MyCode/App_Auto.c @@ -56,8 +56,67 @@ static uint8_t s_seq_type; static uint8_t s_seq_xp; static uint8_t s_seq_po; #define SEQ_SLOTS 12 +#define ARP_CH 12 /* 逐音琶音;垫音通道同一拍会叠多个音,不参与网格 */ static uint8_t s_seq_step[16]; static struct { uint8_t ch, in, out, used; } s_seq_slot[SEQ_SLOTS]; +/* 红圈:同一拍叠上来的音向右 1 个音(图上 1 tik = 两个格子 = 一个八分音符)。 */ +static uint32_t s_grid_t0; +static uint16_t s_grid_unit; +static uint8_t s_grid_on; +static uint16_t s_pending_hold_ms; +static uint8_t s_slot_hold4[SEQ_SLOTS]; +static volatile uint16_t s_hold_report; +static volatile uint8_t s_hold_report_ready; +static volatile uint8_t s_hold_count; + +/* tmr6_ticks 没有在中断里累加,用已经在走的 1ms 时基。 */ +extern uint32_t wk_timebase_get(void); + +static void App_Auto_GridReset(void) +{ + s_grid_on = 0; + s_pending_hold_ms = 0; +} + +/* 当前速度的八分音符,单位 ms。速度范围 40..260。 */ +static uint16_t App_Auto_EighthMs(void) +{ + uint16_t bpm = (uint16_t)mGuiData[GUI_SPEED].Current; + if (bpm < 40u) + bpm = 40u; + return (uint16_t)(30000u / bpm); +} + +static void App_Auto_QueueMidi(MidiFifoItem_t *m, uint16_t hold_ms) +{ + if (hold_ms == 0u) + m->delayCounter = 0; + else + { + uint16_t due = (uint16_t)((uint16_t)wk_timebase_get() + hold_ms); + if (due == 0u) + due = 1u; + m->delayCounter = due; + s_hold_report = hold_ms; + if (s_hold_count < 255u) + s_hold_count++; + s_hold_report_ready = 1u; + } + mymidififo_InQueue(&m_MidiSendFifo, m); +} + +void App_Auto_LogHeldNotes(void) +{ + uint16_t ms; + uint8_t n; + if (!s_hold_report_ready) + return; + ms = s_hold_report; + n = s_hold_count; + s_hold_report_ready = 0; + LOG_I("SEQHOLD", "dly=%u n=%u unit=%u", + (unsigned)ms, (unsigned)n, (unsigned)s_grid_unit); +} static void App_Auto_SeqRefresh(void) { @@ -86,6 +145,7 @@ static void App_Auto_SeqRefresh(void) if (s_seq_on) App_Auto_QueueAllNotesOffMelodic(); s_seq_on = 0; + App_Auto_GridReset(); for (i = 0u; i < SEQ_SLOTS; i++) s_seq_slot[i].used = 0; return; @@ -106,7 +166,11 @@ static void App_Auto_SeqRefresh(void) for (i = 0u; i < 16u; i++) s_seq_step[i] = 0; for (i = 0u; i < SEQ_SLOTS; i++) + { s_seq_slot[i].used = 0; + s_slot_hold4[i] = 0; + } + App_Auto_GridReset(); s_seq_on = 1u; } @@ -116,6 +180,7 @@ static int App_Auto_MapSeq(int channel, int key, int is_on, int *out) int ch; int i; + s_pending_hold_ms = 0; App_Auto_SeqRefresh(); if (!s_seq_on || channel == BASS_CH || channel == DRUM_CH) return 0; @@ -128,15 +193,32 @@ static int App_Auto_MapSeq(int channel, int key, int is_on, int *out) && s_seq_slot[i].in == (uint8_t)key) { *out = s_seq_slot[i].out; + s_pending_hold_ms = (uint16_t)s_slot_hold4[i] * 4u; s_seq_slot[i].used = 0; + s_slot_hold4[i] = 0; return 1; } } *out = key; return 1; } - *out = s_seq[s_seq_step[ch] & 7u]; - s_seq_step[ch] = (uint8_t)((s_seq_step[ch] + 1u) & 7u); + { + uint8_t step = (uint8_t)(s_seq_step[ch] & 7u); + uint32_t now; + *out = s_seq[step]; + s_seq_step[ch] = (uint8_t)((step + 1u) & 7u); + /* 琶音通道同一拍里的后一个音,晚一个八分音符再发出 */ + if (ch == ARP_CH) + { + now = wk_timebase_get(); + if (s_grid_on && (now - s_grid_t0) < (uint32_t)(s_grid_unit / 4u)) + s_pending_hold_ms = s_grid_unit; + else + s_grid_unit = App_Auto_EighthMs(); + s_grid_t0 = now; + s_grid_on = 1u; + } + } for (i = 0; i < SEQ_SLOTS; i++) { if (!s_seq_slot[i].used) @@ -145,6 +227,7 @@ static int App_Auto_MapSeq(int channel, int key, int is_on, int *out) s_seq_slot[i].ch = (uint8_t)ch; s_seq_slot[i].in = (uint8_t)key; s_seq_slot[i].out = (uint8_t)(*out); + s_slot_hold4[i] = (uint8_t)(s_pending_hold_ms / 4u); return 1; } } @@ -152,6 +235,7 @@ static int App_Auto_MapSeq(int channel, int key, int is_on, int *out) s_seq_slot[0].ch = (uint8_t)ch; s_seq_slot[0].in = (uint8_t)key; s_seq_slot[0].out = (uint8_t)(*out); + s_slot_hold4[0] = (uint8_t)(s_pending_hold_ms / 4u); return 1; } @@ -193,7 +277,7 @@ static uint8_t App_Auto_RegFingerprint(void) static void App_Auto_QueueAllNotesOffMelodic(void) { - MidiFifoItem_t m; + MidiFifoItem_t m = {0}; int ch; for (ch = 0; ch < 16; ch++) { @@ -202,7 +286,7 @@ static void App_Auto_QueueAllNotesOffMelodic(void) m.msg[1] = 123; /* All Notes Off */ m.msg[2] = 0; m.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo, &m); + App_Auto_QueueMidi(&m, 0); } } @@ -492,7 +576,7 @@ static int App_Auto_MapNoteOn(int channel, int key) static void Func_CallBack_ProgramChange(int channel, int program) { - MidiFifoItem_t midimsg; + MidiFifoItem_t midimsg = {0}; uint8_t ch = (uint8_t)(channel & 0x0F); uint8_t bank = MIDI_BANK_ACCOMP; /* 通道 0 是硅胶弦。节奏预设常在这里放钢琴(Program 0),会盖掉弦音色。 */ @@ -510,33 +594,33 @@ static void Func_CallBack_ProgramChange(int channel, int program) midimsg.msg[1] = 0x00; /* CC0 Bank MSB */ midimsg.msg[2] = bank; midimsg.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, 0); midimsg.msg[1] = 0x20; /* CC32 Bank LSB */ midimsg.msg[2] = 0; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, 0); midimsg.msg[0] = 0xc0 | ch; midimsg.msg[1] = (uint8_t)program; midimsg.msg[2] = 0; midimsg.msglen = 2; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, 0); } static void Func_CallBack_NoteOff(int channel,int key) { - MidiFifoItem_t midimsg; + MidiFifoItem_t midimsg = {0}; uint8_t flags = 0; int out_key = App_Auto_MapNote(channel, key, &flags, 0); midimsg.msg[0] = 0x80 | (channel & 0x0F); midimsg.msg[1] = (uint8_t)out_key; midimsg.msg[2] = 0; midimsg.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, s_pending_hold_ms); } static void Func_CallBack_NoteOn(int channel,int key,int vel) { - MidiFifoItem_t midimsg; + MidiFifoItem_t midimsg = {0}; int out_key; if (vel == 0) @@ -551,7 +635,7 @@ static void Func_CallBack_NoteOn(int channel,int key,int vel) midimsg.msg[1] = (uint8_t)out_key; midimsg.msg[2] = (uint8_t)vel; midimsg.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, s_pending_hold_ms); } @@ -561,23 +645,23 @@ static void Func_CallBack_CC(int channel,int cc,int value) { return; } - MidiFifoItem_t midimsg; + MidiFifoItem_t midimsg = {0}; midimsg.msg[0] = 0xb0 | channel; midimsg.msg[1] = cc; midimsg.msg[2] = value; midimsg.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, 0); } static void Func_CallBack_PitchWheel(int channel,int cc,int value) { - MidiFifoItem_t midimsg; + MidiFifoItem_t midimsg = {0}; midimsg.msg[0] = 0xe0 | channel; midimsg.msg[1] = cc; midimsg.msg[2] = value; midimsg.msglen = 3; - mymidififo_InQueue(&m_MidiSendFifo,&midimsg); + App_Auto_QueueMidi(&midimsg, 0); } /* Flash Map 0903:对照 ExtFlash_Tone_Addr.h / Doc/.../FLASH_MAP.txt */ diff --git a/project/IAR_V7.4/YNGJ-GT1-M.ewp b/project/IAR_V7.4/YNGJ-GT1-M.ewp index dd9c114..3a35495 100644 --- a/project/IAR_V7.4/YNGJ-GT1-M.ewp +++ b/project/IAR_V7.4/YNGJ-GT1-M.ewp @@ -185,7 +185,7 @@ USE_STDPERIPH_DRIVER AT_START_F403A_V1 autoband - DEBUG_LCD_DUMP=1 + DEBUG_LCD_DUMP=0