From 2afd6b2dc26dd12ecbba36d221a7cc45f19673f2 Mon Sep 17 00:00:00 2001 From: pin Date: Mon, 15 Mar 2010 22:40:45 +0000 Subject: [PATCH] =?utf8?q?utilisation=20directe=20des=20cha=C3=AEnes=20uni?= =?utf8?q?code=20pour=20l'affichage=20des=20paroles.=20prise=20en=20charge?= =?utf8?q?=20des=20notes=20prolong=C3=A9es=20().?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.cri.ensmp.fr/svn/minwii/trunk@88 fe552daf-6dbe-4428-90eb-1537e0879342 --- src/app/minwii.py | 2 +- src/app/musicxml.py | 64 +++++++++++++++++++++++++------- src/app/widgets/playingscreen.py | 2 +- src/songs/synth.py | 19 ++++++++-- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/app/minwii.py b/src/app/minwii.py index 08bbcfd..fe95f7e 100755 --- a/src/app/minwii.py +++ b/src/app/minwii.py @@ -27,7 +27,7 @@ class MinWii(object): #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() diff --git a/src/app/musicxml.py b/src/app/musicxml.py index 49e1984..ab6dbf9 100755 --- a/src/app/musicxml.py +++ b/src/app/musicxml.py @@ -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) - if not note.isRest : + if (not note.isRest) and (not note.tiedStop) : measureNotes.append(note) if previous : previous.next = note + elif note.tiedStop : + assert previous.tiedStart + 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 - 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" @@ -252,6 +259,16 @@ class Note(Tone) : 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')) @@ -292,10 +309,10 @@ class Note(Tone) : 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) : @@ -303,12 +320,12 @@ class Lyric(object) : 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 - return text.encode(encoding) + return text def __str__(self) : - return self.syllabus() + return self.syllabus().encode('utf-8') __repr__ = __str__ @@ -325,7 +342,19 @@ def _getNodeValue(node, path, default=_marker) : 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') @@ -338,7 +367,7 @@ def musicXml2Song(input, partIndex=0, printNotes=False) : parts = doc.getElementsByTagName('part') leadPart = parts[partIndex] - part = Part(leadPart) + part = Part(leadPart, autoDetectChorus=autoDetectChorus) 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("-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()) - musicXml2Song(args[0], partIndex=options.partIndex, printNotes=options.printNotes) - + musicXml2Song(args[0], + partIndex=options.partIndex, + autoDetectChorus=options.autoDetectChorus, + printNotes=options.printNotes) if __name__ == '__main__' : diff --git a/src/app/widgets/playingscreen.py b/src/app/widgets/playingscreen.py index e49079c..ca2e9ff 100755 --- a/src/app/widgets/playingscreen.py +++ b/src/app/widgets/playingscreen.py @@ -183,7 +183,7 @@ class SongPlayingScreen(_PlayingScreenBase) : 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 diff --git a/src/songs/synth.py b/src/songs/synth.py index 07a8a5a..0832b90 100755 --- a/src/songs/synth.py +++ b/src/songs/synth.py @@ -6,7 +6,7 @@ $Id$ $URL$ """ import fluidsynth -from musicxmltosong import musicXml2Song +from app.musicxml import musicXml2Song 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) : - 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) @@ -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("-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("-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]") @@ -60,7 +71,9 @@ def main() : 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, -- 2.20.1