예제 #1
0
class Foo(XMLElement):
    _DTD = Sequence(
        Choice(Sequence(GroupReference(TestGroup), Element(Duration)),
               Sequence(GroupReference(TestGroup), )))

    def __init__(self, *args, **kwargs):
        super().__init__(tag='foo', *args, **kwargs)
예제 #2
0
class ComplexTypeBarline(ComplexType, BarlineAttributes):
    """
    If a barline is other than a normal single barline, it should be represented by a barline type that describes it.
    This includes information about repeats and multiple endings, as well as line style. Barline data is on the same
    level as the other musical data in a score - a child of a measure in a partwise score, or a part in a timewise
    score. This allows for barlines within measures, as in dotted barlines that subdivide measures in complex meters.
    The two fermata elements allow for fermatas on both sides of the barline (the lower one inverted).

    Barlines have a location attribute to make it easier to process barlines independently of the other musical data in
    a score. It is often easier to set up measures separately from entering notes. The location attribute must match
    where the barline element occurs within the rest of the musical data in the score. If location is left, it should be
    the first element in the measure, aside from the print, bookmark, and link elements. If location is right, it should
    be the last element, again with the possible exception of the print, bookmark, and link elements. If no location is
    specified, the right barline is the default. The segno, coda, and divisions attributes work the same way as in the
    sound element. They are used for playback when barline elements contain segno or coda child elements.
    """
    _DTD = Sequence(
        Element(BarStyle, min_occurrence=0),
        GroupReference(Editorial),
        Element(WavyLine, min_occurrence=0),
        Element(Segno, min_occurrence=0),
        Element(Coda, min_occurrence=0),
        Element(Fermata, min_occurrence=0, max_occurrence=2),
        Element(Ending, min_occurrence=0),
        Element(Repeat, min_occurrence=0)
    )

    def __init__(self, *args, **kwargs):
        super().__init__(tag='barline', *args, **kwargs)
예제 #3
0
class Score(XMLElement, DocumentAttributes):
    """The score-partwise element is the root element for a partwise MusicXML score. It includes a score-header group
    followed by a series of parts with measures inside. The document-attributes attribute group includes the version
    attribute.
    """
    _DTD = Sequence(GroupReference(ScoreHeader),
                    Element(Part, max_occurrence=None))

    def __init__(self, *args, **kwargs):
        super().__init__(tag='score-partwise', *args, **kwargs)

    def write(self, path):
        xmlversion = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'
        doctype = '<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML {} Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">\n'.format(
            self.version)

        try:
            if path[-4:] != '.xml':
                path += '.xml'
        except TypeError:
            pass
        output_file = open(path, 'w')
        output_file.write(xmlversion)
        output_file.write(doctype)
        output_file.write(self.to_string())
        output_file.close()
예제 #4
0
class ComplexTypeNotations(ComplexType, PrintObject, OptionalUniqueId):
    """
    Notations refer to musical notations, not XML notations. Multiple notations are allowed in order to represent
    multiple editorial levels. The print-object attribute, added in Version 3.0, allows notations to represent details
    of performance technique, such as fingerings, without having them appear in the score.
    """
    _DTD = Sequence(
        GroupReference(Editorial),
        Choice(Element(Tied),
               Element(Slur),
               Element(Tuplet),
               Element(Glissando),
               Element(Slide),
               Element(Ornaments),
               Element(Technical),
               Element(Articulations),
               Element(Dynamics),
               Element(Fermata),
               Element(Arpeggiate),
               Element(NonArpeggiate),
               Element(AccidentalMark),
               Element(OtherNotation),
               min_occurrence=0,
               max_occurrence=None))

    def __init__(self, *args, **kwargs):
        super().__init__(tag='notations', *args, **kwargs)
예제 #5
0
파일: key.py 프로젝트: alexgorji/musicscore
class TypeKey(ComplexType, KeyNumberAttribute, PrintStyle, PrintObject,
              OptionalUniqueId):
    """
    The key type represents a key signature. Both traditional and non-traditional key signatures are supported.
    The optional number attribute refers to staff numbers. If absent, the key signature applies to all staves in the
    part. Key signatures appear at the start of each system unless the print-object attribute has been set to "no".
    """
    _DTD = (Sequence(
        Choice(
            GroupReference(TraditionalKey),
            GroupReference(NonTraditionalKey,
                           min_occurrence=0,
                           max_occurrence=None)),
        Element(KeyOctave, min_occurrence=0, max_occurrence=None)))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #6
0
class ComplexTypeSystemMargins(ComplexType):
    """
    System margins are relative to the page margins. Positive values indent and negative values reduce the margin size.
    """

    _DTD = Sequence(GroupReference(LeftRightMargins))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #7
0
class ComplexTypeDirection(ComplexType, Placement, Directive,
                           OptionalUniqueId):
    """A direction is a musical indication that is not necessarily attached to a specific note. Two or more may be
    combined to indicate starts and stops of wedges, dashes, etc. For applications where a specific direction is indeed
    attached to a specific note, the direction element can be associated with the note element that follows it in score
    order that is not in a different voice.

    By default, a series of direction-type elements and a series of child elements of a direction-type within a single
    direction element follow one another in sequence visually. For a series of direction-type children, non-positional
    formatting attributes are carried over from the previous element by default."""

    _DTD = Sequence(Element(DirectionType, max_occurrence=None),
                    Element(Offset, min_occurrence=0),
                    GroupReference(EditorialVoiceDirection),
                    GroupReference(Staff, min_occurrence=0),
                    Element(Sound, min_occurrence=0))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #8
