utilisation directe des chaînes unicode pour l'affichage des paroles.
authorpin <pin@fe552daf-6dbe-4428-90eb-1537e0879342>
Mon, 15 Mar 2010 22:40:45 +0000 (22:40 +0000)
committerpin <pin@fe552daf-6dbe-4428-90eb-1537e0879342>
Mon, 15 Mar 2010 22:40:45 +0000 (22:40 +0000)
prise en charge des notes prolongées (<tied/>).

git-svn-id: https://svn.cri.ensmp.fr/svn/minwii/trunk@88 fe552daf-6dbe-4428-90eb-1537e0879342

src/app/minwii.py
src/app/musicxml.py
src/app/widgets/playingscreen.py
src/songs/synth.py

index 08bbcfd..fe95f7e 100755 (executable)
@@ -27,7 +27,7 @@ class MinWii(object):
             #app.run(home)
             #app.close(home)
             
             #app.run(home)
             #app.close(home)
             
-            song = musicXml2Song('/Users/pinbe/dev/minwii/src/songs/chansons/quinquin.xml')
+            song = musicXml2Song('/Users/pinbe/dev/minwii/src/songs/chansons/etoile_neige.xml', printNotes=True)
             playingScreen = SongPlayingScreen(synth, song)
             #playingScreen = PlayingScreen(synth)
             playingScreen.run()
             playingScreen = SongPlayingScreen(synth, song)
             #playingScreen = PlayingScreen(synth)
             playingScreen.run()
index 49e1984..ab6dbf9 100755 (executable)
@@ -73,10 +73,14 @@ class Part(object) :
             divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions))
             for noteNode in measureNode.getElementsByTagName('note') :
                 note = Note(noteNode, divisions, previous)
             divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions))
             for noteNode in measureNode.getElementsByTagName('note') :
                 note = Note(noteNode, divisions, previous)
-                if not note.isRest :
+                if (not note.isRest) and (not note.tiedStop) :
                     measureNotes.append(note)
                     if previous :
                         previous.next = note
                     measureNotes.append(note)
                     if previous :
                         previous.next = note
+                elif note.tiedStop :
+                    assert previous.tiedStart
+                    previous.addDuration(note)
+                    continue
                 else :
                     previous.addDuration(note)
                     continue
                 else :
                     previous.addDuration(note)
                     continue
@@ -114,7 +118,10 @@ class Part(object) :
             elif start is not None and ll > 1 :
                 stop = i
                 break
             elif start is not None and ll > 1 :
                 stop = i
                 break
-        self.chorus = self.notes[start:stop]
+        if not (start or stop) :
+            self.chorus = []
+        else :
+            self.chorus = self.notes[start:stop]
     
     def _findVersesLoops(self) :
         "recherche des couplets / boucles"
     
     def _findVersesLoops(self) :
         "recherche des couplets / boucles"
@@ -252,6 +259,16 @@ class Note(Tone) :
     def __init__(self, node, divisions, previous) :
         self.node = node
         self.isRest = False
     def __init__(self, node, divisions, previous) :
         self.node = node
         self.isRest = False
+        self.tiedStart = False
+        self.tiedStop = False
+        
+        tieds = _getElementsByPath(node, 'notations/tied', [])
+        for tied in tieds :
+            if tied.getAttribute('type') == 'start' :
+                self.tiedStart = True
+            elif tied.getAttribute('type') == 'stop' :
+                self.tiedStop = True
+        
         self.step = _getNodeValue(node, 'pitch/step', None)
         if self.step is not None :
             self.octave = int(_getNodeValue(node, 'pitch/octave'))
         self.step = _getNodeValue(node, 'pitch/step', None)
         if self.step is not None :
             self.octave = int(_getNodeValue(node, 'pitch/octave'))
