def post(self, file): ''' Remove a dot ornament to a given element. ''' neumeid = str(self.get_argument("id", "")) # Bounding box ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) punctum = self.mei.getElementById(neumeid) # check that a punctum element was provided if punctum.getName() == "neume" and punctum.getAttribute("name").getValue() == "punctum": note = punctum.getDescendantsByName("note") if len(note): dot = note[0].getChildrenByName("dot") # if a dot exists if len(dot) == 1: note[0].removeChild(dot[0]) self.update_or_add_zone(punctum, ulx, uly, lrx, lry) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Neumify a group of neumes (with provided ids) and give it the given neume name. Also update bounding box information. ''' nids = str(self.get_argument("nids", "")).split(",") neume_name = str(self.get_argument("name", "")) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) neume = self.create_new_neume(nids, neume_name) self.insert_neume(neume, nids[0]) self.delete_old_neumes(nids) # Bounding box lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) if lrx and lry and ulx and uly: zone = self.get_new_zone(ulx, uly, lrx, lry) self.add_zone(neume, zone) XmlExport.write(self.mei, fname) result = {"nid": neume.getId()} self.write(json.dumps(result)) self.set_status(200)
def output_mei(self, output_path): ''' Write the generated mei to disk ''' # output mei file XmlExport.meiDocumentToFile(self.meidoc, output_path)
def post(self, file): ''' Move the given custos element. Also update the bounding box information. ''' custos_id = str(self.get_argument("id", "")) pname = self.get_argument("pname", None) oct = self.get_argument("oct", None) # bounding box ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) custos = self.mei.getElementById(custos_id) if pname is not None and oct is not None: custos.addAttribute("pname", str(pname)) custos.addAttribute("oct", str(oct)) self.update_or_add_zone(custos, ulx, uly, lrx, lry) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): data = json.loads(self.get_argument("data", "")) nid = str(data["id"]) beforeid = str(data["beforeid"]) # Bounding box ulx = str(data["ulx"]) uly = str(data["uly"]) lrx = str(data["lrx"]) lry = str(data["lry"]) pitch_info = data["pitchInfo"] mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) neume = self.mei.getElementById(nid) if pitch_info is not None: self.neume_pitch_shift(neume, pitch_info) self.reposition_neume(neume, beforeid) self.update_or_add_zone(neume, ulx, uly, lrx, lry) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Move a division before the given element. There is no element to insert before when there is no subsequent staff. In this case, the element is inserted at the end of the last system. Also sets the bounding box information of the new division placement. ''' division_id = str(self.get_argument("id", "")) before_id = str(self.get_argument("beforeid", None)) # bounding box ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) division = self.mei.getElementById(division_id) self.update_zone(division, ulx, uly, lrx, lry) self.reposition_division(division, before_id) XmlExport.write(self.mei, fname) self.set_status(200)
def append_guitar_data(self, tuning, capo): ''' Append meta data about the guitar the transcriber is using ''' mei_path = self.get_abs_path() mei_doc = XmlImport.documentFromFile(mei_path) staff_def = mei_doc.getElementsByName('staffDef')[0] g = Guitar(tuning=str(tuning), capo=capo) sounding_pitches = g.strings # From the MEI guidelines: # "this is given using the written pitch, not the sounding pitch. # For example, the Western 6-string guitar, in standard tuning, sounds an octave below written pitch." written_pitches = [s.pname + str(s.oct+1) for s in sounding_pitches] staff_def.addAttribute('lines', str(len(sounding_pitches))) staff_def.addAttribute('tab.strings', " ".join(written_pitches)) # Capo could be implicitly encoded by setting the pitches of the open strings # but I really don't like this solution. Instructions are lost about how to tune # and perform the piece on the guitar. # TODO: this attribute doesn't exist in MEI, make a custom build if capo > 0: staff_def.addAttribute('tab.capo', str(capo)) XmlExport.meiDocumentToFile(mei_doc, mei_path)
def post(self, file): ''' Insert a custos. Also add a bounding box for this element. ''' pname = str(self.get_argument("pname", "")) oct = str(self.get_argument("oct", "")) before_id = str(self.get_argument("beforeid", None)) # bounding box ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) custos = self.create_custos(pname, oct) self.insert_custos(custos, before_id) self.add_zone(custos, ulx, uly, lrx, lry) XmlExport.write(self.mei, fname) result = {"id": custos.getId()} self.write(json.dumps(result)) self.set_status(200)
def post(self, file): ''' Insert a doh or fah clef, with a given bounding box. Must also update pitched elements on the staff that affected by this clef being inserted. ''' data = json.loads(self.get_argument("data", "")) shape = str(data["shape"]).upper() line = str(data["line"]) before_id = str(data["beforeid"]) # bounding box ulx = str(data["ulx"]) uly = str(data["uly"]) lrx = str(data["lrx"]) lry = str(data["lry"]) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) clef = self.create_clef(shape, line) self.insert_clef(clef, before_id) self.create_zone(ulx, uly, lrx, lry, clef) self.update_pitched_elements(data["pitchInfo"]) XmlExport.write(self.mei, fname) result = {"id": clef.getId()} self.write(json.dumps(result)) self.set_status(200)
def post(self, file): ''' Ungroup a neume with the provided ID into puncta. Create bounding box information for each punctum. ''' data = json.loads(self.get_argument("data", "")) nids = str(data["nids"]).split(",") bboxes = data["bbs"] mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) newids = [] for nid, bb in zip(nids, bboxes): newids.append(self.insert_puncta(nid, bb)) self.delete_old_neume(nid) XmlExport.write(self.mei, fname) result = {"nids": newids} self.write(json.dumps(result)) self.set_status(200)
def post(self, file): ''' Insert a division before the given element. There is one case where there is no element to insert before, when there is no subsequent staff. In this case, the element is inserted at the end of the last system. Also sets the bounding box information of the new punctum. ''' div_type = str(self.get_argument("type", "")) beforeid = str(self.get_argument("beforeid", None)) # bounding box lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) zone = self.create_zone(ulx, uly, lrx, lry) division = self.create_new_division(div_type) self.add_zone(division, zone) self.insert_division(division, beforeid) XmlExport.write(self.mei, fname) result = {"id": division.getId()} self.write(json.dumps(result)) self.set_status(200)
def post(self, file): ''' Change the shape of a given clef. Must also update bounding box data since the glyphs for c and f clefs are different. Must also update pitched elements on the affected staff to correspond with the new clef shape. ''' data = json.loads(self.get_argument("data", "")) clef_id = str(data["id"]) # bounding box ulx = str(data["ulx"]) uly = str(data["uly"]) lrx = str(data["lrx"]) lry = str(data["lry"]) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) clef = self.mei.getElementById(clef_id) # update clef shape clef.addAttribute("shape", str(data["shape"]).upper()) self.update_or_add_zone(clef, ulx, uly, lrx, lry) self.update_pitched_elements(data["pitchInfo"]) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Remove a dot ornament to a given element. ''' neumeid = str(self.get_argument("id", "")) # Bounding box ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) punctum = self.mei.getElementById(neumeid) # check that a punctum element was provided if punctum.getName() == "neume" and punctum.getAttribute( "name").getValue() == "punctum": note = punctum.getDescendantsByName("note") if len(note): dot = note[0].getChildrenByName("dot") # if a dot exists if len(dot) == 1: note[0].removeChild(dot[0]) self.update_or_add_zone(punctum, ulx, uly, lrx, lry) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Move a clef on a staff (must not change staff). Updates the bounding box information of the clef and updates the pitch information (pitch name and octave) of all pitched elements on the affected staff. ''' data = json.loads(self.get_argument("data", "")) clef_id = str(data["id"]) # bounding box ulx = str(data["ulx"]) uly = str(data["uly"]) lrx = str(data["lrx"]) lry = str(data["lry"]) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) clef = self.mei.getElementById(clef_id) # update staff line the clef is on clef.addAttribute("line", str(data["line"])) self.update_or_add_zone(clef, ulx, uly, lrx, lry) self.update_pitched_elements(data["pitchInfo"]) XmlExport.write(self.mei, fname) self.set_status(200)
def append_guitar_data(self, tuning, capo): ''' Append meta data about the guitar the transcriber is using ''' mei_path = self.get_abs_path() mei_doc = XmlImport.documentFromFile(mei_path) staff_def = mei_doc.getElementsByName('staffDef')[0] g = Guitar(tuning=str(tuning), capo=capo) sounding_pitches = g.strings # From the MEI guidelines: # "this is given using the written pitch, not the sounding pitch. # For example, the Western 6-string guitar, in standard tuning, sounds an octave below written pitch." written_pitches = [s.pname + str(s.oct + 1) for s in sounding_pitches] staff_def.addAttribute('lines', str(len(sounding_pitches))) staff_def.addAttribute('tab.strings', " ".join(written_pitches)) # Capo could be implicitly encoded by setting the pitches of the open strings # but I really don't like this solution. Instructions are lost about how to tune # and perform the piece on the guitar. # TODO: this attribute doesn't exist in MEI, make a custom build if capo > 0: staff_def.addAttribute('tab.capo', str(capo)) XmlExport.meiDocumentToFile(mei_doc, mei_path)
def sanitize_mei_str(self, mei_str, output_mei_path=None, prune=True): self.mei_doc = XmlImport.documentFromText(mei_str) self._sanitize_mei(prune) if output_mei_path: XmlExport.meiDocumentToFile(self.mei_doc, str(output_mei_path)) else: return XmlExport.meiDocumentToText(self.mei_doc)
def output_mei(self, output_path): ''' Write the generated mei to disk ''' # output mei file if self.meidoc == None: raise Warning('The MEI document has not yet been created'); return XmlExport.meiDocumentToFile(self.meidoc, output_path)
def write_doc(self, **kwargs): ''' Write the modified MEI document out to a file, clobbering the input file, if no filename parameter is provided. ''' if 'filename' in kwargs: filename = kwargs['filename'] else: filename = self.filename XmlExport.write(self.mei, filename)
def massage_mei(in_file, out_file): try: analysis = make_analysis(in_file) MEI_instructions = TransformData( arranger_to_editor=True, obliterate_incipit=analysis.first_measure_empty, replace_longa=True, editorial_resp=analysis.has_arranger_element, alternates_list=analysis.alternates_list) old_MEI_doc = XmlImport.documentFromFile(in_file) new_MEI_doc = transform_mei(old_MEI_doc, MEI_instructions) XmlExport.meiDocumentToFile(new_MEI_doc, out_file) except Exception as ex: logging.critical(ex) logging.critical("Error during massaging " + in_file)
def mei_append_metamusic(self): ''' Append meta data for the musical work to the mei document ''' mei_path = self.get_abs_path() mei_doc = XmlImport.documentFromFile(mei_path) mei = mei_doc.getRootElement() mei_head = MeiElement('meiHead') music = mei.getChildrenByName('music')[0] file_desc = MeiElement('fileDesc') # title title_stmt = MeiElement('titleStmt') title = MeiElement('title') title.setValue(str(self.fk_mid.title)) # contributers resp_stmt = MeiElement('respStmt') pers_name_artist = MeiElement('persName') pers_name_artist.addAttribute('role', 'artist') pers_name_artist.setValue(str(self.fk_mid.artist)) pers_name_tabber = MeiElement('persName') pers_name_tabber.addAttribute('role', 'tabber') pers_name_tabber.setValue(str(self.fk_mid.copyright)) # encoding information encoding_desc = MeiElement('encodingDesc') app_info = MeiElement('appInfo') application = MeiElement('application') application.setValue('Robotaba') mei_head.addChild(file_desc) file_desc.addChild(title_stmt) title_stmt.addChild(title) title_stmt.addChild(resp_stmt) resp_stmt.addChild(pers_name_artist) resp_stmt.addChild(pers_name_tabber) title_stmt.addChild(encoding_desc) encoding_desc.addChild(app_info) app_info.addChild(application) # attach mei metadata to the document mei.addChildBefore(music, mei_head) XmlExport.meiDocumentToFile(mei_doc, mei_path)
def test_documentwritefailure(self): doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root with self.assertRaises(FileWriteFailureException) as cm: ret = XmlExport.meiDocumentToFile(doc, "C:/StupidPath") self.assertTrue(isinstance(cm.exception, FileWriteFailureException))
def post(self, file): ''' Delete a given custos from the document. Also remove the element's bounding box information. ''' custos_id = str(self.get_argument("id", "")) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) self.delete_custos(custos_id) XmlExport.write(self.mei, fname) self.set_status(200)
def test_exporttostring(self): doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root expected = "<?xml version=\"1.0\"?>\n<mei xmlns=\"http://www.music-encoding.org/ns/mei\" xml:id=\"myid\" meiversion=\"2013\"/>\n"; ret = XmlExport.meiDocumentToText(doc) self.assertEqual(expected, ret)
def write_doc(self, **kwargs): ''' Write the modified MEI document out to a file, clobbering the input file, if no filename parameter is provided. ''' if 'filename' in kwargs: filename = kwargs['filename'] else: filename = self.filename filename_split_initial = os.path.split(filename) filename_dir, mei_filename = filename_split_initial filename_split = os.path.split(filename_dir) filename_split_beg, filename_split_end = filename_split undo_path = filename_split_beg + "/undo/" file_list = [ f for f in os.listdir(undo_path) if os.path.isfile(os.path.join(undo_path, f)) ] file_num = 1 + len(file_list) mei_filename_split = os.path.splitext(mei_filename) mei_name, mei_ext = mei_filename_split if (file_num > 50): file_num = 50 os.remove(undo_path + mei_name + '_01' + mei_ext) file_list.pop(0) for idx, f in enumerate(file_list): if (idx < 9): os.rename( undo_path + f, undo_path + mei_name + '_0' + str(idx + 1) + mei_ext) else: os.rename( undo_path + f, undo_path + mei_name + '_' + str(idx + 1) + mei_ext) if (file_num < 10): XmlExport.write( self.mei, undo_path + mei_name + '_0' + str(file_num) + mei_ext) XmlExport.write(self.mei, filename) else: XmlExport.write( self.mei, undo_path + mei_name + '_' + str(file_num) + mei_ext) XmlExport.write(self.mei, filename)
def post(self, file): ''' Delete a division from the MEI document. Special consideration is taken when deleting divisions of form "final" ''' division_ids = str(self.get_argument("ids", "")) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) for id in division_ids.split(","): division = self.mei.getElementById(id) self.delete_division(division) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Insert a punctum before the given element. There is one case where there is no element to insert before, when there is no subsequent staff. In this case, the element is inserted at the end of the last system. Also sets the bounding box information of the new punctum. ''' beforeid = str(self.get_argument("beforeid", None)) pname = str(self.get_argument("pname", "")) oct = str(self.get_argument("oct", "")) dot_form = self.get_argument("dotform", None) # Bounding box lrx = str(self.get_argument("lrx", None)) lry = str(self.get_argument("lry", None)) ulx = str(self.get_argument("ulx", None)) uly = str(self.get_argument("uly", None)) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) punctum = self.create_new_punctum(pname, oct, dot_form) zone = self.get_new_zone(ulx, uly, lrx, lry) self.add_zone(punctum, zone) if beforeid is None: # get last layer layers = self.mei.getElementsByName("layer") if len(layers): layers[-1].addChild(punctum) else: self.insert_punctum(punctum, beforeid) XmlExport.write(self.mei, fname) result = {"nid": punctum.getId()} self.write(json.dumps(result)) self.set_status(200)
def post(self, file): """ Delete one or more <note> or <neume> elements. Pass in an argument called 'id' with a comma separated list of ids of note elements to delete. If the note's surrounding <nc> element is empty after this, remove it. If the nc's surrounding <neume> element is empty, remove it. Remove any <zone> elements whose ids are referenced by removed <neume>s. Does not reduce the size of the bounding box on a <zone> or change the neume type if it now has a different number of <note> elements. """ todelete = self.get_argument("ids", "") mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) self.do_delete(todelete) XmlExport.write(self.mei, fname) self.set_status(200)
def post(self, file): ''' Delete a doh or fah clef. Must also update pitched elements on the staff that are affected by the deletion of this clef element. ''' clefs_to_delete = json.loads(self.get_argument("data", "")) mei_directory = os.path.abspath(conf.MEI_DIRECTORY) fname = os.path.join(mei_directory, file) self.mei = XmlImport.read(fname) for c in clefs_to_delete: clef = self.mei.getElementById(str(c["id"])) self.delete_clef(clef) self.update_pitched_elements(c["pitchInfo"]) XmlExport.write(self.mei, fname) self.set_status(200)
def save_elite(self, score, output_path=None): ''' Save the elite tablature to the specified output path, or return a string representation of the MeiDocument. The output file should be a copy on the HDD of the original input file, to preserve meta-data and other contents of the file not maintained in the internal representation of the musical document. PARAMETERS ---------- output_path {String}: the output path of the mei file ''' # get list of tablature data to append to note elements # plucks is a list of tuples (MeiElement.id, Pluck) plucks = [] for chromo in self.elites: for g in chromo.genes: if isinstance(g.guitar_event, Pluck): plucks.append((g.score_event.id, g.guitar_event)) elif isinstance(g.guitar_event, Strum): for p, n in zip(g.guitar_event.plucks, g.score_event.notes): plucks.append((n.id, p)) # add the tablature data to the original mei document for p in plucks: note = score.meidoc.getElementById(p[0]) note.addAttribute('tab.string', str(p[1].string+1)) note.addAttribute('tab.fret', str(p[1].fret)) if output_path is not None: # write the modified document to disk XmlExport.meiDocumentToFile(score.meidoc, output_path) else: # return a string of the MeiDocument return XmlExport.meiDocumentToText(score.meidoc)
def test_exportcomment(self): doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root comment = MeiElement("_comment") comment.value = "comment" comment.tail = "t" root.addChild(comment) expected = "<?xml version=\"1.0\"?>\n<mei xmlns=\"http://www.music-encoding.org/ns/mei\" xml:id=\"myid\" meiversion=\"2013\"><!--comment-->t</mei>\n"; ret = XmlExport.meiDocumentToText(doc) self.assertEqual(expected, ret)
def test_exportnamespace(self): doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root xlink = MeiNamespace("xlink", "http://www.w3.org/1999/xlink") attr = MeiAttribute(xlink, "title", "my awesome thing") root.addAttribute(attr) expected = "<?xml version=\"1.0\"?>\n<mei xmlns=\"http://www.music-encoding.org/ns/mei\" \ xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:id=\"myid\" xlink:title=\"my awesome thing\" meiversion=\"2013\"/>\n"; ret = XmlExport.meiDocumentToText(doc) self.assertEqual(expected, ret)
def test_exportvalueandtail(self): doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root note = MeiElement("note") note.id = "noteid" note.value = "value" note.tail = "tail" root.addChild(note) expected = "<?xml version=\"1.0\"?>\n<mei xmlns=\"http://www.music-encoding.org/ns/mei\" xml:id=\"myid\" meiversion=\"2013\"><note xml:id=\"noteid\">value</note>tail</mei>\n"; ret = XmlExport.meiDocumentToText(doc) self.assertEqual(expected, ret)
def write_doc(self, **kwargs): ''' Write the modified MEI document out to a file, clobbering the input file, if no filename parameter is provided. ''' if 'filename' in kwargs: filename = kwargs['filename'] else: filename = self.filename filename_split_initial = os.path.split(filename) filename_dir, mei_filename = filename_split_initial filename_split = os.path.split(filename_dir) filename_split_beg, filename_split_end = filename_split undo_path = filename_split_beg + "/undo/" file_list = [f for f in os.listdir(undo_path) if os.path.isfile(os.path.join(undo_path, f))] file_num = 1 + len(file_list) mei_filename_split = os.path.splitext(mei_filename) mei_name, mei_ext = mei_filename_split if(file_num > 50): file_num = 50 os.remove(undo_path + mei_name + '_01' + mei_ext) file_list.pop(0) for idx, f in enumerate(file_list): if(idx < 9): os.rename(undo_path + f, undo_path + mei_name + '_0' + str(idx + 1) + mei_ext) else: os.rename(undo_path + f, undo_path + mei_name + '_' + str(idx + 1) + mei_ext) if (file_num < 10): XmlExport.write(self.mei, undo_path + mei_name + '_0' + str(file_num) + mei_ext) XmlExport.write(self.mei, filename) else: XmlExport.write(self.mei, undo_path + mei_name + '_' + str(file_num) + mei_ext) XmlExport.write(self.mei, filename)
def write_mei(self, notes, output_path=None): # begin constructing mei document meidoc = MeiDocument() mei = MeiElement('mei') meidoc.setRootElement(mei) mei_head = MeiElement('meiHead') mei.addChild(mei_head) music = MeiElement('music') body = MeiElement('body') mdiv = MeiElement('mdiv') score = MeiElement('score') score_def = MeiElement('scoreDef') # assume 4/4 time signature meter_count = 4 meter_unit = 4 score_def.addAttribute('meter.count', str(meter_count)) score_def.addAttribute('meter.unit', str(meter_unit)) staff_def = MeiElement('staffDef') staff_def.addAttribute('n', '1') staff_def.addAttribute('label.full', 'Electric Guitar') staff_def.addAttribute('clef.shape', 'TAB') instr_def = MeiElement('instrDef') instr_def.addAttribute('n', 'Electric_Guitar') instr_def.addAttribute('midi.channel', '1') instr_def.addAttribute('midi.instrnum', '28') mei.addChild(music) music.addChild(body) body.addChild(mdiv) mdiv.addChild(score) score.addChild(score_def) score_def.addChild(staff_def) staff_def.addChild(instr_def) section = MeiElement('section') score.addChild(section) # another score def score_def = MeiElement('scoreDef') score_def.addAttribute('meter.count', str(meter_count)) score_def.addAttribute('meter.unit', str(meter_unit)) section.addChild(score_def) # start writing pitches to file note_container = None for i, frame_n in enumerate(notes): if i % meter_count == 0: measure = MeiElement('measure') measure.addAttribute('n', str(int(i / meter_count + 1))) staff = MeiElement('staff') staff.addAttribute('n', '1') layer = MeiElement('layer') layer.addAttribute('n', '1') section.addChild(measure) measure.addChild(staff) staff.addChild(layer) note_container = layer if len(frame_n) > 1: chord = MeiElement('chord') for n in frame_n: note = MeiElement('note') pname = n['pname'][0].upper() note.addAttribute('pname', pname) note.addAttribute('oct', str(n['oct'])) if len(n['pname']) > 1 and n['pname'][1] == '#': # there is an accidental note.addAttribute('accid.ges', 's') note.addAttribute('dur', str(meter_unit)) chord.addChild(note) note_container.addChild(chord) else: n = frame_n[0] note = MeiElement('note') pname = n['pname'][0].upper() note.addAttribute('pname', pname) note.addAttribute('oct', str(n['oct'])) if len(n['pname']) > 1 and n['pname'][1] == '#': # there is an accidental note.addAttribute('accid.ges', 's') note.addAttribute('dur', str(meter_unit)) note_container.addChild(note) if output_path is not None: XmlExport.meiDocumentToFile(meidoc, output_path) else: return XmlExport.meiDocumentToText(meidoc)
def __init__(self, incoming_data, original_image, page_number=None): self._recognition_results = incoming_data # self.mei = mod.mei_() self.mei = MeiElement("mei") self.staff = None # Hack: I'm not sure what staff_num is. In any case it's strange to set it to None. # I therefore set it to 0 if page_number is None. if page_number is not None: self.staff_num = int(page_number) else: self.staff_num = 0 self.glyph = None self._note_elements = None self._neume_pitches = [] # set up a basic MEI document structure # header # self.meihead = mod.meiHead_() self.meihead = MeiElement("meiHead") # self.filedesc = mod.fileDesc_() self.filedesc = MeiElement("fileDesc") # self.titlestmt = mod.titleStmt_() self.titlestmt = MeiElement("titleStmt") # self.title = mod.title_() self.title = MeiElement("title") # self.pubstmt = mod.pubStmt_() self.pubstmt = MeiElement("pubStmt") self.titlestmt.addChild(self.title) self.filedesc.addChild(self.titlestmt) self.filedesc.addChild(self.pubstmt) self.meihead.addChild(self.filedesc) self.mei.addChild(self.meihead) # music # self.music = mod.music_() self.music = MeiElement("music") self.facsimile = self._create_facsimile_element() self.surface = self._create_surface_element() self.graphic = self._create_graphic_element(original_image) lg.debug("SELF GRAPHIC:{0}".format( XmlExport.meiElementToText(self.graphic))) self.surface.addChild(self.graphic) self.facsimile.addChild(self.surface) self.music.addChild(self.facsimile) self.layout = self._create_layout_element() self.pg = self._create_page_element() if page_number: # self.pg.attributes = {"n": page_number} self.pg.addAttribute("n", page_number) self.layout.addChild(self.pg) self.music.addChild(self.layout) # self.body = mod.body_() self.body = MeiElement("body") self.music.addChild(self.body) self.mdiv = MeiElement("mdiv") # self.mdiv = mod.mdiv_() self.mdiv.addAttribute("type", "solesmes") self.body.addChild(self.mdiv) # self.score = mod.score_() self.score = MeiElement("score") self.mdiv.addChild(self.score) # self.scoredef = mod.scoreDef_() self.scoredef = MeiElement("scoreDef") self.score.addChild(self.scoredef) # self.section = mod.section_() self.section = MeiElement("section") self.pagebreak = self._create_pb_element() # self.pagebreak.attributes = {"pageref": self.pg.id} self.pagebreak.addAttribute("pageref", self.pg.id) self.section.addChild(self.pagebreak) self.score.addChild(self.section) self.staffgrp = self._create_staffgrp_element() self.staffdef = self._create_staffdef_element() self.staffdef.addAttribute("n", str(self.staff_num)) # trouble self.staffgrp.addChild(self.staffdef) self.scoredef.addChild(self.staffgrp) self.layer = self._create_layer_element() self.layer.addAttribute("n", "1") self.staffel = self._create_staff_element() self.staffel.addAttribute("n", str(self.staff_num)) # trouble self.section.addChild(self.staffel) self.staffel.addChild(self.layer) for sysnum in sorted(self._recognition_results.keys()): syst = self._recognition_results[sysnum] lg.debug("sysnum:{0}".format(sysnum)) self.system = syst self.systembreak = self._parse_system(sysnum, syst) # z = mod.zone_() z = MeiElement("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]} z.addAttribute("ulx", str(self.system['coord'][0])) z.addAttribute("uly", str(self.system['coord'][1])) z.addAttribute("lrx", str(self.system['coord'][2])) z.addAttribute("lry", str(self.system['coord'][3])) self.surface.addChild(z) # self.system.facs = z.id s = self._create_system_element() s.facs = z.id s.addAttribute("facs", s.facs) self.pg.addChild(s) self.systembreak.addAttribute("systemref", s.id) self.mei.addChild(self.music) # if not self.staffel.descendants_by_name('neume'): if not self.staffel.getDescendantsByName("neume"): self.staffgrp.removeChild(self.staffdef) self.section.removeChild(self.staffel) # self.md = MeiDocument.MeiDocument() # self.md.addelement(self.mei) self.md = MeiDocument() self.md.setRootElement(self.mei) print XmlExport.meiElementToText( self.md.getElementById(self.graphic.getId()))