0
class Note(XMLElement, XPosition, Font, Color, Printout, OptionalUniqueId):
    """
    Notes are the most common type of MusicXML data. The MusicXML format keeps the MuseData distinction between
    elements used for sound information and elements used for notation information (e.g., tie is used for sound,
    tied for notation). Thus grace notes do not have a duration element. Cue notes have a duration element, as do
    forward elements, but no tie elements. Having these two types of information available can make interchange
    considerably easier, as some programs handle one type of information much more readily than the other.

    The print-leger attribute is used to indicate whether leger lines are printed. Notes without leger lines are
    used to indicate indeterminate high and low notes. By default, it is set to yes. If print-object is set to no,
    print-leger is interpreted to also be set to no if not present. This attribute is ignored for rests.

    The dynamics and end-dynamics attributes correspond to MIDI 1.0's Note On and Note Off velocities, respectively.
    They are expressed in terms of percentages of the default forte value (90 for MIDI 1.0).

    The attack and release attributes are used to alter the starting and stopping time of the note from when it
    would otherwise occur based on the flow of durations - information that is specific to a performance. They are
    expressed in terms of divisions, either positive or negative. A note that starts a tie should not have a
    release attribute, and a note that stops a tie should not have an attack attribute. The attack and release
    attributes are independent of each other. The attack attribute only changes the starting time of a note, and
    the release attribute only changes the stopping time of a note.

    If a note is played only particular times through a repeat, the time-only attribute shows which times to
    play the note.

    The pizzicato attribute is used when just this note is sounded pizzicato, vs. the pizzicato element which
    changes overall playback between pizzicato and arco.
    """
    _DTD = Sequence(
        Choice(
            Sequence(GroupReference(FullNote), GroupReference(DurationGroup),
                     Element(Tie, 0, 2)),
            Sequence(
                Element(Grace),
                Choice(Sequence(GroupReference(FullNote)),
                       Sequence(GroupReference(FullNote), Element(Tie, 0, 2)),
                       Sequence(Element(Cue), GroupReference(FullNote)))),
            Sequence(Element(Cue), GroupReference(FullNote),
                     GroupReference(DurationGroup)),
        ), Element(Instrument, 0), GroupReference(EditorialVoice, 0),
        Element(Type, 0), Element(Dot, 0, None), Element(Accidental, 0),
        Element(TimeModification, 0, None), Element(Stem, 0),
        Element(Notehead, 0), Element(NoteheadText, 0),
        GroupReference(Staff, 0), Element(Beam, 0, 8),
        Element(Notations, 0, None), Element(Lyric, 0, None), Element(Play, 0))

    def __init__(self, *args, **kwargs):
        super().__init__(tag='note', *args, **kwargs)
예제 #9
0
class ComplexTypeBackup(ComplexType):
    """
    The backup and forward elements are required to coordinate multiple voices in one part, including music on multiple
    staves. The backup type is generally used to move between voices and staves. Thus the backup element does not
    include voice or staff elements. Duration values should always be positive, and should not cross measure boundaries
    or mid-measure changes in the divisions value.
    """
    _DTD = Sequence(Element(Duration), GroupReference(Editorial))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #10
0
class Rest(Event, Measure):
    """
    The rest element indicates notated rests or silences. Rest elements are usually empty, but placement on the staff
    can be specified using display-step and  display-octave elements. If the measure attribute is set to yes, this
    indicates this is a complete measure rest.
    """

    _DTD = Sequence(GroupReference(DisplayStepOctave, min_occurrence=0))

    def __init__(self, measure=None, *args, **kwargs):
        super().__init__(tag='rest', measure=measure, *args, **kwargs)
예제 #11
0
class ComplexTypeDefaults(ComplexType):
    """
    The defaults type specifies score-wide defaults for scaling, layout, and appearance.
    """
    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)

    _DTD = Sequence(Element(Scaling, min_occurrence=0), GroupReference(Layout),
                    Element(Appearance, 0), Element(MusicFont, 0),
                    Element(WordFont, 0), Element(LyricFont, 0, None),
                    Element(LyricLanguage, 0, None))
