00903a154d6b877d4f150de777dfa57017e62743
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,
27 def __init__(self
, node
, autoDetectChorus
=True) :
35 self
._findVersesLoops
()
37 def _parseMusic(self
) :
40 next
= previous
= None
41 for measureNode
in self
.node
.getElementsByTagName('measure') :
42 # divisions de la noire
43 divisions
= int(_getNodeValue(measureNode
, 'attributes/divisions', divisions
))
44 for noteNode
in measureNode
.getElementsByTagName('note') :
45 note
= Note(noteNode
, divisions
, previous
)
46 self
.notes
.append(note
)
48 self
.notes
[noteIndex
-1].next
= note
54 def _findChorus(self
):
55 """ le refrain correspond aux notes pour lesquelles
56 il n'existe q'une seule syllable attachée.
59 for i
, note
in enumerate(self
.notes
) :
61 if start
is None and ll
== 1 :
63 elif start
is not None and ll
> 1 :
66 self
.chorus
= self
.notes
[start
:stop
]
68 def _findVersesLoops(self
) :
69 "recherche des couplets / boucles"
70 verse
= self
.verses
[0]
71 for note
in self
.notes
[:-1] :
74 nll
= len(note
.next
.lyrics
)
77 self
.verses
.append(verse
)
78 verse
.append(self
.notes
[-1])
82 "exécution de la chanson avec l'alternance couplets / refrains"
83 for verse
in self
.verses
:
84 repeats
= len(verse
[0].lyrics
)
86 for i
in range(repeats
) :
91 for note
in self
.chorus
:
98 for note
, verseIndex
in self
.iterNotes() :
99 print note
.name
, note
.midi
, note
.duration
, note
.lyrics
[verseIndex
]
104 def __init__(self
, node
, divisions
, previous
) :
106 self
.step
= _getNodeValue(node
, 'pitch/step')
107 self
.octave
= int(_getNodeValue(node
, 'pitch/octave'))
108 self
.alter
= int(_getNodeValue(node
, 'pitch/alter', 0))
109 self
._duration
= float(_getNodeValue(node
, 'duration'))
111 for ly
in node
.getElementsByTagName('lyric') :
112 self
.lyrics
.append(Lyric(ly
))
114 self
.divisions
= divisions
115 self
.previous
= previous
120 mid
= DIATO_SCALE
[self
.step
]
121 mid
= mid
+ (self
.octave
- OCTAVE_REF
) * 12
122 mid
= mid
+ self
.alter
127 return self
._duration
/ self
.divisions
131 name
= '%s%d' % (self
.step
, self
.octave
)
136 name
= '%s%s' % (name
, abs(self
.alter
) * alterext
)
140 class Lyric(object) :
141 def __init__(self
, node
) :
143 self
.syllabic
= _getNodeValue(node
, 'syllabic', 'single')
144 self
.text
= _getNodeValue(node
, 'text')
147 return self
.text
.encode('utf-8')
153 def _getNodeValue(node
, path
, default
=_marker
) :
155 for name
in path
.split('/') :
156 node
= node
.getElementsByTagName(name
)[0]
157 return node
.firstChild
.nodeValue
159 if default
is _marker
:
164 def musicXml2Song(input, output
, partIndex
=0, printNotes
=False) :
165 if isinstance(input, StringTypes
) :
166 input = open(input, 'r')
169 doc
= d
.documentElement
171 # TODO conversion préalable score-timewise -> score-partwise
172 assert doc
.nodeName
== u
'score-partwise'
174 parts
= doc
.getElementsByTagName('part')
175 leadPart
= parts
[partIndex
]
177 part
= Part(leadPart
)
182 # divisions de la noire
184 # midiNotes, durations, lyrics = [], [], []
186 # for measureNode in leadPart.getElementsByTagName('measure') :
187 # divisions = int(_getNodeValue(measureNode, 'attributes/divisions', divisions))
188 # for noteNode in measureNode.getElementsByTagName('note') :
189 # note = Note(noteNode, divisions)
191 # print note.name, note.midi, note.duration, note.lyric
192 # midiNotes.append(note.midi)
193 # durations.append(note.duration)
194 # lyrics.append(note.lyric)
197 # midiNoteNumbers = midiNotes,
198 # noteLengths = durations,
200 # notesInExtendedScale=None)
205 usage
= "%prog musicXmlFile.xml outputSongFile.smwi [options]"
206 op
= OptionParser(usage
)
207 op
.add_option("-i", "--part-index", dest
="partIndex"
209 , help = "Index de la partie qui contient le champ.")
210 op
.add_option("-p", '--print', dest
='printNotes'
211 , action
="store_true"
213 , help = "Affiche les notes sur la sortie standard (debug)")
215 options
, args
= op
.parse_args()
218 raise SystemExit(op
.format_help())
220 musicXml2Song(args
[0], args
[1], partIndex
=options
.partIndex
, printNotes
=options
.printNotes
)
224 if __name__
== '__main__' :