Ejemplo n.º 1
0
    def test_name_value_copy_constructor(self):
        a = MeiAttribute("pname", "c")
        b = MeiAttribute(a)

        b.value = "d"

        self.assertEqual(b.name, a.name)
        self.assertNotEqual(b.value, a.value)
Ejemplo n.º 2
0
    def update_neume_head_shape(self, id, shape, ulx, uly, lrx, lry):
        """
        Update the head shape of the given punctum.
        Update bounding box, if it has changed.
        Update neume name, if the new head shape changes the name.
        """

        neume = self.mei.getElementById(id)

        nc = neume.getChildrenByName("nc")[0]

        if shape == "punctum":
            neume_name = "punctum"
            nc.setAttributes([])
        elif shape == "punctum_inclinatum":
            neume_name = "punctum"
            attrs = [MeiAttribute("inclinatum", "true")]
            nc.setAttributes(attrs)
        elif shape == "punctum_inclinatum_parvum":
            neume_name = "punctum"
            attrs = [
                MeiAttribute("inclinatum", "true"),
                MeiAttribute("deminutus", "true")
            ]
            nc.setAttributes(attrs)
        elif shape == "quilisma":
            neume_name = "punctum"
            attrs = [MeiAttribute("quilisma", "true")]
            nc.setAttributes(attrs)
        elif shape == "virga":
            neume_name = "virga"
            nc.setAttributes([])
        elif shape == "cavum":
            neume_name = "cavum"
            nc.setAttributes([])
        elif shape == "tractulus":
            neume_name = "tractulus"
            nc.setAttributes([])
        elif shape == "gravis":
            neume_name = "gravis"
            nc.setAttributes([])
        elif shape == "oriscus":
            neume_name = "oriscus"
            nc.setAttributes([])
        elif shape == "stropha":
            neume_name = "stropha"
            nc.setAttributes([])

        neume.addAttribute("name", neume_name)

        self.update_or_add_zone(neume, ulx, uly, lrx, lry)
Ejemplo n.º 3
0
    def getMEIContent(self, dumpVisualization=False):
        """Extract zones and neumes from the source file"""

        neumeElements = []
        zones = []

        for elem in etree.parse(
                self.xmlFile).xpath('/gamera-database/glyphs/glyph'):
            # Get the relevant attributes from the glyph element
            startX = int(elem.get('ulx'))
            endX = startX + int(elem.get('ncols'))

            startY = int(elem.get('uly'))
            endY = startY + int(elem.get('nrows'))

            curNeumeName = elem.xpath('string(./ids/id/@name)')

            # Create the MEI neume element
            newNeumeElement = MeiElement('neume')
            neumeElements.append(newNeumeElement)

            newNeumeElement.id = generate_MEI_ID()

            splitName = curNeumeName[curNeumeName.find(".") + 1:]
            if (splitName in self.neumeNames):
                newNeumeElement.addAttribute(
                    MeiAttribute('name', self.neumeNames[splitName]))
            elif len(splitName) < 3:
                newNeumeElement.addAttribute(
                    MeiAttribute('name', "Letter " + splitName.upper()))
            else:
                newNeumeElement.addAttribute(MeiAttribute('name', splitName))

            zoneID = generate_MEI_ID()
            newNeumeElement.addAttribute(MeiAttribute('facs', zoneID))
            zones.append(Zone(zoneID, startX, startY, endX, endY))

        zoneElements = []

        for zone in self._sortZones(zones,
                                    dumpVisualization=dumpVisualization):
            newZoneElement = MeiElement('zone')
            zoneElements.append(newZoneElement)

            newZoneElement.id = zone.id
            newZoneElement.addAttribute(MeiAttribute('ulx', str(zone.startX)))
            newZoneElement.addAttribute(MeiAttribute('uly', str(zone.startY)))
            newZoneElement.addAttribute(MeiAttribute('lrx', str(zone.endX)))
            newZoneElement.addAttribute(MeiAttribute('lry', str(zone.endY)))

        return zoneElements, neumeElements
