music21.romanText.translate

Translation routines for roman numeral analysis text files, as defined and demonstrated by Dmitri Tymoczko. Also used for the ClercqTemperley format which is similar but a little different.

This module is really only needed for people extending the parser, for others it’s simple to get Harmony, RomanNumeral, Key (or KeySignature) and other objects out of an rntxt file by running this:

>>> monteverdi = corpus.parse('monteverdi/madrigal.3.1.rntxt')
>>> monteverdi.show('text')
{0.0} <music21.metadata.Metadata object at 0x...>
{0.0} <music21.stream.Part ...>
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.key.KeySignature of 1 flat>
        {0.0} <music21.meter.TimeSignature 4/4>
        {0.0} <music21.roman.RomanNumeral vi in F major>
        {3.0} <music21.roman.RomanNumeral V[no3] in F major>
    {4.0} <music21.stream.Measure 2 offset=4.0>
        {0.0} <music21.roman.RomanNumeral I in F major>
        {3.0} <music21.roman.RomanNumeral IV in F major>
    ...

Then the stream can be analyzed with something like this, storing the data to make a histogram of scale degree usage within a key:

>>> degreeDictionary = {}
>>> for el in monteverdi.recurse():
...    if isinstance(el, roman.RomanNumeral):
...         print(f'{el.figure} {el.key}')
...         for p in el.pitches:
...              degree, accidental = el.key.getScaleDegreeAndAccidentalFromPitch(p)
...              if accidental is None:
...                   degreeString = str(degree)
...              else:
...                   degreeString = str(degree) + str(accidental.modifier)
...              if degreeString not in degreeDictionary:
...                   degreeDictionary[degreeString] = 1
...              else:
...                   degreeDictionary[degreeString] += 1
...              degTuple = (str(p), degreeString)
...              print(degTuple)
    vi F major
    ('D5', '6')
    ('F5', '1')
    ('A5', '3')
    V[no3] F major
    ('C5', '5')
    ('G5', '2')
    I F major
    ('F4', '1')
    ('A4', '3')
    ('C5', '5')
    ...
    V6 g minor
    ('F#5', '7#')
    ('A5', '2')
    ('D6', '5')
    i g minor
    ('G4', '1')
    ('B-4', '3')
    ('D5', '5')
    ...

Now if we’d like we can get a Histogram of the data. It’s a little complex, but worth seeing in full:

>>> import operator
>>> histogram = graph.primitives.GraphHistogram()
>>> i = 0
>>> data = []
>>> xLabels = []
>>> values = []
>>> ddList = list(degreeDictionary.items())
>>> for deg,value in sorted(ddList, key=operator.itemgetter(1), reverse=True):
...    data.append((i, degreeDictionary[deg]), )
...    xLabels.append((i+.5, deg), )
...    values.append(degreeDictionary[deg])
...    i += 1
>>> histogram.data = data

These commands give nice labels for the data; optional:

>>> histogram.setIntegerTicksFromData(values, 'y')
>>> histogram.setTicks('x', xLabels)
>>> histogram.setAxisLabel('x', 'ScaleDegree')

Now generate the histogram:

../_images/romanTranslatePitchDistribution.png

PartTranslator

class music21.romanText.translate.PartTranslator(md=None)

A refactoring of the previously massive romanTextToStreamScore function to allow for more fine-grained testing (eventually), and to get past the absurdly high number of nested blocks (the previous translator was written under severe time constraints).

PartTranslator methods

PartTranslator.fillMeasureFromPreviousRn(mFill: Measure) None
PartTranslator.fillToMeasureToken(measureToken: RTMeasure)

Create a series of measures which extend the previous RN until the measure number implied by measureToken.

PartTranslator.parseKeySignatureTag(rtTagged: RTTagged)

Parse a key signature tag which has already been determined to be a key signature.

