mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 06:46:14 +00:00
ABC notation export via Score.to_abc() — v0.41.0
New method converts scores to ABC notation with support for multi-voice, chords, rests, accidentals, and all durations. Pass html=True for a self-contained HTML page with abcjs sheet music rendering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,13 @@
|
||||
|
||||
All notable changes to PyTheory are documented here.
|
||||
|
||||
## 0.41.0
|
||||
|
||||
- **ABC notation export** — `Score.to_abc()` converts scores to ABC notation
|
||||
strings. Supports multi-voice scores (via `V:` directives), chords, rests,
|
||||
accidentals, and all standard durations. Pass `html=True` to get a
|
||||
self-contained HTML page that renders sheet music in the browser via abcjs.
|
||||
|
||||
## 0.40.9
|
||||
|
||||
- **Mellotron synth** — tape-replay keyboard with wow/flutter, tape saturation,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "pytheory"
|
||||
version = "0.40.9"
|
||||
version = "0.41.0"
|
||||
description = "Music Theory for Humans"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""PyTheory: Music Theory for Humans."""
|
||||
|
||||
__version__ = "0.40.9"
|
||||
__version__ = "0.41.0"
|
||||
|
||||
from .tones import Tone, Interval
|
||||
from .systems import System, SYSTEMS, TET
|
||||
|
||||
+12
-6
@@ -4463,11 +4463,13 @@ class Score:
|
||||
|
||||
return f"{abc_acc}{note_char}{oct_str}"
|
||||
|
||||
def _notes_to_abc(self, notes, default_unit, ts):
|
||||
def _notes_to_abc(self, notes, default_unit, ts,
|
||||
bars_per_line=4):
|
||||
"""Convert a list of Note objects to an ABC body string."""
|
||||
beats_per_measure = ts.beats_per_measure
|
||||
parts = []
|
||||
tokens = []
|
||||
beat_in_measure = 0.0
|
||||
measure_count = 0
|
||||
|
||||
for note in notes:
|
||||
beats = note.duration.value
|
||||
@@ -4506,16 +4508,20 @@ class Score:
|
||||
frac = Fraction(multiplier).limit_denominator(16)
|
||||
dur_str = f"{frac.numerator}/{frac.denominator}"
|
||||
|
||||
parts.append(f"{abc_note}{dur_str}")
|
||||
tokens.append(f"{abc_note}{dur_str}")
|
||||
|
||||
beat_in_measure += beats
|
||||
if beat_in_measure >= beats_per_measure - 0.001:
|
||||
parts.append("|")
|
||||
measure_count += 1
|
||||
if measure_count % bars_per_line == 0:
|
||||
tokens.append("|\n")
|
||||
else:
|
||||
tokens.append("|")
|
||||
beat_in_measure -= beats_per_measure
|
||||
|
||||
body = " ".join(parts)
|
||||
body = " ".join(tokens)
|
||||
# Clean up trailing/double barlines
|
||||
body = body.replace("| |", "|").rstrip("| ").rstrip()
|
||||
body = body.replace("| |", "|").rstrip("| \n").rstrip()
|
||||
if not body.endswith("|"):
|
||||
body += " |"
|
||||
return body
|
||||
|
||||
Reference in New Issue
Block a user