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:
parent
2d62e1e41a
commit
439ccf439d
|
|
@ -3,7 +3,7 @@
|
||||||
static uint8_t key_last = KEY_NONE;
|
static uint8_t key_last = KEY_NONE;
|
||||||
|
|
||||||
|
|
||||||
/* LED 期望颜色缓存:索引 = LedNum_TypeDef(0~7),COLOR_OTHER 表示灭 */
|
/* LED ??????????¹×???? = LedNum_TypeDef??0~7????COLOR_OTHER ????? */
|
||||||
//static LedColor_TypeDef led_cache[8] = {
|
//static LedColor_TypeDef led_cache[8] = {
|
||||||
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER,
|
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER,
|
||||||
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER
|
// COLOR_OTHER, COLOR_OTHER, COLOR_OTHER, COLOR_OTHER
|
||||||
|
|
@ -31,7 +31,12 @@ uint8_t app_tm1629_Scan_Key(void)
|
||||||
if(key != key_last)
|
if(key != key_last)
|
||||||
{
|
{
|
||||||
key_last = key;
|
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);
|
TM1629_Handle(key);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,64 @@ static uint8_t pStoreBuffer[PRESET_BUFFER_SIZE];
|
||||||
//static uint8_t* pStoreBuffer;
|
//static uint8_t* pStoreBuffer;
|
||||||
#define DEFAULT_TEMPO 100
|
#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~21)根音本就在低八度(43/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)
|
static void Func_CallBack_ProgramChange(int channel, int program)
|
||||||
{
|
{
|
||||||
MidiFifoItem_t midimsg;
|
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)
|
static void Func_CallBack_NoteOff(int channel,int key)
|
||||||
{
|
{
|
||||||
MidiFifoItem_t midimsg;
|
MidiFifoItem_t midimsg;
|
||||||
midimsg.msg[0] = 0x80 | channel;
|
int out_key = key;
|
||||||
midimsg.msg[1] = 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.msg[2] = 0;
|
||||||
midimsg.msglen = 3;
|
midimsg.msglen = 3;
|
||||||
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
|
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)
|
static void Func_CallBack_NoteOn(int channel,int key,int vel)
|
||||||
{
|
{
|
||||||
MidiFifoItem_t midimsg;
|
MidiFifoItem_t midimsg;
|
||||||
midimsg.msg[0] = 0x90 | channel;
|
int out_key = key;
|
||||||
midimsg.msg[1] = key;
|
if (channel != DRUM_CHANNEL && key >= 0 && key < 128)
|
||||||
midimsg.msg[2] = vel;
|
{
|
||||||
|
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;
|
midimsg.msglen = 3;
|
||||||
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
|
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)
|
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_SetPresetStoreBuffer(pStoreBuffer,PRESET_BUFFER_SIZE);
|
||||||
AutoBandTop1_Init();
|
AutoBandTop1_Init();
|
||||||
AutoBandTop1_RegisterCallBack_NoteOn(Func_CallBack_NoteOn);
|
AutoBandTop1_RegisterCallBack_NoteOn(Func_CallBack_NoteOn);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue