Motif is a .NET 10 music score library built around a mutable, format-agnostic Score
domain model. The current production extension is Guitar Pro support via
Motif.Extensions.GuitarPro, focused on GP7+ .gp archives and raw .gpif, plus a
companion CLI for inspection, conversion, and round-trip diagnostics.
In the current core model, notes store a single sounding Pitch, written-versus-sounding
transposition lives at the track level, exact score time uses rational ScoreTime
fractions, and note duration semantics distinguish written Duration from
SoundingDuration. Guitar Pro-specific fidelity state stays on attached GP extensions
rather than in the core JSON shape. Canonical authored control data now lives on
Score.PointControls and Score.SpanControls, timeline bars can carry explicit written
Start and Duration, and linked-note techniques can use NoteArticulation.Relations
instead of relying only on format-specific flags.
- Read Guitar Pro GP7+
.gparchives and extractContent/score.gpif - Deserialize GPIF XML into a typed raw model
- Resolve GPIF references into a clean domain graph:
Score -> Tracks -> Staves -> StaffMeasures -> Voices -> Beats -> Notes - Preserve score-wide timeline and navigation state on
Score.TimelineBars - Rebuild derived playback order with
ScoreNavigation - Write edited scores back to
.gpif, GP7+.gp, or native.motif - Convert between GP7+
.gp,.gpif,.motif, and mapped JSON withmotif-cli
| Project | Purpose |
|---|---|
Motif.Core |
Format-agnostic domain model, navigation helpers, and serialization helpers |
Motif.Extensions.GuitarPro |
Guitar Pro GP7+ .gp / .gpif read-write support |
Motif |
Convenience package referencing Core and Guitar Pro support |
Motif.CLI (motif-cli) |
CLI for conversion, inspection, and batch diagnostics |
Motif.SchemaExport |
Build-time JSON Schema exporter for native Motif artifacts |
Source/
Motif/ Convenience package
Motif.Core/ Core domain model and navigation helpers
Motif.Extensions.GuitarPro/ Guitar Pro reader/writer, mapper, raw GPIF model
Motif.CLI/ CLI executable project
Motif.SchemaExport/ Build-time JSON Schema exporter
Tests/
Motif.Core.UnitTests/ Core model, navigation, and serialization tests
Motif.Extensions.GuitarPro.UnitTests/
Guitar Pro mapping, writing, and round-trip tests
Motif.IntegrationTests/ CLI integration and regression coverage
docs/
CLI_WORKFLOW.md CLI usage and batch workflows
LIBRARY_WORKFLOW.md Recommended library edit/write workflow
using Motif;
var score = await MotifScore.OpenAsync("song.gp", cancellationToken: cancellationToken);
score.Title = "Edited Title";
// Rebuild derived playback state after navigation-affecting edits.
ScoreNavigation.RebuildPlaybackSequence(score);
await MotifScore.SaveAsync(score, "song-edited.gp", cancellationToken);MotifScore handles mapped JSON and native .motif archives directly, and discovers
extension handlers such as Guitar Pro at runtime. .motif archives always contain
manifest.json and score.json, and now preserve namespaced extensions/ and
resources/ entries so format packages can round-trip supplementary data without the
core archive writer knowing format details. Guitar Pro now uses those locations to carry
raw GP metadata plus non-score archive files through .gp -> .motif -> .gp workflows.
In the current corpus, those preserved non-score entries commonly include VERSION,
Content/BinaryStylesheet, layout/config files, Content/ScoreViews/*,
Content/Stylesheets/*, and in some files Content/Assets/* such as embedded WAV
audio. Preservation is generic: every original .gp archive entry other than
Content/score.gpif is carried forward.
Older pre-GP7 Guitar Pro formats such as .gpx are intentionally unsupported today;
Motif expects those files to be converted forward in Guitar Pro before import.
When a score is opened from a file path, .motif manifests also record the imported
format and source file name in manifest.sources, including extensionless workflows that
use an explicit format hint.
Mapped JSON is intentionally not a self-contained carrier for preserved archive resources,
provenance, or format-specific fidelity state in v1. Use .motif when you need a
portable document that can later export back with preserved contributor payload, and use
MotifScore.ReattachArchiveStateFrom(...) before writing .motif, .gp, or .gpif
from standalone JSON when you still have a source score available.
Use GuitarProWriter directly, or resolve it through MotifScore.CreateWriter("gp"),
when you need Guitar Pro-specific write diagnostics or explicit source-archive control
such as the CLI --source-gp workflow.
Run during development:
dotnet run --project Source/Motif.CLI -- <args>Common commands:
# Export mapped JSON (default output: song.mapped.json)
dotnet run --project Source/Motif.CLI -- song.gp
# Extract raw GPIF
dotnet run --project Source/Motif.CLI -- song.gp song.score.gpif
# Convert raw GPIF to mapped JSON
dotnet run --project Source/Motif.CLI -- song.gpif song.json
# Package a score as a native .motif archive
dotnet run --project Source/Motif.CLI -- song.gp song.motif
# Read a native .motif archive back to mapped JSON
dotnet run --project Source/Motif.CLI -- song.motif song.json
# Write a new .gp archive from mapped JSON with regenerated GP state
dotnet run --project Source/Motif.CLI -- song.json output.gp
# Reattach archive context from an existing source score after standalone JSON edits
dotnet run --project Source/Motif.CLI -- edited.json restored.motif --source-score source.motif
# Preserve non-score archive entries from an existing source archive
dotnet run --project Source/Motif.CLI -- song.json output.gp --source-gp original.gp
# Batch export every .gp file under a directory to JSON
dotnet run --project Source/Motif.CLI -- \
--batch-input-dir ./songs \
--batch-output-dir ./json
# Batch round-trip diagnostics across a corpus
dotnet run --project Source/Motif.CLI -- \
--batch-input-dir ./songs \
--batch-output-dir ./analysis \
--batch-roundtrip-diagnosticsFormats are inferred from file extensions when possible. Use --input-format and
--output-format when extensions are missing or ambiguous. Boolean flags follow the same
pattern everywhere: --flag, --flag=true, and --flag=false.
Known current fidelity limitations are tracked in docs/KNOWN_LIMITATIONS.md.
| Format | Read | Write | Notes |
|---|---|---|---|
gp |
Yes | Yes | Guitar Pro GP7+ ZIP archive containing Content/score.gpif |
gpif |
Yes | Yes | Raw GPIF XML from the GP7+ format family |
motif |
Yes | Yes | Native ZIP archive with manifest.json, score.json, and preserved namespaced extension/resource entries; use this when you need a self-contained portable document |
json |
Yes | Yes | Mapped Score JSON for editing and inspection; not a self-contained carrier for contributor or fidelity payload |
musicxml / mxl |
No | No | Not part of the current CLI or library surface |
midi |
No | No | Not part of the current CLI or library surface |
The CLI intentionally rejects unsupported formats rather than silently routing them.
That includes older pre-GP7 Guitar Pro formats such as .gpx; use Guitar Pro's own
conversion/export workflow first if you need to bring those files into Motif.
Run the full test suite with:
dotnet testCoverage includes real .gp fixtures, mapping fidelity, write diagnostics, public API
shape, and CLI regression tests.
Normal builds now generate JSON Schema artifacts automatically into artifacts/schema/.
This includes:
artifacts/schema/manifest.schema.jsonartifacts/schema/score.schema.jsonartifacts/schema/guitarpro.schema.json
You do not need to run the old Temp/schema-export/* helpers during normal development
builds.