Заменить 0xC0<byte> на 0xC000, чтобы "сбросить" MIDI-инструмент?

У меня есть некоторые MIDI-файлы, сделанные Sibelius (v.4?..) с "необычным" инструментом внутри; Я не слышу мелодию. Я решил, что мне нужно "сбросить" инструмент на 0 (я считаю, что это акустическое рояль).

Итак, я написал программы на Python, используя как python-midi, так и mingus; Эти программы могут изменить MIDI-инструмент, но они обе резко изменили ритм.

Rosegarden делает эту работу довольно хорошо, но я не могу использовать ее в партии.

Затем, после некоторого чтения информации о формате MIDI ( здесь и здесь, например), я написал простой скрипт на Python (см. Ниже), который просто заменяет некоторые строки на другие - заменяет 0xC0[byte] на 0xC000 и тому подобное.

Теперь эти MIDI-файлы звучат хорошо, я все слышу.

Итак, мой вопрос - это "безопасно" (в любом смысле), чтобы сделать это? Как я могу поменять инструменты лучше? Как мне лучше "обнаружить" команду 0xCx в файле MIDI?

Спасибо!

#!/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))

2 ответа

Не безопасно просто заменить все 0xC??? байтов с 0xC?00, главным образом потому, что 0xC??? может указывать дельта-время события и фактически не быть частью события изменения программы. Случайное изменение времени дельты сместит все последующие события в нерабочее время, что будет звучать довольно ужасно, если оно является частью многодорожечной композиции.

Что касается решения, я сомневаюсь, что есть регулярное выражение, которое может обнаруживать события Program Change, возможно, не отслеживая также и дельта-времена. Мой единственный опыт изменения MIDI связан с библиотекой Java, которую я написал, и вы выполнили бы свою задачу с помощью следующего кода:

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

Я написал это от руки, так что вам, вероятно, придется использовать ловушку исключений, но это довольно просто.

Надеюсь, это поможет.

Это работает для меня. Не знаю, что не так, как раньше. python-midi это мило.

#!/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)
Другие вопросы по тегам