I'm using Music21 to programmatically edit MusicXML files in my dataset. What I'm trying to do is divvy up audio and corresponding MusicXML into little snippets. This means that sometimes, snippets' start or end don't align perfectly with the beginning or end of a measure, so I need to delete a certain number of beats in the beginning or end measure.
I want to figure out if there's already a proper way, knowing which beats in a measure to delete, to do this using Music21.
Here's an example of what I want to do:
from music21 import *
musicxml = converter.parse(xml_file_path)
musicxml = musicxml.measures(1,3)
musicxml.show()
musicxml = musicxml.some_function_that_removes_first_few_beats(remove_beats=3)
musicxml.show()
I made separate functions for deleting beats at the start of the excerpt and deleting beats at the end of the excerpt:
def delete_first_beats(xml_score, start_measure, start_beat):
xml_score = copy.deepcopy(xml_score)
start_offset = start_beat - 1
for measure in xml_score.recurse(classFilter=('Measure')):
if measure.number == start_measure:
removed = set()
for note_or_rest in measure.recurse(classFilter=('Note', 'Rest')):
if note_or_rest.offset < start_offset:
removed.add(note_or_rest.activeSite)
note_or_rest.activeSite.remove(note_or_rest)
for stream in removed: stream.insert(0, note.Rest())
return xml_score
And:
def delete_last_beats(xml_score, end_measure, end_beat):
xml_score = copy.deepcopy(xml_score)
end_offset = end_beat - 1
for measure in xml_score.recurse(classFilter=('Measure')):
if measure.number == end_measure:
removed = set()
for note_or_rest in measure.recurse(classFilter=('Note', 'Rest')):
if note_or_rest.offset > end_offset:
removed.add(note_or_rest.activeSite)
note_or_rest.activeSite.remove(note_or_rest)
for stream in removed: stream.insert(end_beat, note.Rest())
return xml_score