X-Git-Url: https://scm.cri.minesparis.psl.eu/git/minwii.git/blobdiff_plain/b9474080161e4611ea3f33e38a3cf2256e8fda06..9d4a748a0863cd7f9dd919362fb2c989e41f5f06:/src/songs/musicxmltosong.py diff --git a/src/songs/musicxmltosong.py b/src/songs/musicxmltosong.py deleted file mode 100755 index 0d4bb99..0000000 --- a/src/songs/musicxmltosong.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- coding: utf-8 -*- -""" -converstion d'un fichier musicxml en objet song minwii. - -$Id$ -$URL$ -""" -import sys -from types import StringTypes -from xml.dom.minidom import parse -from optparse import OptionParser -from Song import Song - -# Do4 <=> midi 60 -OCTAVE_REF = 4 -DIATO_SCALE = {'C' : 60, - 'D' : 62, - 'E' : 64, - 'F' : 65, - 'G' : 67, - 'A' : 69, - 'B' : 71} - -FR_NOTES = {'C' : u'Do', - 'D' : u'Ré', - 'E' : u'Mi', - 'F' : u'Fa', - 'G' : u'Sol', - 'A' : u'La', - 'B' : u'Si'} - -_marker = [] - -class Part(object) : - - def __init__(self, node, autoDetectChorus=True) : - self.node = node - self.notes = [] - self._parseMusic() - self.verses = [[]] - self.chorus = [] - if autoDetectChorus : - self._findChorus() - self._findVersesLoops() - - def _parseMusic(self) : - divisions = 0 - noteIndex = 0 - next = previous = None - for measureNode in self.node.getElementsByTagName('measure') : - # divisions de la noire - divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions)) - for noteNode in measureNode.getElementsByTagName('note') : - note = Note(noteNode, divisions, previous) - self.notes.append(note) - try : - self.notes[noteIndex-1].next = note - except IndexError: - pass - previous = note - noteIndex += 1 - - def _findChorus(self): - """ le refrain correspond aux notes pour lesquelles - il n'existe q'une seule syllable attachée. - """ - start = stop = None - for i, note in enumerate(self.notes) : - ll = len(note.lyrics) - if start is None and ll == 1 : - start = i - elif start is not None and ll > 1 : - stop = i - break - self.chorus = self.notes[start:stop] - - def _findVersesLoops(self) : - "recherche des couplets / boucles" - verse = self.verses[0] - for note in self.notes[:-1] : - verse.append(note) - ll = len(note.lyrics) - nll = len(note.next.lyrics) - if ll != nll : - verse = [] - self.verses.append(verse) - verse.append(self.notes[-1]) - - - def iterNotes(self) : - "exécution de la chanson avec l'alternance couplets / refrains" - for verse in self.verses : - print "---partie---" - repeats = len(verse[0].lyrics) - if repeats > 1 : - for i in range(repeats) : - # couplet - print "---couplet%d---" % i - for note in verse : - yield note, i - # refrain - print "---refrain---" - for note in self.chorus : - yield note, 0 - else : - for note in verse : - yield note, 0 - - def pprint(self) : - for note, verseIndex in self.iterNotes() : - print note.nom, note.name, note.midi, note.duration, note.lyrics[verseIndex] - - - -class Note(object) : - def __init__(self, node, divisions, previous) : - self.node = node - self.step = _getNodeValue(node, 'pitch/step') - self.octave = int(_getNodeValue(node, 'pitch/octave')) - self.alter = int(_getNodeValue(node, 'pitch/alter', 0)) - self._duration = float(_getNodeValue(node, 'duration')) - self.lyrics = [] - for ly in node.getElementsByTagName('lyric') : - self.lyrics.append(Lyric(ly)) - - self.divisions = divisions - self.previous = previous - self.next = None - - @property - def midi(self) : - mid = DIATO_SCALE[self.step] - mid = mid + (self.octave - OCTAVE_REF) * 12 - mid = mid + self.alter - return mid - - @property - def duration(self) : - return self._duration / self.divisions - - @property - def name(self) : - name = '%s%d' % (self.step, self.octave) - if self.alter < 0 : - alterext = 'b' - else : - alterext = '#' - name = '%s%s' % (name, abs(self.alter) * alterext) - return name - - @property - def nom(self) : - name = FR_NOTES[self.step] - if self.alter < 0 : - alterext = 'b' - else : - alterext = '#' - name = '%s%s' % (name, abs(self.alter) * alterext) - return name - - -class Lyric(object) : - - _syllabicModifiers = { - 'single' : '%s', - 'begin' : '%s -', - 'middle' : '- %s -', - 'end' : '- %s' - } - - def __init__(self, node) : - self.node = node - self.syllabic = _getNodeValue(node, 'syllabic', 'single') - self.text = _getNodeValue(node, 'text') - - def __str__(self) : - text = self._syllabicModifiers[self.syllabic] % self.text - return text.encode('utf-8') - __repr__ = __str__ - - - - -def _getNodeValue(node, path, default=_marker) : - try : - for name in path.split('/') : - node = node.getElementsByTagName(name)[0] - return node.firstChild.nodeValue - except : - if default is _marker : - raise - else : - return default - -def musicXml2Song(input, output, partIndex=0, printNotes=False) : - if isinstance(input, StringTypes) : - input = open(input, 'r') - - d = parse(input) - doc = d.documentElement - - # TODO conversion préalable score-timewise -> score-partwise - assert doc.nodeName == u'score-partwise' - - parts = doc.getElementsByTagName('part') - leadPart = parts[partIndex] - - part = Part(leadPart) - - if printNotes : - part.pprint() - - # divisions de la noire -# divisions = 0 -# midiNotes, durations, lyrics = [], [], [] -# -# for measureNode in leadPart.getElementsByTagName('measure') : -# divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions)) -# for noteNode in measureNode.getElementsByTagName('note') : -# note = Note(noteNode, divisions) -# if printNotes : -# print note.name, note.midi, note.duration, note.lyric -# midiNotes.append(note.midi) -# durations.append(note.duration) -# lyrics.append(note.lyric) -# -# song = Song(None, -# midiNoteNumbers = midiNotes, -# noteLengths = durations, -# lyrics = lyrics, -# notesInExtendedScale=None) -# song.save(output) - - -def main() : - usage = "%prog musicXmlFile.xml outputSongFile.smwi [options]" - op = OptionParser(usage) - op.add_option("-i", "--part-index", dest="partIndex" - , default = 0 - , help = "Index de la partie qui contient le champ.") - op.add_option("-p", '--print', dest='printNotes' - , action="store_true" - , default = False - , help = "Affiche les notes sur la sortie standard (debug)") - - options, args = op.parse_args() - - if len(args) != 2 : - raise SystemExit(op.format_help()) - - musicXml2Song(args[0], args[1], partIndex=options.partIndex, printNotes=options.printNotes) - - - -if __name__ == '__main__' : - sys.exit(main())