@@ -292,10 +309,10 @@ class Note(Tone) :
 class Lyric(object) :
     
     _syllabicModifiers = {
 class Lyric(object) :
     
     _syllabicModifiers = {
-        'single' : '%s',
-        'begin'  : '%s -',
-        'middle' : '- %s -',
-        'end'    : '- %s'
+        'single' : u'%s',
+        'begin'  : u'%s -',
+        'middle' : u'- %s -',
+        'end'    : u'- %s'
         }
     
     def __init__(self, node) :
         }
     
     def __init__(self, node) :
@@ -303,12 +320,12 @@ class Lyric(object) :
         self.syllabic = _getNodeValue(node, 'syllabic', 'single')
         self.text = _getNodeValue(node, 'text')
     
         self.syllabic = _getNodeValue(node, 'syllabic', 'single')
         self.text = _getNodeValue(node, 'text')
     
-    def syllabus(self, encoding='utf-8'):
+    def syllabus(self):
         text = self._syllabicModifiers[self.syllabic] % self.text
         text = self._syllabicModifiers[self.syllabic] % self.text
-        return text.encode(encoding)
+        return text
     
     def __str__(self) :
     
     def __str__(self) :
-        return self.syllabus()
+        return self.syllabus().encode('utf-8')
     __repr__  = __str__
         
         
     __repr__  = __str__
         
         
@@ -325,7 +342,19 @@ def _getNodeValue(node, path, default=_marker) :
         else :
             return default
 
         else :
             return default
 
-def musicXml2Song(input, partIndex=0, printNotes=False) :
+def _getElementsByPath(node, path, default=_marker) :
+    try :
+        parts = path.split('/')
+        for name in parts[:-1] :
+            node = node.getElementsByTagName(name)[0]
+        return node.getElementsByTagName(parts[-1])
+    except IndexError :
+        if default is _marker :
+            raise
+        else :
+            return default
+
+def musicXml2Song(input, partIndex=0, autoDetectChorus=True, printNotes=False) :
     if isinstance(input, StringTypes) :
         input = open(input, 'r')
     
     if isinstance(input, StringTypes) :
         input = open(input, 'r')
     
@@ -338,7 +367,7 @@ def musicXml2Song(input, partIndex=0, printNotes=False) :
     parts = doc.getElementsByTagName('part')
     leadPart = parts[partIndex]
     
     parts = doc.getElementsByTagName('part')
     leadPart = parts[partIndex]
     
-    part = Part(leadPart)
+    part = Part(leadPart, autoDetectChorus=autoDetectChorus)
     
     if printNotes :
         part.pprint()
     
     if printNotes :
         part.pprint()
@@ -353,18 +382,27 @@ def main() :
     op.add_option("-i", "--part-index", dest="partIndex"
                  , default = 0
                  , help = "Index de la partie qui contient le champ.")
     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)")
     op.add_option("-p", '--print', dest='printNotes'
                   , action="store_true"
                   , default = False
                   , help = "Affiche les notes sur la sortie standard (debug)")
+
+    op.add_option("-c", '--no-chorus', dest='autoDetectChorus'
+                , action="store_false"
+                , default = True
+                , help = "désactive la détection du refrain")
+
     
     options, args = op.parse_args()
     
     if len(args) != 1 :
         raise SystemExit(op.format_help())
     
     
     options, args = op.parse_args()
     
     if len(args) != 1 :
         raise SystemExit(op.format_help())
     
-    musicXml2Song(args[0], partIndex=options.partIndex, printNotes=options.printNotes)
-    
+    musicXml2Song(args[0],
+                  partIndex=options.partIndex,
+                  autoDetectChorus=options.autoDetectChorus,
+                  printNotes=options.printNotes)
 
 
 if __name__ == '__main__' :
 
 
 if __name__ == '__main__' :
index e49079c..ca2e9ff 100755 (executable)
@@ -183,7 +183,7 @@ class SongPlayingScreen(_PlayingScreenBase) :
         if self.currentColumn:
             self.currentColumn.update(False)
         note, verseIndex = self.noteIterator.next()
         if self.currentColumn:
             self.currentColumn.update(False)
         note, verseIndex = self.noteIterator.next()