Ejemplo n.º 4
0
def switch_tie(meifile, tstamp=False, keep_id=False):
    ''' Changes all ties expressed with attributes into elements. 
    If tstamp is set, it will attempt to generate tstamps instead of startid/endid pairs.
    
    @TODO
    At some point search() will support
    passing in args will narrow down the search by only retrieving objects with that attribute.
    Make sure to update this function when that happens 
    '''

    meifile_flat = meifile.getFlattenedTree()

    for n in meifile_flat:
        if n.hasAttribute('tie'):
            if n.getAttribute("tie").value == 'i' or n.getAttribute(
                    "tie").value == 'm':  #one tie element for each tie!
                #get ancestor measure
                measure = n.getAncestor('measure')
                #create a tie element
                tie = MeiElement("tie")

                #determine attributes according to args
                # atts = {'xml:id': generate_mei_id()}
                atts = MeiAttributeList()
                if tstamp:
                    atts.append(
                        MeiAttribute("tstamp", str(time.id_to_tstamp(n))))
                    # atts['tstamp'] =  time.id_to_tstamp(n)
                if keep_id or (not keep_id and not tstamp):
                    atts.append(MeiAttribute("startid", n.id))
                    # atts['startid'] = n.id

                #add attributes to tie
                tie.attributes = atts

                #add tie to measure
                measure.addChild(tie)
        #remove tie attribute
        n.removeAttribute('tie')
Ejemplo n.º 5
0
    def test_pushtoattributes(self):
        m = MeiElement('mei')
        m.addAttribute('foo', '1')
        m.addAttribute('bar', '2')
        m.addAttribute('baz', '3')

        attrs = m.getAttributes()

        new = MeiAttribute('hi', 'there')

        attrs.push(new)

        self.assertEqual('there', attrs[0].value)
        self.assertEqual(4, len(attrs))
Ejemplo n.º 6
0
 def test_newattrobj(self):
     el = MeiElement("mei")
     at = MeiAttribute("meiversion", "2012")
     el.addAttribute(at)
     self.assertTrue(el.hasAttribute("meiversion"))
