Lower accompaniment by one octave for #IV and V-VII chords.

AutoBand ignores input octave, so shift engine MIDI output by -12 for those chords (except drums) to keep the range from low #IV up to natural IV.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-09-10 22:08:09 +08:00
parent 2d62e1e41a
commit 439ccf439d
2 changed files with 87 additions and 8 deletions

View File

@ -3,7 +3,7 @@
static uint8_t key_last = KEY_NONE;
/* LED 期望颜色缓存:索引 = LedNum_TypeDef0~7COLOR_OTHER 表示灭 */
/* LED ??????????¹×???? = LedNum_TypeDef??0~7????COLOR_OTHER ????? */
//static LedColor_TypeDef led_cache[8] = {
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER,
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER
@ -31,9 +31,14 @@ uint8_t app_tm1629_Scan_Key(void)
if(key != key_last)
{
key_last = key;
LOG_I("KEY", "tm1629 key=%u", (unsigned)key);
if(key >= 1 && key <= 21)
LOG_I("KEY", "tm1629 key=%u pitch=%u type=%u", (unsigned)key,
(unsigned)chord_type_index_map[key].PitchOffset,
(unsigned)chord_type_index_map[key].type);
else
LOG_I("KEY", "tm1629 key=%u", (unsigned)key);
TM1629_Handle(key);
return key;
return key;
}
return KEY_NONE;
}

View File

@ -19,6 +19,64 @@ static uint8_t pStoreBuffer[PRESET_BUFFER_SIZE];
//static uint8_t* pStoreBuffer;
#define DEFAULT_TEMPO 100
/* ======== 路线A#IV 降八度拦截(音师库支持八度前的临时方案) ========
* AutoBand octaveBase
* GetChordNotesByType
* */
#define CHORD_OCTAVE_INTERCEPT_EN 1
#define DRUM_CHANNEL 9 /* 鼓通道不移调 */
/* 当前生效的八度偏移0 或 -12。RAM 余量极小,不用按音符表:
* CC123(All Notes Off)
* NoteOff */
static int8_t s_chord_octave_shift = 0;
static int8_t App_Auto_TargetChordOctaveShift(void)
{
#if CHORD_OCTAVE_INTERCEPT_EN
/* 与 GetChordNotesByType 的根音八度设计对齐(整段伴奏压一个八度):
* V/VI/VII 13~2143/45/47
* #IV 10~12 + Pitch
* -12 */
if (KEY_ID_1629 >= 13 && KEY_ID_1629 <= 21)
return -12;
if (KEY_ID_1629 >= 10 && KEY_ID_1629 <= 12 &&
chord_type_index_map[KEY_ID_1629].PitchOffset == 2)
return -12;
#endif
return 0;
}
static void App_Auto_QueueAllNotesOff(void)
{
MidiFifoItem_t m;
for (int ch = 0; ch < 16; ch++)
{
if (ch == DRUM_CHANNEL) continue;
m.msg[0] = 0xB0 | ch;
m.msg[1] = 123; /* CC123 All Notes Off */
m.msg[2] = 0;
m.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&m);
}
}
/* NoteOn 路径调用:偏移状态翻转时先清旧音,再返回新偏移 */
static int8_t App_Auto_ShiftForNoteOn(void)
{
int8_t target = App_Auto_TargetChordOctaveShift();
if (target != s_chord_octave_shift)
{
LOG_I("OCT", "shift %d->%d chord=%u pitch=%u",
(int)s_chord_octave_shift, (int)target,
(unsigned)KEY_ID_1629,
(unsigned)chord_type_index_map[KEY_ID_1629].PitchOffset);
App_Auto_QueueAllNotesOff();
s_chord_octave_shift = target;
}
return s_chord_octave_shift;
}
static void Func_CallBack_ProgramChange(int channel, int program)
{
MidiFifoItem_t midimsg;
@ -32,8 +90,15 @@ static void Func_CallBack_ProgramChange(int channel, int program)
static void Func_CallBack_NoteOff(int channel,int key)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0x80 | channel;
midimsg.msg[1] = key;
int out_key = key;
if (channel != DRUM_CHANNEL && key >= 0 && key < 128)
{
/* 按当前偏移还原;偏移翻转瞬间的旧音已由 CC123 清掉 */
out_key = key + s_chord_octave_shift;
if (out_key < 0 || out_key > 127) out_key = key;
}
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);
@ -43,9 +108,17 @@ static void Func_CallBack_NoteOff(int channel,int key)
static void Func_CallBack_NoteOn(int channel,int key,int vel)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0x90 | channel;
midimsg.msg[1] = key;
midimsg.msg[2] = vel;
int out_key = key;
if (channel != DRUM_CHANNEL && key >= 0 && key < 128)
{
int8_t shift = (vel == 0) ? s_chord_octave_shift /* vel=0 视同 NoteOff */
: App_Auto_ShiftForNoteOn();
out_key = key + shift;
if (out_key < 0 || out_key > 127) out_key = key;
}
midimsg.msg[0] = 0x90 | (channel & 0x0F);
midimsg.msg[1] = (uint8_t)out_key;
midimsg.msg[2] = (uint8_t)vel;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
@ -135,6 +208,7 @@ static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput)
//
void App_Auto_Init(void)
{
LOG_I("OCT", "intercept build 20260910 en=%d", (int)CHORD_OCTAVE_INTERCEPT_EN);
AutoBandTop1_SetPresetStoreBuffer(pStoreBuffer,PRESET_BUFFER_SIZE);
AutoBandTop1_Init();
AutoBandTop1_RegisterCallBack_NoteOn(Func_CallBack_NoteOn);