Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8e3f481
Refactor: Improve test file loading and error handling, correct mix t…
AlexandreCrevel Jan 31, 2026
af3d9cf
feat: add ASCII tablature generation to CLI, improve error handling, …
AlexandreCrevel Jan 31, 2026
beb0629
feat: Add initial support for Guitar Pro 7+ (.gp) file parsing with G…
AlexandreCrevel Jan 31, 2026
d8b6873
feat: Add support for GP (Guitar Pro 7+) file parsing and fix numerou…
AlexandreCrevel Jan 31, 2026
3db345d
fix: enhance parsing robustness with explicit bounds checks, default …
AlexandreCrevel Jan 31, 2026
33a4e4a
chore: Ignore `.DS_Store` and refactor range check syntax in key sign…
AlexandreCrevel Jan 31, 2026
5bfe392
refactor: reorganize modules into `model`, `io`, and `audio` subdirec…
AlexandreCrevel Jan 31, 2026
0f33380
Merge pull request #1 from AlexandreCrevel/corrections
AlexandreCrevel Jan 31, 2026
5bc9c38
docs: Overhaul project documentation, rename library and CLI componen…
AlexandreCrevel Jan 31, 2026
bded464
Merge pull request #2 from AlexandreCrevel/documentation
AlexandreCrevel Jan 31, 2026
809ad49
feat: Add comprehensive parsing tests for Guitar Pro 3, 4, and 5 form…
AlexandreCrevel Jan 31, 2026
a816cf1
feat: Implement support for Guitar Pro 6 (.gpx) file parsing, replaci…
AlexandreCrevel Feb 1, 2026
10b94ac
chore: Remove unnecessary `.DS_Store` file from the repository.
AlexandreCrevel Feb 1, 2026
a2ffc92
feat: Enhance GPIF and GPX parsing with additional validation checks …
AlexandreCrevel Feb 1, 2026
958d59d
feat: Add tests for ghost, dead, trill, grace, and harmonic notes in …
AlexandreCrevel Feb 1, 2026
0bf7aec
feat: Enhance error handling in file reading and parsing; update test…
AlexandreCrevel Feb 1, 2026
8547f59
refactor: improve code formatting, add warnings for GPIF import, and …
AlexandreCrevel Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ Cargo.lock
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
*.pdb

.DS_Store
56 changes: 56 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Build & Test Commands

```bash
cargo build # Build entire workspace
cargo build -p lib # Build core library only
cargo build -p cli # Build CLI tool
cargo test # Run all tests
cargo test -- --nocapture # Run tests with stdout visible
cargo test test_gp5 # Run tests matching pattern
cargo clippy # Lint
cargo run -p cli -- --input file.gp5 --tab # Run CLI with tablature output
```

Tests live in `lib/src/tests.rs` and parse files from the `test/` directory.

## Architecture

**Workspace crates:**
- `lib` (library name: `scorelib`) — Core parsing library for Guitar Pro files
- `cli` (binary: `score_tool`) — CLI for file inspection and ASCII tablature
- `web_server` (binary: `score_server`) — Experimental web server

**Data model hierarchy:** `Song → Track → Measure → Voice → Beat → Note`

- `Song` holds tracks, measure headers (shared metadata across tracks), MIDI channels, lyrics, and page setup
- Each `Track` has its own `Vec<Measure>`, while `MeasureHeader` metadata is shared at the song level
- `Voice` (1-2 per measure) contains `Beat`s; each `Beat` contains `Note`s
- Effects are split: `NoteEffect` (bend, slide, harmonic, grace) on notes, `BeatEffects` (stroke, chord, mix table) on beats

**Module layout (`lib/src/`):**
- `model/` — All data structures (Song, Track, Measure, Beat, Note, effects, enums, chord, etc.)
- `io/` — Binary I/O primitives (`primitive.rs`), GPIF XML structures (`gpif.rs`), ZIP handling (`gpx.rs`)
- `audio/` — MIDI channel definitions and GM instrument names