Ejemplo n.º 7
0
    def processContigRange(self, ema_range):
        """ Process a contigous range of measures give an MEI doc and an
            EmaExpression.EmaMeasureRange object """

        # get all the spanners for total extension of meaure selection
        # (including gap measures, if present)
        # NB: Doing this for every range may be inefficient for larger files
        spanners = self.getMultiMeasureSpanners(ema_range.measures[0].idx - 1,
                                                ema_range.measures[-1].idx - 1)

        # Let's start with measures
        for i, ema_m in enumerate(ema_range.measures):

            is_first_m = i == 0
            is_last_m = i == len(ema_range.measures) - 1

            # Get requested measure
            measure = self.measures[ema_m.idx - 1]
            events = measure.getChildren()

            # determine current measure beat info
            meter = None
            for change in self.timeChanges:
                if int(change) + 1 <= ema_m.idx:
                    meter = self.beatsInfo[change]

            # Get list of staff numbers in current measure
            sds = [
                int(sd.getAttribute("n").getValue())
                for sd in measure.getClosestStaffDefs()
            ]

            # Set aside selected staff numbers
            s_nos = []

            # Proceed to locate requested staves
            for ema_s in ema_m.staves:
                if ema_s.number not in sds:
                    # CAREFUL: there may be issues with "silent" staves
                    # that may be defined by missing from current measure.
                    # TODO: Write test, fix.
                    raise BadApiRequest("Requested staff is not defined")
                s_nos.append(ema_s.number)

            for s_i, staff in enumerate(measure.getChildrenByName("staff")):
                s_no = s_i
                if staff.hasAttribute("n"):
                    s_no = int(staff.getAttribute("n").getValue())

                if s_no in s_nos:
                    ema_s = ema_m.staves[s_nos.index(s_no)]

                    # Get other elements affecting the staff, e.g. slurs
                    around = []

                    for el in list(events):
                        if self._isInStaff(el, s_no):
                            around.append(el)

                    # Create sets of elements marked for selection, removal and
                    # cutting. Elements are not removed or cut immediately to make
                    # sure that beat calcualtions are accurate.
                    marked_as_selected = MeiElementSet()
                    marked_as_space = MeiElementSet()
                    marked_for_removal = MeiElementSet()
                    marked_for_cutting = MeiElementSet()

                    # Now locate the requested beat ranges within the staff
                    for b_i, ema_beat_range in enumerate(ema_s.beat_ranges):

                        is_first_b = i == 0
                        is_last_b = i == len(ema_s.beat_ranges) - 1

                        def _remove(el):
                            """ Determine whether a removed element needs to
                            be converted to a space or removed altogether"""
                            if is_last_b and is_last_m:
                                marked_for_removal.add(el)
                            else:
                                marked_as_space.add(el)

                        # shorten them names
                        tstamp_first = ema_beat_range.tstamp_first
                        tstamp_final = ema_beat_range.tstamp_final
                        co = self.ema_exp.completenessOptions

                        # check that the requested beats actually fit in the meter
                        if tstamp_first > int(meter["count"])+1 or \
                           tstamp_final > int(meter["count"])+1:
                            raise BadApiRequest(
                                "Request beat is out of measure bounds")

                        # Find all descendants with att.duration.musical (@dur)
                        for layer in staff.getDescendantsByName("layer"):
                            cur_beat = 1.0
                            is_first_match = True

                            for el in layer.getDescendants():

                                if el.hasAttribute(
                                        "dur"
                                ) and not el.hasAttribute("grace"):
                                    dur = self._calculateDur(el, meter)
                                    # TODO still problems with non-consecutive beat ranges
                                    # e.g. @1@3
                                    # exclude descendants at and in between tstamps
                                    if cur_beat >= tstamp_first:
                                        # We round to 4 decimal places to avoid issues caused by
                                        # tuplet-related calculations, which are admittedly not
                                        # well expressed in floating numbers.
                                        if round(cur_beat, 4) <= round(
                                                tstamp_final, 4):
                                            marked_as_selected.add(el)
                                            if is_first_match and "cut" in co:
                                                marked_for_cutting.add(el)
                                                is_first_match = False

                                            # discard from removal set if it had
                                            # been placed there from other beat
                                            # range
                                            marked_as_space.discard(el)

                                            # Cut the duration of the last element
                                            # if completeness = cut
                                            needs_cut = cur_beat + dur > tstamp_final + 1
                                            if needs_cut and "cut" in co:
                                                marked_for_cutting.add(el)
                                                is_first_match = False
                                        elif not marked_as_selected.get(el):
                                            _remove(el)
                                    elif not marked_as_selected.get(el):
                                        marked_as_space.add(el)

                                    # continue
                                    cur_beat += dur

                        # select elements affecting the staff occurring
                        # within beat range
                        for event in around:
                            if not marked_as_selected.get(event):
                                if event.hasAttribute("tstamp"):
                                    ts = float(
                                        event.getAttribute(
                                            "tstamp").getValue())
                                    if ts < 1 and "cut" not in self.ema_exp.completenessOptions:
                                        ts = 1
                                    ts2_att = None
                                    if event.hasAttribute("tstamp2"):
                                        ts2_att = event.getAttribute("tstamp2")
                                    if ts > tstamp_final or (
                                            not ts2_att and ts < tstamp_first):
                                        marked_for_removal.add(event)
                                    elif ts2_att:
                                        ts2 = ts2_att.getValue()
                                        if "+" not in ts2:
                                            if ts2 < tstamp_first:
                                                marked_for_removal.add(event)
                                            elif ts2 == tstamp_final:
                                                marked_as_selected.add(event)
                                                marked_for_removal.discard(
                                                    event)
                                            if ts < tstamp_first and ts2 >= tstamp_final:
                                                marked_as_selected.add(event)
                                                marked_for_removal.discard(
                                                    event)
                                            else:
                                                marked_for_removal.add(event)
                                        else:
                                            marked_as_selected.add(event)
                                    else:
                                        marked_as_selected.add(event)

                                elif event.hasAttribute("startid"):
                                    startid = (event.getAttribute(
                                        "startid").getValue().replace("#", ""))
                                    target = self.doc.getElementById(startid)
                                    if not target:
                                        msg = """Unsupported Encoding: attribute
                                        startid on element {0} does not point to any
                                        element in the document.""".format(
                                            event.getName())
                                        raise UnsupportedEncoding(
                                            re.sub(r'\s+', ' ', msg.strip()))
                                    # Make sure the target event is in the same measure
                                    event_m = event.getAncestor(
                                        "measure").getId()
                                    target_m = target.getAncestor(
                                        "measure").getId()
                                    if not event_m == target_m:
                                        msg = """Unsupported Encoding: attribute
                                        startid on element {0} does not point to an
                                        element in the same measure.""".format(
                                            event.getName())
                                        raise UnsupportedEncoding(
                                            re.sub(r'\s+', ' ', msg.strip()))
                                    else:
                                        if marked_as_selected.get(target):
                                            marked_as_selected.add(event)
                                            marked_for_removal.discard(event)
                                        elif not event.hasAttribute("endid"):
                                            marked_for_removal.add(event)
                                        else:
                                            # Skip if event starts after latest
                                            # selected element with duration
                                            pos = target.getPositionInDocument(
                                            )
                                            is_ahead = False
                                            for i in reversed(
                                                    marked_as_selected.
                                                    getElements()):
                                                if i.hasAttribute("dur"):
                                                    if pos > i.getPositionInDocument(
                                                    ):
                                                        marked_for_removal.add(
                                                            event)
                                                        is_ahead = True
                                                    break

                                            if not is_ahead:
                                                # last chance to keep it:
                                                # must start before and end after
                                                # latest selected element with duration

                                                endid = (
                                                    event.getAttribute("endid")
                                                    .getValue().replace(
                                                        "#", ""))
                                                target2 = self.doc.getElementById(
                                                    endid)
                                                if marked_as_selected.get(
                                                        target2):
                                                    marked_as_selected.add(
                                                        event)
                                                    marked_for_removal.discard(
                                                        event)
                                                else:
                                                    pos2 = target2.getPositionInDocument(
                                                    )
                                                    for i in reversed(
                                                            marked_as_selected.
                                                            getElements()):
                                                        if i.hasAttribute(
                                                                "dur"):
                                                            if pos2 > i.getPositionInDocument(
                                                            ):
                                                                marked_as_selected.add(
                                                                    event)
                                                                marked_for_removal.discard(
                                                                    event)
                                                            else:
                                                                marked_for_removal.add(
                                                                    event)
                                                            break

                    # Remove elements marked for removal
                    if "highlight" not in self.ema_exp.completenessOptions:
                        for el in marked_for_removal:
                            el.getParent().removeChild(el)

                        # Replace elements marked as spaces with actual spaces,
                        # unless completion = nospace, then remove the elements.
                        for el in marked_as_space:
                            parent = el.getParent()
                            if "nospace" not in self.ema_exp.completenessOptions:
                                space = MeiElement("space")
                                space.setId(el.id)
                                space.addAttribute(el.getAttribute("dur"))
                                if el.getAttribute("dots"):
                                    space.addAttribute(el.getAttribute("dots"))
                                elif el.getChildrenByName("dot"):
                                    dots = str(len(
                                        el.getChildrenByName("dot")))
                                    space.addAttribute(
                                        MeiAttribute("dots", dots))
                                parent.addChildBefore(el, space)
                            el.getParent().removeChild(el)
                    else:
                        for el in marked_as_selected:
                            # add to list
                            if self.highlight_el:
                                cur_plist = self.highlight_el.getAttribute(
                                    "plist").getValue()
                                space = ""
                                if len(cur_plist) > 0:
                                    space = " "
                                val = cur_plist + space + "#" + el.getId()
                                self.highlight_el.addAttribute("plist", val)

                else:
                    if "highlight" not in self.ema_exp.completenessOptions:
                        # Remove this staff and its attached events
                        staff.getParent().removeChild(staff)

                        for el in list(events):
                            if self._isInStaff(el, s_no):
                                el.getParent().removeChild(el)

            # At the first measure, also add relevant multi-measure spanners
            # for each selected staff
            if is_first_m:
                if "highlight" not in self.ema_exp.completenessOptions:
                    for evs in spanners.values():
                        for event_id in evs:
                            ev = self.doc.getElementById(event_id)
                            # Spanners starting outside of beat ranges
                            # may be already gone
                            if ev:
                                # Determine staff of event for id changes
                                for ema_s in ema_m.staves:
                                    staff_no = self._isInStaff(
                                        ev, ema_s.number)

                                if staff_no and staff_no in s_nos:
                                    # If the event is attached to more than one staff, just
                                    # consider it attached to the its first one
                                    staff_no = staff_no[0]

                                    staff = None
                                    for staff_candidate in measure.getDescendantsByName(
                                            "staff"):
                                        if staff_candidate.hasAttribute("n"):
                                            n = int(
                                                staff_candidate.getAttribute(
                                                    "n").getValue())
                                            if n == staff_no:
                                                staff = staff_candidate

                                    # Truncate event to start at the beginning of the beat range
                                    if ev.hasAttribute("startid"):
                                        # Set startid to the first event still on staff,
                                        # at the first available layer
                                        try:
                                            layer = (staff.getChildrenByName(
                                                "layer"))
                                            first_id = layer[0].getChildren(
                                            )[0].getId()
                                            ev.getAttribute(
                                                "startid").setValue("#" +
                                                                    first_id)
                                        except IndexError:
                                            msg = """
                                                Unsupported encoding. Omas attempted to adjust the
                                                starting point of a selected multi-measure element
                                                that starts before the selection, but the staff or
                                                layer could not be located.
                                                """
                                            msg = re.sub(
                                                r'\s+', ' ', msg.strip())
                                            raise UnsupportedEncoding(msg)

                                    if ev.hasAttribute("tstamp"):
                                        # Set tstamp to first in beat selection
                                        tstamp_first = 0
                                        for e_s in ema_m.staves:
                                            if e_s.number == staff_no:
                                                tstamp_first = e_s.beat_ranges[
                                                    0].tstamp_first
                                        ev.getAttribute("tstamp").setValue(
                                            str(tstamp_first))

                                    # Truncate to end of range if completeness = cut
                                    # (actual beat cutting will happen when beat ranges are procesed)
                                    if "cut" in self.ema_exp.completenessOptions:
                                        if ev.hasAttribute("tstamp2"):
                                            att = ev.getAttribute("tstamp2")
                                            t2 = att.getValue()
                                            p = re.compile(r"([1-9]+)(?=m\+)")
                                            multimeasure = p.match(t2)
                                            if multimeasure:
                                                new_val = len(mm) - 1
                                                att.setValue(
                                                    p.sub(str(new_val), t2))

                                    # Otherwise adjust tspan2 value to correct distance.
                                    # E.g. given 4 measures with a spanner originating
                                    # in 1 and ending in 4 and a selection of measures 2 and 3,
                                    # change @tspan2 from 3m+X to 2m+X
                                    else:
                                        if ev.hasAttribute("tstamp2"):
                                            att = ev.getAttribute("tstamp2")
                                            t2 = att.getValue()
                                            p = re.compile(r"([1-9]+)(?=m\+)")
                                            multimeasure = p.match(t2)
                                            if multimeasure:
                                                dis = evs[event_id]["distance"]
                                                new_val = int(
                                                    multimeasure.group(
                                                        1)) - dis
                                                att.setValue(
                                                    p.sub(str(new_val), t2))

                                    # move element to first measure and add it to selected
                                    # events "around" the staff.
                                    ev.moveTo(measure)
                else:
                    # Add spanners to annotated selection
                    for evs in spanners.values():
                        for event_id in evs:
                            if self.highlight_el:
                                cur_plist = self.highlight_el.getAttribute(
                                    "plist").getValue()
                                space = ""
                                if len(cur_plist) > 0:
                                    space = " "
                                val = cur_plist + space + "#" + event_id
                                self.highlight_el.addAttribute("plist", val)

        return self.doc
