X-Git-Url: https://scm.cri.ensmp.fr/git/minwii.git/blobdiff_plain/46f3ffd7fdde386f41020171b5733e55a8e64a85..dcb9290b9379098e8946d3ef98e4d7998c434105:/src/minwii/musicxml.py?ds=inline diff --git a/src/minwii/musicxml.py b/src/minwii/musicxml.py index 0ed7085..54d859f 100755 --- a/src/minwii/musicxml.py +++ b/src/minwii/musicxml.py @@ -57,9 +57,8 @@ class Part(object) : self._parseMusic() self.verses = [[]] self.chorus = [] - if autoDetectChorus : - self._findChorus() - self._findVersesLoops() + self.songStartsWithChorus = False + self._findVersesLoops(autoDetectChorus) def _parseMusic(self) : divisions = 0 @@ -83,7 +82,13 @@ class Part(object) : previous.addDuration(note) continue else : - previous.addDuration(note) + try : + previous.addDuration(note) + except AttributeError : + # can occur if part starts with a rest. + if previous is not None : + # something else is wrong. + raise continue previous = note @@ -115,25 +120,7 @@ class Part(object) : self.quarterNoteDuration = int(round(60000/tempo)) - - 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 - if not (start or stop) : - self.chorus = [] - else : - self.chorus = self.notes[start:stop] - - def _findVersesLoops(self) : + def _findVersesLoops(self, autoDetectChorus) : "recherche des couplets / boucles" verse = self.verses[0] for note in self.notes[:-1] : @@ -145,14 +132,21 @@ class Part(object) : self.verses.append(verse) verse.append(self.notes[-1]) + if autoDetectChorus and len(self.verses) > 1 : + for i, verse in enumerate(self.verses) : + if len(verse[0].lyrics) == 1 : + self.chorus = self.verses.pop(i) + self.songStartsWithChorus = i==0 + break + - def iterNotes(self, indefinitely=True) : + def iterNotes(self) : "exécution de la chanson avec l'alternance couplets / refrains" - if indefinitely == False : - iterable = self.verses - else : - iterable = cycle(self.verses) - for verse in iterable : + for verse in self.verses : + if self.songStartsWithChorus : + for note in self.chorus : + yield note, 0 + #print "---partie---" repeats = len(verse[0].lyrics) if repeats > 1 : @@ -168,6 +162,31 @@ class Part(object) : else : for note in verse : yield note, 0 + + @property + def intervalsHistogram(self) : + histogram = {} + it = self.iterNotes() + previousNote = it.next()[0] + for note, _ in it : + interval = note.midi - previousNote.midi + if histogram.has_key(interval) : + histogram[interval] += 1 + else : + histogram[interval] = 1 + previousNote = note + return histogram + + @property + def duration(self) : + 'Durée de référence du morceau en milisecondes' + it = self.iterNotes() + duration = 0 + for note, verseIndex in it : + duration = duration + note.duration + duration = duration * self.quarterNoteDuration # en milisecondes + return duration + def pprint(self) : for note, verseIndex in self.iterNotes(indefinitely=False) : @@ -371,7 +390,8 @@ def musicXml2Song(input, partIndex=0, autoDetectChorus=True, printNotes=False) : doc = d.documentElement # TODO conversion préalable score-timewise -> score-partwise - assert doc.nodeName == u'score-partwise' + if doc.nodeName != u'score-partwise' : + raise ValueError('not a musicxml file') parts = doc.getElementsByTagName('part') leadPart = parts[partIndex] @@ -408,10 +428,13 @@ def main() : if len(args) != 1 : raise SystemExit(op.format_help()) - musicXml2Song(args[0], + song = musicXml2Song(args[0], partIndex=options.partIndex, autoDetectChorus=options.autoDetectChorus, printNotes=options.printNotes) + from pprint import pprint + pprint(song.intervalsHistogram) + print song.duration if __name__ == '__main__' :