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 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 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_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_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 test_exportProcessingInstructions(self): procinst = XmlInstructions() xpi1 = XmlProcessingInstruction("xml-model", "href=\"mei-2012.rng\" type=\"application/xml\" schematypens=\"http://purl.oclc.org/dsdl/schematron\"") xpi2 = XmlProcessingInstruction("xml-stylesheet", "href=\"mei-2012.rng\" type=\"application/xml\" schematypens=\"http://purl.oclc.org/dsdl/schematron\"") procinst.extend([xpi1, xpi2]) doc = MeiDocument() root = MeiElement("mei") root.id = "myid" doc.root = root ret = XmlExport.meiDocumentToText(doc, procinst) expected = "<?xml version=\"1.0\"?>\n<?xml-model href=\"mei-2012.rng\" type=\"application/xml\" \ schematypens=\"http://purl.oclc.org/dsdl/schematron\"?>\n<?xml-stylesheet href=\"mei-2012.rng\" type=\"application/xml\" \ schematypens=\"http://purl.oclc.org/dsdl/schematron\"?>\n<mei xmlns=\"http://www.music-encoding.org/ns/mei\" \ xml:id=\"myid\" meiversion=\"2013\"/>\n" self.assertEqual(expected, ret)
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 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 write_mei(self, notes, audio_path, output_path=None): from pymei import MeiDocument, MeiElement, XmlExport # combine features with the same timestamps note_events = [] for n in notes: ts = n.timestamp.toSeconds() note_num = int(n.values[0]) + 1 # it looks like everything is transposed a semitone down ... transposing up # if the last timestamp is equal to this timestamp, combine into a chord if len(note_events) > 0 and note_events[-1][0] == ts: note_events[-1][1].append(note_num) else: note_events.append([ts, [note_num]]) # sort by timestamp in ascending order note_events = sorted(note_events, key=lambda n: n[0]) # begin constructing mei document meidoc = MeiDocument() mei = MeiElement('mei') meidoc.setRootElement(mei) music = MeiElement('music') timeline = MeiElement('timeline') timeline.addAttribute('avref', str(audio_path)) 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(timeline) 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, note_event in enumerate(note_events): 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 ts = note_event[0] when = MeiElement('when') if i == 0: timeline.addAttribute('origin', when.getId()) when.addAttribute('absolute', str(ts)) timeline.addChild(when) notes = note_event[1] if len(notes) > 1: chord = MeiElement('chord') chord.addAttribute('when', when.getId()) for n in notes: note = MeiElement('note') note_info = PolyTrans.midi_map[n] pname = note_info[0] oct = note_info[1] note.addAttribute('pname', pname[0]) note.addAttribute('oct', str(oct)) if len(pname) > 1 and 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 = notes[0] note = MeiElement('note') note.addAttribute('when', when.getId()) note_info = PolyTrans.midi_map[n] pname = note_info[0] oct = note_info[1] note.addAttribute('pname', pname[0]) note.addAttribute('oct', str(oct)) if len(pname) > 1 and 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 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 test_documentrootnotset(self): doc = MeiDocument() with self.assertRaises(DocumentRootNotSetException) as cm: ret = XmlExport.meiDocumentToText(doc) self.assertTrue(isinstance(cm.exception, DocumentRootNotSetException))