def __init__(self, incoming_data): self._recognition_results = incoming_data self.meidoc = mod.mei_() self.staff = None self.glyph = None self._note_elements = None self._neume_pitches = [] self._global_graphic_element = self._create_graphic_element("foo.jpg") self.meidoc.add_child(self._global_graphic_element) for snum, stf in self._recognition_results.iteritems(): self.staff = stf self.staffel = self._parse_staff(snum, stf) z = mod.zone_() z.id = self._idgen() z.attributes = { "ulx": self.staff["coord"][0], "uly": self.staff["coord"][1], "lrx": self.staff["coord"][2], "lry": self.staff["coord"][3], } self._global_graphic_element.add_child(z) self.staffel.facs = z.id self.meidoc.add_child(self.staffel) self.md = MeiDocument.MeiDocument() self.md.addelement(self.meidoc)
def _create_zone_element(self): zone = mod.zone_() zone.id = self._idgen() zone.attributes = {'ulx': self.glyph['coord'][0], 'uly': self.glyph['coord'][1], \ 'lrx': self.glyph['coord'][2], 'lry': self.glyph['coord'][3]} self.surface.add_child(zone) return zone
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.flat() for n in meifile_flat: if n.has_attribute('tie'): if n.tie=='i' or n.tie=='m': #one tie element for each tie! #get ancestor measure measure = n.ancestor_by_name('measure') #create a tie element tie = mod.tie_() #determine attributes according to args atts = {'xml:id':generate_mei_id()} if tstamp: atts['tstamp'] = time.id_to_tstamp(n) if keep_id or (not keep_id and not tstamp): atts['startid'] = n.id #add attributes to tie tie.attributes = atts #add tie to measure measure.add_child(tie) #remove tie attribute n.remove_attribute('tie')
def _create_custos_element(self): custos = mod.custos_() custos.id = self._idgen() zone = self._create_zone_element() custos.facs = zone.id custos.pitchname = self.glyph['strt_pitch'] return custos
def _create_clef_element(self): clef = mod.clef_() clef.id = self._idgen() zone = self._create_zone_element() clef.facs = zone.id clef.attributes = {"line": self.glyph['strt_pos'], 'shape': self.glyph['form'][0].upper() } return clef
def _create_division_element(self): division = mod.division_() division.id = self._idgen() zone = self._create_zone_element() division.facs = zone.id if self.glyph['form']: division.attributes = {'form': self.glyph['form'][0]} return division
def _create_zone_element(self): zone = mod.zone_() zone.id = self._idgen() zone.attributes = { "ulx": self.glyph["coord"][0], "uly": self.glyph["coord"][1], "lrx": self.glyph["coord"][2], "lry": self.glyph["coord"][3], } self._global_graphic_element.add_child(zone) return zone
def _create_alteration_element(self): accid = mod.accid_() accid.id = self._idgen() if self.glyph['form'] is "sharp": accid.attributes = {"accid": "s"} elif self.glyph['form'] is "flat": accid.attributes = {"accid": "f"} zone = self._create_zone_element() note.facs = zone.id return accid
def add_text_lines(hocrfile, surface, section): """ helper method that adds lines in hocr file to 'surface' and 'section' in mei file """ div=mod.div_() div.id=generate_mei_id() lg=mod.lg_() lg.id=generate_mei_id() section.add_child(div) div.add_child(lg) for line in getlines(hocrfile): # for each line: make new zone and l objects, add zone to surface zone=mod.zone_() zone.id=generate_mei_id() zone.ulx=line['bbox'][0] zone.uly=line['bbox'][1] zone.lrx=line['bbox'][2] zone.lry=line['bbox'][3] l=mod.l_() l.id=generate_mei_id() l.facs=zone.id l.value=correct_text(line) lg.add_child(l) surface.add_child(zone)
def _create_staff_element(self): staff = mod.staff_() staff.id = self._idgen() return staff
def _create_neume_element(self): if "climacus" in self.glyph["form"]: neume = mod.ineume_() else: neume = mod.uneume_() neume.id = self._idgen() zone = self._create_zone_element() neume.facs = zone.id neume.attributes = {"name": self.glyph["form"][0]} # get the form so we can find the number of notes we need to construct. try: # since we define the form of the intervals, we're always off-by-one in the number of notes. num_notes = len(self.NEUME_NOTES[self.glyph["form"][0]]) + 1 except KeyError: raise GameraMeiFormNotFoundError("The form {0} was not found.".format(self.glyph["form"][0])) # do we need to add any further notes? form is pretty loaded, so we # have to check manually, from idx 1 on (since the primary form is always first) # we don't have an off-by-one problem here, since an added interval means an added note check_additional = [i for i in self.ADD_NOTES.keys() if i in self.glyph["form"][1:]] num_notes = num_notes + len(check_additional) self._neume_pitches = [] # note elements are everything after the first form. This determines the shape a note takes. self._note_elements = self.glyph["form"][1:] self._neume_pitches.append(self.glyph["strt_pitch"]) nc = [] if num_notes > 1: # we need to figure out the rest of the pitches in the neume. ivals = [int(d) for d in self._note_elements if d.isdigit()] try: idx = self.SCALE.index(self.glyph["strt_pitch"].upper()) except ValueError: raise GameraMeiPitchNotFoundError( "The pitch {0} was not found in the scale".format(self.glyph["strt_pitch"]) ) if len(ivals) != (num_notes - 1): raise GameraMeiNoteIntervalMismatchError( "There is a mismatch between the number of notes and number of intervals." ) # note elements = torculus.2.2.he.ve # ivals = [2,2] # torculus = ['u','d'] lg.debug(ivals) for n in xrange(len(ivals)): # get the direction dir = self.NEUME_NOTES[self.glyph["form"][0]][n] lg.debug("direction is {0}".format(dir)) iv = ivals[n] n_idx = idx lg.debug("index: {0}".format(idx)) if dir == "u": if (idx + (iv - 1)) >= len(self.SCALE): n_idx = 0 + (iv - 1) else: n_idx = idx + (iv - 1) elif dir == "d": if idx - (iv - 1) < 0: n_idx = len(self.SCALE) + (idx - (iv - 1)) else: n_idx = idx - (iv - 1) idx = n_idx lg.debug("Picking pitch {0}".format(self.SCALE[n_idx])) self._neume_pitches.append(self.SCALE[n_idx]) for n in xrange(num_notes): p = self._neume_pitches[n] nc.append(self._create_note_element(p)) neume.add_children(nc) lg.debug(neume.children) return neume
def _create_clef_element(self): clef = mod.clef_() clef.id = self._idgen() zone = self._create_zone_element() clef.facs = zone.id return clef
def _create_dot_element(self): dot = mod.dot_() dot.id = self._idgen() dot.attributes = {"form": "aug"} return dot
def _create_neume_element(self): full_width_episema = False has_dot = False has_vertical_episema = False has_horizontal_episema = False has_quilisma = False this_neume_form = None local_horizontal_episema = None start_octave = self.glyph['octv'] clef_pos = self.glyph['clef_pos'] clef_type = self.glyph['clef'].split(".")[-1] # f or c. neume = mod.neume_() neume.id = self._idgen() zone = self._create_zone_element() neume.facs = zone.id neumecomponent = mod.nc_() neumecomponent.id = self._idgen() neume.add_child(neumecomponent) if self.glyph['form'][0] == "he": full_width_episema = True del self.glyph['form'][0] # we've removed any global he's, so # any leftovers should be local. if 'he' in self.glyph['form']: has_horizontal_episema = True if 'dot' in self.glyph['form']: has_dot = True if 'q' in self.glyph['form']: has_quilisma = True if 've' in self.glyph['form']: has_vertical_episema = True if 'inclinatum' in self.glyph['form']: neumecomponent.attributes = {'inclinatum': 'true'} neume.attributes = {'name': self.glyph['form'][0]} if 'compound' in self.glyph['form']: # do something and create a new set of pitch contours this_neume_form = [y for y in (self.__parse_contour(n) for n in self.glyph['form']) if y] self._note_elements = [y for y in (self.__parse_steps(n) for n in self.glyph['form']) if y] else: this_neume_form = copy.deepcopy(self.NEUME_NOTES[self.glyph['form'][0]]) self._note_elements = self.glyph['form'][1:] # get the form so we can find the number of notes we need to construct. num_notes = len(this_neume_form) + 1 # we don't have an off-by-one problem here, since an added interval means an added note check_additional = [i for i in self.ADD_NOTES.keys() if i in self.glyph['form'][1:]] if check_additional: for f in check_additional: this_neume_form.extend(self.ADD_NOTES[f]) ## THIS SHOULD BE CHANGED. Otherwise we may end up with two attributes with the # same name. neume.attributes = {"variant": f} num_notes = num_notes + len(check_additional) self._neume_pitches = [] # note elements are everything after the first form. This determines the shape a note takes. self._neume_pitches.append(self.glyph['strt_pitch']) nc = [] note_octaves = [start_octave] if num_notes > 1: # we need to figure out the rest of the pitches in the neume. ivals = [int(d) for d in self._note_elements if d.isdigit()] try: idx = self.SCALE.index(self.glyph['strt_pitch']) except ValueError: raise AomrMeiPitchNotFoundError("The pitch {0} was not found in the scale".format(self.glyph['strt_pitch'])) if len(ivals) != (num_notes - 1): if 'scandicus' in self.glyph['form']: diffr = abs(len(ivals) - (num_notes - 1)) num_notes = num_notes + diffr this_neume_form.extend(diffr * 'u') else: raise AomrMeiNoteIntervalMismatchError("There is a mismatch between the number of notes and number of intervals.") # note elements = torculus.2.2.he.ve # ivals = [2,2] # torculus = ['u','d'] this_pos = copy.deepcopy(self.glyph['strt_pos']) for n in xrange(len(ivals)): # get the direction dir = this_neume_form[n] iv = ivals[n] n_idx = idx if dir == "u": n_idx = ((idx + iv) % len(self.SCALE)) - 1 this_pos -= (iv - 1) elif dir == "d": n_idx = idx - (iv -1) this_pos += (iv - 1) if n_idx < 0: n_idx += len(self.SCALE) idx = n_idx self._neume_pitches.append(self.SCALE[n_idx]) actual_line = 10 - (2*(clef_pos-1)) if clef_type == "c": if this_pos <= actual_line: note_octaves.append(4) elif this_pos > actual_line + 7: note_octaves.append(2) else: note_octaves.append(3) elif clef_type == "f": if (actual_line + 3) >= this_pos > (actual_line - 3): note_octaves.append(3) elif this_pos < (actual_line - 3): note_octaves.append(4) elif this_pos > (actual_line + 3): note_octaves.append(2) if full_width_episema is True: epi = self._create_episema_element() epi.attributes = {"form": "horizontal"} self.layer.add_child(epi) qidxs = [] if has_quilisma: self.__note_addition_figurer_outer("q", qidxs) dotidxs = [] if has_dot: self.__note_addition_figurer_outer("dot", dotidxs) veidxs = [] if has_vertical_episema: self.__note_addition_figurer_outer("ve", veidxs) heidxs = [] if has_horizontal_episema: self.__note_addition_figurer_outer("he", heidxs) for n in xrange(num_notes): p = self._neume_pitches[n] o = note_octaves[n] nt = self._create_note_element(p) nt.attributes = {"oct": o} if n == 0 and full_width_episema is True: epi.attributes = {"startid": nt.id} elif n == num_notes and full_width_episema is True: epi.attributes = {"endid": nt.id} if has_quilisma: if n in qidxs: neumecomponent.attributes = {"quilisma": "true"} if has_dot: if n in dotidxs: d = self._create_dot_element() nt.add_child(d) if has_vertical_episema: if n in veidxs: ep = self._create_episema_element() ep.attributes = {"form": "vertical", "startid": nt.id} self.layer.add_child(ep) if has_horizontal_episema: if n in heidxs: local_horizontal_episema = self._create_episema_element() local_horizontal_episema.attributes = {"form": "horizontal", "startid": nt.id} self.layer.add_child(local_horizontal_episema) if n == num_notes - 1 and local_horizontal_episema: # we've reached the end, and we have an HE we need to close up. local_horizontal_episema.attributes = {"endid": nt.id} nc.append(nt) neumecomponent.add_children(nc) return neume
def _create_system_element(self): system = mod.system_() system.id = self._idgen() return system
def _create_layout_element(self): layout = mod.layout_() layout.id = self._idgen() return layout
def _create_graphic_element(self, imgfile): graphic = mod.graphic_() graphic.id = self._idgen() graphic.attributes = {'xlink:href': imgfile} return graphic
def create_mei(filename): # build new mei file meifile=MeiDocument.MeiDocument() mei=mod.mei_() # header meihead=mod.meihead_() filedesc=mod.filedesc_() titlestmt=mod.titlestmt_() title=mod.title_() pubstmt=mod.pubstmt_() meihead.add_child(filedesc) filedesc.add_children([titlestmt, pubstmt]) titlestmt.add_child(title) # music - facsimile, layout, body music=mod.music_() facsimile=mod.facsimile_() facsimile.id=generate_mei_id() surface=mod.surface_() surface.id=generate_mei_id() graphic=mod.graphic_() graphic.id=generate_mei_id() graphic.attributes={'xlink:href':'%s_original_image.tiff' % (filename,)} facsimile.add_child(surface) surface.add_child(graphic) layout=mod.layout_() layout.id=generate_mei_id() page=mod.page_() page.id=generate_mei_id() page.attributes={'n':filename} layout.add_child(page) body=mod.body_() mdiv=mod.mdiv_() mdiv.attributes={'type':'solesmes'} score=mod.score_() section=mod.section_() pb=mod.pb_() pb.id=generate_mei_id() pb.attributes={'pageref':page.id} body.add_child(mdiv) mdiv.add_child(score) score.add_child(section) section.add_child(pb) music.add_children([facsimile, layout, body]) mei.add_children([meihead, music]) meifile.addelement(mei) return meifile
mei.add_children([meihead, music]) meifile.addelement(mei) return meifile # import hocr and mei files into lists and strip extension where useful hocrfiles=[x.split('.')[0] for x in glob.glob('????.html')] allmeifiles=glob.glob('*.mei') meifiles=[x.split('_')[0] for x in allmeifiles] # for each hocr file: if corresponding mei file exists, open mei and edit - if not, create new mei if options.corrected: for hocrfile in hocrfiles: output_name='%s_corr.mei' % (hocrfile,) if '%s_corr.mei' % (hocrfile,) in allmeifiles else '%s_uncorr.mei' % (hocrfile,) meifile=xmltomei.xmltomei(output_name) if hocrfile in meifiles else create_mei(hocrfile) surface=meifile.search('surface')[0] section=meifile.search('section')[0] add_text_lines(hocrfile, surface, section) meitoxml.meitoxml(meifile, '../mei_corrtxt/%s' % (output_name,)) else: for hocrfile in hocrfiles: meifile=MeiDocument.MeiDocument() mei=mod.mei_() surface=mod.surface_() section=mod.section_() mei.add_children([surface, section]) add_text_lines(hocrfile, surface, section) meifile.addelement(mei) meitoxml.meitoxml(meifile, '../mei_uncorrtxt/%s_mei_fragment.mei' % (hocrfile,))
def _create_division_element(self): division = mod.division_() division.id = self._idgen() zone = self._create_zone_element() division.facs = zone.id return division
def _create_sb_element(self): sb = mod.sb_() sb.id = self._idgen() return sb
def _create_pb_element(self): pb = mod.pb_() pb.id = self._idgen() return pb
def _create_surface_element(self): surface = mod.surface_() surface.id = self._idgen() return surface
def _create_page_element(self): page = mod.page_() page.id = self._idgen() return page
def _create_facsimile_element(self): facsimile = mod.facsimile_() facsimile.id = self._idgen() return facsimile
def _create_episema_element(self): epi = mod.episema_() epi.id = self._idgen() return epi
def _create_note_element(self, pname=None): note = mod.note_() note.id = self._idgen() note.pitchname = pname return note
def __init__(self, incoming_data, original_image, page_number=None): self._recognition_results = incoming_data self.mei = mod.mei_() self.staff = None self.staff_num = 1 self.glyph = None self._note_elements = None self._neume_pitches = [] # set up a basic MEI document structure # header self.meihead = mod.meihead_() self.filedesc = mod.filedesc_() self.titlestmt = mod.titlestmt_() self.title = mod.title_() self.pubstmt = mod.pubstmt_() self.titlestmt.add_child(self.title) self.filedesc.add_children([self.titlestmt, self.pubstmt]) self.meihead.add_child(self.filedesc) self.mei.add_child(self.meihead) # music self.music = mod.music_() self.facsimile = self._create_facsimile_element() self.surface = self._create_surface_element() self.graphic = self._create_graphic_element(original_image) self.surface.add_child(self.graphic) self.facsimile.add_child(self.surface) self.music.add_child(self.facsimile) self.layout = self._create_layout_element() self.pg = self._create_page_element() if page_number: self.pg.attributes = {"n": page_number} self.layout.add_child(self.pg) self.music.add_child(self.layout) self.body = mod.body_() self.music.add_child(self.body) self.mdiv = mod.mdiv_() self.mdiv.attributes = {"type": "solesmes"} self.body.add_child(self.mdiv) self.score = mod.score_() self.mdiv.add_child(self.score) self.scoredef = mod.scoredef_() self.score.add_child(self.scoredef) self.section = mod.section_() self.pagebreak = self._create_pb_element() self.pagebreak.attributes = {"pageref": self.pg.id} self.section.add_child(self.pagebreak) self.score.add_child(self.section) self.staffgrp = self._create_staffgrp_element() self.staffdef = self._create_staffdef_element() self.staffdef.attributes = {'n': self.staff_num} self.staffgrp.add_child(self.staffdef) self.scoredef.add_child(self.staffgrp) self.layer = self._create_layer_element() self.layer.attributes = {'n': 1} self.staffel = self._create_staff_element() self.staffel.attributes = {'n': self.staff_num} self.staffel.add_child(self.layer) self.section.add_child(self.staffel) for sysnum,syst in self._recognition_results.iteritems(): self.system = syst self.systembreak = self._parse_system(sysnum, syst) z = mod.zone_() z.id = self._idgen() z.attributes = {'ulx': self.system['coord'][0], 'uly': self.system['coord'][1], \ 'lrx': self.system['coord'][2], 'lry': self.system['coord'][3]} self.surface.add_child(z) # self.system.facs = z.id s = self._create_system_element() s.facs = z.id self.pg.add_child(s) self.systembreak.attributes = {"systemref": s.id} self.mei.add_child(self.music) if not self.staffel.descendants_by_name('neume'): self.staffgrp.remove_child(self.staffdef) self.section.remove_child(self.staffel) self.md = MeiDocument.MeiDocument() self.md.addelement(self.mei)
def _create_graphic_element(self, imgfile): graphic = mod.graphic_() graphic.id = self._idgen() graphic.attributes = {"xlink:href": imgfile} return graphic
def _create_custos_element(self): custos = mod.custos_() custos.id = self._idgen() zone = self._create_zone_element() custos.facs = zone.id return custos
def _create_layer_element(self): layer = mod.layer_() layer.id = self._idgen() return layer
def _create_staffgrp_element(self): stfgrp = mod.staffgrp_() stfgrp.id = self._idgen() return stfgrp
def create(docname): doc = MeiDocument.MeiDocument(docname) # set up the header root_el = mod.mei_() mei_head = mod.meihead_() file_desc = mod.filedesc_() title_stmt = mod.titlestmt_() title = mod.title_() title_stmt.add_children([title]) encoding_desc = mod.encodingdesc_() proj_desc = mod.projectdesc_() dsc = mod.p_() dsc.value = u"This file was generated by PyMEI 1.0" proj_desc.addchildren([dsc]) file_desc.add_children([title_stmt]) encoding_desc.add_children([proj_desc]) mei_head.add_children([file_desc, encoding_desc]) # set up the body music = mod.music_() bd = mod.body_() md = mod.mdiv_() sc = mod.score_() md.add_children([sc]) bd.add_children([md]) music.add_children([bd]) root_el.addchildren([mei_head, music]) doc.addelement(root_el) return doc