>>> tag = romanText.rtObjects.RTTagged('KeySignature: -4')
>>> tag.isKeySignature()
True
>>> tag.data
'-4'
>>> pt = romanText.translate.PartTranslator()
>>> pt.keySigCurrent is None
True
>>> pt.setKeySigFromFirstKeyToken
True
>>> pt.foundAKeySignatureSoFar
False
>>> pt.parseKeySignatureTag(tag)
>>> pt.keySigCurrent
<music21.key.KeySignature of 4 flats>
>>> pt.setKeySigFromFirstKeyToken
False
>>> pt.foundAKeySignatureSoFar
True
>>> tag = romanText.rtObjects.RTTagged('KeySignature: xyz')
>>> pt.parseKeySignatureTag(tag)
Traceback (most recent call last):
music21.romanText.translate.RomanTextTranslateException:
    Cannot parse key signature: 'xyz'
PartTranslator.processRTChord(a, m, currentOffset)

Process a single RTChord atom.

PartTranslator.setAnalyticKey(a)

Indicates a change in the analyzed key, not a change in anything else, such as the keySignature.

PartTranslator.setMinorRootParse(rtTagged: RTTagged)

Set Roman Numeral parsing standards from a token.

>>> pt = romanText.translate.PartTranslator()
>>> pt.sixthMinor
<Minor67Default.CAUTIONARY: 2>
>>> tag = romanText.rtObjects.RTTagged('SixthMinor: Flat')
>>> tag.isSixthMinor()
True
>>> pt.setMinorRootParse(tag)
>>> pt.sixthMinor
<Minor67Default.FLAT: 4>

Harmonic sets to FLAT for sixth and SHARP for seventh

>>> for config in 'flat sharp quality cautionary harmonic'.split():
...     tag = romanText.rtObjects.RTTagged('Seventh Minor: ' + config)
...     pt.setMinorRootParse(tag)
...     print(pt.seventhMinor)
Minor67Default.FLAT
Minor67Default.SHARP
Minor67Default.QUALITY
Minor67Default.CAUTIONARY
Minor67Default.SHARP
>>> tag = romanText.rtObjects.RTTagged('Sixth Minor: harmonic')
>>> pt.setMinorRootParse(tag)
>>> print(pt.sixthMinor)
Minor67Default.FLAT

Unknown settings raise a RomanTextTranslateException

>>> tag = romanText.rtObjects.RTTagged('Seventh Minor: asdf')
>>> pt.setMinorRootParse(tag)
Traceback (most recent call last):
music21.romanText.translate.RomanTextTranslateException:
    Cannot parse setting vi or vii parsing: 'asdf'
PartTranslator.translateMeasureLineToken(measureLineToken: RTMeasure)

Translate a measure token consisting of a single line such as:

m21 b3 V b4 C: IV

Or it might be a variant measure, or a copy instruction.

PartTranslator.translateOneLineToken(lineToken: RTTagged)

Translates one line token and set the current settings.

A token in this case consists of an entire line’s worth. It might be a token such as ‘Title: Neko Funjatta’ or a composite token such as ‘m23 b4 IV6’

PartTranslator.translateSingleMeasure(measureToken)

Given a measureToken, return a stream.Measure object with the appropriate atoms set.

PartTranslator.translateSingleMeasureAtom(a, m, *, isLastAtomInMeasure=False)

Translate a single atom in a measure token.

a is the Atom m is a stream.Measure object.

Uses coreInsert and coreAppend methods, so must have m.coreElementsChanged() called afterwards.

PartTranslator.translateTokens(tokens)

RomanTextUnprocessedMetadata

class music21.romanText.translate.RomanTextUnprocessedMetadata(tag='', data='', **keywords)

RomanTextUnprocessedMetadata bases

RomanTextUnprocessedMetadata read-only properties

Read-only properties inherited from Music21Object:

Read-only properties inherited from ProtoM21Object:

RomanTextUnprocessedMetadata read/write properties

Read/write properties inherited from Music21Object:

RomanTextUnprocessedMetadata methods

Methods inherited from Music21Object:

Methods inherited from ProtoM21Object:

RomanTextUnprocessedMetadata instance variables

Instance variables inherited from Music21Object:

RomanTextUnprocessedToken

class music21.romanText.translate.RomanTextUnprocessedToken(obj: Any = None, **keywords)

RomanTextUnprocessedToken bases

RomanTextUnprocessedToken read-only properties

Read-only properties inherited from Music21Object:

Read-only properties inherited from ProtoM21Object:

RomanTextUnprocessedToken read/write properties

Read/write properties inherited from Music21Object:

