Compare commits

...

3 Commits

Author SHA1 Message Date
yuquanjun 439ccf439d 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>
2026-09-10 22:08:09 +08:00
yuquanjun 2d62e1e41a Stop drawing status volume bar on mixer page to avoid erasing the back button.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 19:29:47 +08:00
yuquanjun 4aad989263 Reapply master volume at boot/mode-entry/play-start and sync volume bar on settings hub.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 18:58:24 +08:00
11 changed files with 132 additions and 16 deletions

View File

@ -303,6 +303,14 @@ void app_adc_sync_volume(uint16_t val)
app_adc_volume_map_level(val);
}
/* 取当前主音量(复用扫描任务维护的最近一次有效值)。
* ADC
* vol_last0xFFFF */
uint8_t app_adc_get_volume(void)
{
return (vol_last > 127) ? 0 : (uint8_t)vol_last;
}
static void app_adc_volume_process(void)
{
uint16_t val = ADC_ReadChannel(ADC_CHANNEL_1)>>5;

View File

@ -27,4 +27,6 @@ void app_adc_in1_scan_part(uint8_t channel);
bool app_adc_usb_is_plugged(void);
/* 开机/主动采样后同步 vol_last 与 level避免扫描任务误触发或跳变 */
void app_adc_sync_volume(uint16_t val);
/* 取当前主音量0~127供 MasterVolume_Reapply 等重发场景使用 */
uint8_t app_adc_get_volume(void);
#endif

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,7 +31,12 @@ 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;
}

View File

@ -460,6 +460,16 @@ void Send_volume(uint8_t vol)
SendMidiDataToDreamDSP(mMasterSysExVolume,12);
}
/* 重发当前主音量:开机补发 / 进模式主页 / 开始播放前调用。
* Dream SysEx
* "图标低音量、实际音量大" */
void MasterVolume_Reapply(void)
{
uint8_t vol = app_adc_get_volume();
app_adc_sync_volume(vol); /* 兜底刷新 level保证图标与下发值一致 */
Send_volume(vol);
}
void Accomp_UpdatePlayingChord(void)
{
uint8_t midi_note_buff[4] = {0,};
@ -494,6 +504,8 @@ void ADC_IN1_KEY_Handle(uint8_t key,bool on)
case 1: AutoBandTop1_Postamble(0); break;
case 2: AutoBandTop1_Postamble(1); break;
}
/* 前奏/尾奏起奏前补发主音量,保证与图标一致 */
MasterVolume_Reapply();
//AutoBandTop1_Start();
AutoBandTop1_SyncStart();
wk_delay_ms(50);
@ -761,6 +773,10 @@ void Pick_Handle()
note_cnt = GetChordNotesByType(chord_id, chord_type_index_map[chord_id].type, midi_note_buff);
Return_Light_buff(KEY_ID_1629);
/* 首次起奏前补发主音量:防开机 SysEx 丢失后"图标低、实际大" */
if (StartFlag == 0)
MasterVolume_Reapply();
switch(mGuiData[GUI_TAB_INDEX].Current)
{
case 3:

View File

@ -213,6 +213,7 @@ uint8_t GUI_Item_AjustValue(GUI_SWITCH * Group, int8_t Dir);
void GUI_Item_AjustLoopValue(GUI_SWITCH * Group, int8_t Dir);
void Send_volume(uint8_t vol);
void MasterVolume_Reapply(void);
void ADC_IN1_KEY_Handle(uint8_t key,bool on);
void TM1617_Handle(uint8_t key);

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);

View File

@ -163,11 +163,11 @@ void IdleProcess(DisplayTaskMessage_Type msg)
TM1629D_UpdateDisplay(0);
StartTouchTask();
StartScanTask();
/* Dream 上电稍后可能忽略首包 SysEx再发主音量 + 调音台(保持关机前设置) */
/* Dream 上电稍后可能忽略首包 SysEx再发主音量 + 调音台(保持关机前设置)。
* ADC
* MasterVolume_Reapply */
rt_thread_mdelay(400);
vol = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
app_adc_sync_volume(vol);
Send_volume(vol);
MasterVolume_Reapply();
LoadConfig();
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, level, 1, WHITE, GRAY);
break;

View File

@ -244,7 +244,7 @@ void UI_Mixer_Process(DisplayTaskMessage_Type msg)
break;
case MSG_ID_EC_VOL:
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, msg.HiByte, 1, WHITE, GRAY);
/* 调音台子页无状态栏音量条(与返回键重叠);主音量已在 MainTask 下发 */
ResetAutoPowerCount();
break;
}

View File

@ -243,6 +243,8 @@ void Touch_Action(int8_t FLAG, uint8_t ID, uint8_t areaIndex,uint8_t value)
AutoBandTop1_SetRunVar(mGuiData[ID].Current);
}else
{
/* 触摸起奏前补发主音量,保证实际音量与图标一致 */
MasterVolume_Reapply();
AutoBandTop1_FillinWithIndex(value);
AutoBandTop1_Start();
}

View File

@ -124,6 +124,11 @@ void UI_SystemSet_Process(DisplayTaskMessage_Type msg)
label_top();
break;
case MSG_ID_EC_VOL:
/* 主音量已在 MainTask 下发;此处只刷新状态栏音量条,保证与旋钮一致 */
Draw_Volume_Bar(UI0902_VOL_X, UI0902_VOL_Y, msg.HiByte, 1, WHITE, GRAY);
break;
default:
break;
}

View File

@ -54,6 +54,7 @@ void CallUI_Idle(void) {
void CallUI_SongMode(void) {
app_touch_suppress(500);
MasterVolume_Reapply(); /* 进模式补发主音量,防开机 SysEx 丢失后实际音量与图标不符 */
UI_SongMode_Init();
CurrUIProcress = UI_SongMode_Process;
app_log_set_ui_page("Song");
@ -62,6 +63,7 @@ void CallUI_SongMode(void) {
void CallUI_ExpertMode(void) {
app_touch_suppress(500);
MasterVolume_Reapply();
UI_ExpertMode_Init();
// CurrUIProcress = UI_ExpertMode_Process;
CurrUIProcress = UI_SongMode_Process;
@ -71,6 +73,7 @@ void CallUI_ExpertMode(void) {
void CallUI_FreeMode(void) {
app_touch_suppress(500);
MasterVolume_Reapply();
UI_FreeMode_Init();
// CurrUIProcress = UI_FreeMode_Process;
CurrUIProcress = UI_SongMode_Process;