K1Guitar/MyCode/App_Auto.c

719 lines
21 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* App_Auto.c
*
* Created on: Apr 16, 2026
* Author: monosail
*/
#include "autobandtop1.h"
#include <stdint.h>
#include "output2.bin.h"
#include "mymidififo1.h"
#include <stdlib.h>
#include "includes.h"
MidiFifoSeq_t m_MidiSendFifo;
#define PRESET_BUFFER_SIZE (1024*41) /* 2s.res compressed HKTK preset 39760 bytes */
static int m_presetCount = 0;
static uint8_t pStoreBuffer[PRESET_BUFFER_SIZE];
//static uint8_t* pStoreBuffer;
#define DEFAULT_TEMPO 100
/* ======== Bass/和弦分通道八度(无 AutoBand 源码时的输出侧映射) ========
* 代码通道(0 起,与 MIDI status 低 4 位一致):8=bass,9=鼓;其余=和弦。
* 日志打印同号(ch8=bass)。
* ① 指板 I/II(键1~6):原样;移调≥#F(6) 时表格「整体-12」(bass、和弦)。
* ② 指板 III/IV(键7~12):bass -12 地板 E1;和弦通道改走发音顺序(见下)。
* ③ 指板 V~VII(键13~21):bass 同②,移调≥#F 时 bass 再 -12。
* 和弦通道:源品位是 III~VII 时,不再做 -12,按 C 大调「和弦伴奏发音顺序」
* 逐音循环(固定调半音与六弦同一套映射)。I/II 形状仍走上面的八度规则。
* 对照 自动伴奏新更改和弦规则.xlsx「C大调 / 和弦伴奏发音顺序」 */
#define CHORD_REG_FIX_EN 1
#define BASS_CH 8 /* 日志 ch8 */
#define DRUM_CH 9 /* 日志 ch9 */
#define MIDI_E1 28
#define MIDI_E2 40
#define MIDI_GSHARP4 68
#define XPOSE_FS 6 /* C=0 时 #F=6 */
/* 映射策略指纹:变化时 CC123 清旧音,防挂音(不建大音符表) */
static uint8_t s_reg_fp = 0xFFu;
/* 每个指纹周期内 NoteOn 映射日志限额(和弦与 bass 分开,避免和弦占满看不到 bass) */
static uint8_t s_pitch_log_left = 0;
static uint8_t s_bass_log_left = 0;
static uint16_t s_ch_ever_mask = 0; /* 会话内各通道是否出现过 NoteOn */
#define PITCH_LOG_PER_FP 24
#define BASS_LOG_PER_FP 16
static void App_Auto_QueueAllNotesOffMelodic(void);
/* 和弦通道发音顺序:每通道自己的拍点,NoteOff 按进入音配对 */
static uint8_t s_seq[8];
static uint8_t s_seq_on;
static uint8_t s_seq_ready;
static uint8_t s_seq_key;
static uint8_t s_seq_type;
static uint8_t s_seq_xp;
static uint8_t s_seq_po;
#define SEQ_SLOTS 12
static uint8_t s_seq_step[16];
static struct { uint8_t ch, in, out, used; } s_seq_slot[SEQ_SLOTS];
static void App_Auto_SeqRefresh(void)
{
uint8_t key = KEY_ID_1629;
uint8_t type = 0, po = 0;
uint8_t xp = (uint8_t)mGuiData[GUI_TRANSPOSE].Current;
uint8_t seq[8];
uint8_t on;
uint8_t i;
if (key >= 1u && key <= 21u)
{
type = chord_type_index_map[key].type;
po = chord_type_index_map[key].PitchOffset;
}
if (s_seq_ready && key == s_seq_key && type == s_seq_type && xp == s_seq_xp && po == s_seq_po)
return;
on = AccompPattern_Fill(key, seq);
s_seq_key = key;
s_seq_type = type;
s_seq_xp = xp;
s_seq_po = po;
s_seq_ready = 1u;
if (!on)
{
if (s_seq_on)
App_Auto_QueueAllNotesOffMelodic();
s_seq_on = 0;
for (i = 0u; i < SEQ_SLOTS; i++)
s_seq_slot[i].used = 0;
return;
}
if (s_seq_on)
{
uint8_t same = 1u;
for (i = 0u; i < 8u; i++)
{
if (s_seq[i] != seq[i])
same = 0u;
}
if (!same)
App_Auto_QueueAllNotesOffMelodic();
}
for (i = 0u; i < 8u; i++)
s_seq[i] = seq[i];
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_seq_on = 1u;
}
/* 1 = 已用发音顺序处理(out 为最终音高) */
static int App_Auto_MapSeq(int channel, int key, int is_on, int *out)
{
int ch;
int i;
App_Auto_SeqRefresh();
if (!s_seq_on || channel == BASS_CH || channel == DRUM_CH)
return 0;
ch = channel & 15;
if (!is_on)
{
for (i = SEQ_SLOTS - 1; i >= 0; i--)
{
if (s_seq_slot[i].used && s_seq_slot[i].ch == (uint8_t)ch
&& s_seq_slot[i].in == (uint8_t)key)
{
*out = s_seq_slot[i].out;
s_seq_slot[i].used = 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);
for (i = 0; i < SEQ_SLOTS; i++)
{
if (!s_seq_slot[i].used)
{
s_seq_slot[i].used = 1;
s_seq_slot[i].ch = (uint8_t)ch;
s_seq_slot[i].in = (uint8_t)key;
s_seq_slot[i].out = (uint8_t)(*out);
return 1;
}
}
s_seq_slot[0].used = 1;
s_seq_slot[0].ch = (uint8_t)ch;
s_seq_slot[0].in = (uint8_t)key;
s_seq_slot[0].out = (uint8_t)(*out);
return 1;
}
static int App_Auto_ClampMidi(int n)
{
if (n < 0) return 0;
if (n > 127) return 127;
return n;
}
static int App_Auto_ChordDegree(void)
{
if (KEY_ID_1629 < 1 || KEY_ID_1629 > 21)
return 0;
return (int)((KEY_ID_1629 - 1) / 3) + 1; /* 1=I .. 7=VII */
}
static int App_Auto_NeedRegisterFix(void)
{
/* 键 1~6 = I/II:不动;7~21 = III~VII */
return (KEY_ID_1629 >= 7 && KEY_ID_1629 <= 21) ? 1 : 0;
}
static int App_Auto_XposeExtra(void)
{
return (mGuiData[GUI_TRANSPOSE].Current >= XPOSE_FS) ? 1 : 0;
}
static uint8_t App_Auto_RegFingerprint(void)
{
/* bit0=need_fix, bit1=xpose_extra, bit2.. = 粗粒度级数 (key/3) */
uint8_t fp = 0;
if (App_Auto_NeedRegisterFix()) fp |= 0x01u;
if (App_Auto_XposeExtra()) fp |= 0x02u;
if (KEY_ID_1629 >= 1 && KEY_ID_1629 <= 21)
fp |= (uint8_t)(((KEY_ID_1629 - 1) / 3) << 2);
return fp;
}
static void App_Auto_QueueAllNotesOffMelodic(void)
{
MidiFifoItem_t m;
int ch;
for (ch = 0; ch < 16; ch++)
{
if (ch == DRUM_CH) continue;
m.msg[0] = (uint8_t)(0xB0 | ch);
m.msg[1] = 123; /* All Notes Off */
m.msg[2] = 0;
m.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo, &m);
}
}
/* 超出 #G4:在当前和弦内音(GetChordNotesByType,对照和弦表「和弦伴奏」列)中就近 */
static int App_Auto_NearestChordTone(int target)
{
uint8_t buff[4] = {0, 0, 0, 0};
uint8_t n;
uint8_t pcs[4];
int i, oct, best = -1, best_dist = 9999;
uint8_t type;
if (KEY_ID_1629 < 1 || KEY_ID_1629 > 21)
return App_Auto_ClampMidi(target);
type = chord_type_index_map[KEY_ID_1629].type;
n = GetChordNotesByType(KEY_ID_1629, type, buff);
if (n == 0)
return App_Auto_ClampMidi(target > MIDI_GSHARP4 ? MIDI_GSHARP4 : target);
for (i = 0; i < (int)n; i++)
pcs[i] = (uint8_t)(buff[i] % 12);
for (i = 0; i < (int)n; i++)
{
for (oct = 0; oct < 11; oct++)
{
int cand = (int)pcs[i] + oct * 12;
int dist;
if (cand < MIDI_E2 || cand > MIDI_GSHARP4)
continue;
dist = cand - target;
if (dist < 0) dist = -dist;
/* 并列:优先较低者(不超过上限) */
if (dist < best_dist || (dist == best_dist && (best < 0 || cand < best)))
{
best_dist = dist;
best = cand;
}
}
}
if (best < 0)
return MIDI_GSHARP4;
return best;
}
static int App_Auto_MapBassNote(int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x01u; /* bit0: -12 applied */
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u; /* bit1: floored up to E1 */
}
if (App_Auto_XposeExtra() && App_Auto_ChordDegree() >= 5)
{
out -= 12;
f |= 0x04u; /* bit2: xpose extra -12 */
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
static int App_Auto_MapChordNote(int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x01u; /* bit0: -12 */
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u; /* bit3: raised to E2 */
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u; /* bit4: nearest chord tone */
}
if (App_Auto_XposeExtra() && App_Auto_ChordDegree() >= 5)
{
out -= 12;
f |= 0x04u;
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u;
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
/* 转调说明:移调≥#F 时 I/II 也「整体-12」(bass、和弦);不含 III+ 把位音区修正 */
static int App_Auto_MapXposeOverall(int channel, int key, uint8_t *flags)
{
int out = key - 12;
uint8_t f = 0x04u; /* bit2: xpose overall -12 */
if (channel == BASS_CH)
{
while (out < MIDI_E1)
{
out += 12;
f |= 0x02u;
}
}
else
{
while (out < MIDI_E2)
{
out += 12;
f |= 0x08u;
}
if (out > MIDI_GSHARP4)
{
out = App_Auto_NearestChordTone(out);
f |= 0x10u;
}
}
if (flags) *flags = f;
return App_Auto_ClampMidi(out);
}
static int App_Auto_MapNote(int channel, int key, uint8_t *flags, int is_on)
{
int out = key;
if (flags) *flags = 0;
#if CHORD_REG_FIX_EN
if (channel == DRUM_CH || key < 0 || key > 127)
return key;
if (App_Auto_MapSeq(channel, key, is_on, &out))
{
if (flags) *flags = 0x20u; /* 发音顺序 */
return out;
}
if (App_Auto_NeedRegisterFix())
{
/* III+:把位音区修正;V~VII 且 ≥#F 时 Map* 内再叠转调 -12 */
if (channel == BASS_CH)
out = App_Auto_MapBassNote(key, flags);
else
out = App_Auto_MapChordNote(key, flags);
}
else if (App_Auto_XposeExtra())
{
/* I/II + 移调≥#F:表格「整体-12 (bass、和弦)」 */
out = App_Auto_MapXposeOverall(channel, key, flags);
}
else
{
/* I/II + 移调 C~F:正常和弦逻辑,不改八度 */
return key;
}
#else
(void)channel;
(void)is_on;
#endif
return out;
}
static const char *App_Auto_RoleName(int channel)
{
if (channel == DRUM_CH) return "drum";
if (channel == BASS_CH) return "bass";
return "chord";
}
static void App_Auto_LogPitch(int channel, int key, int out, uint8_t flags, int is_on)
{
const char *role;
int deg;
int fix;
int xf;
int pass;
if (channel == DRUM_CH)
return;
if (channel == BASS_CH)
{
if (s_bass_log_left == 0)
return;
}
else if (s_pitch_log_left == 0)
{
return;
}
role = App_Auto_RoleName(channel);
deg = App_Auto_ChordDegree();
fix = App_Auto_NeedRegisterFix();
xf = App_Auto_XposeExtra();
/* PASS = 未做任何八度映射(I/II 且移调 C~F) */
pass = ((!fix && !xf) || channel == DRUM_CH) ? 1 : 0;
LOG_I("PITCH", "%s ch%u(%s) %d->%d d=%d deg=%d chord=%u xp=%u xf=%d fl=0x%02X %s%s%s%s",
is_on ? "on" : "off",
(unsigned)channel, role, /* 0 基,与 BASS_CH=8 一致 */
key, out, out - key,
deg, (unsigned)KEY_ID_1629,
(unsigned)mGuiData[GUI_TRANSPOSE].Current, xf,
(unsigned)flags,
pass ? "PASS " : "",
(flags & 0x10u) ? "NEAR " : "",
(flags & 0x02u) ? "E1UP " : "",
(flags & 0x08u) ? "E2UP " : "");
if (channel == BASS_CH)
{
if (s_bass_log_left > 0)
s_bass_log_left--;
}
else if (s_pitch_log_left > 0)
{
s_pitch_log_left--;
}
}
/* NoteOn 路径:策略变化时清旧音;返回映射后音高 */
static int App_Auto_MapNoteOn(int channel, int key)
{
#if CHORD_REG_FIX_EN
uint8_t fp = App_Auto_RegFingerprint();
uint8_t flags = 0;
int out;
if (fp != s_reg_fp)
{
if (s_reg_fp != 0xFFu)
{
LOG_I("REG", "fp %u->%u chord=%u deg=%d xp=%u xf=%d",
(unsigned)s_reg_fp, (unsigned)fp,
(unsigned)KEY_ID_1629,
App_Auto_ChordDegree(),
(unsigned)mGuiData[GUI_TRANSPOSE].Current,
App_Auto_XposeExtra());
App_Auto_QueueAllNotesOffMelodic();
}
else
{
LOG_I("REG", "fp init %u chord=%u deg=%d xp=%u",
(unsigned)fp, (unsigned)KEY_ID_1629,
App_Auto_ChordDegree(),
(unsigned)mGuiData[GUI_TRANSPOSE].Current);
}
s_reg_fp = fp;
s_pitch_log_left = PITCH_LOG_PER_FP;
s_bass_log_left = BASS_LOG_PER_FP;
s_ch_ever_mask = 0; /* 新策略周期重新报到通道 */
}
out = App_Auto_MapNote(channel, key, &flags, 1);
if (channel >= 0 && channel < 16)
{
uint16_t bit = (uint16_t)(1u << channel);
if ((s_ch_ever_mask & bit) == 0u)
{
s_ch_ever_mask |= bit;
LOG_I("REG", "ch-seen ch%u role=%s key=%d",
(unsigned)channel, App_Auto_RoleName(channel), key);
}
}
App_Auto_LogPitch(channel, key, out, flags, 1);
return out;
#else
(void)channel;
return key;
#endif
}
static void Func_CallBack_ProgramChange(int channel, int program)
{
MidiFifoItem_t midimsg;
uint8_t ch = (uint8_t)(channel & 0x0F);
uint8_t bank = MIDI_BANK_ACCOMP;
/* 通道 0 是硅胶弦。节奏预设常在这里放钢琴(Program 0),会盖掉弦音色。 */
if (ch == 0)
{
uint8_t slot = mGuiData[GUI_TIMBRE_SELECT].Current;
if (slot > 4u)
slot = 0;
bank = MIDI_BANK_STRING;
program = Timbre_index[slot];
}
LOG_I("REG", "pc ch%u prog=%d", (unsigned)channel, program);
/* 伴奏走 Bank0;弦音色走 Bank1。先 Bank Select 再 PC */
midimsg.msg[0] = 0xb0 | ch;
midimsg.msg[1] = 0x00; /* CC0 Bank MSB */
midimsg.msg[2] = bank;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
midimsg.msg[1] = 0x20; /* CC32 Bank LSB */
midimsg.msg[2] = 0;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
midimsg.msg[0] = 0xc0 | ch;
midimsg.msg[1] = (uint8_t)program;
midimsg.msg[2] = 0;
midimsg.msglen = 2;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
}
static void Func_CallBack_NoteOff(int channel,int key)
{
MidiFifoItem_t midimsg;
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);
}
static void Func_CallBack_NoteOn(int channel,int key,int vel)
{
MidiFifoItem_t midimsg;
int out_key;
if (vel == 0)
{
uint8_t flags = 0;
out_key = App_Auto_MapNote(channel, key, &flags, 0); /* 视同 NoteOff */
}
else
out_key = App_Auto_MapNoteOn(channel, 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);
}
static void Func_CallBack_CC(int channel,int cc,int value)
{
if(cc == 7|| cc == 11)
{
return;
}
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0xb0 | channel;
midimsg.msg[1] = cc;
midimsg.msg[2] = value;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
}
static void Func_CallBack_PitchWheel(int channel,int cc,int value)
{
MidiFifoItem_t midimsg;
midimsg.msg[0] = 0xe0 | channel;
midimsg.msg[1] = cc;
midimsg.msg[2] = value;
midimsg.msglen = 3;
mymidififo_InQueue(&m_MidiSendFifo,&midimsg);
}
/* Flash Map 0903:对照 ExtFlash_Tone_Addr.h / Doc/.../FLASH_MAP.txt */
static const char *ToneFlashMapBank(uint32_t abs)
{
if (abs >= EXTFLASH_BIN1_RHYTHM_ADDR &&
abs < EXTFLASH_BIN1_RHYTHM_ADDR + EXTFLASH_BIN1_RHYTHM_SIZE)
return "BIN1_RHYTHM";
if (abs >= EXTFLASH_BIN2_SONG_HAITIAN_ADDR &&
abs < EXTFLASH_BIN2_SONG_HAITIAN_ADDR + EXTFLASH_BIN2_SONG_HAITIAN_SIZE)
return "BIN2_SONG_HAITIAN";
if (abs >= EXTFLASH_BIN3_UNIVERSAL_ADDR &&
abs < EXTFLASH_BIN3_UNIVERSAL_ADDR + EXTFLASH_BIN3_UNIVERSAL_SIZE)
return "BIN3_UNIVERSAL";
if (abs >= FLASH_ADDR_AUTOBAND_LEGACY &&
abs < FLASH_ADDR_AUTOBAND_LEGACY + 0x10000UL)
return "LEGACY_AUTOBAND";
return "OUT_OF_MAP";
}
static uint32_t s_flash_rd_last_base = 0xFFFFFFFFu;
static uint16_t s_flash_rd_log_cnt = 0;
/* 最近一次 LoadPreset 是否成功;失败时禁止拨片起奏(防空库 + TMR6 ISR 崩) */
static volatile uint8_t s_preset_ready = 0;
int App_Auto_LoadPresetFromFlash(int presetIndex)
{
int ret = AutoBandTop1_LoadPresetItemFromFlash(presetIndex);
if (ret == 0)
{
const char *name = AutoBandTop1_GetPresetName();
int count = AutoBandTop1_GetPresetItemCount();
s_preset_ready = (count > 0 && name != NULL && name[0] != '\0') ? 1u : 0u;
}
else
{
s_preset_ready = 0u;
AutoBandTop1_Stop();
StartFlag = 0;
}
return ret;
}
uint8_t App_Auto_IsPresetReady(void)
{
return s_preset_ready;
}
static int Func_CallBack_ReadFlash(int address,int length,uint8_t* pOutput)
{
uint32_t base = (uint32_t)ADDRESS;
uint32_t abs = base + (uint32_t)address;
const char *bank;
if (base != s_flash_rd_last_base) {
s_flash_rd_last_base = base;
s_flash_rd_log_cnt = 0;
LOG_I("FLASH_RD", "bank base=0x%08X map=%s (BIN1=0x%08X BIN2=0x%08X BIN3=0x%08X)",
(unsigned)base,
ToneFlashMapBank(base),
(unsigned)EXTFLASH_BIN1_RHYTHM_ADDR,
(unsigned)EXTFLASH_BIN2_SONG_HAITIAN_ADDR,
(unsigned)EXTFLASH_BIN3_UNIVERSAL_ADDR);
}
bank = ToneFlashMapBank(abs);
/* 加载阶段打印前若干次 + 每次 offset==0;避免播放期刷屏 */
if (s_flash_rd_log_cnt < 16u || address == 0) {
LOG_I("FLASH_RD", "abs=0x%08X off=%d len=%d map=%s",
(unsigned)abs, address, length, bank);
if (s_flash_rd_log_cnt < 0xFFFFu)
s_flash_rd_log_cnt++;
if (s_flash_rd_log_cnt == 16u)
LOG_I("FLASH_RD", "further reads omitted (same base)");
} else if (bank[0] == 'O') {
/* 读到 Map 外:始终告警 */
LOG_W("FLASH_RD", "OUT_OF_MAP abs=0x%08X off=%d len=%d base=0x%08X",
(unsigned)abs, address, length, (unsigned)base);
}
W25Q128_Read(pOutput, abs, length);
return 0;
}
//
void App_Auto_Init(void)
{
LOG_I("REG", "ch map bass=%d drum=%d fix=%d E1=%d E2=%d Gs4=%d",
BASS_CH, DRUM_CH, CHORD_REG_FIX_EN, MIDI_E1, MIDI_E2, MIDI_GSHARP4);
LOG_I("REG", "PITCH log: chN(role) in->out d=delta deg=I..VII xp=xpose xf=#Fextra fl=flags");
AutoBandTop1_SetPresetStoreBuffer(pStoreBuffer,PRESET_BUFFER_SIZE);
AutoBandTop1_Init();
AutoBandTop1_RegisterCallBack_NoteOn(Func_CallBack_NoteOn);
AutoBandTop1_RegisterCallBack_NoteOff(Func_CallBack_NoteOff);
AutoBandTop1_RegisterCallBack_ProgChange(Func_CallBack_ProgramChange);
AutoBandTop1_RegisterCallBack_CC(Func_CallBack_CC);
AutoBandTop1_RegisterCallBack_PitchWheel(Func_CallBack_PitchWheel);
AutoBandTop1_RegisterReadFlashCallback(Func_CallBack_ReadFlash);
m_presetCount = AutoBandTop1_GetPresetItemCount();
int ret = App_Auto_LoadPresetFromFlash(0);
if (ret != 0)
{
uint8_t hdr[16];
W25Q128_Read(hdr, (uint32_t)ADDRESS, 16);
LOG_E("AUTO", "LoadPreset fail ret=%d addr=0x%08X map=%s magic=%02X%02X%02X%02X cnt=%lu",
ret, (unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS),
hdr[0], hdr[1], hdr[2], hdr[3],
(unsigned long)(hdr[12] | (hdr[13] << 8) | (hdr[14] << 16) | (hdr[15] << 24)));
}
else
{
LOG_I("AUTO", "LoadPreset ok name=%s addr=0x%08X map=%s",
AutoBandTop1_GetPresetName() ? AutoBandTop1_GetPresetName() : "?",
(unsigned)ADDRESS, ToneFlashMapBank((uint32_t)ADDRESS));
AutoBandTop1_ChangeBPM(mGuiData[1].Current);
}
}
//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
//{
// if (htim == (&htim6)) {
// // 1ms timer
// AutoBandTop1_Metronome_External_1msTick();
// }
//}
// 接下来的<E69DA5>??????题是如何测试<E6B58B>??????
// <20>??????以调<E4BBA5>??????
//void AutoBandTop1_Start(void); //<2F>??????动节<E58AA8>??????
//void AutoBandTop1_Stop(void); //停<>??伴<>??
//void AutoBandTop1_SyncStart(void);//同<>?<3F>启<EFBFBD>??????
//void AutoBandTop1_SetRunVar(int varIndex);//设置变<E7BDAE>?<3F>(0-3<>??????
//void AutoBandTop1_Preamble(int index);//设置前<E7BDAE>?<3F>(0-3<>??????
//void AutoBandTop1_Postamble(int index);//位置尾<E7BDAE>?<3F>(0-3<>??????
//void AutoBandTop1_Fillin(void);//触发一<E58F91>??????插入
//如果<E5A682>??????同<>?<3F>启<EFBFBD>??????,需要再调用void AutoBandTop1_Note_On(int32_t key,int32_t vel);来输入一<E585A5>??????音<>?<3F>(例<EFBC88>?<3F>C3)来<EFBC89>??????定和弦根<E5BCA6>??????
//在哪里调用这些函数?