从Musicxml提取信息
我刚开始学习编程和Python,但我现在的研究主要是从musicxml文件中提取数据。我有一段音乐,想要找出这段音乐中出现的意外音符的数量,这些音符不属于调号的一部分。我不知道该怎么做,能不能请大家帮帮我?下面是我正在查看的musicxml文件中的一个小节的例子:
<measure number='19'>
<print new-system='no'/>
<note>
<rest/>
<duration>768</duration>
<voice>1</voice>
<type>quarter</type>
<staff>1</staff>
</note>
<backup>
<duration>768</duration>
</backup>
<note>
<pitch>
<step>E</step>
<octave>4</octave>
</pitch>
<duration>2304</duration>
<tie type='start'/>
<voice>2</voice>
<type>half</type>
<dot/>
<staff>1</staff>
<notations>
<tied type='start'/>
<slur type='stop' number='1'/>
</notations>
</note>
<backup>
<duration>1536</duration>
</backup>
<note>
<pitch>
<step>E</step>
<alter>3</alter>
<octave>3</octave>
</pitch>
<duration>1536</duration>
<voice>1</voice>
<type>half</type>
<staff>1</staff>
</note>
<note>
<chord/>
<pitch>
<step>G</step>
<alter>4</alter>
<octave>3</octave>
</pitch>
<duration>1536</duration>
<voice>1</voice>
<type>half</type>
<staff>1</staff>
</note>
<backup>
<duration>2304</duration>
</backup>
<note>
<pitch>
<step>E</step>
<octave>2</octave>
</pitch>
<duration>2304</duration>
<voice>5</voice>
<type>half</type>
<dot/>
<staff>2</staff>
</note>
</measure>
这个问题的意思是要在musicxml文件中搜索,并计算
<pitch>
<step>*</step>
<alter>**</alter>
...
出现的次数,其中 * 不是(F或C),同时还要找出 * 是F或C的次数,并且后面没有跟<alter>
标签。
任何帮助或建议都非常感谢!
2 个回答
3
Python有一个叫做 xml.dom 的模块,这个模块可以让你快速浏览XML文件。如果你有过网页开发的经验,这个模块的用法和JavaScript中的文档对象模型(DOM)非常相似。
from xml.dom.minidom import parse, parseString
def get_step(note):
stepNode = note.getElementsByTagName("step")[0]
#get the text from the Text Node within the <step>,
#and convert it from unicode to ascii
return str(stepNode.childNodes[0].nodeValue)
def get_alter(note):
alters = note.getElementsByTagName("alter")
if len(alters) == 0:
return None
return alters[0]
def is_rest(note):
return len(note.getElementsByTagName("rest")) > 0
def is_accidental(note):
return get_alter(note) != None
dom = parse("data.xml")
notes = dom.getElementsByTagName("note")
#rests don't have steps or alters, so we don't care about them. Filter them out.
notes = filter(lambda note: not is_rest(note), notes)
#compile a list of notes of all accidentals (notes with <alter> tags)
accidentals = filter(is_accidental, notes)
#remove notes that are F or C
accidentals_that_are_not_f_or_c = filter(lambda note: get_step(note) not in ["F", "C"], accidentals)
#compile a list of notes that don't contain the alter tag
non_accidentals = filter(lambda note: not is_accidental(note), notes)
#remove notes that are not F or C
non_accidentals_that_are_f_or_c = filter(lambda note: get_step(note) in ["F", "C"], non_accidentals)
print "Accidental notes that are not F or C:"
if len(accidentals_that_are_not_f_or_c) == 0:
print "(None found)"
else:
for note in accidentals_that_are_not_f_or_c:
print get_step(note)
print "Non-accidental notes that are F or C:"
if len(non_accidentals_that_are_f_or_c) == 0:
print "(None found)"
else:
for note in non_accidentals_that_are_f_or_c:
print get_step(note), get_step(note) in ["F", "C"]
输出:
Accidental notes that are not F or C:
E
G
Non-accidental notes that are F or C:
(None found)
8
我对Python的细节不太了解,但我有两个关于MusicXML的建议:
1) 你的问题提到的是“变音符”,但你的代码却关注于“alter”元素。其实,alter元素是用来表示音高变化的,而变音符元素则是用来表示书写上的变音符。你到底想要哪个呢?在MusicXML中,声音和书写方式之间的这种区别是很常见的,理解这一点对于研究MusicXML文件非常重要。
2) 如果你是编程和Python的新手,我建议你使用一个专门为音乐学设计的高级工具包,它对MusicXML支持得很好。这样你可以把问题的复杂度降低,进展会更快。一个明显的选择是music21工具包,它也是用Python写的。你可以在这里找到更多信息:http://web.mit.edu/music21/。
祝你的研究顺利!