문제

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

올바른 솔루션이 없습니다

다른 팁

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)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top