예제 #12
0
class ComplexTypePartGroup(ComplexType):
    """
    The part-group element indicates groupings of parts in the score, usually indicated by braces and brackets. Braces
    that are used for multi-staff parts should be defined in the attributes element for that part. The part-group start
    element appears before the first score-part in the group. The part-group stop element appears after the last
    score-part in the group.

    The number attribute is used to distinguish overlapping and nested part-groups, not the sequence of groups. As with
    parts, groups can have a name and abbreviation. Values for the child elements are ignored at the stop of a group.

    A part-group element is not needed for a single multi-staff part. By default, multi-staff parts include a brace
    symbol and (if appropriate given the bar-style) common barlines. The symbol formatting for a multi-staff part can
    be more fully specified using the part-symbol element.
    """
    _DTD = Sequence(Element(GroupName, min_occurrence=0),
                    Element(GroupNameDisplay, min_occurrence=0),
                    Element(GroupAbbreviation, min_occurrence=0),
                    Element(GroupAbbreviationDisplay, min_occurrence=0),
                    Element(GroupSymbol, min_occurrence=0),
                    Element(GroupBarline, min_occurrence=0),
                    Element(GroupTime, min_occurrence=0),
                    GroupReference(Editorial))
    _ATTRIBUTES = []

    def __init__(self, type, number='1', *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.type = type
        self.number = number

    @property
    def number(self):
        return self.get_attribute('number')

    @number.setter
    def number(self, value):
        if value is None:
            self.remove_attribute('number')
        else:
            Token(value)
            self._ATTRIBUTES.insert(0, 'number')
            self.set_attribute('number', value)

    @property
    def type(self):
        return self.get_attribute('type')

    @type.setter
    def type(self, value):
        if value is None:
            self.remove_attribute('type')
        else:
            TypeStartStop(value)
            self._ATTRIBUTES.insert(0, 'type')
            self.set_attribute('type', value)
예제 #13
0
class Time(XMLElement, PrintObject, OptionalUniqueId):
    """
    Time signatures are represented by the beats element for the numerator and the beat-type element for the
    denominator. The symbol attribute is used indicate common and cut time symbols as well as a single number display.
    Multiple pairs of beat and beat-type elements are used for composite time signatures with multiple denominators,
    such as 2/4 + 3/8. A composite such as 3+2/8 requires only one beat/beat-type pair.
    The print-object attribute allows a time signature to be specified but not printed, as is the case for excerpts
    from the middle of a score. The value is "yes" if not present. The optional number attribute refers to staff numbers
    within the part. If absent, the time signature applies to all staves in the part.
    """

    _DTD = Choice(
        Sequence(GroupReference(TimeSignature, max_occurrence=None),
                 Element(Interchangeable, min_occurrence=0)),
        Element(SenzaMisura))

    def __init__(self, *args, **kwargs):
        super().__init__(tag='time', *args, **kwargs)
예제 #14
0
class ComplexTypePrint(ComplexType, PrintAttributes, OptionalUniqueId):
    """
    The print type contains general printing parameters, including the layout elements defined in the layout.mod file.
    The part-name-display and part-abbreviation-display elements used in the score.mod file may also be used here to
    change how a part name or abbreviation is displayed over the course of a piece. They take effect when the current
    measure or a succeeding measure starts a new system.

    Layout elements in a print statement only apply to the current page, system, staff, or measure. Music that follows
    continues to take the default values from the layout included in the defaults element.
    """
    _DTD = Sequence(GroupReference(Layout),
                    Element(MeasureLayout, min_occurrence=0),
                    Element(MeasureNumbering, min_occurrence=0),
                    Element(PartNameDisplay, min_occurrence=0),
                    Element(PartAbbreviationDisplay, min_occurrence=0))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #15
0
class ComplexTypeAttributes(ComplexType):
    """
    The attributes element contains musical information that typically changes on measure boundaries. This
    includes key and time signatures, clefs, transpositions, and staving. When attributes are changed
    mid-measure, it affects the music in score order, not in MusicXML document order
    """
    _DTD = Sequence(
        GroupReference(Editorial), Element(Divisions, min_occurrence=0),
        Element(Key, min_occurrence=0, max_occurrence=None),
        Element(Time, min_occurrence=0, max_occurrence=None),
        Element(Staves, min_occurrence=0), Element(PartSymbol,
                                                   min_occurrence=0),
        Element(Instruments, min_occurrence=0),
        Element(Clef, min_occurrence=0, max_occurrence=None),
        Element(StaffDetails, min_occurrence=0, max_occurrence=None),
        Element(Transpose, min_occurrence=0, max_occurrence=None),
        Element(Directive, min_occurrence=0, max_occurrence=None),
        Element(MeasureStyle, min_occurrence=0, max_occurrence=None))

    def __init__(self, tag, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
예제 #16
0
class ComplexTypePageMargins(ComplexType):
    """Page margins are specified either for both even and odd pages, or via separate odd and even page number values.
    The type attribute is not needed when used as part of a print element. If omitted when the page-margins type is
    used in the defaults element, "both" is the default value."""

    _DTD = Sequence(GroupReference(AllMargins))

    def __init__(self, tag, type_=None, *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
        self.type = type_

    @property
    def type(self):
        return self.get_attribute('type')

    @type.setter
    def type(self, value):
        if value is None:
            self.remove_attribute('type')
        else:
            TypeMarginType(value)
            self._ATTRIBUTES = ['type']
            self.set_attribute('type', value)
예제 #17
0
class TreeChord(XMLTree):
    _DTD = Sequence(
        Choice(
            Sequence(GroupReference(FullNote), Element(Duration),
                     Element(Tie, 0, 2)),
            Sequence(Element(Cue), GroupReference(FullNote),
                     Element(Duration)),
        ), Element(Attributes, 0), Element(Direction, 0, None),
        Element(Instrument, 0), GroupReference(EditorialVoice, 0),
        Element(Type, 0), Element(Dot, 0, None),
        Element(TimeModification, 0, None), Element(Stem, 0),
        Element(Notehead, 0), Element(NoteheadText, 0),
        GroupReference(Staff, 0), Element(Beam, 0, 8),
        Element(Notations, 0, None), Element(Lyric, 0, None), Element(Play, 0))

    def __init__(self,
                 midis=71,
                 quarter_duration=1,
                 zero_mode='grace',
                 **kwargs):
        super().__init__(**kwargs)
        self.parent_tree_part_voice = None
        self.parent_beat = None
        self._notes = None
        self._offset = None
        self._quarter_duration = None
        self._zero_mode = None
        self.zero_mode = zero_mode
        self.quarter_duration = quarter_duration
        self._midis = None
        self._pre_grace_chords = []
        self._post_grace_chords = []

        self.midis = midis
        self._tail = False
        self._head = False
        self._is_adjoinable = True
        self._flags = None

        self._manual_type = False
        self._manual_dots = False
        self._manual_staff_number = None
        self.manual_voice_number = None
        self.is_finger_tremolo = False
        self.relative_x = None
        self.tie_orientation = None

    # //private methods
    def _generate_notes(self):
        output = []
        if self.zero_mode == 'remove' and self.quarter_duration == 0:
            return output

        for index, midi in enumerate(self.midis):
            note = TreeNote(parent_chord=self, event=midi.get_pitch_rest())
            note.update_grace()
            note.accidental.set_force_show(midi.accidental.force_show)
            note.accidental.set_force_hide(midi.accidental.force_hide)
            note.is_finger_tremolo = self.is_finger_tremolo
            if self.relative_x is not None:
                note.relative_x = self.relative_x
            if midi.notehead:
                note.add_child(midi.notehead)

            for child in self.get_children():
                if isinstance(child, Lyric) and index != 0:
                    pass

                elif isinstance(child, Notations) and index != 0:
                    grandchildren = child.get_children()
                    for grandchild in grandchildren:
                        if type(grandchild) not in (Ornaments, Technical,
                                                    Articulations, Dynamics):
                            note._add_notations(grandchild)
                elif isinstance(child, Direction):
                    pass
                elif isinstance(child, Attributes):
                    pass
                else:
                    note.add_child(child)
            if index > 0:
                note.add_child(Chord())
            output.append(note)
        return output

    def _get_staff_object(self):
        try:
            return self.get_children_by_type(StaffElement)[0]
        except IndexError:
            return None

    def _get_direction_types(self):
        output = []
        for direction in self.get_children_by_type(Direction):
            for dt in direction.get_children_by_type(DirectionType):
                output.append(dt)
        return output

    def _remove_direction(self, direction):
        self.remove_child(direction)

    def _remove_direction_type(self, direction_type):
        parent = direction_type.up
        parent.remove_child(direction_type)
        if not parent.get_children():
            self._remove_direction(parent)

    def _set_staff_number(self, val):
        if not isinstance(val, int):
            raise TypeError(
                'staff_number.value must be of type int not{}'.format(
                    type(val)))
        staff = self._get_staff_object()
        if staff is None:
            self.add_child(StaffElement(val))
        else:
            staff.value = val

    # //public properties
    @property
    def end_position(self):
        return self.offset + self.quarter_duration

    @property
    def flags(self):

        if self._flags is None:
            self._flags = set()
        return self._flags

    @property
    def is_adjoinable(self):
        return self._is_adjoinable

    @is_adjoinable.setter
    def is_adjoinable(self, value):
        if not isinstance(value, bool):
            raise TypeError(
                'is_adjoinable.value must be of type bool not{}'.format(
                    type(value)))
        self._is_adjoinable = value

    @property
    def is_head(self):
        return self._head

    @property
    def is_rest(self):
        if self.midis[0].value == 0:
            return True
        return False

    @property
    def is_tail(self):
        return self._tail

    @property
    def is_tied_to_next(self):
        if 'start' in self.tie_types:
            return True
        return False

    @property
    def is_tied_to_previous(self):
        if 'stop' in self.tie_types:
            return True
        return False

    @property
    def manual_staff_number(self):
        return self._manual_staff_number

    @manual_staff_number.setter
    def manual_staff_number(self, val):
        if not isinstance(val, int):
            raise TypeError(
                'manual_staff_number.value must be of type int not{}'.format(
                    type(val)))
        self._manual_staff_number = val
        self._set_staff_number(val)

    @property
    def midis(self):
        return self._midis

    @midis.setter
    def midis(self, values):
        try:
            values = list(values)
        except TypeError:
            values = [values]

        output = []
        for midi in values:
            if not isinstance(midi, Midi):
                output.append(Midi(midi))
            else:
                output.append(midi)

        for midi in output:
            if midi.value == 0 and len(values) > 1:
                raise ValueError('midi with value 0 must be alone.')

        output = sorted(output, key=lambda midi: midi.value)

        self._midis = output

    @property
    def notes(self):
        if self._notes is None:
            self._notes = self._generate_notes()
        return self._notes

    @property
    def next_in_score(self):
        index = self.parent_tree_part_voice.chords.index(self)
        if index == len(self.parent_tree_part_voice.chords) - 1:
            current_part = self.parent_tree_part_voice.parent_tree_part_staff.parent_part
            next_measure = current_part.up.next
            if next_measure:
                next_part = next_measure.get_part_with_id(id=current_part.id)
                next_chord = next_part.get_staff(
                    self.parent_tree_part_voice.parent_tree_part_staff.number
                ).get_voice(self.parent_tree_part_voice.number).chords[0]
                return next_chord
            else:
                return None
        else:
            return self.parent_tree_part_voice.chords[index + 1]

    @property
    def offset(self):
        if self._offset is None:
            self.update_offset()
        return self._offset

    @property
    def position_in_beat(self):
        index_in_beat = self.parent_beat.chords.index(self)
        if index_in_beat == 0:
            return 0
        previous_in_beat = self.parent_beat.chords[index_in_beat - 1]

        return previous_in_beat.position_in_beat + previous_in_beat.quarter_duration

    @property
    def previous_in_part_voice(self):
        index = self.parent_tree_part_voice.chords.index(self)
        if index == 0:
            return None
        return self.parent_tree_part_voice.chords[index - 1]

    @property
    def previous_in_score_voice(self):
        if self.previous_in_part_voice is None:
            current_part = self.parent_tree_part_voice.parent_tree_part_staff.parent_part
            previous_measure = current_part.up.previous
            if previous_measure:
                previous_part = previous_measure.get_part_with_id(
                    id=current_part.id)
                previous_chord = \
                    previous_part.get_staff(self.parent_tree_part_voice.parent_tree_part_staff.number).get_voice(
                        self.parent_tree_part_voice.number).chords[-1]
                return previous_chord
            else:
                return None
        else:
            return self.previous_in_part_voice

    @property
    def quarter_duration(self):
        return self._quarter_duration

    @quarter_duration.setter
    def quarter_duration(self, value):
        if not isinstance(value, int) and not isinstance(
                value, float) and not isinstance(value, Fraction):
            raise TypeError(
                'quarter_duration must be of type int, float or Fraction not {}'
                .format(type(value)))

        if value < 0:
            raise ValueError(
                'quarter_duration {} must be zero or positive'.format(value))

        if not isinstance(self.quarter_duration, Fraction):
            self._quarter_duration = Fraction(value)
        else:
            self._quarter_duration = value

    @property
    def staff_number(self):
        staff = self._get_staff_object()
        if staff:
            return staff.value
        else:
            return None

    @staff_number.setter
    def staff_number(self, val):
        if self.manual_staff_number is None:
            self._set_staff_number(val)

    @property
    def tie_types(self):
        return [tie.type for tie in self.get_children_by_type(Tie)]

    @property
    def tremoli(self):
        try:
            return self.get_children_by_type(
                Notations)[0].get_children_by_type(
                    Ornaments)[0].get_children_by_type(Tremolo)
        except IndexError:
            return []

    def update_offset(self):
        if self.previous_in_part_voice:
            output = self.previous_in_part_voice.offset + self.previous_in_part_voice.quarter_duration
            self._offset = output
        else:
            self._offset = 0

    @property
    def zero_mode(self):
        return self._zero_mode

    @zero_mode.setter
    def zero_mode(self, val):
        permitted = ['remove', 'grace']
        if val not in permitted:
            raise ValueError('zero_mode.value {} must be in {}'.format(
                val, permitted))
        self._zero_mode = val

    @property
    def __name__(self):
        # return self.parent_tree_part_voice.__name__ + ' ' + 'ch:' + str(self.parent_tree_part_voice.chords.index(self) + 1)
        return self.parent_tree_part_voice.__name__ + '.' + str(
            self.parent_tree_part_voice.chords.index(self) + 1)

    # //public methods
    # add

    def add_action_dynamics(self, value, **kwargs):
        dynamics = self.add_dynamics(value, **kwargs)[0]
        direction = dynamics.up.up
        direction_type = direction.add_child(DirectionType())

        direction_type.add_child(Words(value='»'))
        for child in direction.get_children():
            if child.get_children_by_type(Dynamics):
                direction.remove_child(child)

        direction_type = direction.add_child(DirectionType())
        direction_type.add_child(dynamics)
        direction_type = direction.add_child(DirectionType())
        direction_type.add_child(Words(value='«', font_size=10))

    def add_articulation(self, articulation, **kwargs):
        def add_type(dict):
            new_dict = dict.copy()
            if 'type' not in new_dict:
                new_dict['type'] = 'up'
            return new_dict

        def add_breath_mark_value(dict):
            new_dict = dict.copy()
            if 'value' not in new_dict:
                new_dict['value'] = 'comma'
            return new_dict

        articulations = {
            'accent': Accent(**kwargs),
            'strong-accent': StrongAccent(**add_type(kwargs)),
            'staccato': Staccato(**kwargs),
            'tenuto': Tenuto(**kwargs),
            'detached-legato': DetachedLegato(**kwargs),
            'staccatissimo': Staccatissimo(**kwargs),
            'spiccato': Spiccato(**kwargs),
            'scoop': Scoop(**kwargs),
            'plop': Plop(**kwargs),
            'doit': Doit(**kwargs),
            'falloff': Falloff(**kwargs),
            'breath-mark': BreathMark(**add_breath_mark_value(kwargs)),
            'caesura': Caesura(**kwargs),
            'stress': Stress(**kwargs),
            'unstress': Unstress(**kwargs)
        }

        if articulation not in articulations:
            raise ValueError('articulation {}  must be in {}'.format(
                articulation, list(articulations.keys())))

        return self.add_articulation_object(articulations[articulation])

    def add_articulation_object(self, articulation_object):

        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        try:
            articulations = notations.get_children_by_type(Articulations)[0]
        except IndexError:
            articulations = notations.add_child(Articulations())

        articulations.add_child(articulation_object)

    def add_bracket(self, type, line_end, placement='above', **kwargs):
        d = self.add_child(Direction(placement=placement))
        dt = d.add_child(DirectionType())
        dt.add_child(Bracket(type=type, line_end=line_end, **kwargs))

    def add_clef(self, clef):
        try:
            attributes = self.get_children_by_type(Attributes)[0]
        except IndexError:
            attributes = self.add_child(Attributes())
        clef_copy = clef.__deepcopy__()
        attributes.add_child(clef_copy)

    def add_dynamics(self, values, placement='below', **kwargs):
        dynamic_classes = [
            P, PP, PPP, PPPP, PPPPP, PPPPPP, F, FF, FFF, FFFF, FFFFF, FFFFFF,
            MP, MF, SF, SFP, SFPP, FP, RF, RFZ, SFZ, SFFZ, FZ, N, PF, SFZP
        ]
        tags = [d._TAG for d in dynamic_classes]

        if isinstance(values, str) or not hasattr(values, '__iter__'):
            values = [values]

        direction = self.add_child(Direction(placement=placement))
        direction_type = direction.add_child(DirectionType())
        output = []
        for value in values:
            try:
                index = tags.index(value)
            except ValueError:
                raise ValueError('wrong dynamics value')
            dynamics = direction_type.add_child(Dynamics(**kwargs))
            dynamics.add_child(dynamic_classes[index]())
            output.append(dynamics)

        return output

    def add_fermata(self, value='normal', **kwargs):
        fermata = Fermata(value, **kwargs)
        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        notations.add_child(fermata)

    def add_flag(self, flag):
        if not isinstance(flag, TreeChordFlag1) and not isinstance(flag, TreeChordFlag2) \
                and not isinstance(flag, TreeChordFlag3):
            raise TypeError(
                'flag must be of type TreeChordFlag1, TreeChordFlag2 or TreeChordFlag3 not {}'
                .format(flag.__class__))
        if self._flags is None:
            self._flags = set()
        self._flags.add(flag)

    def add_grace_chords(self, chords, mode='pre'):
        permitted = ['pre', 'post']
        if mode not in permitted:
            raise ValueError('mode must be in {}'.format(permitted))
        try:
            chords = list(chords)
        except TypeError:
            chords = [chords]

        for chord in chords:
            if not isinstance(chord, TreeChord):
                raise TypeError('wrong type {}'.format(type(chord)))
        for chord in chords:
            chord.quarter_duration = 0
            chord.zero_mode = 'grace'
            if mode == 'pre':
                self._pre_grace_chords.append(chord)
            else:
                self._post_grace_chords.append(chord)

    def add_harmonic(self, interval):
        if len(self.midis) != 1:
            raise Exception(
                'harmonic can only be added to chords with one midi')
        new_midi = self.add_midi(self.midis[0].value + interval)

        alter = self.midis[0].get_pitch_name()[1]

        if alter:
            if alter > 0:
                new_midi.accidental.mode = 'sharp'
            else:
                new_midi.accidental.mode = 'flat'
        else:
            new_midi.accidental.mode = 'flat'

        self.midis[-1].add_notehead('diamond', filled='no')

    def add_lyric(self,
                  text=None,
                  number=1,
                  syllabic=None,
                  extend=None,
                  **kwargs):
        lyric = self.add_child(Lyric(number=str(number), **kwargs))
        if syllabic is not None:
            lyric.add_child(Syllabic(syllabic))
        if extend is not None:
            lyric.add_child(Extend(extend))
        if text is not None:
            lyric.add_child(Text(str(text)))
        return lyric

    def add_pedal(self, type, placement='below', **kwargs):
        d = self.add_child(Direction(placement=placement))
        dt = d.add_child(DirectionType())
        dt.add_child(Pedal(type=type, **kwargs))

    def add_midi(self, val):
        if val == 0:
            raise ValueError('midi with value 0 can not be added.')

        if not isinstance(val, Midi):
            val = Midi(val)

        self._midis.append(val)
        return val

    def add_notations_object(self, object):
        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        notations.add_child(object)
        return object

    def add_slide(self, type, **kwargs):
        object = Slide(type, **kwargs)
        return self.add_notations_object(object)

    def add_slur_object(self, slur):
        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        notations.add_child(slur)
        return slur

    def add_slur(self, type, **kwargs):
        slur = Slur(type, **kwargs)
        return self.add_slur_object(slur)

    def add_technical_object(self, technical_object):

        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        try:
            technical = notations.get_children_by_type(Technical)[0]
        except IndexError:
            technical = notations.add_child(Technical())

        technical.add_child(technical_object)

    def add_tuplet(self, type, number=1):
        normals = {
            3: 2,
            5: 4,
            6: 4,
            7: 4,
            9: 8,
            10: 8,
            11: 8,
            12: 8,
            13: 8,
            14: 8,
            15: 8
        }
        types = {8: '32nd', 4: '16th', 2: 'eighth'}
        actual_notes = self.parent_beat.best_div
        normal_notes = normals[actual_notes]
        normal_type = types[normal_notes / self.parent_beat.duration]
        if type != 'continue':
            try:
                notations = self.notations
            except AttributeError:
                notations = self.add_child(Notations())

            v = self.get_children_by_type(Voice)[0]
            if int(v.value) % 2 == 0:
                placement = 'below'
            else:
                placement = 'above'

            notations.add_child(
                Tuplet(type=type,
                       number=number,
                       bracket='yes',
                       placement=placement))

        tm = self.add_child(TimeModification())
        tm.add_child(ActualNotes(actual_notes))
        tm.add_child(NormalNotes(normal_notes))
        tm.add_child(NormalType(normal_type))

    def add_tremolo(self, number=3, **kwargs):

        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        try:
            ornaments = notations.get_children_by_type(Ornaments)[0]
        except IndexError:
            ornaments = notations.add_child(Ornaments())

        ornaments.add_child(Tremolo(value=number, **kwargs))

    def get_notations(self):
        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())
        return notations

    def get_ornaments(self):
        notations = self.get_notations()
        try:
            ornaments = notations.get_children_by_type(Ornaments)[0]
        except IndexError:
            ornaments = notations.add_child(Ornaments())
        return ornaments

    def add_trill_mark(self, **kwargs):
        ornaments = self.get_ornaments()
        return ornaments.add_child(TrillMark(**kwargs))

    def add_wavy_line(self, **kwargs):
        ornaments = self.get_ornaments()
        return ornaments.add_child(WavyLine(**kwargs))

    def add_tie(self, value):
        if value not in ('stop', 'start'):
            raise NotImplementedError(
                'value {} cannot be a tie value'.format(value))

        try:
            notations = self.get_children_by_type(Notations)[0]
        except IndexError:
            notations = self.add_child(Notations())

        if value == 'start' and 'start' not in self.tie_types:
            self.add_child(Tie('start'))
            notations.add_child(Tied('start',
                                     orientation=self.tie_orientation))

        elif value == 'stop' and 'stop' not in self.tie_types:
            self.add_child(Tie('stop'))
            notations.add_child(Tied('stop'))

    def add_wedge(self, value, placement='below', **kwargs):
        wedge_object = Wedge(value, **kwargs)

        direction = self.add_child(Direction(placement=placement))
        direction_type = direction.add_child(DirectionType())
        wedge = direction_type.add_child(wedge_object)
        #
        # dynamics.add_child(dynamic_classes[index]())

        return wedge

    def add_words(self, words, placement='above', **kwargs):
        d = self.add_child(Direction(placement=placement))
        dt = d.add_child(DirectionType())
        if isinstance(words, Words):
            if kwargs:
                raise ValueError(
                    'no keywords possible if add_words gets a Words()')
            dt.add_child(words)
        else:
            dt.add_child(Words(value=str(words), **kwargs))

    # get

    def get_articulations(self):
        output = []
        for notations in self.get_children_by_type(Notations):
            articulations = notations.get_children_by_type(Articulations)
            for articulation in articulations:
                output.extend(articulation.get_children())
        return output

    def get_clef(self):
        try:
            attributes = self.get_children_by_type(Attributes)[0]
            return attributes.get_children_by_type(TreeClef)[0]
        except IndexError:
            return None

    def get_dynamics(self):
        directions = self.get_children_by_type(Direction)
        for direction in directions:
            direction_types = direction.get_children_by_type(DirectionType)
            for direction_type in direction_types:
                for child in direction_type.get_children():
                    if isinstance(child, Dynamics):
                        return child.get_children()[0].to_string()[1:-3]
        return None

    def get_notes(self):
        return self.notes

    def get_pre_grace_chords(self):
        return self._pre_grace_chords

    def get_post_grace_chords(self):
        return self._post_grace_chords

    def get_words(self):
        output = []
        for dt in self._get_direction_types():
            for child in dt.get_children():
                if isinstance(child, Words):
                    output.append(child)
        return output

    # remove

    def remove_dynamics(self):
        for direction_type in self._get_direction_types():
            for child in direction_type.get_children():
                if isinstance(child, Dynamics):
                    direction_type.remove_child(child)
            if not direction_type.get_children():
                self._remove_direction_type(direction_type)

    def remove_flag(self, flag):
        if flag in self._flags:
            self._flags.remove(flag)

    def remove_from_score(self):
        if 'stop' in self.tie_types and 'start' not in self.tie_types:
            self.remove_tie('stop')
            previous_chord = self.previous_in_score_voice
            if previous_chord:
                previous_chord.remove_tie('start')

        elif 'start' in self.tie_types and 'stop' not in self.tie_types:
            self.remove_tie('start')
            next_chord = self.next_in_score
            if next_chord:
                next_chord.remove_tie('stop')

                for l in self.get_children_by_type(Lyric):
                    next_chord.add_child(l)
                for n in self.get_children_by_type(Notations):
                    next_chord.add_child(n)
                for d in self.get_children_by_type(Direction):
                    next_chord.add_child(d)
                clef = self.get_clef()
                if clef:
                    next_chord.add_clef(clef)

        self.parent_beat.chords.remove(self)
        self.parent_tree_part_voice.chords.remove(self)

    def remove_notations(self):
        notations = self.get_children_by_type(Notations)
        for notation in notations:
            self.remove_child(notation)

    def remove_previous_tie(self):
        if 'stop' in self.tie_types:
            self.remove_tie('stop')
            try:
                self.previous_in_score_part.remove_tie('start')
            except AttributeError:
                pass

    def remove_slur(self, type):
        try:
            notations = self.get_children_by_type(Notations)[0]
            slurs = [
                s for s in notations.get_children_by_type(Slur)
                if s.type == type
            ]
            for slur in slurs:
                notations.remove_child(slur)
            if not notations.get_children():
                self.remove_child(notations)
        except IndexError:
            pass

    def remove_tie(self, type):
        if type in self.tie_types:
            notations = self.get_children_by_type(Notations)[0]
            tie = [
                t for t in self.get_children_by_type(Tie) if t.type == type
            ][0]
            self.remove_child(tie)

            tied = [
                t for t in notations.get_children_by_type(Tied)
                if t.type == type
            ][0]
            notations.remove_child(tied)
            if not notations.get_children():
                self.remove_child(notations)

    def remove_voice(self):
        for voice in self.get_children_by_type(Voice):
            self.remove_child(voice)

    # set

    def set_manual_type(self, val, **kwargs):
        try:
            chord_type = self.get_children_by_type(Type)[0]
            self.remove_child(chord_type)
        except IndexError:
            self.add_child(Type(value=val, **kwargs))

        self._manual_type = True

    def set_manual_dots(self, val):
        try:
            for dot in self.get_children_by_type(Dot):
                self.remove_child(dot)
        except IndexError:
            pass
        for i in range(val):
            self.add_child(Dot())

        self._manual_dots = True

    def set_staff_number(self, staff_number):
        self.manual_staff_number = staff_number

    def set_tie_orientation(self, orientation):
        if self.is_tied_to_next:
            tied = [
                t for t in self.get_children_by_type(Notations)
                [0].get_children_by_type(Tied) if t.type == 'start'
            ]
            for t in tied:
                t.orientation = orientation

    def set_voice_number(self, voice_number):
        self.manual_voice_number = voice_number

    # update

    def update_dot(self):
        if self._manual_dots is False:
            _dot = 0

            if self.quarter_duration.numerator % 3 == 0:
                _dot = 1
            elif self.quarter_duration == Fraction(
                    1, 2) and self.parent_beat.best_div == 6:
                _dot = 1
            elif self.quarter_duration == Fraction(
                    1, 4) and self.parent_beat.best_div == 6:
                _dot = 1
            elif (self.quarter_duration == Fraction(3, 9)
                  or self.quarter_duration == Fraction(
                      6, 9)) and self.parent_beat.best_div == 9:
                _dot = 1
            elif self.quarter_duration == Fraction(7, 8):
                _dot = 2
            elif self.quarter_duration == Fraction(7, 4):
                _dot = 2
            else:
                _dot = 0

            for dot in self.get_children_by_type(Dot):
                self.remove_child(dot)

            for i in range(_dot):
                self.add_child(Dot())

    def update_type(self):
        """get type of a Note() depending on its quantized duration and return it [whole, half, quarter, eighth, 16th,
        32nd, 64th]"""
        _types = {
            (1, 12): '32nd',
            (1, 11): '32nd',
            (2, 11): '16th',
            (3, 11): '16th',
            (4, 11): 'eighth',
            (6, 11): 'eighth',
            (8, 11): 'quarter',
            (1, 10): '32nd',
            (3, 10): '16th',
            (1, 9): '32nd',
            (2, 9): '16th',
            (4, 9): 'eighth',
            (8, 9): 'quarter',
            (1, 8): '32nd',
            (3, 8): '16th',
            (7, 8): 'eighth',
            (1, 7): '16th',
            (2, 7): 'eighth',
            (3, 7): 'eighth',
            (4, 7): 'quarter',
            (6, 7): 'quarter',
            (1, 6): '16th',
            (1, 5): '16th',
            (2, 5): 'eighth',
            (3, 5): 'eighth',
            (4, 5): 'quarter',
            (1, 4): '16th',
            (2, 4): 'eighth',
            (3, 4): 'eighth',
            (7, 4): 'quarter',
            (1, 3): 'eighth',
            (2, 3): 'quarter',
            (3, 2): 'quarter',
            (1, 2): 'eighth',
            (1, 1): 'quarter',
            (2, 1): 'half',
            (3, 1): 'half',
            (4, 1): 'whole',
            (6, 1): 'whole',
            (8, 1): 'breve',
            (12, 1): 'breve'
        }

        if self._manual_type is False:
            tremoli_types = [tremolo.type for tremolo in self.tremoli]

            if self.quarter_duration == 0:
                value = 'eighth'

            elif ('start' in tremoli_types or 'stop' in tremoli_types):
                show_duration = self.quarter_duration * 2
                value = _types[(show_duration.numerator,
                                show_duration.denominator)]
                if not self.get_children_by_type(TimeModification):
                    tm = TimeModification()
                    tm.add_child(ActualNotes(2))
                    tm.add_child(NormalNotes(1))
                    self.add_child(tm)
            else:
                value = _types[(self.quarter_duration.numerator,
                                self.quarter_duration.denominator)]

            try:
                chord_type = self.get_children_by_type(Type)[0]
                chord_type.value = value
            except IndexError:
                self.add_child(Type(value))

    # others

    def change_range(self, min_midi, max_midi, microtone=2):
        if self.is_rest:
            pass
        else:
            scale = Scale(self.midis[0].value,
                          self.midis[-1].value,
                          min_midi,
                          max_midi,
                          step=2 / microtone)
            self.midis = [scale(midi.value) for midi in self.midis]

    def force_tie(self):
        self.is_adjoinable = False

    def has_same_pitches(self, other_chord):
        if len(self.notes) == len(other_chord.notes):
            for note_1, note_2 in zip(self.notes, other_chord.notes):
                if isinstance(note_1.event, Rest) or isinstance(
                        note_2.event, Rest):
                    return False
                pitch_1 = note_1.pitch.dump()
                pitch_2 = note_2.pitch.dump()
                if len(pitch_1) == len(pitch_2):
                    for i in range(1, len(pitch_1)):
                        if pitch_1[i].value != pitch_2[i].value:
                            return False
                    return True
        return False

    def inverse(self):
        intervals = xToD([midi.value for midi in self.midis])
        intervals = [-interval for interval in intervals]
        self.midis = dToX(intervals, first_element=self.midis[0].value)

    def split(self, *ratios):
        if len(ratios) == 1:
            ratios = ratios[0]

        new_ratios = [
            Fraction(Fraction(ratio), Fraction(sum(ratios)))
            for ratio in ratios
        ]

        old_duration = self.quarter_duration

        self.quarter_duration *= new_ratios[0]

        new_chords = [
            self.split_copy(quarter_duration=ratio * old_duration)
            for ratio in new_ratios[1:]
        ]
        for ch in new_chords:
            ch.tie_orientation = self.tie_orientation

        if 'start' in self.tie_types:
            new_chords[-1].add_tie('start')

        if not self.is_adjoinable:
            self.is_adjoinable = True
            new_chords[-1].is_adjoinable = False

        for tremolo in self.tremoli:
            new_chords[-1].add_tremolo(number=tremolo.value)

        new_chords.insert(0, self)

        if self.midis[0].value != 0:
            for new_chord in new_chords[1:]:
                new_chord.add_tie('stop')

            for new_chord in new_chords[:-1]:
                new_chord.add_tie('start')

        return new_chords

    def to_rest(self):
        self.midis = [0]
        self.remove_tie('stop')
        self.remove_tie('start')
        for notation in self.get_children_by_type(Notations):
            articulations = notation.get_children_by_type(Articulations)
            for articulation in articulations:
                notation.remove_child(articulation)

    def transpose(self, interval):
        for midi in self.midis:
            if midi.value != 0:
                midi.value += interval

    def untie(self):
        if 'start' in self.tie_types:
            self.remove_tie('start')
            try:
                self.next.remove_tie('stop')
            except AttributeError:
                pass

    # //copy

    def tremolo_chord_copy(self):
        new_chord = self.split_copy(quarter_duration=0)
        # new_chord = TreeChord()
        # new_chord.midis = self.midis
        # new_chord.manual_staff_number = self.manual_staff_number
        return new_chord

    def split_copy(self, quarter_duration):
        new_chord = TreeChord(quarter_duration=quarter_duration)

        new_chord.midis = self.midis
        new_chord.parent_tree_part_voice = self.parent_tree_part_voice
        new_chord.parent_beat = self.parent_beat

        if self._flags is not None:
            new_chord._flags = []
            for flag in self._flags:
                new_chord._flags.append(flag.__deepcopy__())

        new_chord._offset = None
        new_chord.is_finger_tremolo = self.is_finger_tremolo
        for grace_chord in self.get_post_grace_chords():
            new_chord.add_grace_chords(grace_chord.__deepcopy__(), mode='post')

        try:
            voice = self.get_children_by_type(Voice)[0]
            new_chord.add_child(voice)
        except IndexError:
            pass

        try:
            staff = self.get_children_by_type(StaffElement)[0]
            new_chord.add_child(staff)
        except IndexError:
            pass

        try:
            stem = self.get_children_by_type(Stem)[0]
            new_chord.add_child(stem)
        except IndexError:
            pass

        try:
            notehead = self.get_children_by_type(Notehead)[0]
            new_chord.add_child(notehead)
        except IndexError:
            pass

        return new_chord

    def deepcopy_for_SimpleFormat(self):
        new_chord = TreeChord(quarter_duration=self.quarter_duration,
                              zero_mode=self.zero_mode)
        new_chord.midis = [midi.__deepcopy__() for midi in self.midis]
        for child in self.get_children():
            if not isinstance(child, Voice):
                new_chord.add_child(child)
        for grace_chord in self.get_pre_grace_chords():
            new_chord.add_grace_chords(grace_chord.deepcopy_for_SimpleFormat())
        for grace_chord in self.get_post_grace_chords():
            new_chord.add_grace_chords(
                grace_chord.deepcopy_for_SimpleFormat().__deepcopy__(), 'post')
        return new_chord

    def __deepcopy__(self, memodict={}):
        new_chord = TreeChord(quarter_duration=self.quarter_duration,
                              zero_mode=self.zero_mode)
        new_chord.midis = [midi.__deepcopy__() for midi in self.midis]
        for child in self.get_children():
            if isinstance(child, Notations):
                copied_notations = Notations()
                for grand_child in child.get_children():
                    copied_notations.add_child(grand_child)
                new_chord.add_child(copied_notations)
            else:
                new_chord.add_child(child)

        new_chord.is_adjoinable = self.is_adjoinable
        if self._flags:
            new_chord._flags = []
            for flag in self._flags:
                new_chord._flags.append(flag.__deepcopy__())

        new_chord._flags = self._flags
        new_chord._manual_type = self._manual_type
        new_chord._manual_staff_number = self._manual_staff_number
        new_chord.tie_orientation = self.tie_orientation

        for grace_chord in self.get_pre_grace_chords():
            new_chord.add_grace_chords(grace_chord.__deepcopy__())

        for grace_chord in self.get_post_grace_chords():
            new_chord.add_grace_chords(grace_chord.__deepcopy__(), 'post')
        return new_chord
예제 #18
0
class Measure(XMLElement, MeasureAttributes):
    _DTD = Sequence(GroupReference(MusicData))

    def __init__(self, number=None, *args, **kwargs):
        super().__init__(tag='measure', number=number, *args, **kwargs)
예제 #19
0
                    min_occurrence=0
                ),
                Element(Text)
                ,
                min_occurrence=0,
                max_occurrence=None
            ),
            Element(Extend, min_occurrence=0)
        ),
        Element(Extend),
        Element(Laughing),
        Element(Humming)
    ),
    Element(EndLine, min_occurrence=0),
    Element(EndParagraph, min_occurrence=0),
    GroupReference(Editorial)
)

