[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f1temdeireyiaa":3,"$f1jdyhcxs1px0z":9,"$f37m5ms424eu7l":42,"$f1vfehz25gtqnf":43},{"postCount":4,"commentCount":5,"tagCount":6,"categoryCount":7,"totalViews":8},10,1,11,5,54,{"id":10,"title":11,"slug":12,"excerpt":13,"cover":14,"status":15,"publishedAt":16,"viewCount":4,"likeCount":17,"favoriteCount":17,"createdAt":18,"updatedAt":19,"category":20,"author":22,"tags":25,"_count":39,"content":40,"attachments":41},7,"ApolloTab README","apollotab-readme","`ApolloTab` 是一个功能完整的 Python 库，用于解析、渲染和播放 Guitar Pro (.gp3\u002F.gp4\u002F.gp5\u002F.gpx\u002F.gp) 格式的吉他谱文件。","","published","2026-08-28T06:43:42.369Z",0,"2026-08-28T06:43:42.372Z","2026-10-02T00:47:05.923Z",{"id":7,"name":21,"slug":21},"仓库README",{"id":5,"username":23,"nickname":23,"avatar":24},"zhuwenqian",null,[26,30,34,36],{"id":27,"name":28,"slug":29},2,"Python 3","python3",{"id":31,"name":32,"slug":33},3,"GUI","gui",{"id":7,"name":35,"slug":35},"Qt5",{"id":37,"name":38,"slug":38},12,"音乐",{"comments":17},"[![Python 3.11+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.8+-blue.svg)](https:\u002F\u002Fwww.python.org\u002Fdownloads\u002F)\n[![License: LGPL 2.1](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-LGPL_2.1-orange.svg)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FLGPL-2.1\u002F)\n[![PyPI version](https:\u002F\u002Fbadge.fury.io\u002Fpy\u002FApolloTab.svg)](https:\u002F\u002Fpypi.org\u002Fproject\u002FApolloTab\u002F)\n\n[仓库地址](https:\u002F\u002Fgithub.com\u002FZhuwenqian\u002FApolloTab)\n\n**Guitar Pro 文件解析、渲染与音频播放引擎库**\n\n`ApolloTab` 是一个功能完整的 Python 库，用于解析、渲染和播放 Guitar Pro (.gp3\u002F.gp4\u002F.gp5\u002F.gpx\u002F.gp) 格式的吉他谱文件。\n\n## 核心功能\n\n- **文件解析**: 完整支持 GP3\u002FGP4\u002FGP5\u002FGPX\u002FGP(GP7\u002FGP8) 格式，提取歌曲信息、音轨、小节、音符、技巧标记\n- **智能调度**: `parse_score()` 根据文件扩展名自动选择对应解析器\n- **六线谱渲染**: 使用 QPainter 将乐谱数据渲染为高质量六线谱图像（QPixmap），支持多页输出\n- **音频播放**: 基于 FluidSynth 的 MIDI 合成引擎，支持 SoundFont 音色库实时播放，含 Bank Select + Program Change\n- **反复记号**: 完整支持反复记号（`||:` \u002F `:||`）展开与播放光标同步\n- **节拍器**: 内置节拍器功能，独立 MIDI 通道(15)，可配置音量和拍号\n- **动态主题注册**: 运行时主题注册 `ThemeConfig.register_theme()`，支持自定义配色方案\n- **技巧支持**: 18种演奏技巧（击弦、勾弦、推弦、滑音、泛音、颤音等）\n- **高度可配置**: 渲染参数完全可调（线宽、间距、颜色、字体等）\n- **主题支持**: 内置黑白\u002F深色配色方案，支持自定义主题扩展\n\n## 安装\n\n### 从 PyPI 安装（推荐）\n\n```bash\npip install ApolloTab\n```\n\n### 从源码安装\n\n```bash\n# 克隆仓库\ngit clone https:\u002F\u002Fgithub.com\u002Fyour-repo\u002FApolloTab.git\ncd ApolloTab\n\n# 安装依赖\npip install -e .\n\n# 或安装开发环境（含测试工具）\npip install -e \".[dev]\"\n```\n\n## 快速开始\n\n### 1. 解析 GTP 文件\n\n```python\nfrom ApolloTab import parse_gtp\n\n# 解析 Guitar Pro 文件\nsong = parse_gtp(\"my_song.gp5\")\n\n# 查看基本信息\nprint(f\"标题: {song.title}\")\nprint(f\"艺术家: {song.artist}\")\nprint(f\"BPM: {song.tempo}\")\nprint(f\"音轨数: {song.track_count}\")\n\n# 遍历音轨\nfor track in song.tracks:\n    print(f\"\\n音轨: {track.name}\")\n    print(f\"调弦: {track.strings}\")\n    print(f\"小节数: {len(track.measures)}\")\n```\n\n### 2. 渲染六线谱图像\n\n```python\nfrom ApolloTab import render_gtp\n\n# 一键渲染（返回多页 QPixmap 列表）\npages = render_gtp(\"my_song.gp5\", track_index=0)\n\n# pages 是 List[QPixmap]，每页一张图片\nfor i, page in enumerate(pages):\n    page.save(f\"output_page_{i + 1}.png\")\n    print(f\"已保存第 {i + 1} 页\")\n\n# 或者使用 TabRenderer 类进行更精细的控制\nfrom ApolloTab import TabRenderer, RenderConfig\n\n# 自定义渲染配置\nconfig = RenderConfig(\n    page_width=2480,      # 页面宽度(px)，调整效果: 越大越清晰但内存占用更多\n    page_height=3508,     # 页面高度(px)，A4@300dpi标准尺寸\n    line_color=\"#000000\", # 弦线颜色\n)\n\nrenderer = TabRenderer(config=config)\npages = renderer.render(song, track_index=0)\n\n# 访问布局数据（用于播放光标等功能）\nlayouts = renderer.last_layouts  # List[PageLayout]\n```\n\n### 3. 音频播放\n\n```python\nfrom ApolloTab import (\n    parse_gtp,\n    MidiConverter,\n    SynthEngine,\n)\n\n# 解析文件\nsong = parse_gtp(\"my_song.gp5\")\n\n# 转换为 MIDI 事件序列\nconverter = MidiConverter()\nevents = converter.convert(song, track_index=0)\n\n# 初始化音频引擎\nengine = SynthEngine()\nengine.initialize()                    # 初始化 FluidSynth 合成器\nengine.load_soundfont()               # 自动搜索并加载 SoundFont\nengine.set_instrument(0, 27)          # 设置通道0为电吉他(MIDI程序号27)\n\n# 加载事件并播放\nengine.load_events(events, bpm=song.tempo)\nengine.play()\n\n# 控制播放\nimport time\ntime.sleep(5)  # 播放5秒\nengine.pause()\ntime.sleep(2)  # 暂停2秒\nengine.resume()\ntime.sleep(5)  # 继续播放5秒\n\n# 停止并清理\nengine.stop()\n```\n\n### 4. 完整示例：解析 → 渲染 → 播放\n\n```python\nfrom ApolloTab import (\n    parse_gtp,\n    TabRenderer,\n    MidiConverter,\n    SynthEngine,\n    RenderConfig,\n)\n\ndef process_gtp_file(file_path: str, track_index: int = 0):\n    \"\"\"\n    完整处理流程：解析 → 渲染 → 播放\n    \n    参数:\n        file_path:   .gp3\u002F.gp4\u002F.gp5\u002F.gpx 文件路径\n        track_index: 要处理的音轨索引（默认第1条）\n    \"\"\"\n    # ===== 步骤1: 解析 =====\n    print(f\"[1\u002F3] 正在解析: {file_path}\")\n    song = parse_gtp(file_path)\n    print(f\"  ✓ 标题: {song.title}, BPM: {song.tempo}\")\n    \n    # ===== 步骤2: 渲染 =====\n    print(\"[2\u002F3] 正在渲染六线谱...\")\n    renderer = TabRenderer(RenderConfig())\n    pages = renderer.render(song, track_index=track_index)\n    \n    for i, page in enumerate(pages):\n        output_file = f\"{song.title}_track{track_index}_p{i + 1}.png\"\n        page.save(output_file)\n        print(f\"  ✓ 已保存: {output_file} ({page.width()}x{page.height()}px)\")\n    \n    # ===== 步骤3: 播放 =====\n    print(\"[3\u002F3] 正在初始化音频...\")\n    converter = MidiConverter()\n    events = converter.convert(song, track_index=track_index)\n    \n    engine = SynthEngine()\n    engine.initialize()\n    engine.load_soundfont()\n    engine.set_instrument(0, 27)\n    engine.load_events(events, bpm=song.tempo)\n    \n    print(\"  ▶ 开始播放 (按 Ctrl+C 停止)...\")\n    engine.play()\n    \n    try:\n        while engine.is_playing:\n            time.sleep(0.1)\n    except KeyboardInterrupt:\n        print(\"\\n  ⏹ 停止播放\")\n        engine.stop()\n\n# 使用示例\nif __name__ == \"__main__\":\n    import sys\n    \n    if len(sys.argv) \u003C 2:\n        print(\"用法: python example.py \u003C文件路径.gp5> [音轨索引]\")\n        sys.exit(1)\n    \n    file_path = sys.argv[1]\n    track_index = int(sys.argv[2]) if len(sys.argv) > 2 else 0\n    \n    process_gtp_file(file_path, track_index)\n```\n\n## API 参考\n\n### 核心函数\n\n| 函数                              | 说明        | 返回值             |\n| ------------------------------- | --------- | --------------- |\n| `parse_gtp(path)`               | 解析GTP文件   | `GTPSong`       |\n| `parse_score(path)`             | 智能调度（自动识别格式）| `GTPSong` |\n| `render_gtp(path, track_index)` | 一键渲染GTP文件 | `List[QPixmap]` |\n\n### 主要类\n\n#### 数据模型 (`ApolloTab.models`)\n\n| 类名           | 说明                    |\n| ------------ | --------------------- |\n| `GTPSong`    | 歌曲对象（标题\u002F艺术家\u002FBPM\u002F音轨列表） |\n| `GTPTrack`   | 音轨对象（名称\u002F调弦\u002F小节列表）      |\n| `GTPMeasure` | 小节对象（拍号\u002F重复记号\u002F拍列表）     |\n| `GTPBeat`    | 拍对象（时值\u002F附点\u002F音符列表）       |\n| `GTPNote`    | 音符对象（品格\u002F弦\u002FMIDI音高\u002F技巧）  |\n\n#### 解析器 (`ApolloTab.parser`)\n\n| 类                   | 说明                              |\n| -------------------- | --------------------------------- |\n| `GTPParser`          | GTP文件解析器类 (GP3\u002FGP4\u002FGP5\u002FGPX) |\n| `GP7Parser`          | GP7\u002FGP8 (.gp) ZIP解包解析器       |\n| `GpifParser`         | GP7\u002FGP8 GPIF XML内容解析器        |\n| `BinaryStylesheet`   | GP7\u002FGP8 二进制样式表解析器        |\n| `PartConfiguration`  | GP7\u002FGP8 声部配置解析器            |\n| `parse_score(path)`  | 智能调度（根据扩展名自动选择）    |\n\n**用法**:\n\n```python\nfrom ApolloTab import parse_score\n\n# 根据扩展名自动识别格式\nsong = parse_score(\"song.gp\")      # GP7\u002FGP8\nsong = parse_score(\"song.gp5\")     # GP5\nsong = parse_score(\"song.gpx\")     # GPX\n\n# 或直接指定解析器\nfrom ApolloTab.parser import GTPParser, GP7Parser\n\nparser = GTPParser()\nsong = parser.parse(\"song.gp5\")\n\ngp7 = GP7Parser()\nsong = gp7.parse(\"song.gp\")\n```\n\n#### 渲染器 (`ApolloTab.renderer`)\n\n| 类名                | 说明      |\n| ----------------- | ------- |\n| `TabRenderer`     | 六线谱渲染引擎 |\n| `TabLayoutEngine` | 布局计算引擎  |\n\n**用法**:\n\n```python\nfrom ApolloTab.renderer import TabRenderer, RenderConfig\n\nrenderer = TabRenderer(RenderConfig())\npages = renderer.render(song, track_index=0)\n```\n\n#### 音频引擎 (`ApolloTab.audio`)\n\n| 类名                 | 说明               |\n| ------------------ | ---------------- |\n| `MidiConverter`     | GTP数据→MIDI事件转换器  |\n| `SynthEngine`       | FluidSynth音频合成引擎 |\n| `MidiEvent`         | 单个MIDI事件数据模型     |\n| `MetronomeConfig`   | 节拍器配置（启用、音量、拍号） |\n| `MetronomeGenerator` | 节拍器MIDI事件生成器    |\n\n**用法**:\n\n```python\nfrom ApolloTab.audio import (\n    MidiConverter, SynthEngine,\n    MetronomeConfig, MetronomeGenerator,\n)\n\nconverter = MidiConverter()\nevents = converter.convert(song, track_index=0)\n\nengine = SynthEngine()\nengine.initialize()\nengine.load_soundfont()\nengine.load_events(events, bpm=song.tempo)  # 主事件流（不再混入节拍器）\nengine.play()\n\n# [v1.4.0] 节拍器事件独立加载：通过独立线程播放，不与主事件流混合\n# 切换节拍器开关\u002F音量时无需重建主事件\nconfig = MetronomeConfig(enabled=True, volume=0.8, gain=1.5)\nticks_per_beat = 480\nmetro_events = MetronomeGenerator.generate_for_song(\n    song=song, track_index=0, config=config,\n    expanded_indices=converter.expand_measure_indices(song.tracks[0].measures),\n    ticks_per_beat=ticks_per_beat,\n)\nengine.load_metronome_events(\n    events=metro_events, bpm=song.tempo, ticks_per_beat=ticks_per_beat,\n)\n# 关闭：engine.unload_metronome_events()\n```\n\n#### 工具 (`ApolloTab.utils`)\n\n| 类\u002F常量              | 说明                    |\n| ----------------- | -------------------- |\n| `RenderConfig`    | 渲染参数配置（全部可调）   |\n| `ThemeConfig`     | 渲染主题配置（配色方案）     |\n| `TechniqueType`   | 技巧类型枚举（18种）    |\n| `StandardTunings` | 标准调弦定义            |\n| `NoteDuration`    | 时值枚举              |\n\n## 配置说明\n\n### ThemeConfig - 渲染主题\n\nApolloTab 支持多套内置配色方案，适用于不同使用场景：\n\n```python\nfrom ApolloTab import TabRenderer, ThemeConfig\n\n# 获取预设主题\nlight_theme = ThemeConfig.get_theme(\"light\")   # 黑白配色（适合打印）\ndark_theme = ThemeConfig.get_theme(\"dark\")    # 深色配色（护眼模式）\n\n# 列出所有可用主题\navailable = ThemeConfig.list_themes()  # [\"light\", \"dark\"]\n\n# 使用主题\nrenderer = TabRenderer()\nrenderer.set_theme(\"light\")           # 通过名称切换\nrenderer.set_theme(dark_theme)        # 通过实例切换\n\n# 或在初始化时指定\nconfig = RenderConfig(theme=ThemeConfig.get_theme(\"light\"))\nrenderer = TabRenderer(config)\n\n# 自定义主题（可扩展）\nmy_theme = ThemeConfig(\n    colors={\n        \"COLOR_BG\": \"#FFFDE7\",       # 米黄色背景\n        \"COLOR_TEXT\": \"#212121\",     # 近黑色文字\n        # ... 其他颜色参数（可选，缺失的使用深色主题默认值）\n    },\n    theme_name=\"sepia\"               # 自定义名称\n)\nrenderer.set_theme(my_theme)\n```\n\n**内置主题:**\n\n| 主题名称 | 背景色 | 文字色 | 适用场景 |\n| ------ | ------ | ------ | ------ |\n| `light` | `#FFFFFF` (纯白) | `#000000` (黑色) | 打印输出、白天使用 |\n| `dark` | `#1E1E2E` (深蓝灰) | `#E2E8F0` (亮白灰) | 夜间模式、护眼 |\n\n### RenderConfig 渲染参数\n\n```python\nconfig = RenderConfig(\n    # 页面尺寸\n    page_width=2480,       # 页面宽度(px), 调整效果: A4@300dpi=2480, 屏幕显示可用1200\n    page_height=3508,      # 页面高度(px), 调整效果: A4@3508, 可根据需要调整\n    \n    # 边距\n    margin_top=80,         # 上边距(px), 调整效果: 增大则内容下移\n    margin_bottom=60,      # 下边距(px)\n    margin_left=60,        # 左边距(px)\n    margin_right=60,       # 右边距(px)\n    \n    # 六线谱样式\n    string_spacing=12,     # 弦线间距(px), 调整效果: 增大则谱子更宽更易读\n    line_width=1,          # 弦线粗细(px), 调整效果: 0.5=细线, 2=粗线\n    line_color=\"#333333\",  # 弦线颜色(十六进制), 调整效果: 改变整体色调\n    \n    # 字体设置\n    font_family=\"Arial\",   # 字体族, 调整效果: 使用系统支持的字体的名称\n    font_size_fret=10,     # 品格数字大小(px), 调整效果: 增大则数字更清晰\n    font_size_technique=9, # 技巧标记大小(px),\n    \n    # 系统间距\n    system_spacing=40,     # 系统(行)间距(px), 调整效果: 增大则行间空白更多\n)\n```\n\n### SynthEngine 音频参数\n\n```python\nengine = SynthEngine(\n    sample_rate=44100,     # 采样率(Hz), 调整效果: 48000更清晰但CPU占用更高\n    buffer_size=512,       # 缓冲区大小, 调整效果: 256延迟更低但可能爆音\n    gain=0.8,              # 主音量(0.0-1.0), 调整效果: 1.0=最大音量\n)\n```\n\n## 支持的演奏技巧\n\n| 技巧              | 缩写     | 符号类型     |\n| --------------- | ------ | -------- |\n| 击弦 Hammer-On    | H      | 文字标签     |\n| 勾弦 Pull-Off     | P      | 文字标签     |\n| 上滑音 Slide Up    | s\u002FS    | 连线+箭头    |\n| 下滑音 Slide Down  | S      | 连线+箭头    |\n| 推弦 Bend         | B      | 弧线+箭头+度数 |\n| 颤音 Vibrato      | \\~     | 波浪线      |\n| 闷音 Palm Mute    | P.M.   | 虚线延长线    |\n| 断奏 Staccato     | .      | 点标记      |\n| 延音 Let Ring     | 虚线延长线  | \u003Cbr \u002F>   |\n| 自然泛音 N.H.       | 菱形标记   | \u003Cbr \u002F>   |\n| 人工泛音 A.H.       | 菱形+文字  | \u003Cbr \u002F>   |\n| 震音拨弦 Trem.Pick. | 斜线下划线  | \u003Cbr \u002F>   |\n| 颤音 Trill        | \"tr\"文字 | \u003Cbr \u002F>   |\n| 装饰音 Grace Note  | 小音符    | \u003Cbr \u002F>   |\n| 重音 Accentuated  | >      | 符号       |\n| 幽灵音 Ghost Note  | 括号包裹   | \u003Cbr \u002F>   |\n\n## 开发指南\n\n### 项目结构\n\n```\nApolloTab\u002F\n├── __init__.py               # 包入口，导出核心API\n├── py.typed                  # PEP 561 类型提示标记\n├── player.py                 # 播放控制器（时间线 + 音频同步）\n├── parser\u002F\n│   ├── __init__.py\n│   ├── gtp_parser.py         # PyGuitarPro → GTPSong (GP3\u002FGP4\u002FGP5\u002FGPX)\n│   ├── gp7_parser.py         # GP7\u002FGP8 ZIP解包与文件流读取\n│   ├── gpif_parser.py        # GP7\u002FGP8 GPIF XML完整解析器\n│   ├── binary_stylesheet.py  # GP7\u002FGP8 二进制样式表解析\n│   └── part_configuration.py # GP7\u002FGP8 声部配置解析\n├── models\u002F\n│   ├── __init__.py\n│   ├── song.py           # 歌曲模型\n│   ├── track.py          # 音轨模型\n│   ├── measure.py        # 小节模型\n│   ├── beat.py           # 拍模型\n│   └── note.py           # 音符模型\n├── renderer\u002F\n│   ├── __init__.py\n│   ├── tab_renderer.py   # 六线谱绘制引擎\n│   └── layout_engine.py  # 坐标布局计算\n├── audio\u002F\n│   ├── __init__.py\n│   ├── midi_converter.py # GTP → MIDI事件转换\n│   └── synth_engine.py   # FluidSynth合成引擎\n└── utils\u002F\n    ├── __init__.py\n    └── constants.py      # 全局常量定义\n```\n\n### 本地开发\n\n```bash\n# 克隆仓库\ngit clone https:\u002F\u002Fgithub.com\u002Fyour-repo\u002FApolloTab.git\ncd ApolloTab\n\n# 创建虚拟环境\npython -m venv venv\nsource venv\u002Fbin\u002Factivate  # Linux\u002FMac\n# 或 .\\venv\\Scripts\\activate  # Windows\n\n# 安装开发依赖\npip install -e \".[dev]\"\n\n# 运行测试\npytest tests\u002F -v\n\n# 代码格式化\nblack ApolloTab\u002F\nisort ApolloTab\u002F\n\n# 类型检查\nmypy ApolloTab\u002F\n```\n\n## 依赖项\n\n### 必需依赖\n\n| 包名                                                         | 版本      | 用途                  | 许可证      |\n| ---------------------------------------------------------- | ------- | ------------------- | -------- |\n| [pyguitarpro](https:\u002F\u002Fgithub.com\u002FPerlence\u002FPyGuitarPro)          | >=0.10.1 | Guitar Pro文件解析      | LGPL-3.0 |\n| [pyfluidsynth](https:\u002F\u002Fgithub.com\u002Fnwhitehead\u002Fpyfluidsynth) | >=1.4.0  | FluidSynth Python绑定   | LGPL-2.1 |\n\n> **注意**: PyQt5 已不再是 pip 依赖。在 ARM 架构上需通过 `apt` 安装后手动创建软链接，pip 无法直接安装。渲染引擎会在运行时检测并使用已安装的 PyQt5。\n\n### 可选依赖\n\n| 组名  | 包名                         | 用途      |\n| --- | -------------------------- | ------- |\n| dev | pytest, black, isort, mypy | 开发和测试工具 |\n\n## 许可证\n\n本项目采用 [LGPL 2.1](LICENSE) 开源协议。\n\n## 贡献\n\n欢迎提交 Issue 和 Pull Request！\n\n1. Fork 本仓库\n2. 创建特性分支 (`git checkout -b feature\u002FAmazingFeature`)\n3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)\n4. 推送到分支 (`git push origin feature\u002FAmazingFeature`)\n5. 提交 Pull Request\n\n## 相关项目\n\n- **[TAB Score Viewer](https:\u002F\u002Fgithub.com\u002FZhuwenqian\u002Ftab-score-viewer)** - 基于 ApolloTab 的完整吉他谱查看器应用\n- **[pyguitarpro](https:\u002F\u002Fgithub.com\u002FPerlence\u002FPyGuitarPro)** - Guitar Pro 文件解析底层库\n- **[FluidSynth](https:\u002F\u002Fgithub.com\u002FFluidSynth\u002Ffluidsynth)** - 实时 MIDI 合成引擎\n\n***\n\n**版本**: v1.3.0",[],[],{"prev":44,"next":48},{"id":45,"title":46,"slug":47},6,"Hello KSP Launcher","hello-ksp-launcher",{"id":49,"title":50,"slug":51},8,"Hello KSP Launcher v1.3.0","hello-ksp-launcher-v1-3-0"]