从Musicxml中提取信息

8

我是一名新手,对编程和Python不熟悉,但我的研究很多涉及从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个回答

8

我无法提供Python细节方面的帮助,但是我有两个与MusicXML相关的建议:

1)您的问题以半音记号为基础,但是您的代码侧重于alter元素。alter元素用于音高变化; accidental元素用于书写半音记号。你在找哪一个?声音和符号之间的二重性在MusicXML中很常见,对于使用MusicXML文件进行研究很重要。

2)如果您刚开始学习编程和Python,我建议使用专门针对音乐学的高级工具包,并且具有良好的MusicXML支持。您将把问题域提升到更高的水平,这应该可以让您更快地取得进展。显然的选择是music21工具包,它也是用Python编写的。请访问http://web.mit.edu/music21/获取更多信息。

祝你研究顺利!


谢谢Michael,我发现music21非常有用。在我的musicxml文件中,使用alter标签代替了升降号。我正在尝试找到所有相对于给定调号而言是升降号的音符。在music21中有没有快速的方法可以做到这一点?那么对于某些在乐曲中某处改变调号的作品呢? - user2025161
嗨2025161:在music21中,您可以使用.flat.notes(假设没有和弦;或者如果有,则使用.getElementsByClass('Note'))迭代每个音符,然后对于每个Note对象,将其.pitch.accidental对象与n.getContextByClass('KeySignature').accidentalByStep(n.pitch.step)进行比较,并找到它们不同的地方。请注意,这个简单的代码运行时间为O(n ^ 2);您可以缓存您的KeySignature对象,以使其在大型乐谱上更快运行。 - Michael Scott Asato Cuthbert

3

Python有一个xml.dom模块,可以让您快速浏览XML文件。如果您有Web开发经验,这与JavaScript的文档对象模型非常相似。

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)

谢谢您的回复,但是那段代码给我的结果和我导入lxml.etree并使用musicxml.xpath('count(//alter)')的结果一样。我想要编译一个所有升降号(在<alter>标签下)的音符名称列表,然后删除其中的F或C。我还需要编译一个不包含<alter>标签的音符列表,并删除其中不是F或C的音符。请原谅我的无知,我真的很新手。 - user2025161

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接