Writer for the ‘RomanText’ format (Tymoczko, Gotham, Cuthbert, & Ariza ISMIR 2019)


class music21.romanText.writeRoman.RnWriter(obj: Music21Object)

Extracts the relevant information from a source (usually a Stream of RomanNumeral objects) for writing to text files in the ‘RomanText’ format (rntxt).

Writing rntxt is handled externally in the WriteRoman() so most users will never need to call this class directly, only invoking it indirectly through .write(‘rntxt’). Possible exceptions include users who want to convert Roman numerals into rntxt type strings and want to work with those strings directly, without writing to disk.

For consistency with the show() and write() methods across music21, this class is theoretically callable on any type of music21 object. Most relevant use cases will involve calling a stream containing one or more Roman numerals. This class supports any such stream: an Opus object of one or more scores, a Score with or without Part (s), a Part, or a Measure.

>>> scoreBach = corpus.parse('bach/choraleAnalyses/riemenschneider004.rntxt')
>>> rnWriterFromScore = romanText.writeRoman.RnWriter(scoreBach)

The strings are stored in the RnWriter’s combinedList variable, starting with the metadata:

>>> rnWriterFromScore.combinedList[0]
'Composer: J. S. Bach'

Composer and work metadata is inherited from score metadata wherever possible. A composer entry will register directly as will any entries for workTitle, movementNumber, and movementName (see prepTitle() for details).

>>> rnWriterFromScore.combinedList[0] == 'Composer: ' + rnWriterFromScore.composer

As always, these metadata entries are user-settable. Make any adjustments to the metadata before calling this class.

After the metadata, the list continues with strings for each measure in order. Here’s the last in our example:

>>> rnWriterFromScore.combinedList[-1]
'm10 V6/V b2 V b3 I'

In the case of the score, the top part is assumed to contain the Roman numerals. This is consistent with the parsing of rntxt which involves putting Roman numerals in a part (the top, and only part) within a score.

In all other cases, the objects are iteratively inserted into larger streams until we end up with a part object (e.g. measure > part).

>>> rn = roman.RomanNumeral('viio64', 'a')
>>> rnWriterFromRn = romanText.writeRoman.RnWriter(rn)
>>> rnWriterFromRn.combinedList[0]
'Composer: Composer unknown'
>>> rnWriterFromRn.combinedList[-1]
'm0 a: viio64'

RnWriter bases

RnWriter read-only properties

Read-only properties inherited from ProtoM21Object:

RnWriter methods

RnWriter.getChordString(rn: RomanNumeral)

Produce a string from a Roman numeral with the chord and the key if that key constitutes a change from the foregoing context.

>>> p = stream.Part()
>>> m = stream.Measure()
>>> m.insert(0, meter.TimeSignature('4/4'))
>>> m.insert(0, roman.RomanNumeral('V', 'G'))
>>> p.insert(0, m)
>>> testCase = romanText.writeRoman.RnWriter(p)
>>> sameKeyChord = testCase.getChordString(roman.RomanNumeral('I', 'G'))
>>> sameKeyChord
>>> changeKeyChord = testCase.getChordString(roman.RomanNumeral('V', 'D'))
>>> changeKeyChord
'D: V'

Prepares a sequential list of text lines, with time signatures and Roman numerals adding this to the (already prepared) metadata preamble ready for printing.

>>> p = stream.Part()
>>> m = stream.Measure(number=1)
>>> m.insert(0, meter.TimeSignature('4/4'))
>>> m.insert(0, roman.RomanNumeral('V', 'G'))
>>> p.insert(0, m)
>>> testCase = romanText.writeRoman.RnWriter(p)
>>> testCase.combinedList[-1]  # Last entry, after the metadata
'm1 G: V'

This follows the wider rntxt syntax in supporting Time Signature (TimeSignature) changes and Repeats marks (Repeat) but only (currently) between measures.

Let’s add a new measure to the stream we started, with a time signature change beforehand and both start and end repeats in it:

>>> m2 = stream.Measure(number=2)
>>> m2.insert(0, meter.TimeSignature('3/4'))
>>> m2.leftBarline = bar.Repeat(direction='start')
>>> m2.rightBarline = bar.Repeat(direction='end')
>>> m2.insert(0, roman.RomanNumeral('I', 'G'))
>>> p.insert(0, m2)
>>> testCase = romanText.writeRoman.RnWriter(p)

The last line of the .combinedList gives the new measure:

>>> testCase.combinedList[-1]
'm2 ||: I :||'

The line before that gives the time signature change:

>>> testCase.combinedList[-2]
'Time Signature: 3/4'
RnWriter.prepTitle(md: Metadata)

Attempt to prepare a single work title from the score metadata looking at each of the title, movementNumber and movementName attributes. Failing that, a placeholder ‘Title unknown’ stands in.

>>> s = stream.Score()
>>> rnScore = romanText.writeRoman.RnWriter(s)
>>> rnScore.title
'Title unknown'
>>> s.insert(0, metadata.Metadata())
>>> s.metadata.title = 'Fake title'
>>> s.metadata.movementNumber = 123456789
>>> s.metadata.movementName = 'Fake movementName'
>>> rnScoreWithMD = romanText.writeRoman.RnWriter(s)
>>> rnScoreWithMD.title
'Fake title - No.123456789: Fake movementName'

Methods inherited from ProtoM21Object:


music21.romanText.writeRoman.intBeat(beat: str | int | float | Fraction, roundValue: int = 2)

Converts beats to integers if possible, and otherwise to rounded decimals. Accepts input as string, int, float, or fractions.Fraction.

>>> testInt = romanText.writeRoman.intBeat(1, roundValue=2)
>>> testInt
>>> testFrac = romanText.writeRoman.intBeat(8 / 3, roundValue=2)
>>> testFrac
>>> testStr = romanText.writeRoman.intBeat('0.666666666', roundValue=2)
>>> testStr

The roundValue sets the number of decimal places to round to. The default is two:

>>> testRound2 = romanText.writeRoman.intBeat(1.11111111, roundValue=2)
>>> testRound2

But this can be set to any integer:

>>> testRound1 = romanText.writeRoman.intBeat(1.11111111, roundValue=1)
>>> testRound1

Raises an error if called on a negative value.

music21.romanText.writeRoman.rnString(measureNumber: int | str, beat: str | int | float | Fraction, chordString: str, inString: str | None = '')

Creates or extends a string of RomanText such that the output corresponds to a single measure line.

If the inString is not given, None, or an empty string then this function starts a new line.

>>> lineStarter = romanText.writeRoman.rnString(14, 1, 'G: I')
>>> lineStarter
'm14 G: I'

For any other inString, that string is the start of a measure line continued by the new values

>>> continuation = romanText.writeRoman.rnString(14, 2, 'viio6', 'm14 G: I')
>>> continuation
'm14 G: I b2 viio6'

Naturally, this function requires the measure number of any such continuation to match that of the inString and raises an error where that is not the case.

As these examples show, the chordString can be a Roman numeral alone (e.g. ‘viio6’) or one prefixed by a change of key (‘G: I’).