Converter for parsing the tabular representations of harmonic analysis such as the DCMLab’s Annotated Beethoven Corpus (Neuwirth et al. 2018).


class music21.romanText.tsvConverter.M21toTSV(m21Stream: Score, dcml_version: int = 2)

Conversion starting with a music21 stream. Exports to tabular data format and (optionally) writes the file.

>>> bachHarmony = corpus.parse('bach/choraleAnalyses/riemenschneider001.rntxt')

The initialization includes the preparation of a list of lists, so

>>> initial = romanText.tsvConverter.M21toTSV(bachHarmony, dcml_version=2)
>>> tsvData = initial.tsvData
>>> from music21.romanText.tsvConverter import DCML_V2_HEADERS
>>> tsvData[1][DCML_V2_HEADERS.index('chord')]

M21toTSV methods

M21toTSV.m21ToTsv() list[list[str]]

Converts a list of music21 chords to a list of lists which can then be written to a tsv file with toTsv(), or processed another way.

M21toTSV.write(filePathAndName: str)

Writes a list of lists (e.g. from m21ToTsv()) to a tsv file.


class music21.romanText.tsvConverter.TabChord

An intermediate representation format for moving between tabular data in DCML v1 and music21 chords.

TabChord bases

TabChord read/write properties

Read/write properties inherited from TabChordBase:

TabChord methods

Methods inherited from TabChordBase:


class music21.romanText.tsvConverter.TabChordBase

Abstract base class for intermediate representation format for moving between tabular data and music21 chords.

TabChordBase read/write properties


For easier interoperability with the DCML standards, we now use the column name ‘chord’ from the DCML file. But to preserve backwards- compatibility, we add this property, which is an alias for ‘chord’.

>>> tabCd = romanText.tsvConverter.TabChord()
>>> tabCd.chord = 'viio7'
>>> tabCd.combinedChord
>>> tabCd.combinedChord = 'IV+'
>>> tabCd.chord

TabChordBase methods

TabChordBase.populateFromRow(row: list[str], headIndices: dict[str, tuple[int, type]], extraIndices: dict[int, str]) None
TabChordBase.tabToM21() Harmony

Creates and returns a music21.roman.RomanNumeral() object from a TabChord with all shared attributes. NB: call changeRepresentation() first if .representationType is not ‘m21’ but you plan to process it with m21 (e.g. moving it into a stream).

>>> tabCd = romanText.tsvConverter.TabChord()
>>> tabCd.numeral = 'vii'
>>> tabCd.global_key = 'F'
>>> tabCd.local_key = 'V'
>>> tabCd.representationType = 'm21'
>>> m21Ch = tabCd.tabToM21()

Now we can check it’s a music21 RomanNumeral():

>>> m21Ch.figure


class music21.romanText.tsvConverter.TabChordV2

An intermediate representation format for moving between tabular data in DCML v2 and music21 chords.

TabChordV2 bases

TabChordV2 read/write properties

TabChordV2.beat: float

‘beat’ has been removed from DCML v2 in favor of ‘mn_onset’ and ‘mc_onset’. ‘mn_onset’ is equivalent to ‘beat’, except that ‘mn_onset’ is zero-indexed where ‘beat’ was 1-indexed, and ‘mn_onset’ is in fractions of a whole-note rather than in quarter notes.

>>> tabCd = romanText.tsvConverter.TabChordV2()
>>> tabCd.mn_onset = 0.0
>>> tabCd.beat
>>> tabCd.mn_onset = 0.5
>>> tabCd.beat
>>> tabCd.beat = 1.5
>>> tabCd.beat
TabChordV2.global_key: str

‘global_key’ has been renamed ‘globalkey’ in DCML v2. This property is provided as an alias for ‘globalkey’ so that TabChord and TabChordV2 can be used in the same way.

TabChordV2.local_key: str

‘local_key’ has been renamed ‘localkey’ in DCML v2. This property is provided as an alias for ‘localkey’ so that TabChord and TabChordV2 can be used in the same way.

TabChordV2.measure: int

‘measure’ has been removed from DCML v2 in favor of ‘mn’ and ‘mc’. ‘mn’ is equivalent to ‘measure’, so this property is provided as an alias.

Read/write properties inherited from TabChordBase:

TabChordV2 methods

Methods inherited from TabChordBase:


class music21.romanText.tsvConverter.TsvHandler(tsvFile: str, dcml_version: int = 1)

Conversion starting with a TSV file.

First we need to get a score. (Don’t worry about this bit.)

>>> name = 'tsvEg_v1.tsv'
>>> path = common.getSourceFilePath() / 'romanText' / name
>>> handler = romanText.tsvConverter.TsvHandler(path)
>>> handler.tsvToChords()

These should be TabChords now.

>>> testTabChord1 = handler.chordList[0]
>>> testTabChord1.combinedChord

Good. We can make them into music21 Roman-numerals.

>>> m21Chord1 = testTabChord1.tabToM21()
>>> m21Chord1.figure

And for our last trick, we can put the whole collection in a music21 stream.

