1 # -*- coding: utf-8 -*-
3 converstion d'un fichier musicxml en objet song minwii.
9 from types
import StringTypes
10 from xml
.dom
.minidom
import parse
11 from optparse
import OptionParser
16 DIATO_SCALE
= {'C' : 60,
24 FR_NOTES
= {'C' : u
'Do',
36 def __init__(self
, node
, autoDetectChorus
=True) :
44 self
._findVersesLoops
()
46 def _parseMusic(self
) :
49 next
= previous
= None
50 for measureNode
in self
.node
.getElementsByTagName('measure') :
51 # divisions de la noire
52 divisions
= int(_getNodeValue(measureNode
, 'attributes/divisions', divisions
))
53 for noteNode
in measureNode
.getElementsByTagName('note') :
54 note
= Note(noteNode
, divisions
, previous
)
55 self
.notes
.append(note
)
57 self
.notes
[noteIndex
-1].next
= note
63 def _findChorus(self
):
64 """ le refrain correspond aux notes pour lesquelles
65 il n'existe q'une seule syllable attachée.
68 for i
, note
in enumerate(self
.notes
) :
70 if start
is None and ll
== 1 :
72 elif start
is not None and ll
> 1 :
75 self
.chorus
= self
.notes
[start
:stop
]
77 def _findVersesLoops(self
) :
78 "recherche des couplets / boucles"
79 verse
= self
.verses
[0]
80 for note
in self
.notes
[:-1] :
83 nll
= len(note
.next
.lyrics
)
86 self
.verses
.append(verse
)
87 verse
.append(self
.notes
[-1])
91 "exécution de la chanson avec l'alternance couplets / refrains"
92 for verse
in self
.verses
:
94 repeats
= len(verse
[0].lyrics
)
96 for i
in range(repeats
) :
98 print "---couplet%d---" % i
102 print "---refrain---"
103 for note
in self
.chorus
:
110 for note
, verseIndex
in self
.iterNotes() :
111 print note
.nom
, note
.name
, note
.midi
, note
.duration
, note
.lyrics
[verseIndex
]
116 def __init__(self
, node
, divisions
, previous
) :
118 self
.step
= _getNodeValue(node
, 'pitch/step')
119 self
.octave
= int(_getNodeValue(node
, 'pitch/octave'))
120 self
.alter
= int(_getNodeValue(node
, 'pitch/alter', 0))
121 self
._duration
= float(_getNodeValue(node
, 'duration'))
123 for ly
in node
.getElementsByTagName('lyric') :
124 self
.lyrics
.append(Lyric(ly
))
126 self
.divisions
= divisions
127 self
.previous
= previous
132 mid
= DIATO_SCALE
[self
.step
]
133 mid
= mid
+ (self
.octave
- OCTAVE_REF
) * 12
134 mid
= mid
+ self
.alter
139 return self
._duration
/ self
.divisions
143 name
= '%s%d' % (self
.step
, self
.octave
)
148 name
= '%s%s' % (name
, abs(self
.alter
) * alterext
)
153 name
= FR_NOTES
[self
.step
]
158 name
= '%s%s' % (name
, abs(self
.alter
) * alterext
)
162 class Lyric(object) :
164 _syllabicModifiers
= {
171 def __init__(self
, node
) :
173 self
.syllabic
= _getNodeValue(node
, 'syllabic', 'single')
174 self
.text
= _getNodeValue(node
, 'text')
177 text
= self
._syllabicModifiers
[self
.syllabic
] % self
.text
178 return text
.encode('utf-8')
184 def _getNodeValue(node
, path
, default
=_marker
) :
186 for name
in path
.split('/') :
187 node
= node
.getElementsByTagName(name
)[0]
188 return node
.firstChild
.nodeValue
190 if default
is _marker
:
195 def musicXml2Song(input, output
, partIndex
=0, printNotes
=False) :
196 if isinstance(input, StringTypes
) :
197 input = open(input, 'r')
200 doc
= d
.documentElement
202 # TODO conversion préalable score-timewise -> score-partwise
203 assert doc
.nodeName
== u
'score-partwise'
205 parts
= doc
.getElementsByTagName('part')
206 leadPart
= parts
[partIndex
]
208 part
= Part(leadPart
)
213 # divisions de la noire
215 # midiNotes, durations, lyrics = [], [], []
217 # for measureNode in leadPart.getElementsByTagName('measure') :
218 # divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions))
219 # for noteNode in measureNode.getElementsByTagName('note') :
220 # note = Note(noteNode, divisions)
222 # print note.name, note.midi, note.duration, note.lyric
223 # midiNotes.append(note.midi)
224 # durations.append(note.duration)
225 # lyrics.append(note.lyric)
228 # midiNoteNumbers = midiNotes,
229 # noteLengths = durations,
231 # notesInExtendedScale=None)
236 usage
= "%prog musicXmlFile.xml outputSongFile.smwi [options]"
237 op
= OptionParser(usage
)
238 op
.add_option("-i", "--part-index", dest
="partIndex"
240 , help = "Index de la partie qui contient le champ.")
241 op
.add_option("-p", '--print', dest
='printNotes'
242 , action
="store_true"
244 , help = "Affiche les notes sur la sortie standard (debug)")
246 options
, args
= op
.parse_args()
249 raise SystemExit(op
.format_help())
251 musicXml2Song(args
[0], args
[1], partIndex
=options
.partIndex
, printNotes
=options
.printNotes
)
255 if __name__
== '__main__' :