Ejemplo n.º 8
0
    def neumify(self, ids, type_id, head_shapes, ulx, uly, lrx, lry):
        '''
        Neumify a group of neumes (with provided ids)
        and give it the given neume name. Also update
        bounding box information.
        '''
        # get neume name and variant from type id
        type_split = type_id.split(".")
        if type_split[-1].isdigit():
            type_split.pop()
        if len(type_split) == 1:
            attrs = [MeiAttribute("name", type_split[0])]
        else:
            variant = " ".join(type_split[1:])
            attrs = [
                MeiAttribute("name", type_split[0]),
                MeiAttribute("variant", variant)
            ]

        new_neume = MeiElement("neume")
        new_neume.setAttributes(attrs)
        ncs = []
        cur_nc = None

        iNote = 0
        for id in ids:
            ref_neume = self.mei.getElementById(str(id))
            if ref_neume:
                # get underlying notes
                notes = ref_neume.getDescendantsByName("note")
                for n in notes:
                    head = str(head_shapes[iNote])
                    # check if a new nc must be opened
                    if head == 'punctum' and cur_nc != 'punctum':
                        ncs.append(MeiElement("nc"))
                        cur_nc = head
                    elif head == 'punctum_inclinatum' and cur_nc != 'punctum_inclinatum':
                        new_nc = MeiElement("nc")
                        new_nc.addAttribute("inclinatum", "true")
                        ncs.append(new_nc)
                        cur_nc = head
                    elif head == 'punctum_inclinatum_parvum' and cur_nc != 'punctum_inclinatum_parvum':
                        new_nc = MeiElement("nc")
                        new_nc.addAttribute("inclinatum", "true")
                        new_nc.addAttribute("deminutus", "true")
                        ncs.append(new_nc)
                        cur_nc = head
                    elif head == 'quilisma' and cur_nc != 'quilisma':
                        new_nc = MeiElement("nc")
                        new_nc.addAttribute("quilisma", "true")
                        ncs.append(new_nc)
                        cur_nc = head
                    elif cur_nc is None:
                        ncs.append(MeiElement("nc"))
                        cur_nc = 'punctum'

                    ncs[-1].addChild(n)
                    iNote += 1

        new_neume.setChildren(ncs)

        # insert the new neume
        before = self.mei.getElementById(ids[0])
        parent = before.getParent()

        if before and parent:
            parent.addChildBefore(before, new_neume)

        # remove the old neumes from the mei document
        for id in ids:
            neume = self.mei.getElementById(str(id))
            if neume:
                # remove facs data
                facs = neume.getAttribute("facs")
                if facs:
                    facsid = facs.value
                    # Remove the zone if it exists
                    zone = self.mei.getElementById(str(facsid))
                    if zone and zone.name == "zone":
                        zone.parent.removeChild(zone)

                # now remove the neume
                neume.parent.removeChild(neume)

        # update bounding box data
        self.update_or_add_zone(new_neume, ulx, uly, lrx, lry)

        result = {"id": new_neume.getId()}
        return result
