From 14775dcbc21f22d7420edadbeac9a98503c73430 Mon Sep 17 00:00:00 2001 From: Malcolm Sailor Date: Thu, 22 Sep 2022 09:54:51 -0400 Subject: [PATCH 1/4] remove colons from repeat tests; handle empty measures --- music21/romanText/translate.py | 58 +++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/music21/romanText/translate.py b/music21/romanText/translate.py index 939767353d..0d95bef130 100644 --- a/music21/romanText/translate.py +++ b/music21/romanText/translate.py @@ -130,6 +130,7 @@ from music21 import bar from music21 import base from music21 import common +from music21 import duration from music21 import exceptions21 from music21 import harmony from music21 import key @@ -574,6 +575,10 @@ def translateMeasureLineToken(self, measureLineToken: rtObjects.RTMeasure): else: m = self.translateSingleMeasure(measureLineToken) + if m.barDuration.quarterLength == 0: + m.duration = duration.Duration( + self.tsCurrent.barDuration.quarterLength + ) p.coreAppend(m) def fillToMeasureToken(self, measureToken: rtObjects.RTMeasure): @@ -791,6 +796,10 @@ def translateSingleMeasureAtom(self, a, m, *, isLastAtomInMeasure=False): # Is it ok, however, that this condition will match if self.tsCurrent # is None? Previously, that case was excluded below. m.rightBarline = bar.Repeat(direction='end') + if self.tsCurrent is not None: + m.setElementOffset( + m.rightBarline, self.tsCurrent.barDuration.quarterLength + ) elif self.currentOffsetInMeasure == 0: if isinstance(a, rtObjects.RTRepeatStart): m.leftBarline = bar.Repeat(direction='start') @@ -1608,6 +1617,18 @@ def testTuplets(self): self.assertEqual(n2.offset, common.opFrac(11 / 6)) self.assertEqual(n2.duration.quarterLength, common.opFrac(13 / 6)) + def testCopyEmptyMeasures(self) -> None: + from music21 import converter + empty_measures_with_copy = textwrap.dedent('''' + Time Signature: 2/4 + m1 I + m2 V + m3 = m1 + m4-5 = m1-2 + ''') + s = converter.parse(empty_measures_with_copy, format='romanText') + assert s.duration.quarterLength == 10 + def testRepeats(self) -> None: from music21 import converter @@ -1636,8 +1657,8 @@ def _test_ending_contents( # Test simple repeats simple_repeats = textwrap.dedent(''' Time Signature: 3/4 - m1: ||: V - m2: I :|| + m1 ||: V + m2 I :|| ''') s = converter.parse(simple_repeats, format='romanText') br_iter = s[bar.Repeat] @@ -1649,7 +1670,7 @@ def _test_ending_contents( single_bar_repeats = textwrap.dedent(''' Time Signature: 2/4 - m1: ||: I :|| + m1 ||: I :|| ''') s = converter.parse(single_bar_repeats, format='romanText') br_iter = s[bar.Repeat] @@ -1661,10 +1682,10 @@ def _test_ending_contents( empty_bars_with_repeats = textwrap.dedent(''' Time Signature: 2/4 - m1: I - m2: ||: - m3: :|| - m4: ||: :|| + m1 I + m2 ||: + m3 :|| + m4 ||: :|| ''') s = converter.parse(empty_bars_with_repeats, format='romanText') br_iter = s[bar.Repeat] @@ -1674,14 +1695,15 @@ def _test_ending_contents( _repeat_tester(end_repeat1, 'end', 2.0, 3) _repeat_tester(start_repeat2, 'start', 0.0, 4) _repeat_tester(end_repeat2, 'end', 2.0, 4) + _test_expanded(s, 14.0) three_endings = textwrap.dedent(''' Time Signature: 3/4 - m1: ||: I - m2a: IV :|| - m2b: V :|| - m2c: I + m1 ||: I + m2a IV :|| + m2b V :|| + m2c I ''') s = converter.parse(three_endings, format='romanText') br_iter = s[bar.Repeat] @@ -1700,13 +1722,13 @@ def _test_ending_contents( more_complex_example = textwrap.dedent(''' TimeSignature: 3/4 - m1: ||: I - m2a: IV - m3a: V :|| - m2b: V :|| - m2c: IV - m3c: V - m4: I + m1 ||: I + m2a IV + m3a V :|| + m2b V :|| + m2c IV + m3c V + m4 I ''') s = converter.parse(more_complex_example, format='romanText') br_iter = s[bar.Repeat] From 865c35a5a172fc2738b67058c9739702de00385f Mon Sep 17 00:00:00 2001 From: Malcolm Sailor Date: Thu, 22 Sep 2022 10:03:58 -0400 Subject: [PATCH 2/4] handle tsCurrent is None --- music21/romanText/translate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/music21/romanText/translate.py b/music21/romanText/translate.py index 0d95bef130..c1296cb063 100644 --- a/music21/romanText/translate.py +++ b/music21/romanText/translate.py @@ -575,7 +575,7 @@ def translateMeasureLineToken(self, measureLineToken: rtObjects.RTMeasure): else: m = self.translateSingleMeasure(measureLineToken) - if m.barDuration.quarterLength == 0: + if self.tsCurrent is not None and m.barDuration.quarterLength == 0: m.duration = duration.Duration( self.tsCurrent.barDuration.quarterLength ) From 107ae977aa58860d19dccdb4ab52b2c2787c19c0 Mon Sep 17 00:00:00 2001 From: Malcolm Sailor Date: Thu, 22 Sep 2022 10:06:12 -0400 Subject: [PATCH 3/4] barDuration -> duration --- music21/romanText/translate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/music21/romanText/translate.py b/music21/romanText/translate.py index c1296cb063..9d02ba90c9 100644 --- a/music21/romanText/translate.py +++ b/music21/romanText/translate.py @@ -575,7 +575,7 @@ def translateMeasureLineToken(self, measureLineToken: rtObjects.RTMeasure): else: m = self.translateSingleMeasure(measureLineToken) - if self.tsCurrent is not None and m.barDuration.quarterLength == 0: + if self.tsCurrent is not None and m.duration.quarterLength == 0: m.duration = duration.Duration( self.tsCurrent.barDuration.quarterLength ) From 192ed81c3b3d185b323fd64f2fb08a3c7a5a0483 Mon Sep 17 00:00:00 2001 From: Malcolm Sailor Date: Thu, 22 Sep 2022 15:51:04 -0400 Subject: [PATCH 4/4] fillMeasureFromPreviousRn --- music21/romanText/translate.py | 44 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/music21/romanText/translate.py b/music21/romanText/translate.py index 9d02ba90c9..e9a55e65b9 100644 --- a/music21/romanText/translate.py +++ b/music21/romanText/translate.py @@ -130,7 +130,6 @@ from music21 import bar from music21 import base from music21 import common -from music21 import duration from music21 import exceptions21 from music21 import harmony from music21 import key @@ -575,10 +574,8 @@ def translateMeasureLineToken(self, measureLineToken: rtObjects.RTMeasure): else: m = self.translateSingleMeasure(measureLineToken) - if self.tsCurrent is not None and m.duration.quarterLength == 0: - m.duration = duration.Duration( - self.tsCurrent.barDuration.quarterLength - ) + if m.duration.quarterLength == 0: + self.fillMeasureFromPreviousRn(m) p.coreAppend(m) def fillToMeasureToken(self, measureToken: rtObjects.RTMeasure): @@ -590,19 +587,7 @@ def fillToMeasureToken(self, measureToken: rtObjects.RTMeasure): for i in range(self.lastMeasureNumber + 1, measureToken.number[0]): mFill = stream.Measure() mFill.number = i - if self.previousRn is not None: - newRn = copy.deepcopy(self.previousRn) - newRn.lyric = '' - # set to entire bar duration and tie - newRn.duration = copy.deepcopy(self.tsAtTimeOfLastChord.barDuration) - if self.previousRn.tie is None: - self.previousRn.tie = tie.Tie('start') - else: - self.previousRn.tie.type = 'continue' - # set to stop for now; may extend on next iteration - newRn.tie = tie.Tie('stop') - self.previousRn = newRn - mFill.append(newRn) + self.fillMeasureFromPreviousRn(mFill) appendMeasureToRepeatEndingsDict(self.lastMeasureToken, mFill, self.repeatEndings, i) @@ -610,6 +595,21 @@ def fillToMeasureToken(self, measureToken: rtObjects.RTMeasure): self.lastMeasureNumber = measureToken.number[0] - 1 self.lastMeasureToken = measureToken + def fillMeasureFromPreviousRn(self, mFill: stream.Measure) -> None: + if self.previousRn is not None: + newRn = copy.deepcopy(self.previousRn) + newRn.lyric = '' + # set to entire bar duration and tie + newRn.duration = copy.deepcopy(self.tsAtTimeOfLastChord.barDuration) + if self.previousRn.tie is None: + self.previousRn.tie = tie.Tie('start') + else: + self.previousRn.tie.type = 'continue' + # set to stop for now; may extend on next iteration + newRn.tie = tie.Tie('stop') + self.previousRn = newRn + mFill.append(newRn) + def parseKeySignatureTag(self, rtTagged: rtObjects.RTTagged): ''' Parse a key signature tag which has already been determined to @@ -1695,6 +1695,14 @@ def _test_ending_contents( _repeat_tester(end_repeat1, 'end', 2.0, 3) _repeat_tester(start_repeat2, 'start', 0.0, 4) _repeat_tester(end_repeat2, 'end', 2.0, 4) + for measure in s[stream.Measure]: + rn_iter = measure[roman.RomanNumeral] + self.assertEqual(len(rn_iter), 1) + # mypy complains about the next line because + # RecursiveIterator.first() has t.Optional type, but we know + # it will not be None because we have just asserted that rn_iter + # has length 1 + self.assertEqual(rn_iter.first().figure, 'I') # type: ignore _test_expanded(s, 14.0)