_marker = []
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.distinctNotes = []
+ self.quarterNoteDuration = 500
self._parseMusic()
self.verses = [[]]
self.chorus = []
def _parseMusic(self) :
divisions = 0
previous = None
+ distinctNotesDict = {}
for measureNode in self.node.getElementsByTagName('measure') :
measureNotes = []
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
previous = note
+
self.notes.extend(measureNotes)
+
+ for note in measureNotes :
+ if not distinctNotesDict.has_key(note.midi) :
+ distinctNotesDict[note.midi] = True
+ self.distinctNotes.append(note)
# barres de reprises
try :
barline = Barline(barlineNode, measureNotes)
if barline.repeat :
self.repeats.append(barline)
+
+ self.distinctNotes.sort(lambda a, b : cmp(a.midi, b.midi))
+ sounds = self.node.getElementsByTagName('sound')
+ tempo = 120
+ for sound in sounds :
+ if sound.hasAttribute('tempo') :
+ tempo = float(sound.getAttribute('tempo'))
+ break
+
+ self.quarterNoteDuration = int(round(60000/tempo))
+
+
def _findChorus(self):
""" le refrain correspond aux notes pour lesquelles
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 iterNotes(self, indefinitely=True) :
"exécution de la chanson avec l'alternance couplets / refrains"
- print 'indefinitely', indefinitely
if indefinitely == False :
iterable = self.verses
else :
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._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 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 column(self):
return self.scale.index(self.midi)
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) :
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__
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')
parts = doc.getElementsByTagName('part')
leadPart = parts[partIndex]
- part = Part(leadPart)
+ part = Part(leadPart, autoDetectChorus=autoDetectChorus)
if printNotes :
part.pprint()
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__' :