RomanTextUnprocessedToken methods

Methods inherited from Music21Object:

Methods inherited from ProtoM21Object:

RomanTextUnprocessedToken instance variables

Instance variables inherited from ElementWrapper:

Instance variables inherited from Music21Object:

Functions

music21.romanText.translate.appendMeasureToRepeatEndingsDict(rtMeasureObj: RTMeasure, m: Measure, repeatEndings: dict, measureNumber=None)

Takes an RTMeasure object (which might represent one or more measures; but currently only one) and a music21 stream.Measure object and store it as a tuple in the repeatEndings dictionary to mark where the translator should later mark for adding endings.

If the optional measureNumber is specified, we use that rather than the token number to add to the dict.

This does not yet work for skipped measures.

>>> rtm = romanText.rtObjects.RTMeasure('m15a V6 b1.5 V6/5 b2 I b3 viio6')
>>> rtm.repeatLetter
['a']
>>> rtm2 = romanText.rtObjects.RTMeasure('m15b V6 b1.5 V6/5 b2 I')
>>> rtm2.repeatLetter
['b']
>>> repeatEndings = {}
>>> m1 = stream.Measure()
>>> m2 = stream.Measure()
>>> romanText.translate.appendMeasureToRepeatEndingsDict(rtm, m1, repeatEndings)
>>> repeatEndings
{1: [(15, <music21.stream.Measure 0a offset=0.0>)]}
>>> romanText.translate.appendMeasureToRepeatEndingsDict(rtm2, m2, repeatEndings)
>>> repeatEndings[1], repeatEndings[2]
([(15, <music21.stream.Measure 0a offset=0.0>)],
 [(15, <music21.stream.Measure 0b offset=0.0>)])
>>> repeatEndings[2][0][1] is m2
True
music21.romanText.translate.fixPickupMeasure(partObject)

Fix a pickup measure if any.

We determine a pickup measure by being measure 0 and not having an RN object at the beginning. Will also pad the last measure right and cut the duration of the final chord to match.

Demonstration: an otherwise incorrect part

>>> p = stream.Part()
>>> m0 = stream.Measure()
>>> m0.number = 0
>>> k0 = key.Key('G')
>>> m0.insert(0, k0)
>>> m0.insert(0, meter.TimeSignature('4/4'))
>>> m0.insert(3, roman.RomanNumeral('I', k0, quarterLength=1.0))
>>> m1 = stream.Measure()
>>> m1.number = 1
>>> m1.append(roman.RomanNumeral('V', k0, quarterLength=4.0))
>>> m2 = stream.Measure()
>>> m2.number = 2
>>> m2.append(roman.RomanNumeral('I', k0, quarterLength=4.0))
>>> p.insert(0, m0)
>>> p.insert(4, m1)
>>> p.insert(8, m2)

After running fixPickupMeasure()

>>> romanText.translate.fixPickupMeasure(p)
>>> p.show('text')
{0.0} <music21.stream.Measure 0 offset=0.0>
    {0.0} <music21.key.Key of G major>
    {0.0} <music21.meter.TimeSignature 4/4>
    {0.0} <music21.roman.RomanNumeral I in G major>
{1.0} <music21.stream.Measure 1 offset=1.0>
    {0.0} <music21.roman.RomanNumeral V in G major>
{5.0} <music21.stream.Measure 2 offset=5.0>
    {0.0} <music21.roman.RomanNumeral I in G major>
>>> m0.paddingLeft
3.0
>>> m2.paddingRight
1.0
>>> m2[roman.RomanNumeral].last().duration
<music21.duration.Duration 3.0>
music21.romanText.translate.romanTextToStreamOpus(rtHandler, inputM21=None)

The main processing routine for RomanText objects that may or may not be multi movement.

Takes in a romanText.rtObjects.RTFile() object, or a string as rtHandler.

Runs romanTextToStreamScore() as its main work.

If inputM21 is None then it will create a Score or Opus object.

Return either a Score object, or, if a multi-movement work is defined, an Opus object.

music21.romanText.translate.romanTextToStreamScore(rtHandler, inputM21=None)

The main processing module for single-movement RomanText works.

Given a romanText handler or string, return or fill a Score Stream.