Skip to content

Commit 7307031

Browse files
Squash merge of new AnnExtra annotation/comparison algorithm (using set distance).
Squashed commit of the following: commit 1148786 Author: Greg Chapman <[email protected]> Date: Mon Feb 3 13:32:07 2025 -0800 Refactor extra ignoring. And ignore empty tempos and staffinfos, not just emptydirections. commit d12ba94 Author: Greg Chapman <[email protected]> Date: Mon Feb 3 11:33:00 2025 -0800 Better extra pairing to avoid diffs where there aren't any. commit e41726e Author: Greg Chapman <[email protected]> Date: Sun Feb 2 16:24:31 2025 -0800 Extra text output: don't print info dict if your outputing an info change (just the changed entries). commit 093a12a Author: Greg Chapman <[email protected]> Date: Sun Feb 2 15:57:35 2025 -0800 A few more tweaks to AnnExtra diff text output. commit fb94267 Author: Greg Chapman <[email protected]> Date: Sun Feb 2 12:24:16 2025 -0800 Improved symbolic for clef and keysig. commit 9ef7cc8 Author: Greg Chapman <[email protected]> Date: Sun Feb 2 12:12:47 2025 -0800 Extras: improve readable_str() commit 0c68977 Author: Greg Chapman <[email protected]> Date: Sun Feb 2 12:03:28 2025 -0800 Don't crash if mm.text is None. commit 55407a3 Author: Greg Chapman <[email protected]> Date: Sun Feb 2 11:39:17 2025 -0800 Extras: no duration for a bunch of them. commit fa50723 Author: Greg Chapman <[email protected]> Date: Sun Feb 2 11:28:48 2025 -0800 Oops forgot to include new AnnExtra fields in __str__() for comparison. commit fa78b6b Author: Greg Chapman <[email protected]> Date: Sat Feb 1 16:02:24 2025 -0800 Fix a few bugs. commit ecdf215 Author: Greg Chapman <[email protected]> Date: Sat Feb 1 15:27:29 2025 -0800 Extras: split annotation into three optional fields: content (if there's a visible string) with symbols = len(content), symbolic (if there's a simple description of everything with symbols = 1, and infodict (if there is more than on simple thing to describe) with symbols = len(dict). commit 55aa68e Author: Greg Chapman <[email protected]> Date: Fri Jan 31 14:15:34 2025 -0800 More readable extra.kind. commit cec83cd Author: Greg Chapman <[email protected]> Date: Fri Jan 31 14:06:33 2025 -0800 Update Copyright date to include 2025. commit 7a9cfe0 Author: Greg Chapman <[email protected]> Date: Fri Jan 31 14:04:22 2025 -0800 Better readable string (diff text output) for AnnExtra. commit 628f9b8 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 17:30:48 2025 -0800 For extras, split content and kind, and use set distance algorithm. commit fd2ab38 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 12:13:21 2025 -0800 Add symbols.txt, a description of symbol counts and symbolic error counts used by musicdiff. commit 7ec4818 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 11:34:01 2025 -0800 Squashed commit of the following: commit f7eefb8 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 11:16:55 2025 -0800 Squashed merge of develop for Release 4.1. Squashed commit of the following: commit fd962ee Author: Greg Chapman <[email protected]> Date: Thu Jan 30 11:16:17 2025 -0800 Update READMEs, setup.py, and LICENSE for Release 4.1. commit 9f0cf12 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:51:07 2025 -0800 Update tests to know about new symbol counting changes. commit 08e6185 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:39:39 2025 -0800 Tests: add SER output to command line tests. commit 2188808 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:14:47 2025 -0800 AnnExtra symbol count has len(content) now and AnnExtra symbol error count includes Levenshtein distance of content. AnnStaffGroups are sorted now, and instead of comparing all the part indices, we compare lowest and highest. commit 7dc9ef0 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 16:45:47 2025 -0800 Make sure metadata item value ends up being a string. commit 3f78626 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 16:37:47 2025 -0800 More symbol count (notation_size) and symbol error count (cost) changes. Trying to make them match eachother better, and make more sense. commit a58acf3 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 12:33:35 2025 -0800 Release Notes again. commit a757ad7 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 12:32:04 2025 -0800 Stop assuming that the two different extras are both either a Spanner or not. They could be one of each. commit 3e08d22 Author: Greg Chapman <[email protected]> Date: Mon Jan 27 15:57:25 2025 -0800 ReleaseNotes update. commit 1904528 Author: Greg Chapman <[email protected]> Date: Sun Jan 26 12:10:21 2025 -0800 Update ReleaseNotes 4.1 commit b060304 Author: Greg Chapman <[email protected]> Date: Sat Jan 25 14:01:25 2025 -0800 musicdiff text output expected results have changed a little due to symbol counting (notation_size and cost) changes. commit b618d74 Author: Greg Chapman <[email protected]> Date: Fri Jan 24 14:31:06 2025 -0800 AnnLyric.notation_size: identifiers are only worth 1, not len(identifier). Print SER even if cost == 0. Handle numSymbolsInGroundTruth being 0 without dividing by 0. commit a6f76e9 Author: Greg Chapman <[email protected]> Date: Fri Jan 24 14:27:30 2025 -0800 New release notes for v4.1.0 commit d05187d Author: Greg Chapman <[email protected]> Date: Thu Jan 23 15:18:44 2025 -0800 Another lyrics and extras adjustment (lower the costs). commit 09e92e1 Author: Greg Chapman <[email protected]> Date: Thu Jan 23 15:03:42 2025 -0800 For extras and lyrics, notation_size does not include offset/duration, and diff cost is incremented by only 1 for differences in each of those fields. commit 80a630a Author: Greg Chapman <[email protected]> Date: Thu Jan 23 12:33:15 2025 -0800 Better notation_size and comparison cost for extras and lyrics. commit 45b54e6 Author: Greg Chapman <[email protected]> Date: Tue Jan 21 14:14:03 2025 -0800 Ignore SenzaMisuraTimeSignature (since it is displayed as no timesig at all). commit 1d08dd9 Author: Greg Chapman <[email protected]> Date: Tue Jan 21 11:37:49 2025 -0800 Refactor SER output into Visualization, and return a dict[str, str]. To print it as text, we convert to JSON and print that. commit a176105 Author: Greg Chapman <[email protected]> Date: Thu Jan 16 09:03:42 2025 -0800 Compute SER = symbolic errors/num symbols in ground truth (i.e. file2). commit 067a96d Author: Greg Chapman <[email protected]> Date: Thu Jan 16 08:56:17 2025 -0800 Add to cost any syntax errors fixed by converter21 parse code. Some lint, too. commit bfdcf32 Author: Greg Chapman <[email protected]> Date: Mon Dec 2 17:19:53 2024 -0800 New output format "ser" that prints num errors/max num syms of the two scores. commit 16d2603 Author: Greg Chapman <[email protected]> Date: Mon Dec 2 12:23:37 2024 -0800 Always return cost in symbol errors from diff() and from musicdiff command. commit 31b31e7 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 21:46:53 2024 -0800 First cut at fixing Humdrum syntax errors. commit e54c259 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:49:01 2024 -0800 Back out that AnnStaffGroup cost change; I don't like the results, and I wasn't convinced to begin with. commit eafb018 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:40:38 2024 -0800 More notation_size tweaks: AnnMeasure should include lyric sizes, and AnnStaffGroup should add 1 for each enclosed part/staff. commit 8f903d9 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:29:09 2024 -0800 Fix comment typo. commit e6922a7 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:22:43 2024 -0800 Don't precompute notation_size, cache it if it is ever computed. Many objects never are asked their notation size, especially if the scores are very similar, so don't pay the price unless you have to (but only pay it once). commit 352bc95 Author: Greg Chapman <[email protected]> Date: Wed Nov 27 17:49:58 2024 -0800 First cut at comparing different number of parts. commit fd962ee Author: Greg Chapman <[email protected]> Date: Thu Jan 30 11:16:17 2025 -0800 Update READMEs, setup.py, and LICENSE for Release 4.1. commit 9f0cf12 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:51:07 2025 -0800 Update tests to know about new symbol counting changes. commit 08e6185 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:39:39 2025 -0800 Tests: add SER output to command line tests. commit 2188808 Author: Greg Chapman <[email protected]> Date: Thu Jan 30 10:14:47 2025 -0800 AnnExtra symbol count has len(content) now and AnnExtra symbol error count includes Levenshtein distance of content. AnnStaffGroups are sorted now, and instead of comparing all the part indices, we compare lowest and highest. commit 7dc9ef0 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 16:45:47 2025 -0800 Make sure metadata item value ends up being a string. commit 3f78626 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 16:37:47 2025 -0800 More symbol count (notation_size) and symbol error count (cost) changes. Trying to make them match eachother better, and make more sense. commit a58acf3 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 12:33:35 2025 -0800 Release Notes again. commit a757ad7 Author: Greg Chapman <[email protected]> Date: Tue Jan 28 12:32:04 2025 -0800 Stop assuming that the two different extras are both either a Spanner or not. They could be one of each. commit 3e08d22 Author: Greg Chapman <[email protected]> Date: Mon Jan 27 15:57:25 2025 -0800 ReleaseNotes update. commit 1904528 Author: Greg Chapman <[email protected]> Date: Sun Jan 26 12:10:21 2025 -0800 Update ReleaseNotes 4.1 commit b060304 Author: Greg Chapman <[email protected]> Date: Sat Jan 25 14:01:25 2025 -0800 musicdiff text output expected results have changed a little due to symbol counting (notation_size and cost) changes. commit b618d74 Author: Greg Chapman <[email protected]> Date: Fri Jan 24 14:31:06 2025 -0800 AnnLyric.notation_size: identifiers are only worth 1, not len(identifier). Print SER even if cost == 0. Handle numSymbolsInGroundTruth being 0 without dividing by 0. commit a6f76e9 Author: Greg Chapman <[email protected]> Date: Fri Jan 24 14:27:30 2025 -0800 New release notes for v4.1.0 commit d05187d Author: Greg Chapman <[email protected]> Date: Thu Jan 23 15:18:44 2025 -0800 Another lyrics and extras adjustment (lower the costs). commit 09e92e1 Author: Greg Chapman <[email protected]> Date: Thu Jan 23 15:03:42 2025 -0800 For extras and lyrics, notation_size does not include offset/duration, and diff cost is incremented by only 1 for differences in each of those fields. commit 80a630a Author: Greg Chapman <[email protected]> Date: Thu Jan 23 12:33:15 2025 -0800 Better notation_size and comparison cost for extras and lyrics. commit 45b54e6 Author: Greg Chapman <[email protected]> Date: Tue Jan 21 14:14:03 2025 -0800 Ignore SenzaMisuraTimeSignature (since it is displayed as no timesig at all). commit 1d08dd9 Author: Greg Chapman <[email protected]> Date: Tue Jan 21 11:37:49 2025 -0800 Refactor SER output into Visualization, and return a dict[str, str]. To print it as text, we convert to JSON and print that. commit a176105 Author: Greg Chapman <[email protected]> Date: Thu Jan 16 09:03:42 2025 -0800 Compute SER = symbolic errors/num symbols in ground truth (i.e. file2). commit 067a96d Author: Greg Chapman <[email protected]> Date: Thu Jan 16 08:56:17 2025 -0800 Add to cost any syntax errors fixed by converter21 parse code. Some lint, too. commit bfdcf32 Author: Greg Chapman <[email protected]> Date: Mon Dec 2 17:19:53 2024 -0800 New output format "ser" that prints num errors/max num syms of the two scores. commit 16d2603 Author: Greg Chapman <[email protected]> Date: Mon Dec 2 12:23:37 2024 -0800 Always return cost in symbol errors from diff() and from musicdiff command. commit 31b31e7 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 21:46:53 2024 -0800 First cut at fixing Humdrum syntax errors. commit e54c259 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:49:01 2024 -0800 Back out that AnnStaffGroup cost change; I don't like the results, and I wasn't convinced to begin with. commit eafb018 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:40:38 2024 -0800 More notation_size tweaks: AnnMeasure should include lyric sizes, and AnnStaffGroup should add 1 for each enclosed part/staff. commit 8f903d9 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:29:09 2024 -0800 Fix comment typo. commit e6922a7 Author: Greg Chapman <[email protected]> Date: Sun Dec 1 19:22:43 2024 -0800 Don't precompute notation_size, cache it if it is ever computed. Many objects never are asked their notation size, especially if the scores are very similar, so don't pay the price unless you have to (but only pay it once). commit 352bc95 Author: Greg Chapman <[email protected]> Date: Wed Nov 27 17:49:58 2024 -0800 First cut at comparing different number of parts.
1 parent f7eefb8 commit 7307031

File tree

9 files changed

+1391
-301
lines changed

9 files changed

+1391
-301
lines changed

ReleaseNotes_4.1.0.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Changes since 4.0.0:
99
In support of SER, notation_sizes (a.k.a. symbol counts) and diff costs (a.k.a.
1010
symbolic error counts) have been reviewed and updated:
1111
AnnNote.notation_size(): add 1 symbol for slash on grace note
12-
AnnExtra.notation_size(): 1 symbol for the text, add 1 symbol if there is any
12+
AnnExtra.notation_size(): len(text) for the text, add 1 symbol if there is any
1313
style specified
14-
AnnExtra diff error count: text diff is 1 symbol error, offset diff is 1 symbol
15-
error, duration diff is 1 symbol error, style diff is 1 symbol error
14+
AnnExtra diff error count: text diff is Levenshtein distance, offset diff is
15+
1 symbol error, duration diff is 1 symbol error, style diff is 1 symbol error
1616
AnnLyric.notation_size(): use len(text) as symbol count instead of 1;
1717
add 1 symbol if there's a verse number;
1818
add 1 symbol if there's a verse identifier different from the number;

musicdiff/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# https://github.com/fosfrancesco/music-score-diff.git
77
# by Francesco Foscarin <[email protected]>
88
#
9-
# Copyright: (c) 2022-2024 Francesco Foscarin, Greg Chapman
9+
# Copyright: (c) 2022-2025 Francesco Foscarin, Greg Chapman
1010
# License: MIT, see LICENSE
1111
# ------------------------------------------------------------------------------
1212

musicdiff/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# https://github.com/fosfrancesco/music-score-diff.git
1010
# by Francesco Foscarin <[email protected]>
1111
#
12-
# Copyright: (c) 2022-2024 Francesco Foscarin, Greg Chapman
12+
# Copyright: (c) 2022-2025 Francesco Foscarin, Greg Chapman
1313
# License: MIT, see LICENSE
1414
# ------------------------------------------------------------------------------
1515
import sys

musicdiff/annotation.py

Lines changed: 103 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# https://github.com/fosfrancesco/music-score-diff.git
99
# by Francesco Foscarin <[email protected]>
1010
#
11-
# Copyright: (c) 2022-2024 Francesco Foscarin, Greg Chapman
11+
# Copyright: (c) 2022-2025 Francesco Foscarin, Greg Chapman
1212
# License: MIT, see LICENSE
1313
# ------------------------------------------------------------------------------
1414

@@ -649,50 +649,29 @@ def __init__(
649649
Style, Metadata, or Voicing.
650650
"""
651651
self.extra = extra.id
652-
self.offset: OffsetQL
653-
self.duration: OffsetQL
654-
self.numNotes: int = 1
655-
656-
if isinstance(extra, m21.spanner.Spanner):
657-
self.numNotes = len(extra)
658-
firstNote: m21.note.GeneralNote | m21.spanner.SpannerAnchor = (
659-
M21Utils.getPrimarySpannerElement(extra)
660-
)
661-
lastNote: m21.note.GeneralNote | m21.spanner.SpannerAnchor = (
662-
extra.getLast()
663-
)
664-
self.offset = firstNote.getOffsetInHierarchy(measure)
665-
# to compute duration we need to use offset-in-score, since the end note might
666-
# be in another Measure. Except for ArpeggioMarkSpanners, where the duration
667-
# doesn't matter, so we just set it to 0, rather than figuring out the longest
668-
# duration in all the notes/chords in the arpeggio.
669-
if isinstance(extra, m21.expressions.ArpeggioMarkSpanner):
670-
self.duration = 0.
671-
else:
672-
startOffsetInScore: OffsetQL = firstNote.getOffsetInHierarchy(score)
673-
try:
674-
endOffsetInScore: OffsetQL = opFrac(
675-
lastNote.getOffsetInHierarchy(score) + lastNote.duration.quarterLength
676-
)
677-
except m21.sites.SitesException:
678-
endOffsetInScore = startOffsetInScore
679-
self.duration = opFrac(endOffsetInScore - startOffsetInScore)
680-
elif isinstance(extra, m21.bar.Barline):
681-
# we ignore offset for barlines; barline offset is derived from the objects in the
682-
# measure, which are already being compared.
683-
self.offset = 0.0
684-
self.duration = extra.duration.quarterLength
685-
elif isinstance(extra, m21.harmony.ChordSymbol):
686-
# we ignore duration for ChordSymbols, it is often 0.0 or 1.0, and meaningless.
687-
self.offset = extra.getOffsetInHierarchy(measure)
688-
self.duration = 0.0
689-
else:
690-
self.offset = extra.getOffsetInHierarchy(measure)
691-
self.duration = extra.duration.quarterLength
692-
693-
self.content: str = M21Utils.extra_to_string(extra, detail)
652+
self.kind: str = M21Utils.extra_to_kind(extra)
694653
self.styledict: dict = {}
695654

655+
# kind-specific fields (set to None if not relevant)
656+
657+
# content is a string that (if not None) should be counted as 1 symbol per character
658+
# (e.g. "con fiero")
659+
self.content: str | None = M21Utils.extra_to_string(extra, self.kind, detail)
660+
661+
# symbolic is a string that (if not None) should be counted as 1 symbol (e.g. "G2+8")
662+
self.symbolic: str | None = M21Utils.extra_to_symbolic(extra, self.kind, detail)
663+
664+
# offset and/or duration are sometimes relevant
665+
self.offset: OffsetQL | None = None
666+
self.duration: OffsetQL | None = None
667+
self.offset, self.duration = M21Utils.extra_to_offset_and_duration(
668+
extra, self.kind, measure, score, detail
669+
)
670+
671+
# infodict (kind-specific elements; each element is worth one musical symbol)
672+
self.infodict: dict[str, str] = M21Utils.extra_to_infodict(extra, self.kind, detail)
673+
674+
# styledict
696675
if DetailLevel.includesStyle(detail):
697676
if not isinstance(extra, m21.harmony.ChordSymbol):
698677
# We don't (yet) compare style of ChordSymbols, because Humdrum has no way (yet)
@@ -705,8 +684,7 @@ def __init__(
705684
smuflTextSuppressed: bool = False
706685
if (isinstance(extra, m21.tempo.MetronomeMark)
707686
and not extra.textImplicit
708-
and extra.text
709-
and not self.content.startswith('MM:TX:')):
687+
and M21Utils.parse_note_equal_num(extra.text) != (None, None)):
710688
smuflTextSuppressed = True
711689

712690
self.styledict = M21Utils.obj_to_styledict(
@@ -728,43 +706,102 @@ def notation_size(self) -> int:
728706
int: The notation size of the annotated extra
729707
"""
730708
if self._cached_notation_size is None:
731-
cost: int = len(self.content)
732-
cost += 2 # for offset and duration
709+
cost: int = 0
710+
if self.content is not None:
711+
cost += len(self.content)
712+
if self.symbolic is not None:
713+
cost += 1
714+
if self.offset is not None:
715+
cost += 1
716+
if self.duration is not None:
717+
cost += 1
718+
cost += len(self.infodict)
733719
if self.styledict:
734-
cost += 1 # someday we might count items in styledict
720+
cost += 1 # someday we might add len(styledict) instead of 1
735721
self._cached_notation_size = cost
736722

737723
return self._cached_notation_size
738724

739725
def readable_str(self, name: str = "", idx: int = 0, changedStr: str = "") -> str:
740-
string: str = self.content
726+
string: str = self.content or ""
727+
if self.symbolic:
728+
if string:
729+
string += " "
730+
string += self.symbolic
731+
if self.infodict and name != "info":
732+
for i, k in enumerate(self.infodict):
733+
if string:
734+
string += " "
735+
string += f"{k}:{self.infodict[k]}"
736+
741737
if name == "":
742-
if self.duration > 0:
743-
string += f" dur={M21Utils.ql_to_string(self.duration)}"
744-
if self.numNotes != 1:
745-
string += f" numNotes={self.numNotes}"
738+
if self.duration is not None:
739+
if string:
740+
string += " "
741+
string += f"dur={M21Utils.ql_to_string(self.duration)}"
746742
return string
747743

748744
if name == "content":
749-
return string
745+
if self.content is None:
746+
return ""
747+
return self.content
748+
749+
if name == "symbolic":
750+
if self.symbolic is None:
751+
return ""
752+
return self.symbolic
750753

751754
if name == "offset":
752-
string += f" offset={M21Utils.ql_to_string(self.offset)}"
755+
if self.offset is None:
756+
return ""
757+
if string:
758+
string += " "
759+
string += f"offset={M21Utils.ql_to_string(self.offset)}"
753760
return string
754761

755762
if name == "duration":
756-
string += f" dur={M21Utils.ql_to_string(self.duration)}"
763+
if self.duration is None:
764+
return ""
765+
if string:
766+
string += " "
767+
string += f"dur={M21Utils.ql_to_string(self.duration)}"
757768
return string
758769

759-
if name == "style":
770+
if name == "info":
760771
changedKeys: list[str] = changedStr.split(',')
761772
if not changedKeys:
762-
string += " changedStyle={}"
773+
if string:
774+
string += " "
775+
string += "changedInfo={}"
763776
return string
764777

765-
string += " changedStyle={"
778+
if string:
779+
string += " "
780+
string += "changedInfo={"
766781

767782
needsComma: bool = False
783+
for i, k in enumerate(changedKeys):
784+
if k in self.infodict:
785+
if needsComma:
786+
string += ", "
787+
string += f"{k}:{self.infodict[k]}"
788+
needsComma = True
789+
string += "}"
790+
return string
791+
792+
if name == "style":
793+
changedKeys = changedStr.split(',')
794+
if not changedKeys:
795+
if string:
796+
string += " "
797+
string += "changedStyle={}"
798+
return string
799+
800+
if string:
801+
string += " "
802+
string += "changedStyle={"
803+
804+
needsComma = False
768805
for i, k in enumerate(changedKeys):
769806
if k in self.styledict:
770807
if needsComma:
@@ -788,9 +825,11 @@ def __str__(self) -> str:
788825
Returns:
789826
str: the compared representation of the AnnExtra. Does not consider music21 id.
790827
"""
791-
string = f'{self.content},off={self.offset},dur={self.duration}'
792-
if self.numNotes != 1:
793-
string += f',numNotes={self.numNotes}'
828+
string = f'{self.kind},content={self.content},symbol={self.symbolic}'
829+
string += f',off={self.offset},dur={self.duration}'
830+
# then any info fields
831+
for k, v in self.infodict.items():
832+
string += f",{k}={v}"
794833
# and then any style fields
795834
for k, v in self.styledict.items():
796835
string += f",{k}={v}"
@@ -1187,7 +1226,8 @@ def __init__(
11871226

11881227
# For correct comparison, sort the extras_list, so that any extras
11891228
# that all have the same offset are sorted alphabetically.
1190-
self.extras_list.sort(key=lambda e: (e.offset, str(e)))
1229+
# 888 need to sort by class here? Or not at all?
1230+
self.extras_list.sort(key=lambda e: (e.kind, e.offset))
11911231

11921232
self.lyrics_list: list[AnnLyric] = []
11931233
if DetailLevel.includesLyrics(detail):

0 commit comments

Comments
 (0)