Question

I've got some MIDI files made by Sibelius (v.4?..) with "unusual" instrument within; I can not hear the melody. I decided that I need to "reset" instrument to 0 (Acoustic Grand Piano, I believe).

So, I wrote a Python programs using both python-midi and mingus; these programs could change MIDI instrument, but they both changed rhythm dramatically.

Rosegarden does this job quite well, but I can not use it in a batch.

Next, after some reading of MIDI format information (here and here, for instance) I wrote a simple Python script (see below), which simply replaces some strings with another ones --- replaces 0xC0[byte] with 0xC000 and like that.

Now those MIDI files sounds OK, I can hear everything.

So, my question is --- is it "safe" (in any meaning) to do this? How I can change instruments better? How I can "detect" 0xCx command in MIDI file better?

Thank you!

#!/usr/bin/env python
#

import sys
import re

patt = re.compile('(\xC0|\xC1|\xC2|\xC3|\xC4|\xC5|\xC6|\xC7).')

try:
    filein = sys.argv[1]
except IndexError:
    print "Specify input file as an argument."
    sys.exit(1)

try:
    fileout = sys.argv[2]
except IndexError:
    fileout = '%s-out2.mid' % filein.replace('.mid', '')

filein_data = open(filein, 'rb').read()

open(fileout, 'wb').write(patt.sub('\1\x00',filein_data))

No correct solution

OTHER TIPS

It is not safe to simply replace all 0xC??? bytes with 0xC?00, mainly because 0xC??? could be indicating an event's delta time and not actually be part of a Program Change event. Accidentally modifying a delta time will shift all subsequent events off-time, which will sound pretty awful if it's part of a multi-track composition.

As for a solution, I doubt there's a regex that can detect Program Change events without possibly picking up delta times as well. My only experience with modifying MIDI is with the Java library I wrote, and you would accomplish your task with the following code:

MidiFile input = new MidiFile(INPUT_FILE);

for(MidiTrack T : input.getTracks()) {
    Iterator<MidiEvent> it = T.getEvents().iterator();
    while(it.hasNext()) {
        MidiEvent E = it.next();
        if(E instanceof ProgramChange) {
            E.setProgramNumber(0);
        }
    }
}

input.writeToFile(OUTPUT_FILE);

I wrote that free-hand so you'll likely have to use some exception catching, but it's fairly straight-forward.

Hope that helps.

This works for me. Dontknow what's wrong prevoiusly. python-midi is nice.

#!/usr/bin/env python
#
# Sets all instruments' numbers to zero.
#

import sys
import midi

try:
    infile = sys.argv[1]
except IndexError:
    print "Specify input file as an argument, please."
    sys.exit(1)

try:
    outfile = sys.argv[2]
except IndexError:
    outfile = '%s-out.mid' % infile.replace('.mid', '')

midi_data = midi.read_midifile(infile)

for track_idx in range(len(midi_data)):
    for event in midi_data[track_idx]:
        if isinstance(event, midi.ProgramChangeEvent):
            event.data = map(lambda x: 0, event.data)

midi.write_midifile(outfile, midi_data)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top