**Trait-based parsing API:** Functionality is organized into ~12 traits (e.g., `SongTrackOps`, `SongMeasureOps`, `SongNoteOps`, `SongEffectOps`, `SongChordOps`) implemented on `Song`. Each trait provides `read_*` and `write_*` methods for its domain. All traits are re-exported from `lib.rs`.

**Binary parsing pattern:** All GP3/4/5 parsing uses a `(data: &[u8], seek: &mut usize)` cursor pattern. Low-level reads go through `io::primitive` functions (`read_byte`, `read_int`, `read_short`, `read_int_byte_size_string`, etc.).

**Version branching:** `Song.version.number` is a `(u8, u8, u8)` tuple. Format-specific logic branches on this throughout the parsing code (e.g., GP5 has separate author field, different padding bytes).

**GP7+ (.gp) parsing** uses a different path: ZIP extraction → XML deserialization via `serde`/`quick-xml` into `Gpif` structs → conversion to `Song` model.

## Format Support

- GP3, GP4, GP5: Full read support, partial write support
- GP7 (.gp): Initial read support via GPIF XML
- GP6 (.gpx): Not yet implemented
- Error handling currently uses `panic!()` — no `Result` types yet

## File Structure Documentation

Binary format specs are in `lib/FILE-STRUCTURE*.md` files — useful when modifying parsing logic.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
authors = ["slundi"]

[workspace]
resolver = "2"
members = ["lib", "cli", "web_server"]
201 changes: 201 additions & 0 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Guitar Pro Parser Documentation

## 1. Introduction

`guitarproparser` is a Rust library (`scorelib`) and CLI tool (`score_tool`) for reading and writing Guitar Pro files (`.gp3`, `.gp4`, `.gp5`). It provides a comprehensive data structure to represent musical partitutres (tablature and notation).

This documentation is designed to be exhaustive for both human developers and AI coding assistants needing to understand the codebase.

## 2. Quick Start

### CLI Tool (`score_tool`)

A CLI is provided to inspect files and generate ASCII tablatures.

**Usage:**
```bash
cargo run -p cli -- --input path/to/file.gp5 --tab
```

**Options:**
- `--input <FILE>`: Path to the Guitar Pro file.
- `--tab` (or `-t`): Visualize the first track as ASCII tablature.

### Library (`scorelib`)

**Dependency:**
Add the library to your `Cargo.toml`:
```toml
[dependencies]
lib = { path = "path/to/guitarproparser/lib" } # Rename 'lib' to 'scorelib' recommended
```

**Basic Usage:**
```rust
use scorelib::gp::Song;
use std::fs;
use fraction::ToPrimitive; // crate 'fraction' is used for durations

fn main() {
let mut song = Song::default();
let data = fs::read("clementi.gp5").expect("File not found");

// Auto-detect format via extension usually, but here calling specific reader:
song.read_gp5(&data);

println!("Song: {}", song.name);

// Iterate tracks
for track in &song.tracks {
println!("Track: {} ({} strings)", track.name, track.strings.len());
// Iterate measures
for measure in &track.measures {
// ...
}
}
}
```

### Traits and Extensions

The library uses traits to extend `Song` with parsing and writing capabilities. This allows the core `Song` struct to remain clean while providing a large API for different formats and features.

```rust
use scorelib::model::song::Song;
use scorelib::model::track::SongTrackOps;
// ... other trait imports ...

// Now song has .read_tracks(), .write_tracks(), etc.
```

## 3. Architecture & Data Structures

The data model follows a hierarchical structure typical of musical scores.

### Hierarchy
`Song` -> `Track` -> `Measure` -> `Voice` -> `Beat` -> `Note`

### key Structures

#### `Song` (`lib/src/model/song.rs`)
The root object representing the entire file.
- **Metadata**: `name`, `artist`, `album`, `author`, `copyright`, `writer`, `transcriber`, `comments`.
- **Global Properties**: `tempo`, `key`, `version` (GP version tuple).
- **Content**: `tracks` (`Vec<Track>`), `measure_headers` (`Vec<MeasureHeader>`).
- **Channels**: `channels` (`Vec<MidiChannel>`) - MIDI instrument configuration.

