pythonmusic21

Music21: remove percussion based on channel number


I have some midi files [sample] from which I'd like to remove percussion.

Here's what I've been using to read midi files and then save midi back to disk. The resulting sound is great:

path = 'lld.midi'
score = music21.converter.parse(path, 
    forceSource=False, 
    quantizePost=False,
).stripTies(inPlace=True)  
score.write('midi', 'score.midi')

enter image description here

Since percussion is stored on channel 10 in midi, I thought I could strip the percussion with something like:

m = music21.midi.MidiFile()
m.open(path)
m.read()

tracks = []
for track in m.tracks:
    keep = True
    for event in track.events:
        if event.channel == 10:
            keep = False
    if keep: 
        tracks.append(track)
            
s = music21.midi.translate.midiTracksToStreams(tracks, quantizePost=False)
s.write('midi', 'no-percussion.midi')

This does strip the percussion, but it seems to mess up the note timing as well:

enter image description here

What am I missing? If others can offer advice as to how I can correct the timings of the MidiFile approach, I'd be very grateful!


Solution

  • Lord have mercy I needed to pass forceSource=False into the midiTracksToStreams call as well:

    m = music21.midi.MidiFile()
    m.open(path)
    m.read()
    
    tracks = [t for t in m.tracks if not any([e.channel == 10 for e in t.events])]        
    score = music21.stream.Score()
    music21.midi.translate.midiTracksToStreams(tracks,                                            
        inputM21=score,
        forceSource=False, 
        quantizePost=False,
        ticksPerQuarter=m.ticksPerQuarterNote,
        quarterLengthDivisors=(4,3),
    )       
    score.write('midi', fp='out.midi')