music21.musicxml.xmlSoundParser

Functions that convert the <sound> tag to the many music21 objects that this tag might represent.

Pulled out because xmlToM21 got way too big. These are plain functions (not methods/a mixin) that take the owning MeasureParser as their first argument (like in makeNotation).

Functions

music21.musicxml.xmlSoundParser.setSound(mp: MeasureParser, mxSound: ET.Element, *, mxDir: ET.Element | None, totalOffset: float) None[source]

Takes a <sound> tag and creates objects from it on the MeasureParser mp. Presently only handles <sound tempo=’x’> events and inserts them as MetronomeMarks.

If the <sound> tag is a child of a <direction> tag, the direction information is used to set the placement of the MetronomeMark. (xmlToM21 calls this routine directly in that circumstance.)

Setup:

>>> from music21.musicxml.xmlSoundParser import setSound
>>> from xml.etree.ElementTree import fromstring as EL
>>> mp = musicxml.xmlToM21.MeasureParser()

A <sound> with a tempo attribute inserts a MetronomeMark:

>>> setSound(mp, EL('<sound tempo="144"/>'), mxDir=None, totalOffset=2.0)
>>> mp.stream.coreElementsChanged()
>>> mp.stream.getElementsByClass(tempo.MetronomeMark).first()
<music21.tempo.MetronomeMark Quarter=144 (playback only)>

A <sound> without a tempo attribute is (currently) a no-op, so no second mark is added. This should change soon.

>>> setSound(mp, EL('<sound dynamics="70"/>'), mxDir=None, totalOffset=0.0)
>>> mp.stream.coreElementsChanged()
>>> len(mp.stream[tempo.MetronomeMark])
1
music21.musicxml.xmlSoundParser.setSoundTempo(mp: MeasureParser, mxSound: ET.Element, *, mxDir: ET.Element | None, staffKey: int, totalOffset: float) None[source]

Add a metronome mark from the tempo attribute of a <sound> tag to the MeasureParser mp.

>>> from music21.musicxml.xmlSoundParser import setSoundTempo
>>> from xml.etree.ElementTree import fromstring as EL
>>> mp = musicxml.xmlToM21.MeasureParser()
>>> setSoundTempo(mp, EL('<sound tempo="92"/>'), mxDir=None, staffKey=1, totalOffset=0.0)
>>> mp.stream.coreElementsChanged()
>>> mm = mp.stream[tempo.MetronomeMark].first()
>>> mm
<music21.tempo.MetronomeMark Quarter=92 (playback only)>
>>> mm.numberSounding
92
>>> mm.number is None
True
music21.musicxml.xmlSoundParser.xmlSound(mp: MeasureParser, mxSound: ET.Element) None[source]

Convert a <sound> tag to one or more relevant objects (presently just MetronomeMark), and add it or them to the core and staffReference of the MeasureParser mp.

Reads offset is from mp via .offsetMeasureNote so the mark lands at the current position in the measure.

Set up everything:

>>> from music21.musicxml.xmlSoundParser import xmlSound
>>> from xml.etree.ElementTree import fromstring as EL
>>> mp = musicxml.xmlToM21.MeasureParser()
>>> mp.offsetMeasureNote = 2.0
>>> len(mp.stream[tempo.MetronomeMark])
0

Now call the routine.

>>> xmlSound(mp, EL('<sound tempo="128"/>'))

Nothing is returned, but the stream inside the MeasureParser now has a metronomeMark at the .offsetMeasureNote of mp. Because all the routines in this module are optimized for speed, we first need to call coreElementsChanged before querying the stream for each of them (normally the MeasureParser does this for us after parsing the entire measure).

>>> mp.stream.coreElementsChanged()
>>> mm = mp.stream[tempo.MetronomeMark].first()
>>> mm
<music21.tempo.MetronomeMark Quarter=128 (playback only)>
>>> mm.offset
2.0

A <sound> tag may also carry its own <offset> child, which is measured in MusicXML divisions and shifts the mark relative to the current position. mp.divisions is the number of divisions per quarter note, so with 8 divisions per quarter an <offset> of 4 is half a quarter note – an eighth note – and the mark lands an eighth later than .offsetMeasureNote:

>>> mp = musicxml.xmlToM21.MeasureParser()
>>> mp.divisions = 8
>>> mp.offsetMeasureNote = 2.0
>>> xmlSound(mp, EL('<sound tempo="108"><offset>4</offset></sound>'))
>>> mp.stream.coreElementsChanged()
>>> mp.stream[tempo.MetronomeMark].first().offset
2.5