note_dtd = Sequence(
    Choice(
        Sequence(
            Element(Grace),
            Choice(
                Sequence(
                    GroupReference(FullNote)
                ),
                Sequence(
                    GroupReference(FullNote),
                    Element(Tie, 0, 2)
                ),
                Sequence(
예제 #20
0
class Part(XMLElement, PartAttributes):
    _DTD = Sequence(GroupReference(MusicData))

    def __init__(self, id, *args, **kwargs):
        super().__init__(tag='part', id=id, *args, **kwargs)
예제 #21
0
class ComplexTypeLyric(ComplexType, Justify, Position, Placement, Color,
                       PrintObject, TimeOnly, OptionalUniqueId):
    """The lyric type represents text underlays for lyrics, based on Humdrum with support for other formats. Two text
    elements that are not separated by an elision element are part of the same syllable, but may have different text
    formatting. The MusicXML XSD is more strict than the DTD in enforcing this by disallowing a second syllabic element
    unless preceded by an elision element. The lyric number indicates multiple lines, though a name can be used as well
    (as in Finale's verse / chorus / section specification).

    Justification is center by default; placement is below by default. The print-object attribute can override a note's
    print-lyric attribute in cases where only some lyrics on a note are printed, as when lyrics for later verses are
    printed in a block of text rather than with each note. The time-only attribute precisely specifies which lyrics are
    to be sung which time through a repeated section.
    """

    # todo: sorting mixed Sequence with min_occurrence = 0 and max_occurrence = None and check_occurrence.
    #  Syllabic doubled by sort
    _DTD = Sequence(
        Choice(
            Sequence(
                Element(Syllabic, min_occurrence=0),
                Element(Text),
                # Sequence(
                #     Sequence(
                #         Element(Elision),
                #         Element(Syllabic, min_occurrence=0),
                #         min_occurrence=0
                #     ),
                #     Element(Text)
                #     # ,
                #     # min_occurrence=0,
                #     # max_occurrence=None
                # ),
                Element(Extend, min_occurrence=0)),
            Element(Extend),
            Element(Laughing),
            Element(Humming)),
        Element(EndLine, min_occurrence=0),
        Element(EndParagraph, min_occurrence=0),
        GroupReference(Editorial))

    def __init__(self, tag, number='1', *args, **kwargs):
        super().__init__(tag=tag, *args, **kwargs)
        self.number = number

    @property
    def number(self):
        return self.get_attribute('number')

    @number.setter
    def number(self, value):
        if value is None:
            self.remove_attribute('number')
        else:
            Token(value)
            self._ATTRIBUTES.insert(0, 'number')
            self.set_attribute('number', value)

    @property
    def name(self):
        return self.get_attribute('name')

    @name.setter
    def name(self, value):
        if value is None:
            self.remove_attribute('name')
        else:
            Token(value)
            self._ATTRIBUTES.insert(0, 'name')
            self.set_attribute('name', value)
예제 #22
0
    _TAG = 'top-margin'

    def __init__(self, value=None, *args, **kwargs):
        super().__init__(tag=self._TAG, value=value, *args, **kwargs)


class BottomMargin(XMLElement, TypeTenths):
    _TAG = 'bottom-margin'

    def __init__(self, value=None, *args, **kwargs):
        super().__init__(tag=self._TAG, value=value, *args, **kwargs)


"""
The left-right-margins group specifies horizontal margins in tenths.
"""

LeftRightMargins = Sequence(
    Element(LeftMargin),
    Element(RightMargin)
)

"""
The all-margins group specifies both horizontal and vertical margins in tenths.
"""
AllMargins = Sequence(
    GroupReference(LeftRightMargins),
    Element(TopMargin),
    Element(BottomMargin)
)
예제 #23
0
    )
)

# seq4 = GroupReference(FullNote)

# seq4 = Sequence(
#     Element(Chord, min_occurrence=0),
#     Choice(
#         Element(Pitch),
#         Element(Unpitched),
#         Element(Rest)
#     )
# )

seq4 = Sequence(
    GroupReference(FullNote)
)

seq5 = Choice(
    Sequence(
        GroupReference(FullNote),
        Element(Tie, 0, 2)
    )
)

seq6 = Sequence(
    Element(Grace),
    Choice(
        Sequence(
            GroupReference(FullNote)
        ),