ApolloTab 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,934 @@
1
+ Metadata-Version: 2.4
2
+ Name: ApolloTab
3
+ Version: 0.2.0
4
+ Summary: Guitar Pro file parsing, rendering, and audio playback engine library
5
+ Author: ZhuWenqian
6
+ Maintainer: ZhuWenqian
7
+ License-Expression: MPL-2.0
8
+ Project-URL: Homepage, https://github.com/Zhuwenqian/ApolloTab
9
+ Project-URL: Documentation, https://github.com/Zhuwenqian/ApolloTab#readme
10
+ Project-URL: Repository, https://github.com/Zhuwenqian/ApolloTab.git
11
+ Project-URL: Issues, https://github.com/Zhuwenqian/ApolloTabissues
12
+ Keywords: guitar-pro,gtp,tab,music,midi,renderer,audio,synth,guitar
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI
23
+ Classifier: Topic :: Multimedia :: Graphics
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: pyguitarpro>=0.11
29
+ Requires-Dist: PyQt5>=5.15
30
+ Requires-Dist: pyfluidsynth>=1.4.0
31
+ Provides-Extra: full
32
+ Requires-Dist: pyguitarpro>=0.11; extra == "full"
33
+ Requires-Dist: PyQt5>=5.15; extra == "full"
34
+ Requires-Dist: pyfluidsynth>=1.4.0; extra == "full"
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=7.0; extra == "dev"
37
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
38
+ Requires-Dist: black>=23.0; extra == "dev"
39
+ Requires-Dist: isort>=5.12; extra == "dev"
40
+ Requires-Dist: mypy>=1.0; extra == "dev"
41
+ Requires-Dist: build>=0.10; extra == "dev"
42
+ Requires-Dist: twine>=4.0; extra == "dev"
43
+ Dynamic: license-file
44
+
45
+ # ApolloTab
46
+
47
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: MPL 2.0](https://img.shields.io/badge/License-MPL_2.0-orange.svg)](https://opensource.org/licenses/MPL-2.0/)
49
+ [![PyPI version](https://badge.fury.io/py/ApolloTab.svg)](https://pypi.org/project/ApolloTab/)
50
+
51
+ **Guitar Pro File Parsing, Rendering, and Audio Playback Engine Library**
52
+
53
+ `ApolloTab` is a fully-featured Python library for parsing, rendering, and playing Guitar Pro (.gp3/.gp4/.gp5/.gpx) tablature files.
54
+
55
+ ## Features
56
+
57
+ - **File Parsing**: Full support for GP3/GP4/GP5/GPX formats — extract song info, tracks, measures, notes, technique markings
58
+ - **Tablature Rendering**: Render high-quality tablature images (QPixmap) using QPainter with multi-page output
59
+ - **Audio Playback**: Real-time MIDI synthesis engine based on FluidSynth with SoundFont support
60
+ - **Technique Support**: 18 playing techniques (hammer-on, pull-off, bend, slide, harmonic, vibrato, etc.)
61
+ - **Highly Configurable**: Fully adjustable rendering parameters (line width, spacing, colors, fonts, etc.)
62
+
63
+ ## Installation
64
+
65
+ ### Install from PyPI (Recommended)
66
+
67
+ ```bash
68
+ pip install ApolloTab
69
+ ```
70
+
71
+ ### Install from Source
72
+
73
+ ```bash
74
+ git clone https://github.com/your-repo/ApolloTab.git
75
+ cd ApolloTab
76
+
77
+ pip install -e .
78
+
79
+ # Or install dev environment (with test tools)
80
+ pip install -e ".[dev]"
81
+ ```
82
+
83
+ ## Quick Start
84
+
85
+ ### 1. Parse a GTP File
86
+
87
+ ```python
88
+ from ApolloTab import parse_gtp
89
+
90
+ song = parse_gtp("my_song.gp5")
91
+
92
+ print(f"Title: {song.title}")
93
+ print(f"Artist: {song.artist}")
94
+ print(f"BPM: {song.tempo}")
95
+ print(f"Track count: {song.track_count}")
96
+
97
+ for track in song.tracks:
98
+ print(f"\nTrack: {track.name}")
99
+ print(f"Tuning: {track.strings}")
100
+ print(f"Measures: {len(track.measures)}")
101
+ ```
102
+
103
+ ### 2. Render Tablature Images
104
+
105
+ ```python
106
+ from ApolloTab import render_gtp
107
+
108
+ pages = render_gtp("my_song.gp5", track_index=0)
109
+
110
+ for i, page in enumerate(pages):
111
+ page.save(f"output_page_{i + 1}.png")
112
+ print(f"Saved page {i + 1}")
113
+
114
+ # Or use TabRenderer for finer control
115
+ from ApolloTab import TabRenderer, RenderConfig
116
+
117
+ config = RenderConfig(
118
+ page_width=2480,
119
+ page_height=3508,
120
+ line_color="#000000",
121
+ )
122
+
123
+ renderer = TabRenderer(config=config)
124
+ pages = renderer.render(song, track_index=0)
125
+
126
+ layouts = renderer.last_layouts # List[PageLayout]
127
+ ```
128
+
129
+ ### 3. Audio Playback
130
+
131
+ ```python
132
+ from ApolloTab import (
133
+ parse_gtp,
134
+ MidiConverter,
135
+ SynthEngine,
136
+ )
137
+
138
+ song = parse_gtp("my_song.gp5")
139
+
140
+ converter = MidiConverter()
141
+ events = converter.convert(song, track_index=0)
142
+
143
+ engine = SynthEngine()
144
+ engine.initialize()
145
+ engine.load_soundfont()
146
+ engine.set_instrument(0, 27) # Electric Guitar (MIDI program 27)
147
+
148
+ engine.load_events(events, bpm=song.tempo)
149
+ engine.play()
150
+
151
+ import time
152
+ time.sleep(5)
153
+ engine.pause()
154
+ time.sleep(2)
155
+ engine.resume()
156
+ time.sleep(5)
157
+
158
+ engine.stop()
159
+ ```
160
+
161
+ ### 4. Complete Example: Parse -> Render -> Play
162
+
163
+ ```python
164
+ from ApolloTab import (
165
+ parse_gtp,
166
+ TabRenderer,
167
+ MidiConverter,
168
+ SynthEngine,
169
+ RenderConfig,
170
+ )
171
+
172
+ def process_gtp_file(file_path: str, track_index: int = 0):
173
+ """
174
+ Complete workflow: Parse -> Render -> Play
175
+
176
+ Args:
177
+ file_path: Path to .gp3/.gp4/.gp5/.gpx file
178
+ track_index: Track index to process (default: first track)
179
+ """
180
+ # Step 1: Parse
181
+ print(f"[1/3] Parsing: {file_path}")
182
+ song = parse_gtp(file_path)
183
+ print(f" OK Title: {song.title}, BPM: {song.tempo}")
184
+
185
+ # Step 2: Render
186
+ print("[2/3] Rendering tablature...")
187
+ renderer = TabRenderer(RenderConfig())
188
+ pages = renderer.render(song, track_index=track_index)
189
+
190
+ for i, page in enumerate(pages):
191
+ output_file = f"{song.title}_track{track_index}_p{i + 1}.png"
192
+ page.save(output_file)
193
+ print(f" OK Saved: {output_file} ({page.width()}x{page.height()}px)")
194
+
195
+ # Step 3: Play
196
+ print("[3/3] Initializing audio...")
197
+ converter = MidiConverter()
198
+ events = converter.convert(song, track_index=track_index)
199
+
200
+ engine = SynthEngine()
201
+ engine.initialize()
202
+ engine.load_soundfont()
203
+ engine.set_instrument(0, 27)
204
+ engine.load_events(events, bpm=song.tempo)
205
+
206
+ print(" > Playing (Ctrl+C to stop)...")
207
+ engine.play()
208
+
209
+ try:
210
+ while engine.is_playing:
211
+ time.sleep(0.1)
212
+ except KeyboardInterrupt:
213
+ print("\n [] Stopped")
214
+ engine.stop()
215
+
216
+ if __name__ == "__main__":
217
+ import sys
218
+
219
+ if len(sys.argv) < 2:
220
+ print("Usage: python example.py <file_path.gp5> [track_index]")
221
+ sys.exit(1)
222
+
223
+ file_path = sys.argv[1]
224
+ track_index = int(sys.argv[2]) if len(sys.argv) > 2 else 0
225
+
226
+ process_gtp_file(file_path, track_index)
227
+ ```
228
+
229
+ ## API Reference
230
+
231
+ ### Core Functions
232
+
233
+ | Function | Description | Return Value |
234
+ |----------|-------------|--------------|
235
+ | `parse_gtp(path)` | Parse GTP file | `GTPSong` |
236
+ | `render_gtp(path, track_index)` | One-click render GTP file | `List[QPixmap]` |
237
+
238
+ ### Main Classes
239
+
240
+ #### Data Models (`ApolloTab.models`)
241
+
242
+ | Class | Description |
243
+ |-------|-------------|
244
+ | `GTPSong` | Song object (title/artist/BPM/tracks list) |
245
+ | `GTPTrack` | Track object (name/tuning/measures list) |
246
+ | `GTPMeasure` | Measure object (time signature/repeat marks/beats list) |
247
+ | `GTPBeat` | Beat object (duration/dot/notes list) |
248
+ | `GTPNote` | Note object (fret/string/MIDI pitch/techniques) |
249
+
250
+ #### Parser (`ApolloTab.parser`)
251
+
252
+ | Class | Description |
253
+ |-------|-------------|
254
+ | `GTPParser` | GTP file parser class |
255
+
256
+ **Usage**:
257
+ ```python
258
+ from ApolloTab.parser import GTPParser
259
+
260
+ parser = GTPParser()
261
+ song = parser.parse("song.gp5")
262
+ ```
263
+
264
+ #### Renderer (`ApolloTab.renderer`)
265
+
266
+ | Class | Description |
267
+ |-------|-------------|
268
+ | `TabRenderer` | Tablature rendering engine |
269
+ | `TabLayoutEngine` | Layout calculation engine |
270
+
271
+ **Usage**:
272
+ ```python
273
+ from ApolloTab.renderer import TabRenderer, RenderConfig
274
+
275
+ renderer = TabRenderer(RenderConfig())
276
+ pages = renderer.render(song, track_index=0)
277
+ ```
278
+
279
+ #### Audio Engine (`ApolloTab.audio`)
280
+
281
+ | Class | Description |
282
+ |-------|-------------|
283
+ | `MidiConverter` | GTP data to MIDI event converter |
284
+ | `SynthEngine` | FluidSynth audio synthesis engine |
285
+ | `MidiEvent` | Single MIDI event data model |
286
+
287
+ **Usage**:
288
+ ```python
289
+ from ApolloTab.audio import MidiConverter, SynthEngine
290
+
291
+ converter = MidiConverter()
292
+ events = converter.convert(song, track_index=0)
293
+
294
+ engine = SynthEngine()
295
+ engine.initialize()
296
+ engine.load_soundfont()
297
+ engine.load_events(events, bpm=120)
298
+ engine.play()
299
+ ```
300
+
301
+ #### Utilities (`ApolloTab.utils`)
302
+
303
+ | Class / Constant | Description |
304
+ |------------------|-------------|
305
+ | `RenderConfig` | Rendering parameter configuration (all adjustable) |
306
+ | `TechniqueType` | Technique type enum (18 types) |
307
+ | `StandardTunings` | Standard tuning definitions |
308
+ | `NoteDuration` | Duration enum |
309
+
310
+ ## Configuration
311
+
312
+ ### RenderConfig Parameters
313
+
314
+ ```python
315
+ config = RenderConfig(
316
+ # Page size
317
+ page_width=2480, # Page width(px), effect: larger = sharper but more memory
318
+ page_height=3508, # Page height(px), A4@300dpi standard size
319
+
320
+ # Margins
321
+ margin_top=80, # Top margin(px), effect: larger = content shifts down
322
+ margin_bottom=60, # Bottom margin(px)
323
+ margin_left=60, # Left margin(px)
324
+ margin_right=60, # Right margin(px)
325
+
326
+ # Tablature style
327
+ string_spacing=12, # String line spacing(px), effect: larger = wider, more readable
328
+ line_width=1, # Line thickness(px), effect: 0.5=thin, 2=thick
329
+ line_color="#333333", # Line color(hex), effect: changes overall tone
330
+
331
+ # Font settings
332
+ font_family="Arial", # Font family, effect: use system-supported font name
333
+ font_size_fret=10, # Fret number font size(px), effect: larger = clearer numbers
334
+ font_size_technique=9, # Technique label font size(px),
335
+
336
+ # System spacing
337
+ system_spacing=40, # System(row) spacing(px), effect: larger = more whitespace between rows
338
+ )
339
+ ```
340
+
341
+ ### SynthEngine Audio Parameters
342
+
343
+ ```python
344
+ engine = SynthEngine(
345
+ sample_rate=44100, # Sample rate(Hz), effect: 48000 = clearer but higher CPU usage
346
+ buffer_size=512, # Buffer size, effect: 256 = lower latency but may cause audio glitches
347
+ gain=0.8, # Master volume(0.0-1.0), effect: 1.0 = max volume
348
+ )
349
+ ```
350
+
351
+ ## Supported Techniques
352
+
353
+ | Technique | Abbreviation | Symbol Type |
354
+ |-----------|-------------|-------------|
355
+ | Hammer-On | H | Text label |
356
+ | Pull-Off | P | Text label |
357
+ | Slide Up | s/S | Line + arrow |
358
+ | Slide Down | S | Line + arrow |
359
+ | Bend | B | Arc + arrow + degree |
360
+ | Vibrato | ~ | Wavy line |
361
+ | Palm Mute | P.M. | Dashed extension |
362
+ | Staccato | . | Dot mark |
363
+ | Let Ring | Dashed extension | |
364
+ | Natural Harmonic N.H. | Diamond mark | |
365
+ | Artificial Harmonic A.H. | Diamond + text | |
366
+ | Tremolo Picking Trem.Pick. | Diagonal underline | |
367
+ | Trill | "tr" text | |
368
+ | Grace Note | Small note | |
369
+ | Accentuated | > | Symbol |
370
+ | Ghost Note | Parentheses | |
371
+
372
+ ## Development Guide
373
+
374
+ ### Project Structure
375
+
376
+ ```
377
+ ApolloTab/
378
+ ├── __init__.py # Package entry, exports core API
379
+ ├── py.typed # PEP 561 type hint marker
380
+ ├── parser/
381
+ │ ├── __init__.py
382
+ │ └── gtp_parser.py # PyGuitarPro -> GTPSong conversion
383
+ ├── models/
384
+ │ ├── __init__.py
385
+ │ ├── song.py # Song model
386
+ │ ├── track.py # Track model
387
+ │ ├── measure.py # Measure model
388
+ │ ├── beat.py # Beat model
389
+ │ └── note.py # Note model
390
+ ├── renderer/
391
+ │ ├── __init__.py
392
+ │ ├── tab_renderer.py # Tablature drawing engine
393
+ │ └── layout_engine.py # Coordinate layout calculation
394
+ ├── audio/
395
+ │ ├── __init__.py
396
+ │ ├── midi_converter.py # GTP -> MIDI event conversion
397
+ │ └── synth_engine.py # FluidSynth synthesis engine
398
+ └── utils/
399
+ ├── __init__.py
400
+ └── constants.py # Global constant definitions
401
+ ```
402
+
403
+ ### Local Development
404
+
405
+ ```bash
406
+ git clone https://github.com/your-repo/ApolloTab.git
407
+ cd ApolloTab
408
+
409
+ python -m venv venv
410
+ source venv/bin/activate # Linux/Mac
411
+ # or .\venv\Scripts\activate # Windows
412
+
413
+ pip install -e ".[dev]"
414
+
415
+ pytest tests/ -v
416
+
417
+ black ApolloTab/
418
+ isort ApolloTab/
419
+
420
+ mypy ApolloTab/
421
+ ```
422
+
423
+ ### Publish to PyPI
424
+
425
+ ```bash
426
+ python -m build
427
+ twine check dist/*
428
+ twine upload --repository testpypi dist/*
429
+ twine upload dist/*
430
+ ```
431
+
432
+ ## Dependencies
433
+
434
+ ### Required Dependencies
435
+
436
+ | Package | Version | Purpose | License |
437
+ |---------|---------|---------|---------|
438
+ | [pyguitarpro](https://github.com/ozono/guitarpro) | >=0.11 | Guitar Pro file parsing | LGPL-2.1 |
439
+ | [PyQt5](https://www.riverbankcomputing.com/software/pyqt/) | >=5.15 | GUI rendering framework | GPL v3 |
440
+ | [pyfluidsynth](https://github.com/nwhitehead/pyfluidsynth) | >=1.4.0 | FluidSynth Python binding | LGPL-2.1 |
441
+
442
+ ### Optional Dependencies
443
+
444
+ | Group | Package | Purpose |
445
+ |-------|---------|---------|
446
+ | dev | pytest, black, isort, mypy | Development and testing tools |
447
+
448
+ ## License
449
+
450
+ This project is licensed under the [MIT License](LICENSE).
451
+
452
+ ## Contributing
453
+
454
+ Issues and Pull Requests are welcome!
455
+
456
+ 1. Fork this repository
457
+ 2. Create a feature branch (`git checkout -b feature/AmazingFeature`)
458
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
459
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
460
+ 5. Submit a Pull Request
461
+
462
+ ## Related Projects
463
+
464
+ - **[TAB Score Viewer](https://github.com/your-repo/tab-score-viewer)** - Complete guitar tab viewer app built on ApolloTab
465
+ - **[pyguitarpro](https://github.com/ozono/guitarpro)** - Underlying library for Guitar Pro file parsing
466
+ - **[FluidSynth](https://github.com/FluidSynth/fluidsynth)** - Real-time MIDI synthesis engine
467
+
468
+ ---
469
+
470
+ **Version**: v0.2.0
471
+ **Last Updated**: 2026-06-12
472
+ **Compatibility**: Windows / Linux / macOS (Python 3.8+)
473
+
474
+ ---
475
+
476
+ ---
477
+
478
+ # ApolloTab(中文)
479
+
480
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
481
+ [![License: MPL 2.0](https://img.shields.io/badge/License-MPL_2.0-orange.svg)](https://opensource.org/licenses/MPL-2.0/)
482
+ [![PyPI version](https://badge.fury.io/py/ApolloTab.svg)](https://pypi.org/project/ApolloTab/)
483
+
484
+ **Guitar Pro 文件解析、渲染与音频播放引擎库**
485
+
486
+ `ApolloTab` 是一个功能完整的 Python 库,用于解析、渲染和播放 Guitar Pro (.gp3/.gp4/.gp5/.gpx) 格式的吉他谱文件。
487
+
488
+ ## 核心功能
489
+
490
+ - **文件解析**: 完整支持 GP3/GP4/GP5/GPX 格式,提取歌曲信息、音轨、小节、音符、技巧标记
491
+ - **六线谱渲染**: 使用 QPainter 将乐谱数据渲染为高质量六线谱图像(QPixmap),支持多页输出
492
+ - **音频播放**: 基于 FluidSynth 的 MIDI 合成引擎,支持 SoundFont 音色库实时播放
493
+ - **技巧支持**: 18种演奏技巧(击弦、勾弦、推弦、滑音、泛音、颤音等)
494
+ - **高度可配置**: 渲染参数完全可调(线宽、间距、颜色、字体等)
495
+
496
+ ## 安装
497
+
498
+ ### 从 PyPI 安装(推荐)
499
+
500
+ ```bash
501
+ pip install ApolloTab
502
+ ```
503
+
504
+ ### 从源码安装
505
+
506
+ ```bash
507
+ # 克隆仓库
508
+ git clone https://github.com/your-repo/ApolloTab.git
509
+ cd ApolloTab
510
+
511
+ # 安装依赖
512
+ pip install -e .
513
+
514
+ # 或安装开发环境(含测试工具)
515
+ pip install -e ".[dev]"
516
+ ```
517
+
518
+ ## 快速开始
519
+
520
+ ### 1. 解析 GTP 文件
521
+
522
+ ```python
523
+ from ApolloTab import parse_gtp
524
+
525
+ # 解析 Guitar Pro 文件
526
+ song = parse_gtp("my_song.gp5")
527
+
528
+ # 查看基本信息
529
+ print(f"标题: {song.title}")
530
+ print(f"艺术家: {song.artist}")
531
+ print(f"BPM: {song.tempo}")
532
+ print(f"音轨数: {song.track_count}")
533
+
534
+ # 遍历音轨
535
+ for track in song.tracks:
536
+ print(f"\n音轨: {track.name}")
537
+ print(f"调弦: {track.strings}")
538
+ print(f"小节数: {len(track.measures)}")
539
+ ```
540
+
541
+ ### 2. 渲染六线谱图像
542
+
543
+ ```python
544
+ from ApolloTab import render_gtp
545
+
546
+ # 一键渲染(返回多页 QPixmap 列表)
547
+ pages = render_gtp("my_song.gp5", track_index=0)
548
+
549
+ # pages 是 List[QPixmap],每页一张图片
550
+ for i, page in enumerate(pages):
551
+ page.save(f"output_page_{i + 1}.png")
552
+ print(f"已保存第 {i + 1} 页")
553
+
554
+ # 或者使用 TabRenderer 类进行更精细的控制
555
+ from ApolloTab import TabRenderer, RenderConfig
556
+
557
+ # 自定义渲染配置
558
+ config = RenderConfig(
559
+ page_width=2480, # 页面宽度(px),调整效果: 越大越清晰但内存占用更多
560
+ page_height=3508, # 页面高度(px),A4@300dpi标准尺寸
561
+ line_color="#000000", # 弦线颜色
562
+ )
563
+
564
+ renderer = TabRenderer(config=config)
565
+ pages = renderer.render(song, track_index=0)
566
+
567
+ # 访问布局数据(用于播放光标等功能)
568
+ layouts = renderer.last_layouts # List[PageLayout]
569
+ ```
570
+
571
+ ### 3. 音频播放
572
+
573
+ ```python
574
+ from ApolloTab import (
575
+ parse_gtp,
576
+ MidiConverter,
577
+ SynthEngine,
578
+ )
579
+
580
+ # 解析文件
581
+ song = parse_gtp("my_song.gp5")
582
+
583
+ # 转换为 MIDI 事件序列
584
+ converter = MidiConverter()
585
+ events = converter.convert(song, track_index=0)
586
+
587
+ # 初始化音频引擎
588
+ engine = SynthEngine()
589
+ engine.initialize() # 初始化 FluidSynth 合成器
590
+ engine.load_soundfont() # 自动搜索并加载 SoundFont
591
+ engine.set_instrument(0, 27) # 设置通道0为电吉他(MIDI程序号27)
592
+
593
+ # 加载事件并播放
594
+ engine.load_events(events, bpm=song.tempo)
595
+ engine.play()
596
+
597
+ # 控制播放
598
+ import time
599
+ time.sleep(5) # 播放5秒
600
+ engine.pause()
601
+ time.sleep(2) # 暂停2秒
602
+ engine.resume()
603
+ time.sleep(5) # 继续播放5秒
604
+
605
+ # 停止并清理
606
+ engine.stop()
607
+ ```
608
+
609
+ ### 4. 完整示例:解析 → 渲染 → 播放
610
+
611
+ ```python
612
+ from ApolloTab import (
613
+ parse_gtp,
614
+ TabRenderer,
615
+ MidiConverter,
616
+ SynthEngine,
617
+ RenderConfig,
618
+ )
619
+
620
+ def process_gtp_file(file_path: str, track_index: int = 0):
621
+ """
622
+ 完整处理流程:解析 → 渲染 → 播放
623
+
624
+ 参数:
625
+ file_path: .gp3/.gp4/.gp5/.gpx 文件路径
626
+ track_index: 要处理的音轨索引(默认第1条)
627
+ """
628
+ # ===== 步骤1: 解析 =====
629
+ print(f"[1/3] 正在解析: {file_path}")
630
+ song = parse_gtp(file_path)
631
+ print(f" ✓ 标题: {song.title}, BPM: {song.tempo}")
632
+
633
+ # ===== 步骤2: 渲染 =====
634
+ print("[2/3] 正在渲染六线谱...")
635
+ renderer = TabRenderer(RenderConfig())
636
+ pages = renderer.render(song, track_index=track_index)
637
+
638
+ for i, page in enumerate(pages):
639
+ output_file = f"{song.title}_track{track_index}_p{i + 1}.png"
640
+ page.save(output_file)
641
+ print(f" ✓ 已保存: {output_file} ({page.width()}x{page.height()}px)")
642
+
643
+ # ===== 步骤3: 播放 =====
644
+ print("[3/3] 正在初始化音频...")
645
+ converter = MidiConverter()
646
+ events = converter.convert(song, track_index=track_index)
647
+
648
+ engine = SynthEngine()
649
+ engine.initialize()
650
+ engine.load_soundfont()
651
+ engine.set_instrument(0, 27)
652
+ engine.load_events(events, bpm=song.tempo)
653
+
654
+ print(" ▶ 开始播放 (按 Ctrl+C 停止)...")
655
+ engine.play()
656
+
657
+ try:
658
+ while engine.is_playing:
659
+ time.sleep(0.1)
660
+ except KeyboardInterrupt:
661
+ print("\n ⏹ 停止播放")
662
+ engine.stop()
663
+
664
+ # 使用示例
665
+ if __name__ == "__main__":
666
+ import sys
667
+
668
+ if len(sys.argv) < 2:
669
+ print("用法: python example.py <文件路径.gp5> [音轨索引]")
670
+ sys.exit(1)
671
+
672
+ file_path = sys.argv[1]
673
+ track_index = int(sys.argv[2]) if len(sys.argv) > 2 else 0
674
+
675
+ process_gtp_file(file_path, track_index)
676
+ ```
677
+
678
+ ## API 参考
679
+
680
+ ### 核心函数
681
+
682
+ | 函数 | 说明 | 返回值 |
683
+ |------|------|--------|
684
+ | `parse_gtp(path)` | 解析GTP文件 | `GTPSong` |
685
+ | `render_gtp(path, track_index)` | 一键渲染GTP文件 | `List[QPixmap]` |
686
+
687
+ ### 主要类
688
+
689
+ #### 数据模型 (`ApolloTab.models`)
690
+
691
+ | 类名 | 说明 |
692
+ |------|------|
693
+ | `GTPSong` | 歌曲对象(标题/艺术家/BPM/音轨列表) |
694
+ | `GTPTrack` | 音轨对象(名称/调弦/小节列表) |
695
+ | `GTPMeasure` | 小节对象(拍号/重复记号/拍列表) |
696
+ | `GTPBeat` | 拍对象(时值/附点/音符列表) |
697
+ | `GTPNote` | 音符对象(品格/弦/MIDI音高/技巧) |
698
+
699
+ #### 解析器 (`ApolloTab.parser`)
700
+
701
+ | 类名 | 说明 |
702
+ |------|------|
703
+ | `GTPParser` | GTP文件解析器类 |
704
+
705
+ **用法**:
706
+ ```python
707
+ from ApolloTab.parser import GTPParser
708
+
709
+ parser = GTPParser()
710
+ song = parser.parse("song.gp5")
711
+ ```
712
+
713
+ #### 渲染器 (`ApolloTab.renderer`)
714
+
715
+ | 类名 | 说明 |
716
+ |------|------|
717
+ | `TabRenderer` | 六线谱渲染引擎 |
718
+ | `TabLayoutEngine` | 布局计算引擎 |
719
+
720
+ **用法**:
721
+ ```python
722
+ from ApolloTab.renderer import TabRenderer, RenderConfig
723
+
724
+ renderer = TabRenderer(RenderConfig())
725
+ pages = renderer.render(song, track_index=0)
726
+ ```
727
+
728
+ #### 音频引擎 (`ApolloTab.audio`)
729
+
730
+ | 类名 | 说明 |
731
+ |------|------|
732
+ | `MidiConverter` | GTP数据→MIDI事件转换器 |
733
+ | `SynthEngine` | FluidSynth音频合成引擎 |
734
+ | `MidiEvent` | 单个MIDI事件数据模型 |
735
+
736
+ **用法**:
737
+ ```python
738
+ from ApolloTab.audio import MidiConverter, SynthEngine
739
+
740
+ converter = MidiConverter()
741
+ events = converter.convert(song, track_index=0)
742
+
743
+ engine = SynthEngine()
744
+ engine.initialize()
745
+ engine.load_soundfont()
746
+ engine.load_events(events, bpm=120)
747
+ engine.play()
748
+ ```
749
+
750
+ #### 工具 (`ApolloTab.utils`)
751
+
752
+ | 类/常量 | 说明 |
753
+ |---------|------|
754
+ | `RenderConfig` | 渲染参数配置(全部可调) |
755
+ | `TechniqueType` | 技巧类型枚举(18种) |
756
+ | `StandardTunings` | 标准调弦定义 |
757
+ | `NoteDuration` | 时值枚举 |
758
+
759
+ ## 配置说明
760
+
761
+ ### RenderConfig 渲染参数
762
+
763
+ ```python
764
+ config = RenderConfig(
765
+ # 页面尺寸
766
+ page_width=2480, # 页面宽度(px), 调整效果: A4@300dpi=2480, 屏幕显示可用1200
767
+ page_height=3508, # 页面高度(px), 调整效果: A4@3508, 可根据需要调整
768
+
769
+ # 边距
770
+ margin_top=80, # 上边距(px), 调整效果: 增大则内容下移
771
+ margin_bottom=60, # 下边距(px)
772
+ margin_left=60, # 左边距(px)
773
+ margin_right=60, # 右边距(px)
774
+
775
+ # 六线谱样式
776
+ string_spacing=12, # 弦线间距(px), 调整效果: 增大则谱子更宽更易读
777
+ line_width=1, # 弦线粗细(px), 调整效果: 0.5=细线, 2=粗线
778
+ line_color="#333333", # 弦线颜色(十六进制), 调整效果: 改变整体色调
779
+
780
+ # 字体设置
781
+ font_family="Arial", # 字体族, 调整效果: 使用系统支持的字体的名称
782
+ font_size_fret=10, # 品格数字大小(px), 调整效果: 增大则数字更清晰
783
+ font_size_technique=9, # 技巧标记大小(px),
784
+
785
+ # 系统间距
786
+ system_spacing=40, # 系统(行)间距(px), 调整效果: 增大则行间空白更多
787
+ )
788
+ ```
789
+
790
+ ### SynthEngine 音频参数
791
+
792
+ ```python
793
+ engine = SynthEngine(
794
+ sample_rate=44100, # 采样率(Hz), 调整效果: 48000更清晰但CPU占用更高
795
+ buffer_size=512, # 缓冲区大小, 调整效果: 256延迟更低但可能爆音
796
+ gain=0.8, # 主音量(0.0-1.0), 调整效果: 1.0=最大音量
797
+ )
798
+ ```
799
+
800
+ ## 支持的演奏技巧
801
+
802
+ | 技巧 | 缩写 | 符号类型 |
803
+ |------|------|----------|
804
+ | 击弦 Hammer-On | H | 文字标签 |
805
+ | 勾弦 Pull-Off | P | 文字标签 |
806
+ | 上滑音 Slide Up | s/S | 连线+箭头 |
807
+ | 下滑音 Slide Down | S | 连线+箭头 |
808
+ | 推弦 Bend | B | 弧线+箭头+度数 |
809
+ | 颤音 Vibrato | ~ | 波浪线 |
810
+ | 闷音 Palm Mute | P.M. | 虚线延长线 |
811
+ | 断奏 Staccato | . | 点标记 |
812
+ | 延音 Let Ring | 虚线延长线 | |
813
+ | 自然泛音 N.H. | 菱形标记 | |
814
+ | 人工泛音 A.H. | 菱形+文字 | |
815
+ | 震音拨弦 Trem.Pick. | 斜线下划线 | |
816
+ | 颤音 Trill | "tr"文字 | |
817
+ | 装饰音 Grace Note | 小音符 | |
818
+ | 重音 Accentuated | > | 符号 |
819
+ | 幽灵音 Ghost Note | 括号包裹 | |
820
+
821
+ ## 开发指南
822
+
823
+ ### 项目结构
824
+
825
+ ```
826
+ ApolloTab/
827
+ ├── __init__.py # 包入口,导出核心API
828
+ ├── py.typed # PEP 561 类型提示标记
829
+ ├── parser/
830
+ │ ├── __init__.py
831
+ │ └── gtp_parser.py # PyGuitarPro → GTPSong 转换
832
+ ├── models/
833
+ │ ├── __init__.py
834
+ │ ├── song.py # 歌曲模型
835
+ │ ├── track.py # 音轨模型
836
+ │ ├── measure.py # 小节模型
837
+ │ ├── beat.py # 拍模型
838
+ │ └── note.py # 音符模型
839
+ ├── renderer/
840
+ │ ├── __init__.py
841
+ │ ├── tab_renderer.py # 六线谱绘制引擎
842
+ │ └── layout_engine.py # 坐标布局计算
843
+ ├── audio/
844
+ │ ├── __init__.py
845
+ │ ├── midi_converter.py # GTP → MIDI事件转换
846
+ │ └── synth_engine.py # FluidSynth合成引擎
847
+ └── utils/
848
+ ├── __init__.py
849
+ └── constants.py # 全局常量定义
850
+ ```
851
+
852
+ ### 本地开发
853
+
854
+ ```bash
855
+ # 克隆仓库
856
+ git clone https://github.com/your-repo/ApolloTab.git
857
+ cd ApolloTab
858
+
859
+ # 创建虚拟环境
860
+ python -m venv venv
861
+ source venv/bin/activate # Linux/Mac
862
+ # 或 .\venv\Scripts\activate # Windows
863
+
864
+ # 安装开发依赖
865
+ pip install -e ".[dev]"
866
+
867
+ # 运行测试
868
+ pytest tests/ -v
869
+
870
+ # 代码格式化
871
+ black ApolloTab/
872
+ isort ApolloTab/
873
+
874
+ # 类型检查
875
+ mypy ApolloTab/
876
+ ```
877
+
878
+ ### 发布到 PyPI
879
+
880
+ ```bash
881
+ # 1. 构建分发包
882
+ python -m build
883
+
884
+ # 2. 检查包内容
885
+ twine check dist/*
886
+
887
+ # 3. 发布到 TestPyPI(测试)
888
+ twine upload --repository testpypi dist/*
889
+
890
+ # 4. 发布到正式 PyPI
891
+ twine upload dist/*
892
+ ```
893
+
894
+ ## 依赖项
895
+
896
+ ### 必需依赖
897
+
898
+ | 包名 | 版本 | 用途 | 许可证 |
899
+ |------|------|------|--------|
900
+ | [pyguitarpro](https://github.com/ozono/guitarpro) | >=0.11 | Guitar Pro文件解析 | LGPL-2.1 |
901
+ | [PyQt5](https://www.riverbankcomputing.com/software/pyqt/) | >=5.15 | GUI渲染框架 | GPL v3 |
902
+ | [pyfluidsynth](https://github.com/nwhitehead/pyfluidsynth) | >=1.4.0 | FluidSynth Python绑定 | LGPL-2.1 |
903
+
904
+ ### 可选依赖
905
+
906
+ | 组名 | 包名 | 用途 |
907
+ |------|------|------|
908
+ | dev | pytest, black, isort, mypy | 开发和测试工具 |
909
+
910
+ ## 许可证
911
+
912
+ 本项目采用 [MIT License](LICENSE) 开源协议。
913
+
914
+ ## 贡献
915
+
916
+ 欢迎提交 Issue 和 Pull Request!
917
+
918
+ 1. Fork 本仓库
919
+ 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
920
+ 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
921
+ 4. 推送到分支 (`git push origin feature/AmazingFeature`)
922
+ 5. 提交 Pull Request
923
+
924
+ ## 相关项目
925
+
926
+ - **[TAB Score Viewer](https://github.com/your-repo/tab-score-viewer)** - 基于 ApolloTab 的完整吉他谱查看器应用
927
+ - **[pyguitarpro](https://github.com/ozono/guitarpro)** - Guitar Pro 文件解析底层库
928
+ - **[FluidSynth](https://github.com/FluidSynth/fluidsynth)** - 实时 MIDI 合成引擎
929
+
930
+ ---
931
+
932
+ **版本**: v0.2.0
933
+ **最后更新**: 2026-06-12
934
+ **兼容性**: Windows / Linux / macOS (Python 3.8+)