Skip to content
Merged
Changes from all commits
Commits
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
57 changes: 55 additions & 2 deletions music21/scale/scala/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,12 @@ def parse(self) -> None:
self.description = line
elif count == 2:
if line != '':
self.pitchCount = int(line)
# only the first token is data; the format ignores any
# trailing characters, so a comment can follow the value
self.pitchCount = int(line.split()[0])
else: # remaining counts are pitches
if line != '':
sp = ScalaPitch(line)
sp = ScalaPitch(line.split()[0])
sp.parse()
self.pitchValues.append(sp)

Expand Down Expand Up @@ -744,6 +746,57 @@ def testScalaFileA(self) -> None:
'<music21.interval.Interval m2 (+50c)>',
'<music21.interval.Interval m3>'])

def testCommentAfterAPitchValue(self) -> None:
# noinspection SpellCheckingInspection
msg = r'''! commented.scl
!
A scale whose values carry trailing comments
3
!
10/9 ! A\ ; 8 |mi|la|re|
454.75 (427)
2/1 ! octave
'''
ss = ScalaData(msg)
ss.parse()
self.assertEqual(ss.pitchCount, 3)
self.assertEqual(len(ss.pitchValues), 3)
self.assertEqual([f'{x.cents:.5f}' for x in ss.pitchValues],
['182.40371', '454.75000', '1200.00000'])

# two bundled files the old parser read without raising, and got
# wrong: the comment's digits were appended to the value
newton = parse('newton_15_out_of_53')
assert newton is not None
self.assertEqual(newton.pitchValues[0].src, '10/9')
self.assertEqual(f'{newton.pitchValues[0].cents:.5f}', '182.40371')

loops = parse('sparschuh-jsbloops440')
assert loops is not None
self.assertEqual(loops.pitchValues[8].src, '1760/1055')
self.assertEqual(f'{loops.pitchValues[8].cents:.5f}', '885.99892')

def testEveryBundledScalaFileParses(self) -> None:
# a guard on the archive itself: a file added or edited upstream that
# this parser cannot read should fail here rather than at the point
# some scale is asked for. The description line is not checked, as the
# format allows it to be empty.
paths = getPaths()
self.assertGreater(len(paths), 3000)
for fp in paths:
sf = ScalaFile()
sf.open(fp)
try:
ss = sf.read()
finally:
sf.close()
self.assertIsNotNone(ss.pitchCount, fp)
self.assertEqual(len(ss.pitchValues), ss.pitchCount, fp)
for sp in ss.pitchValues:
self.assertIsNotNone(sp.cents, f'{fp}: {sp.src!r}')
self.assertTrue(math.isfinite(t.cast(float, sp.cents)),
f'{fp}: {sp.src!r}')


# ------------------------------------------------------------------------------
# define presented order in documentation
Expand Down
Loading