# -*- coding: utf-8 -*-
"""
-converstion d'un fichier musicxml en objet song minwii.
+conversion d'un fichier musicxml en objet song minwii.
$Id$
$URL$
'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',
def __init__(self, node, autoDetectChorus=True) :
self.node = node
self.notes = []
+ self.repeats = []
self._parseMusic()
self.verses = [[]]
self.chorus = []
def _parseMusic(self) :
divisions = 0
- noteIndex = 0
- next = previous = None
+ 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 :
- self.notes.append(note)
- try :
- self.notes[noteIndex-1].next = note
- except IndexError:
- pass
+ measureNotes.append(note)
+ if previous :
+ previous.next = note
else :
previous.addDuration(note)
continue
-
previous = note
- noteIndex += 1
+ 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
verse.append(self.notes[-1])
- def iterNotes(self) :
+ def iterNotes(self, indefinitely=True) :
"exécution de la chanson avec l'alternance couplets / refrains"
- for verse in self.verses :
+ 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 :
yield note, 0
def pprint(self) :
- for note, verseIndex in self.iterNotes() :
- print note.nom, note.name, note.midi, note.duration, note.lyrics[verseIndex]
+ for note, verseIndex in self.iterNotes(indefinitely=False) :
+ print note, note.lyrics[verseIndex]
def assignNotesFromMidiNoteNumbers(self):
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(object) :
+class Note(Tone) :
scale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]
def __init__(self, node, divisions, previous) :
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 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 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):
self.syllabic = _getNodeValue(node, 'syllabic', 'single')
self.text = _getNodeValue(node, 'text')
- def __str__(self) :
+ def syllabus(self, encoding='utf-8'):
text = self._syllabicModifiers[self.syllabic] % self.text
- return text.encode('utf-8')
+ return text.encode(encoding)
+
+ def __str__(self) :
+ return self.syllabus()
__repr__ = __str__
return part
- # 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]"
+ usage = "%prog musicXmlFile.xml [options]"
op = OptionParser(usage)
op.add_option("-i", "--part-index", dest="partIndex"
, default = 0