-        syllabus = note.lyrics[verseIndex].syllabus(encoding="iso-8859-1")
+        syllabus = note.lyrics[verseIndex].syllabus()
         column = self.columns[note.midi]
         column.update(True, syllabus)
         self.currentColumn = column
         column = self.columns[note.midi]
         column.update(True, syllabus)
         self.currentColumn = column
index 07a8a5a..0832b90 100755 (executable)
@@ -6,7 +6,7 @@ $Id$
 $URL$
 """
 import fluidsynth
 $URL$
 """
 import fluidsynth
-from musicxmltosong import musicXml2Song
+from app.musicxml import musicXml2Song
 from time import sleep
 import sys
 from optparse import OptionParser
 from time import sleep
 import sys
 from optparse import OptionParser
@@ -28,7 +28,10 @@ class SongPlayer(object) :
     def play(self) :
         fs = self.fs
         for note, verseIndex in self.part.iterNotes(indefinitely=False) :
     def play(self) :
         fs = self.fs
         for note, verseIndex in self.part.iterNotes(indefinitely=False) :
-            print note, note.lyrics[verseIndex]
+            try :
+                print note, note.lyrics[verseIndex]
+            except IndexError :
+                print note, '?'
             fs.noteon(0, note.midi, 64)
             duration = note.duration * self.quarterNoteDuration / 1000
             sleep(duration)
             fs.noteon(0, note.midi, 64)
             duration = note.duration * self.quarterNoteDuration / 1000
             sleep(duration)
@@ -44,13 +47,21 @@ def main() :
     op.add_option("-i", "--part-index", dest="partIndex"
                  , default = 0
                  , help = "Index de la partie qui contient le champ.")
     op.add_option("-i", "--part-index", dest="partIndex"
                  , default = 0
                  , help = "Index de la partie qui contient le champ.")
+
+    op.add_option("-c", '--no-chorus', dest='autoDetectChorus'
+             , action="store_false"
+             , default = True
+             , help = "désactive la détection du refrain")
+
     op.add_option("-q", "--quarter-note-duration", dest="quarterNoteDuration"
                   , type="int", default=400
                   , help="Durée de la noire [default] (en millisecondes)"
                   )
     op.add_option("-q", "--quarter-note-duration", dest="quarterNoteDuration"
                   , type="int", default=400
                   , help="Durée de la noire [default] (en millisecondes)"
                   )
+
     op.add_option("-b", "--bank", dest="bank"
                   , type="int", default="0"
                   , help="midi bank [default]")
     op.add_option("-b", "--bank", dest="bank"
                   , type="int", default="0"
                   , help="midi bank [default]")
+
     op.add_option("-p", "--preset", dest="preset"
                 , type="int", default="0"
                 , help="midi preset [default]")
     op.add_option("-p", "--preset", dest="preset"
                 , type="int", default="0"
                 , help="midi preset [default]")
@@ -60,7 +71,9 @@ def main() :
     if len(args) != 1 :
         raise SystemExit(op.format_help())
     
     if len(args) != 1 :
         raise SystemExit(op.format_help())
     
-    song = musicXml2Song(args[0], partIndex=options.partIndex)
+    song = musicXml2Song(args[0],
+                         partIndex=options.partIndex,
+                         autoDetectChorus=options.autoDetectChorus)
     sp = SongPlayer(song,
                     '/Users/pinbe/dev/minwii/fluid-soundfont-3.1/FluidR3_GM.sf2',
                     quarterNoteDuration=options.quarterNoteDuration,
     sp = SongPlayer(song,
                     '/Users/pinbe/dev/minwii/fluid-soundfont-3.1/FluidR3_GM.sf2',
                     quarterNoteDuration=options.quarterNoteDuration,