Ejemplo n.º 9
0
 def test_name_value_constructor(self):
     a = MeiAttribute("pname", "c")
     self.assertEqual("pname", a.name)
     self.assertEqual("c", a.value)
Ejemplo n.º 10
0
    def _initMEI(self):
        """Initialize a new MEI document

        Sets the attributes meiDoc, surface, and initLayer
        """

        self.meiDoc = MeiDocument()

        root = MeiElement("mei")
        root.id = generate_MEI_ID()
        self.meiDoc.root = root

        #needs meiHead here
        meiHead = MeiElement('meiHead')
        fileDesc = MeiElement('fileDesc')
        titleStmt = MeiElement('titleStmt')
        title = MeiElement('title')
        pubStmt = MeiElement('pubStmt')
        date = MeiElement('date')
        encodingDesc = MeiElement('encodingDesc')
        projectDesc = MeiElement('projectDesc')
        p = MeiElement('p')

        music = MeiElement('music')
        facsimile = MeiElement('facsimile')

        self.surface = MeiElement('surface')

        # Label the surface with the name of the input file, which could help
        # identify the original image
        label = os.path.basename(os.path.splitext(self.xmlFile)[0])
        self.surface.addAttribute(MeiAttribute('label', label))

        #systems get added to page
        #neumes get added to systems

        body = MeiElement('body')
        mdiv = MeiElement('mdiv')
        pages = MeiElement('pages')
        page = MeiElement('page')
        page.id = generate_MEI_ID()

        initSystem = MeiElement('system')
        initSystem.id = generate_MEI_ID()

        initStaff = MeiElement('staff')
        initStaff.id = generate_MEI_ID()

        self.initLayer = MeiElement('layer')
        self.initLayer.id = generate_MEI_ID()

        root.addChild(meiHead)
        meiHead.addChild(fileDesc)
        fileDesc.addChild(titleStmt)
        titleStmt.addChild(title)
        fileDesc.addChild(pubStmt)
        pubStmt.addChild(date)
        meiHead.addChild(encodingDesc)
        encodingDesc.addChild(projectDesc)
        projectDesc.addChild(p)

        root.addChild(music)
        music.addChild(facsimile)
        facsimile.addChild(self.surface)
        music.addChild(body)
        body.addChild(mdiv)
        mdiv.addChild(pages)
        pages.addChild(page)
        page.addChild(initSystem)
        initSystem.addChild(initStaff)
        initStaff.addChild(self.initLayer)