>>> out_stream = handler.toM21Stream()

TsvHandler methods

TsvHandler.prepStream() Score

Prepares a music21 stream for the harmonic analysis to go into. Specifically: creates the score, part, and measure streams, as well as some (the available) metadata based on the original TSV data. Works like the .template() method, except that we don’t have a score to base the template on as such.

TsvHandler.toM21Stream() Score

Takes a list of TabChords (self.chordList, prepared by .tsvToChords()), converts those TabChords in RomanNumerals (converting to the music21 representation format as necessary), creates a suitable music21 stream (by running .prepStream() using data from the TabChords), and populates that stream with the new RomanNumerals.

TsvHandler.tsvToChords() None

Converts a list of lists (of the type imported by importTsv) into TabChords (i.e. a list of TabChords).


music21.romanText.tsvConverter.characterSwaps(preString: str, minor: bool = True, direction: str = 'm21-DCML') str

Character swap function to coordinate between the two notational versions, for instance swapping between ‘%’ and ‘/o’ for the notation of half diminished (for example).

>>> testStr = 'ii%'
>>> romanText.tsvConverter.characterSwaps(testStr, minor=False, direction='DCML-m21')
music21.romanText.tsvConverter.getForm(rn: RomanNumeral) str

Takes a music21.roman.RomanNumeral object and returns the string indicating ‘form’ expected by the DCML standard.

>>> romanText.tsvConverter.getForm(roman.RomanNumeral('V'))
>>> romanText.tsvConverter.getForm(roman.RomanNumeral('viio7'))
>>> romanText.tsvConverter.getForm(roman.RomanNumeral('IVM7'))
>>> romanText.tsvConverter.getForm(roman.RomanNumeral('III+'))
>>> romanText.tsvConverter.getForm(roman.RomanNumeral('IV+M7'))
>>> romanText.tsvConverter.getForm(roman.RomanNumeral('viiø7'))
music21.romanText.tsvConverter.getLocalKey(local_key: str, global_key: str, convertDCMLToM21: bool = False) str

Re-casts comparative local key (e.g. ‘V of G major’) in its own terms (‘D’).

>>> romanText.tsvConverter.getLocalKey('V', 'G')
>>> romanText.tsvConverter.getLocalKey('ii', 'C')
>>> romanText.tsvConverter.getLocalKey('i', 'C')

By default, assumes an m21 input, and operates as such:

>>> romanText.tsvConverter.getLocalKey('#vii', 'a')

Set convert=True to convert from DCML to m21 formats. Hence;

>>> romanText.tsvConverter.getLocalKey('vii', 'a', convertDCMLToM21=True)
music21.romanText.tsvConverter.getSecondaryKey(rn: str, local_key: str) str

Separates comparative Roman-numeral for tonicizations like ‘V/vi’ into the component parts of a Roman-numeral (V) and a (very) local key (vi) and expresses that very local key in relation to the local key also called (DCML column 11).

While .getLocalKey() work on the figure and key pair:

>>> romanText.tsvConverter.getLocalKey('vi', 'C')

With .getSecondaryKey(), we’re interested in the relative root of a secondaryRomanNumeral:

>>> romanText.tsvConverter.getSecondaryKey('V/vi', 'C')
music21.romanText.tsvConverter.handleAddedTones(dcmlChord: str) str

Converts DCML added-tone syntax to music21.

>>> romanText.tsvConverter.handleAddedTones('V(64)')
>>> romanText.tsvConverter.handleAddedTones('i(4+2)')
>>> romanText.tsvConverter.handleAddedTones('Viio7(b4-5)/V')

When in root position, 7 does not replace 8: >>> romanText.tsvConverter.handleAddedTones(‘vi(#74)’) ‘vi[no3][add#7][add4]’

When not in root position, 7 does replace 8: >>> romanText.tsvConverter.handleAddedTones(‘ii6(11#7b6)’) ‘ii6[no8][no5][add11][add#7][addb6]’

‘0’ can be used to indicate root-replacement by 7 in a root-position chord. We need to change ‘0’ to ‘7’ because music21 changes the 0 to ‘o’ (i.e., a diminished chord). >>> romanText.tsvConverter.handleAddedTones(‘i(#0)’) ‘i[no1][add#7]’

music21.romanText.tsvConverter.isMinor(test_key: str) bool

Checks whether a key is minor or not simply by upper vs lower case.

>>> romanText.tsvConverter.isMinor('F')
>>> romanText.tsvConverter.isMinor('f')
music21.romanText.tsvConverter.localKeyAsRn(local_key: Key, global_key: Key) str

Takes two music21.key.Key objects and returns the roman numeral for local_key relative to global_key.

>>> k1 = key.Key('C')
>>> k2 = key.Key('e')
>>> romanText.tsvConverter.localKeyAsRn(k1, k2)
>>> k3 = key.Key('C#')
>>> romanText.tsvConverter.localKeyAsRn(k3, k2)
>>> romanText.tsvConverter.localKeyAsRn(k2, k1)