#### `Track` (`lib/src/model/track.rs`)
Represents a single instrument (e.g., "Electric Guitar").
- **Identity**: `name`, `color`, `channel_index`.
- **Instrument**: `strings` (`Vec<(i8, i8)>` - string number & midi tuning), `fret_count`, `capo`.
- **Content**: `measures` (`Vec<Measure>`).
- **Settings**: `TrackSettings` (tablature/notation visibility, etc.).

#### `Measure` (`lib/src/model/measure.rs`)
Represents a bar of music for a specific track.
*Note: Global measure info (time signature, key signature, repeat bars) is stored in `Song.measure_headers`.*
- **Structure**: `voices` (`Vec<Voice>`) - usually contains 1 or 2 voices.
- **Properties**: `clef`, `line_break`.
- **Position**: `start` (accumulated time).

#### `Voice` (`lib/src/model/beat.rs`)
A rhythmic container within a measure. GP5 supports up to 2 voices (e.g., Lead + Bass in one staff).
- **Content**: `beats` (`Vec<Beat>`).

#### `Beat` (`lib/src/model/beat.rs`)
A rhythmic unit containing notes.
- **Rhythm**: `duration` (`Duration` struct), `tuplets`.
- **Content**: `notes` (`Vec<Note>`), `text` (lyrics/text above), `effect` (`BeatEffects` - e.g., mix table changes, strokes).
- **Properties**: `status` (Normal, Rest, Empty).

#### `Note` (`lib/src/model/note.rs`)
A single sound event.
- **Pitch**: `value` (fret number 0-99), `string` (string index 1-N).
- **Dynamics**: `velocity` (MIDI velocity).
- **Effects**: `NoteEffect` (bend, slide, hammer, harmonic, vibrato, grace note, etc.).
- **Type**: `kind` (Normal, Tie, Dead, Rest).

## 4. Effects System

Effects are categorized by where they apply:

- **Note Effects** (`lib/src/model/note.rs` -> `NoteEffect`):
- `bend`: `BendEffect` (points, type).
- `grace`: `GraceEffect` (fret, duration, transition).
- `slides`: `Vec<SlideType>`.
- `harmonic`: `HarmonicEffect` (Natural, Artificial, Tapped, Pinch, Semi).
- `hammer`/`pull_off`, `palm_mute`, `staccato`, `let_ring`, `vibrato`, `trill`, `tremolo_picking`.

- **Beat Effects** (`lib/src/model/beat.rs` -> `BeatEffects`):
- `stroke`: Up/Down strums.
- `mix_table_change`: Tempo, Volume, Pan, Instrument automation changes.
- `pick_stroke`.

- **Track Effects**: RSE (Realistic Sound Engine) settings, EQ, Humanize.

## 5. Low-Level I/O (`lib/src/io.rs`)

The `io` module provides primitives for reading binary data types used in GP formats:
- `read_byte`, `read_signed_byte`, `read_bool`.
- `read_int` (4 bytes), `read_short` (2 bytes).
- `read_chunk_string`: Pascal-style strings.
- `read_string_byte`: String prefixed by byte length.
- `read_string_int`: String prefixed by int length.

The parsing is sequential. Functions take a `data: &[u8]` slice and a mutable `seek: &mut usize` cursor.

## 6. Supported Formats

| Feature | GP3 (`.gp3`) | GP4 (`.gp4`) | GP5 (`.gp5`) | GP6/GP7 (`.gpx`/`.gp`) |
|---------|--------------|--------------|--------------|-----------------------|
| **Read** | ✅ Full | ✅ Full | ✅ High | ✅ Initial (experimental) |
| **Write** | ⚠️ Partial | ⚠️ Partial | ⚠️ Partial | ❌ Not Implemented |

**Known Limitations in GP5:**
- Complex "Direction" symbols (Segno, Coda) on advanced files may parsing issues.
- RSE (Realistic Sound Engine) data is largely skipped or partially read.

## 7. Development Guide

### Running Tests
The repository contains a suite of integration tests in `lib/src/lib.rs` (module `test`).
```bash
cd lib
cargo test
```
*Note: `test_gp5_demo_complex` and `test_gp3_writing` are currently ignored due to known limitations.*

