déplacement.
[minwii.git] / src / songs / musicxmltosong.py
diff --git a/src/songs/musicxmltosong.py b/src/songs/musicxmltosong.py
deleted file mode 100755 (executable)
index 7eedf53..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-conversion 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 itertools import cycle
-#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}
-
-CHROM_SCALE = {  0 : ('C',  0),
-                 1 : ('C',  1),
-                 2 : ('D',  0),
-                 3 : ('E', -1),
-                 4 : ('E',  0),
-                 5 : ('F',  0),
-                 6 : ('F',  1),
-                 7 : ('G',  0),
-                 8 : ('G',  1),
-                 9 : ('A',  0),
-                10 : ('B', -1),
-                11 : ('B',  0)}
-
-
-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) :
-    
-    requiresExtendedScale = False
-    scale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]
-    quarterNoteLength = 400
-    
-    def __init__(self, node, autoDetectChorus=True) :
-        self.node = node
-        self.notes = []
-        self.repeats = []
-        self._parseMusic()
-        self.verses = [[]]
-        self.chorus = []
-        if autoDetectChorus :
-            self._findChorus()
-        self._findVersesLoops()
-    
-    def _parseMusic(self) :
-        divisions = 0
-        previous = None
-
-        for measureNode in self.node.getElementsByTagName('measure') :
-            measureNotes = []
-            
-            # iteration sur les notes
-            # divisions de la noire
-            divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions))
-            for noteNode in measureNode.getElementsByTagName('note') :
-                note = Note(noteNode, divisions, previous)
-                if not note.isRest :
-                    measureNotes.append(note)
-                    if previous :
-                        previous.next = note
-                else :
-                    previous.addDuration(note)
-                    continue
-                previous = note
-            self.notes.extend(measureNotes)
-            
-            # barres de reprises
-            try :
-                barlineNode = measureNode.getElementsByTagName('barline')[0]
-            except IndexError :
-                continue
-            
-            barline = Barline(barlineNode, measureNotes)
-            if barline.repeat :
-                self.repeats.append(barline)
-
-    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, indefinitely=True) :
-        "exécution de la chanson avec l'alternance couplets / refrains"
-        print 'indefinitely', indefinitely
-        if indefinitely == False :
-            iterable = self.verses
-        else :
-            iterable = cycle(self.verses)
-        for verse in iterable :
-            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(indefinitely=False) :
-            print note, note.lyrics[verseIndex]
-
-
-    def assignNotesFromMidiNoteNumbers(self):
-        # TODO faire le mapping bande hauteur midi
-        for i in range(len(self.midiNoteNumbers)):
-            noteInExtendedScale = 0
-            while self.midiNoteNumbers[i] > self.scale[noteInExtendedScale] and noteInExtendedScale < len(self.scale)-1:
-                noteInExtendedScale += 1
-            if self.midiNoteNumbers[i]<self.scale[noteInExtendedScale]:
-                noteInExtendedScale -= 1
-            self.notes.append(noteInExtendedScale)
-
-
-class Barline(object) :
-
-    def __init__(self, node, measureNotes) :
-        self.node = node
-        location = self.location = node.getAttribute('location') or 'right'
-        try :
-            repeatN = node.getElementsByTagName('repeat')[0]
-            repeat = {'direction' : repeatN.getAttribute('direction'),
-                      'times' : int(repeatN.getAttribute('times') or 1)}
-            if location == 'left' :
-                repeat['note'] = measureNotes[0]
-            elif location == 'right' :
-                repeat['note'] = measureNotes[-1]
-            else :
-                raise ValueError(location)
-            self.repeat = repeat
-        except IndexError :
-            self.repeat = None
-    
-    def __str__(self)  :
-        if self.repeat :
-            if self.location == 'left' :
-                return '|:'
-            elif self.location == 'right' :
-                return ':|'
-        return '|'
-
-    __repr__ = __str__
-
-
-class Tone(object) :
-    
-    @staticmethod
-    def midi_to_step_alter_octave(midi):
-        stepIndex = midi % 12
-        step, alter = CHROM_SCALE[stepIndex]
-        octave = midi / 12 - 1
-        return step, alter, octave
-    
-    
-    def __init__(self, *args) :
-        if len(args) == 3 :
-            self.step, self.alter, self.octave = args
-        elif len(args) == 1 :
-            midi = args[0]
-            self.step, self.alter, self.octave = Tone.midi_to_step_alter_octave(midi)
-
-    @property
-    def midi(self) :
-        mid = DIATO_SCALE[self.step]
-        mid = mid + (self.octave - OCTAVE_REF) * 12
-        mid = mid + self.alter
-        return mid
-
-    
-    @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 Note(Tone) :
-    scale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]
-    
-    def __init__(self, node, divisions, previous) :
-        self.node = node
-        self.isRest = False
-        self.step = _getNodeValue(node, 'pitch/step', None)
-        if self.step is not None :
-            self.octave = int(_getNodeValue(node, 'pitch/octave'))
-            self.alter = int(_getNodeValue(node, 'pitch/alter', 0))
-        elif self.node.getElementsByTagName('rest') :
-            self.isRest = True
-        else :
-            NotImplementedError(self.node.toxml('utf-8'))
-            
-        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
-    
-    def __str__(self) :
-        return (u'%5s %2s %2d %4s' % (self.nom, self.name, self.midi, round(self.duration, 2))).encode('utf-8')
-    
-    def __repr__(self) :
-        return self.name.encode('utf-8')
-    
-    def addDuration(self, note) :
-        self._duration = self.duration + note.duration
-        self.divisions = 1
-    
-#    @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
-    
-    @property
-    def column(self):
-        return self.scale.index(self.midi)
-    
-
-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 syllabus(self, encoding='utf-8'):
-        text = self._syllabicModifiers[self.syllabic] % self.text
-        return text.encode(encoding)
-    
-    def __str__(self) :
-        return self.syllabus()
-    __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, 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()
-
-    return part
-
-    
-    
-def main() :
-    usage = "%prog musicXmlFile.xml [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) != 1 :
-        raise SystemExit(op.format_help())
-    
-    musicXml2Song(args[0], partIndex=options.partIndex, printNotes=options.printNotes)
-    
-
-
-if __name__ == '__main__' :
-    sys.exit(main())