Skip to content

Commit

Permalink
Merge pull request #1484 from cuthbertLab/variant-abc
Browse files Browse the repository at this point in the history
Add docs about abcFormat version, better docs
  • Loading branch information
mscuthbert authored Nov 24, 2022
2 parents bcaf1f6 + 698095f commit c9db6b7
Showing 1 changed file with 61 additions and 40 deletions.
101 changes: 61 additions & 40 deletions music21/abcFormat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@
(PC users might need: 'c:/program files (x86)/easyabc/easyabc.exe')
(Thanks to Norman Schmidt for the heads-up)
There is a two-step process in converting ABC files to Music21 Streams. First this module
There is a two-step process in converting ABC files to music21 Streams. First this module
reads in the text-based .abc file and converts all the information into ABCToken objects. Then
the function :func:`music21.abcFormat.translate.abcToStreamScore` of
the :ref:`moduleAbcFormatTranslate` module
translates those Tokens into music21 objects.
Music21 implements the entire v1.6 ABC standard (January 1997) found at
https://abcnotation.com/standard/abc_v1.6.txt . The system aims to support the
v2.1 ABC standard (December 2011) found at
https://abcnotation.com/wiki/abc:standard:v2.1 but some parts (e.g. 4.10 Variant Endings) are not
implemented. No support is yet given for the draft 2.2 standard.
'''
from __future__ import annotations

Expand Down Expand Up @@ -103,6 +109,7 @@
('|', 'regular'),
(':', 'dotted'),
]
ABC_BARS_DICT = {d[0]: d[1] for d in ABC_BARS}

# store a mapping of ABC representation to pitch values
# key is (srcStr, carriedAccidental, str(keySignature)
Expand Down Expand Up @@ -781,15 +788,20 @@ def getDefaultQuarterLength(self) -> float:


class ABCBar(ABCToken):
'''
An ABCBar token represents a barline, possibly with repeat information.
Currently 4.10 Variant
'''
# given a logical unit, create an object
# may be a chord, notes, metadata, bars
__slots__ = ('barType', 'barStyle', 'repeatForm')

def __init__(self, src):
super().__init__(src)
self.barType = None # repeat or barline
self.barStyle = None # regular, heavy-light, etc
self.repeatForm = None # end, start, bidrectional, first, second
self.barType = '' # repeat or barline
self.barStyle = '' # regular, heavy-light, etc
self.repeatForm = '' # end, start, bidrectional, first, second

def parse(self):
'''
Expand Down Expand Up @@ -821,41 +833,44 @@ def parse(self):
>>> ab.repeatForm
'start'
'''
for abcStr, barTypeString in ABC_BARS:
if abcStr == self.src.strip():
# this gets lists of elements like
# light-heavy-repeat-end
barTypeComponents = barTypeString.split('-')
# this is a list of attributes
if 'repeat' in barTypeComponents:
self.barType = 'repeat'
elif ('first' in barTypeComponents
or 'second' in barTypeComponents):
self.barType = 'barline'
# environLocal.printDebug(['got repeat 1/2:', self.src])
else:
self.barType = 'barline'

# case of regular, dotted
if len(barTypeComponents) == 1:
self.barStyle = barTypeComponents[0]

# case of light-heavy, light-light, etc
elif len(barTypeComponents) >= 2:
# must get out cases of the start-tags for repeat boundaries
# not yet handling
if 'first' in barTypeComponents:
self.barStyle = 'regular'
self.repeatForm = 'first' # not a repeat
elif 'second' in barTypeComponents:
self.barStyle = 'regular'
self.repeatForm = 'second' # not a repeat
else:
self.barStyle = barTypeComponents[0] + '-' + barTypeComponents[1]
# repeat form is either start/end for normal repeats
# get extra repeat information; start, end, first, second
if len(barTypeComponents) > 2:
self.repeatForm = barTypeComponents[3]
src_strip: str = self.src.strip()
if src_strip not in ABC_BARS_DICT:
return

barTypeString = ABC_BARS_DICT[src_strip]
# this gets lists of elements like
# light-heavy-repeat-end
barTypeComponents = barTypeString.split('-')
# this is a list of attributes
if 'repeat' in barTypeComponents:
self.barType = 'repeat'
elif ('first' in barTypeComponents
or 'second' in barTypeComponents):
self.barType = 'barline'
# environLocal.printDebug(['got repeat 1/2:', self.src])
else:
self.barType = 'barline'

# case of regular, dotted
if len(barTypeComponents) == 1:
self.barStyle = barTypeComponents[0]

# case of light-heavy, light-light, etc
elif len(barTypeComponents) >= 2:
# must get out cases of the start-tags for repeat boundaries
# not yet handling
if 'first' in barTypeComponents:
self.barStyle = 'regular'
self.repeatForm = 'first' # not a repeat
elif 'second' in barTypeComponents:
self.barStyle = 'regular'
self.repeatForm = 'second' # not a repeat
else:
self.barStyle = barTypeComponents[0] + '-' + barTypeComponents[1]
# repeat form is either start/end for normal repeats
# get extra repeat information; start, end, first, second
if len(barTypeComponents) > 2:
self.repeatForm = barTypeComponents[3]

def isRepeat(self) -> bool:
if self.barType == 'repeat':
Expand Down Expand Up @@ -1733,7 +1748,13 @@ def parse(self, forceKeySignature=None, forceDefaultQuarterLength=None):
self.chordSymbols, nonChordSymStr = self._splitChordSymbols(self.src)

# position of the closing bracket
pos = nonChordSymStr.index(']')
try:
pos = nonChordSymStr.index(']')
except ValueError:
raise ABCHandlerException(
f'Bad chord indicator: {self.src}: no closing bracket found.'
)

# Length modifier string behind the chord brackets
outerLengthModifierStr = nonChordSymStr[pos + 1:]
# String in the chord brackets
Expand Down

0 comments on commit c9db6b7

Please sign in to comment.