diff --git a/Global/Global.c b/Global/Global.c index a5a7210..3dc9504 100644 --- a/Global/Global.c +++ b/Global/Global.c @@ -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 }; diff --git a/UI/UI_global.c b/UI/UI_global.c index 7a5bf9f..f357e2e 100644 --- a/UI/UI_global.c +++ b/UI/UI_global.c @@ -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,间�?像素 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: diff --git a/device/LCD_ILI9341/Drv_ILI9341_Lcd_ChineseFont.h b/device/LCD_ILI9341/Drv_ILI9341_Lcd_ChineseFont.h index 7132594..31115ea 100644 --- a/device/LCD_ILI9341/Drv_ILI9341_Lcd_ChineseFont.h +++ b/device/LCD_ILI9341/Drv_ILI9341_Lcd_ChineseFont.h @@ -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] = { diff --git a/project/inc/LocalSongNames.h b/project/inc/LocalSongNames.h new file mode 100644 index 0000000..32b5ffc --- /dev/null +++ b/project/inc/LocalSongNames.h @@ -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 */ diff --git a/project/inc/includes.h b/project/inc/includes.h index 7a784c3..b058015 100644 --- a/project/inc/includes.h +++ b/project/inc/includes.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" diff --git a/tools/gen_local_song_names.py b/tools/gen_local_song_names.py new file mode 100644 index 0000000..5e76dbd --- /dev/null +++ b/tools/gen_local_song_names.py @@ -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()) diff --git a/tools/pack_extflash_tone_0903.py b/tools/pack_extflash_tone_0903.py index 9761e39..d6683e2 100644 --- a/tools/pack_extflash_tone_0903.py +++ b/tools/pack_extflash_tone_0903.py @@ -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()