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
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 = []
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)
- self.notes.append(note)
- try :
- self.notes[noteIndex-1].next = note
- except IndexError:
- pass
+ if not note.isRest :
+ 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
def iterNotes(self) :
"exécution de la chanson avec l'alternance couplets / refrains"
- for verse in self.verses :
+ for verse in cycle(self.verses) :
print "---partie---"
repeats = len(verse[0].lyrics)
if repeats > 1 :
def pprint(self) :
for note, verseIndex in self.iterNotes() :
- print note.nom, note.name, note.midi, note.duration, note.lyrics[verseIndex]
-
+ 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 Note(object) :
+ scale = [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]
+
def __init__(self, node, divisions, previous) :
self.node = node
- self.step = _getNodeValue(node, 'pitch/step')
- self.octave = int(_getNodeValue(node, 'pitch/octave'))
- self.alter = int(_getNodeValue(node, 'pitch/alter', 0))
+ 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.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]
name = '%s%s' % (name, abs(self.alter) * alterext)
return name
+ @property
+ def column(self):
+ return self.scale.index(self.midi)
+
class Lyric(object) :
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__