Drive local song titles from CSV and add 海阔天空 glyphs.
UI shows LocalSongNames instead of bare indices; pack regenerates the header; WQY font gains the four display characters. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7b5667b179
commit
8c3c14ccf8
|
|
@ -26,7 +26,7 @@ GUI_SWITCH mGuiData[] = {
|
|||
GUI_SWITCH ParamGuiData[] =
|
||||
{
|
||||
{ 0, 0, 30, SONG_MODE_PARAM}, // 0 节奏类型(1.bin,约 31 首)
|
||||
{ 0, 0, 0, EXPRESS_MODE_PARAM}, // 1 本地曲目(2.bin,先 1 首可扩)
|
||||
{ 0, 0, 0, EXPRESS_MODE_PARAM}, // 1 本地曲目(2.bin;Max 由 UI_ReloadTonePreset←LOCAL_SONG_COUNT)
|
||||
{ 0, 0, 2, ALL_MODE_PARAM}, // 2
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,16 @@ void UI_ReloadTonePreset(void)
|
|||
UI_ApplyToneAddress();
|
||||
if (mGuiData[GUI_AUTOBAND_SW].Current)
|
||||
{
|
||||
AutoBandTop1_LoadPresetItemFromFlash(ParamGuiData[EXPRESS_MODE_PARAM].Current);
|
||||
GUI_SWITCH *local = &ParamGuiData[EXPRESS_MODE_PARAM];
|
||||
local->Max = (LOCAL_SONG_COUNT > 0) ? (uint16_t)(LOCAL_SONG_COUNT - 1) : 0;
|
||||
if (local->Current > local->Max)
|
||||
local->Current = local->Max;
|
||||
AutoBandTop1_LoadPresetItemFromFlash(local->Current);
|
||||
{
|
||||
int bin_n = AutoBandTop1_GetPresetItemCount();
|
||||
if (bin_n != LOCAL_SONG_COUNT)
|
||||
LOG_W("tone", "local song count csv=%d bin=%d", LOCAL_SONG_COUNT, bin_n);
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (mGuiData[GUI_TAB_INDEX].Current)
|
||||
|
|
@ -377,7 +386,10 @@ void show_Param(const LEBEL_UI *UI, GUI_SWITCH *Group)
|
|||
// 拼接序号 1. 2. 3.
|
||||
sprintf(NumBuf, "%d.", idx);
|
||||
uint16_t num_w = (uint16_t)(strlen(NumBuf) * UI0902_ASCII_W(UI->Text_size));
|
||||
GET_ParamNum_Str(Group->Current, 0, Textstr_new, Group->Id);
|
||||
if (Group->Id == EXPRESS_MODE_PARAM && Group->Current < LOCAL_SONG_COUNT)
|
||||
strcpy(Textstr_new, LocalSongNameGbk[Group->Current]);
|
||||
else
|
||||
GET_ParamNum_Str(Group->Current, 0, Textstr_new, Group->Id);
|
||||
uint32_t string_start_x = LCD_ShowMixedString(UI->x+10, UI->x + UI->w, text_y, (uint8_t *)Textstr_new , LCD_ALIGN_CENTER, WHITE, BLACK, UI->Text_size, 1);
|
||||
//序号X = 中文起点 - 数字宽度 - 5,间<EFBC8C>?像素
|
||||
uint16_t num_x = string_start_x - num_w;
|
||||
|
|
@ -953,8 +965,11 @@ void GET_ParamNum_Str(int16_t NUM, uint8_t ValidLen, char* Str, uint8_t hasSign)
|
|||
}
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
sprintf(Str, "%d", NUM);
|
||||
case 1: /* EXPRESS_MODE_PARAM:本地曲目显示名(CSV→LocalSongNames.h) */
|
||||
if (NUM >= 0 && NUM < LOCAL_SONG_COUNT)
|
||||
strcpy(Str, LocalSongNameGbk[NUM]);
|
||||
else
|
||||
sprintf(Str, "%d", NUM);
|
||||
return;
|
||||
break;
|
||||
case 2:
|
||||
|
|
|
|||
|
|
@ -55,6 +55,11 @@ const char CHS8Table[][2] = {
|
|||
{0xB3,0xA7}, // 厂
|
||||
{0xC9,0xE8}, // 设
|
||||
{0xD6,0xC3}, // 置
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
const char CHS9Table[][2] = {
|
||||
|
|
@ -116,6 +121,11 @@ const char CHS9Table[][2] = {
|
|||
{0xD0,0xCD}, // 型
|
||||
{0xB5,0xD8}, // 地
|
||||
{0xC4,0xBF}, // 目
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
const char CHS11Table[][2] = {
|
||||
|
|
@ -177,6 +187,11 @@ const char CHS11Table[][2] = {
|
|||
{0xD0,0xCD}, // 型
|
||||
{0xB5,0xD8}, // 地
|
||||
{0xC4,0xBF}, // 目
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -237,6 +252,11 @@ const char CHS12Table[][2] = {
|
|||
{0xD0,0xCD}, // 型
|
||||
{0xB5,0xD8}, // 地
|
||||
{0xC4,0xBF}, // 目
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
const char CHS13Table[][2] = {
|
||||
|
|
@ -425,6 +445,11 @@ const char CHS13Table[][2] = {
|
|||
{0xDC, 0xB0},// 馨
|
||||
{0xC1,0xAC}, // 连
|
||||
{0xCA,0xC7}, // 是
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -612,6 +637,11 @@ const char CHS15Table[][2] = {
|
|||
{0xB6,0xD3}, // 队
|
||||
{0xD1,0xF4}, // 阳
|
||||
{0xDC,0xB0}, // 馨
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
const char CHS16Table[][2] = {
|
||||
|
|
@ -803,6 +833,10 @@ const char CHS16Table[][2] = {
|
|||
{0xC6,0xD5}, // 普
|
||||
{0xCD,0xA8}, // 通
|
||||
{0xD2,0xB5}, // 业
|
||||
{0xBA,0xA3}, // 海
|
||||
{0xC0,0xAB}, // 阔
|
||||
{0xCC,0xEC}, // 天
|
||||
{0xBF,0xD5}, // 空
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -892,6 +926,10 @@ const unsigned char Chinese_font_8[][8] = {
|
|||
{0x00,0x60,0x40,0x40,0x40,0x40,0x00,0x80},/*"厂",48*/
|
||||
{0x0E,0x02,0x03,0xC0,0x5A,0x40,0x64,0x31},/*"设",49*/
|
||||
{0x7E,0x7E,0x18,0xFF,0x7E,0x42,0x7E,0xFF},/*"置",50*/
|
||||
{0x08,0x00,0x2E,0x3F,0x57,0x96,0x1F,0x06},/*"海",51*/
|
||||
{0x1F,0x41,0x89,0x89,0xA9,0xDD,0xD7,0xC1},/*"阔",52*/
|
||||
{0x7E,0x00,0x00,0xFF,0x18,0x00,0x00,0x81},/*"天",53*/
|
||||
{0x18,0x41,0x00,0x00,0x3C,0x00,0x00,0x7F},/*"空",54*/
|
||||
};
|
||||
|
||||
const unsigned char Chinese_font_12[][24] = {
|
||||
|
|
@ -951,6 +989,10 @@ const unsigned char Chinese_font_12[][24] = {
|
|||
{0x7E,0x40,0x29,0x40,0x29,0x40,0xFF,0x40,0x29,0x40,0x28,0x40,0x4C,0xC0,0x04,0x00,0x3F,0x80,0x04,0x00,0xFF,0xE0,0x00,0x00},/*"型",53*/
|
||||
{0x21,0x00,0x25,0x00,0x25,0x40,0xF5,0xC0,0x27,0x40,0x2D,0x40,0x25,0x40,0x25,0xC0,0x35,0x20,0xC4,0x20,0x03,0xE0,0x00,0x00},/*"地",54*/
|
||||
{0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x00,0x00},/*"目",55*/
|
||||
{0x44,0x00,0x27,0xE0,0x88,0x00,0x57,0xC0,0x15,0x40,0x2F,0xE0,0x29,0x40,0xC9,0x40,0x4F,0xE0,0x40,0x40,0x41,0x80,0x00,0x00},/*"海",56*/
|
||||
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA0,0x60,0x00,0x00},/*"阔",57*/
|
||||
{0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0xC0,0x60,0x00,0x00},/*"天",58*/
|
||||
{0x04,0x00,0x7F,0xE0,0x40,0x20,0x89,0x00,0x10,0x80,0x60,0x40,0x1F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xE0,0x00,0x00},/*"空",59*/
|
||||
};
|
||||
|
||||
const unsigned char Chinese_font_9[][18] = {
|
||||
|
|
@ -1012,6 +1054,10 @@ const unsigned char Chinese_font_9[][18] = {
|
|||
{0x7D,0x00,0x13,0x00,0xFF,0x00,0x77,0x00,0x11,0x00,0x09,0x00,0x08,0x00,0x08,0x00,0xFF,0x80},/*"型",55*/
|
||||
{0x02,0x00,0x0A,0x00,0xEB,0x00,0x6F,0x00,0x1B,0x00,0x0B,0x00,0x2B,0x00,0xC8,0x80,0x07,0x80},/*"地",56*/
|
||||
{0x3E,0x00,0x00,0x00,0x3E,0x00,0x22,0x00,0x22,0x00,0x3E,0x00,0x00,0x00,0x3E,0x00,0x22,0x00},/*"目",57*/
|
||||
{0x48,0x00,0x0F,0x80,0x0F,0x00,0x2F,0x00,0x1F,0x80,0x13,0x00,0xDF,0x80,0x41,0x80,0x42,0x00},/*"海",58*/
|
||||
{0x5F,0x80,0x00,0x80,0x84,0x80,0x84,0x80,0x9E,0x80,0xA4,0x80,0xDE,0x80,0xDE,0x80,0x81,0x80},/*"阔",59*/
|
||||
{0x7F,0x00,0x08,0x00,0x08,0x00,0xFF,0x80,0x08,0x00,0x14,0x00,0x14,0x00,0x00,0x00,0xC1,0x80},/*"天",60*/
|
||||
{0x08,0x00,0x7F,0x80,0x80,0x00,0x00,0x00,0x41,0x00,0x1E,0x00,0x08,0x00,0x08,0x00,0x7F,0x80},/*"空",61*/
|
||||
};
|
||||
|
||||
const unsigned char Chinese_font_11[][22] = {
|
||||
|
|
@ -1073,6 +1119,10 @@ const unsigned char Chinese_font_11[][22] = {
|
|||
{0x7E,0x40,0x29,0x40,0x29,0x40,0xFF,0x40,0x29,0x40,0x28,0x40,0x4C,0xC0,0x04,0x00,0x3F,0x80,0x04,0x00,0xFF,0xE0},/*"型",55*/
|
||||
{0x21,0x00,0x25,0x00,0x25,0x40,0xF5,0xC0,0x27,0x40,0x2D,0x40,0x25,0x40,0x25,0xC0,0x35,0x20,0xC4,0x20,0x03,0xE0},/*"地",56*/
|
||||
{0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80,0x20,0x80,0x3F,0x80,0x20,0x80},/*"目",57*/
|
||||
{0x44,0x00,0x27,0xE0,0x88,0x00,0x57,0xC0,0x15,0x40,0x2F,0xE0,0x29,0x40,0xC9,0x40,0x4F,0xE0,0x40,0x40,0x41,0x80},/*"海",58*/
|
||||
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA0,0x60},/*"阔",59*/
|
||||
{0x7F,0xC0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0xC0,0x60},/*"天",60*/
|
||||
{0x04,0x00,0x7F,0xE0,0x40,0x20,0x89,0x00,0x10,0x80,0x60,0x40,0x1F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xE0},/*"空",61*/
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1266,6 +1316,10 @@ const unsigned char Chinese_font_13[][26] = {
|
|||
{0xFD,0xC0,0x11,0x40,0x7F,0xE0,0x57,0x40,0x55,0xC0,0xBF,0x20,0x84,0x00,0xFF,0xE0,0x20,0x80,0x7F,0xC0,0x20,0x80,0x3F,0x80,0x00,0x00},/*"馨",182*/
|
||||
{0x01,0x00,0x41,0x00,0x2F,0xF0,0x22,0x00,0x04,0x80,0xE7,0xE0,0x20,0x80,0x2F,0xF0,0x20,0x80,0x20,0x80,0x50,0x80,0x8F,0xF0,0x00,0x00},/*"连",183*/
|
||||
{0x1F,0x80,0x10,0x80,0x1F,0x80,0x10,0x80,0x1F,0x80,0x00,0x00,0xFF,0xF0,0x02,0x00,0x13,0xC0,0x12,0x00,0x2A,0x00,0xC7,0xF0,0x00,0x00},/*"是",184*/
|
||||
{0x44,0x00,0x27,0xF0,0x08,0x00,0x87,0xE0,0x45,0x20,0x24,0xA0,0x3F,0xF0,0x29,0x20,0xC8,0xA0,0x4F,0xF0,0x40,0x20,0x40,0xC0,0x00,0x00},/*"海",185*/
|
||||
{0x4F,0xE0,0x20,0x20,0xA1,0xA0,0x96,0x20,0xC2,0x20,0xAF,0xA0,0x92,0x20,0xAF,0xA0,0xE8,0xA0,0xAF,0xA0,0xA8,0xA0,0x80,0x60,0x00,0x00},/*"阔",186*/
|
||||
{0x7F,0xE0,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xF0,0x04,0x00,0x0A,0x00,0x0A,0x00,0x11,0x00,0x10,0x80,0x20,0x40,0xC0,0x30,0x00,0x00},/*"天",187*/
|
||||
{0x04,0x00,0xFF,0xE0,0x80,0x20,0x91,0x20,0x20,0x80,0xC0,0x40,0x3F,0x80,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xFF,0xE0,0x00,0x00},/*"空",188*/
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1456,6 +1510,10 @@ const unsigned char Chinese_font_15[][30] = {
|
|||
{0x00,0x80,0xF8,0x80,0x88,0x80,0x90,0x80,0x90,0x80,0xA0,0x80,0x90,0x80,0x89,0x40,0x89,0x40,0xCA,0x20,0xB2,0x20,0x84,0x10,0x88,0x08,0x90,0x04,0x00,0x00},/*"队",180*/
|
||||
{0x00,0x00,0x7D,0xF8,0x45,0x08,0x49,0x08,0x49,0x08,0x51,0x08,0x49,0xF8,0x45,0x08,0x45,0x08,0x65,0x08,0x59,0x08,0x41,0xF8,0x41,0x08,0x41,0x08,0x00,0x00},/*"阳",181*/
|
||||
{0x10,0xE0,0xFE,0xA0,0x11,0x18,0x7F,0xF0,0x52,0x90,0x7E,0x60,0x42,0x90,0xBF,0xF0,0x02,0x00,0xFF,0xF8,0x50,0x50,0x9F,0xC8,0x10,0x40,0x1F,0xC0,0x00,0x00},/*"馨",182*/
|
||||
{0x42,0x00,0x22,0x00,0x23,0xFC,0x04,0x00,0x93,0xF0,0x52,0x90,0x22,0x50,0x2F,0xFC,0x24,0x90,0xC4,0x50,0x44,0x10,0x47,0xFC,0x40,0x10,0x40,0x60,0x00,0x00},/*"海",183*/
|
||||
{0x20,0x08,0x1B,0xFC,0x08,0x08,0x50,0x68,0x4B,0x88,0x40,0x88,0x57,0xF8,0x48,0x88,0x4B,0xE8,0x5A,0x28,0x4A,0x28,0x4B,0xE8,0x4A,0x28,0x40,0x18,0x00,0x00},/*"阔",184*/
|
||||
{0x00,0x00,0x3F,0xF0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFF,0xFC,0x02,0x00,0x05,0x00,0x04,0x80,0x08,0x40,0x10,0x20,0x20,0x1C,0xC0,0x08,0x00,0x00},/*"天",185*/
|
||||
{0x04,0x00,0x02,0x00,0x7F,0xF8,0x40,0x10,0x88,0x80,0x10,0x40,0x20,0x20,0x40,0x10,0x3F,0xE0,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFF,0xF8,0x00,0x00},/*"空",186*/
|
||||
};
|
||||
|
||||
const unsigned char Chinese_font_16[][32] = {
|
||||
|
|
@ -1645,6 +1703,10 @@ const unsigned char Chinese_font_16[][32] = {
|
|||
{0x08,0x20,0x04,0x40,0x7F,0xFC,0x04,0x40,0x24,0x48,0x14,0x50,0xFF,0xFE,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10},/*"普",183*/
|
||||
{0x00,0x00,0x47,0xF8,0x20,0x10,0x21,0xA0,0x00,0x40,0x07,0xFC,0xE4,0x44,0x24,0x44,0x27,0xFC,0x24,0x44,0x24,0x44,0x27,0xFC,0x24,0x44,0x24,0x54,0x54,0x08,0x8F,0xFE},/*"通",184*/
|
||||
{0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x40,0x44,0x44,0x24,0x44,0x24,0x48,0x14,0x48,0x14,0x50,0x14,0x60,0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x40,0xFF,0xFE,0x00,0x00},/*"业",185*/
|
||||
{0x01,0x00,0x21,0x00,0x11,0xFC,0x12,0x00,0x85,0xF8,0x41,0x08,0x49,0x48,0x09,0x28,0x17,0xFE,0x11,0x08,0xE2,0x48,0x22,0x28,0x23,0xFC,0x20,0x08,0x20,0x50,0x00,0x20},/*"海",186*/
|
||||
{0x20,0x00,0x17,0xFC,0x00,0x04,0x48,0x34,0x45,0xC4,0x64,0x44,0x50,0x44,0x51,0xF4,0x44,0x44,0x48,0x44,0x79,0xF4,0x49,0x14,0x49,0x14,0x49,0xF4,0x40,0x04,0x40,0x0C},/*"阔",187*/
|
||||
{0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0xFE,0x01,0x00,0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x10,0x10,0x20,0x08,0xC0,0x06},/*"天",188*/
|
||||
{0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x88,0x24,0x10,0x10,0x20,0x08,0x00,0x00,0x1F,0xF0,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x00,0x00},/*"空",189*/
|
||||
};
|
||||
|
||||
const unsigned char Chinese_font_24[][72] = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef __LOCAL_SONG_NAMES_H
|
||||
#define __LOCAL_SONG_NAMES_H
|
||||
|
||||
/* Auto-generated by tools/gen_local_song_names.py from local_songs.csv — do not hand-edit. */
|
||||
/* Display names are GBK for LCD_ShowMixedString; codes match 2.bin preset ASCII (e.g. HKTK). */
|
||||
|
||||
#define LOCAL_SONG_COUNT 1
|
||||
|
||||
static const char * const LocalSongNameGbk[LOCAL_SONG_COUNT] = {
|
||||
"\xBA\xA3\xC0\xAB\xCC\xEC\xBF\xD5", /* 0: 海阔天空 */
|
||||
};
|
||||
|
||||
static const char * const LocalSongCode[LOCAL_SONG_COUNT] = {
|
||||
"HKTK", /* 0 */
|
||||
};
|
||||
|
||||
#endif /* __LOCAL_SONG_NAMES_H */
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#include "Drv_ILI9341_Lcd_Image_UI0902.h"
|
||||
#include "UI0902_Res_Addr.h"
|
||||
#include "ExtFlash_Tone_Addr.h"
|
||||
#include "LocalSongNames.h"
|
||||
#include "Drv_ILI9341_Lcd_Dump.h"
|
||||
#include "Drv_XPT2046_Touch.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Generate project/inc/LocalSongNames.h from Doc/音色文件/0903/local_songs.csv.
|
||||
|
||||
CSV columns: index,code,name
|
||||
index — preset index in 2.bin (0-based)
|
||||
code — ASCII code in bin preset name (e.g. HKTK from 1.HKTK)
|
||||
name — display name (Unicode); written as GBK byte escapes for the LCD font
|
||||
|
||||
Run standalone or from pack_extflash_tone_0903.py after packing 2.bin.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REPO = ROOT.parent.parent
|
||||
CSV_PATH = REPO / "Doc" / "音色文件" / "0903" / "local_songs.csv"
|
||||
OUT_HDR = ROOT / "project" / "inc" / "LocalSongNames.h"
|
||||
|
||||
|
||||
def gbk_c_string(text: str) -> str:
|
||||
raw = text.encode("gbk")
|
||||
return "".join(f"\\x{b:02X}" for b in raw)
|
||||
|
||||
|
||||
def load_rows(path: Path) -> list[dict]:
|
||||
if not path.is_file():
|
||||
raise FileNotFoundError(f"missing {path}")
|
||||
with path.open("r", encoding="utf-8-sig", newline="") as f:
|
||||
reader = csv.DictReader(f)
|
||||
rows = list(reader)
|
||||
if not rows:
|
||||
raise SystemExit(f"{path}: no song rows")
|
||||
out = []
|
||||
for i, row in enumerate(rows):
|
||||
try:
|
||||
idx = int((row.get("index") or "").strip())
|
||||
except ValueError as e:
|
||||
raise SystemExit(f"{path}: bad index on row {i + 2}: {row!r}") from e
|
||||
code = (row.get("code") or "").strip()
|
||||
name = (row.get("name") or "").strip()
|
||||
if not code or not name:
|
||||
raise SystemExit(f"{path}: empty code/name on row {i + 2}")
|
||||
out.append({"index": idx, "code": code, "name": name})
|
||||
out.sort(key=lambda r: r["index"])
|
||||
for expect, row in enumerate(out):
|
||||
if row["index"] != expect:
|
||||
raise SystemExit(
|
||||
f"{path}: indices must be contiguous from 0; "
|
||||
f"expected {expect}, got {row['index']}"
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def write_header(rows: list[dict], path: Path) -> None:
|
||||
n = len(rows)
|
||||
name_lines = []
|
||||
code_lines = []
|
||||
for r in rows:
|
||||
esc = gbk_c_string(r["name"])
|
||||
name_lines.append(f' "{esc}", /* {r["index"]}: {r["name"]} */')
|
||||
code_lines.append(f' "{r["code"]}", /* {r["index"]} */')
|
||||
|
||||
body = f"""#ifndef __LOCAL_SONG_NAMES_H
|
||||
#define __LOCAL_SONG_NAMES_H
|
||||
|
||||
/* Auto-generated by tools/gen_local_song_names.py from local_songs.csv — do not hand-edit. */
|
||||
/* Display names are GBK for LCD_ShowMixedString; codes match 2.bin preset ASCII (e.g. HKTK). */
|
||||
|
||||
#define LOCAL_SONG_COUNT {n}
|
||||
|
||||
static const char * const LocalSongNameGbk[LOCAL_SONG_COUNT] = {{
|
||||
{chr(10).join(name_lines)}
|
||||
}};
|
||||
|
||||
static const char * const LocalSongCode[LOCAL_SONG_COUNT] = {{
|
||||
{chr(10).join(code_lines)}
|
||||
}};
|
||||
|
||||
#endif /* __LOCAL_SONG_NAMES_H */
|
||||
"""
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(body, encoding="utf-8", newline="\n")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
rows = load_rows(CSV_PATH)
|
||||
write_header(rows, OUT_HDR)
|
||||
print(f"Wrote {OUT_HDR} ({len(rows)} song(s) from {CSV_PATH.name})")
|
||||
for r in rows:
|
||||
print(f" [{r['index']}] {r['code']} {r['name']}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -17,6 +17,8 @@ Outputs:
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1] # firmware project root
|
||||
|
|
@ -135,6 +137,12 @@ def main() -> None:
|
|||
" AutoBand -> FLASH_ADDR_AUTOBAND_LEGACY 0x9EB5F (unchanged; overlaps 2.bin region — do not enable until remapped)",
|
||||
" Boot logo -> UI0902_BOOT_LOGO_ADDR (full-screen); packed logo.bin only pads 0x0..0xCB70",
|
||||
" Charging -> EXTFLASH_CHARGING_ADDR",
|
||||
"",
|
||||
"Add a local song:",
|
||||
" 1. Pack the new preset into 2.bin",
|
||||
" 2. Append a row to local_songs.csv (index,code,name)",
|
||||
" 3. python tools/pack_extflash_tone_0903.py (also regenerates LocalSongNames.h)",
|
||||
" 4. Rebuild firmware and flash MCU + ExtFlash",
|
||||
]
|
||||
OUT_MAP.write_text("\n".join(map_lines) + "\n", encoding="utf-8", newline="\n")
|
||||
|
||||
|
|
@ -147,6 +155,12 @@ def main() -> None:
|
|||
raise SystemExit("ERROR: pack overflows into UI0902_RES_BASE")
|
||||
print(f"OK: {0x00100000 - cursor} bytes free before UI0902 @ 0x00100000")
|
||||
|
||||
# Keep LocalSongNames.h in sync with Doc/.../local_songs.csv when packing tones.
|
||||
gen = ROOT / "tools" / "gen_local_song_names.py"
|
||||
r = subprocess.run([sys.executable, str(gen)], check=False)
|
||||
if r.returncode != 0:
|
||||
raise SystemExit(f"gen_local_song_names.py failed ({r.returncode})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue