Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extracting information from Musicxml

I am new to programming and Python, but a lot of my current research concerns extracting data from musicxml files. I have a piece of music and want to extract the number of accidentals that occur in a piece that do not form part of the key signature. I have no idea how to do this, please could someone help? Here's an example of one measure from the musicxml file I am looking at:

<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>

The problem translates to searching through the musicxml file and counting the number of times

<pitch>
   <step>*</step>
   <alter>**</alter>
       ...

occurs where * is not (F or C) and also finding the number of times that * is F or C and is not followed by the <alter> tag.

Any help or advice would be much appreciated!

like image 957
user2025161 Avatar asked Jan 30 '13 12:01

user2025161


People also ask

How do I Export my logic score from MusicXML?

Export a score project in MusicXML format In Logic Pro, choose File > Export > Score as MusicXML. In the Save dialog, type a name for the exported file and browse to a location to save it. Click Save.

Can finale open MusicXML files?

Finale can import MusicXML 2.0 files (compressed and uncompressed, . mxl and . xml), MusicXML 1.1 files, and MusicXML 1.0 files.

Can MuseScore open MusicXML?

Apart from native format files (*. mscz and *. mscx), MuseScore can also open MusicXML, compressed MusicXML and MIDI files, as well as a variety of files in other formats.


2 Answers

I can't help with Python details, but I have two MusicXML-related suggestions:

1) Your question is phrased in terms of accidentals, but your code focuses on the alter element. The alter element is used for pitch alteration; the accidental element is what is used for written accidentals. Which one are you looking for? The duality between how much sounds and how it appears in notation is common in MusicXML, and important to understand for doing research with MusicXML files.

2) If you are new to programming and Python, I would suggest using a higher-level toolkit designed expressly for musicology with good MusicXML support. You will move the problem domain up to a higher level which should let you make progress a lot faster. The obvious choice for this is the music21 toolkit, which is also written in Python. There's lots more information at http://web.mit.edu/music21/.

Good luck with your research!

like image 116
Michael Avatar answered Sep 20 '22 09:09

Michael


python has an xml.dom module that allows you to quickly navigate through xml files. If you have any experience with web development, it's very similar to javascript's document object model.

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"]

output:

Accidental notes that are not F or C:
E
G
Non-accidental notes that are F or C:
(None found)
like image 24
Kevin Avatar answered Sep 22 '22 09:09

Kevin