def glyph_to_element(classifier, glyph, surface): ''' Translates a glyph as output by the pitchfinder into an MEI element, registering bounding boxes in the given surface. Currently the assumption is that no MEI information in the given classifier is more than one level deep - that is, everything is either a single element (clef, custos) or the child of a single element (neumes). ''' name = str(glyph['name']) try: xml = classifier[name] except KeyError: print('entry {} not found in classifier table!'.format(name)) return None # remove everything up to the first dot in the name of the glyph try: name = name[:name.index('.')] except ValueError: pass # if this is an element with no children, then just apply a pitch and position to it if not list(xml): return create_primitive_element(xml, glyph, surface) # else, this element has at least one child (is a neume) ncs = list(xml) els = [create_primitive_element(nc, glyph, surface) for nc in ncs] parent = MeiElement(xml.tag) parent.setChildren(els) if len(els) < 2: return parent # if there's more than one element, must resolve intervals between ncs for i in range(1, len(els)): prev_nc = parent.children[i - 1] cur_nc = parent.children[i] new_pname, new_octave = resolve_interval(prev_nc, cur_nc) cur_nc.addAttribute('pname', new_pname) cur_nc.addAttribute('oct', new_octave) cur_nc.removeAttribute('intm') return parent
def neumify(self, ids, type_id, liquescence, 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)] ''' # need to determine how to encode these different types of liquescence in the MEI document if liquescence: if liquescence == "alt": attrs.append(MeiAttribute("variant", "liquescence")) elif liquescence == "aug": attrs.append(MeiAttribute("variant", "liquescence_aug")) elif liquescence == "dim": attrs.append(MeiAttribute("variant", "liquescence_dim")) ''' 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
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