### Error Handling (Current State)
The parser currently uses `panic!` for errors (e.g., file too short, invalid format).
*Future Plan:* Migrate to `Result<T, ParseError>` for robust error handling.

### Adding Support for New Version
To add parsing for a new version:
1. Define reader methods in `Song` (e.g., `read_gp6`).
2. Implement version-specific logic in `read_track`, `read_measure`, etc., usually switched by `self.version.number`.

## 8. For AI Agents (Context)

When navigating this codebase:
1. **Entry Point**: `lib/src/lib.rs` exports modules. `lib/src/song.rs` contains the `read_gpX` entry methods.
2. **Logic Flow**: `read_gpX` -> `read_version` -> `read_info` -> `read_tracks` -> `read_measures`.
3. **Data Flow**: Measures are stored per track. `song.tracks[t].measures[m]` corresponds to `song.measure_headers[m]`. The header contains timing info (time sig, key sig) shared across all tracks for that measure index.
4. **One-indexing**: GP formats often use 1-based indexing for user-facing values (strings, tracks). Internally, Vectors are 0-indexed. Be careful with loop bounds.
- Note strings: `note.string` is often 1-based in GP data.
- Fret values: 0 is open string, >0 is fret.

### Common Tasks Patterns
- **Iterating Notes**:
```rust
for track in &song.tracks {
for measure in &track.measures {
for voice in &measure.voices {
for beat in &voice.beats {
for note in &beat.notes {
// Process note
}
}
}
}
}
```
50 changes: 41 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
# Guitar tools
# Guitar Pro Tools

## Introduction
A comprehensive suite of tools for parsing, manipulating, and visualizing Guitar Pro files in Rust.

In the beginning, this was just a library to read gGuitar Pro files, but I had lot of ideas so I split this sproject:
## Project Structure

- the [library](lib/README.md) to read **Guitar Pro** files (GP3, GP4, GP5, GPX, GP) and **MuseScore** files (MSCZ)
- the [CLI tool](cli/README.md) to perform batch operations
- a [web server](web_server/README.md) to search music scores and tabs using a database through a future documented API
This workspace is divided into several crates:

## About me
- **[lib](lib/README.md)** (`scorelib`): The core library to read and write **Guitar Pro** files (GP3, GP4, GP5, GPX, GP7) and **MuseScore** files (MSCZ). It provides a unified data model for musical scores.
- **[cli](cli/README.md)** (`score_tool`): A command-line interface to inspect files, view metadata, and generate ASCII tablatures.
- **web_server**: (Experimental) A web server to search and browse music scores through an API.

I started to play guitar in 2019 and I have a pack of Guitar Pro files and sometimes I get a new files from [Songsterr](https://www.songsterr.com/). I want to write a better documentation but I don't know all the stuffs that I can see on a score ;)
## Features

In order to make another software (with advanced search, chord detection, ...), I need a library that is able to parse and write Guitar Pro files.
- **Multi-format support**: Read GP3, GP4, GP5, and early support for GP6/7 (.gp, .gpx).
- **Rich Data Model**: Exhaustive representation of tracks, measures, beats, notes, and musical effects.
- **ASCII Visualization**: Generate text-based tablatures directly from the CLI.
- **Extensible Architecture**: Module-based design with traits for easy extension.

## Usage

To get started with the CLI, run:

```bash
cargo run -p cli -- --input path/to/song.gp5 --tab
```

## Roadmap

### Library
- [x] Refactor core into `model`, `io`, and `audio` modules.
- [x] Comprehensive trait-based API for `Song` operations.
- [x] High-fidelity GP5 parsing.
- [x] Initial support for GP6/7 (.gp/.gpx) formats.
- [ ] Improved MuseScore (.mscz) support.
- [ ] Full RSE (Realistic Sound Engine) data parsing.
- [ ] Export to MIDI/Audio.

### CLI
- [x] Basic metadata inspection.
- [x] ASCII Tablature generation.
- [ ] Batch conversion tool.
- [ ] Advanced search and filtering.

## License

This project is licensed under the MIT License.
Loading