既存の .mid ファイルを解析し、楽器を「アコースティック グランド ピアノ」から「バイオリン」などに変更して、元に戻すか、別の .mid ファイルとして保存したいと考えています。
ドキュメントで見たところ、楽器はprogram_change
orpatch_change
ディレクティブで変更されますが、既存の MIDI ファイルでこれを行うライブラリは見つかりません。それらはすべて、ゼロから作成された MIDI ファイルのみをサポートしているようです。
パッケージがこれMIDI
を行いますが、正確な方法は midi ファイルの元の内容によって異なります。
MIDI ファイルは 1 つまたは複数のトラックで構成され、各トラックは、ノート オフ、ノート オン、プログラム チェンジなど、16 チャンネルのいずれかの一連のイベントです。これらの最後のものは、チャンネルに割り当てられた楽器を変更します。それはあなたが変更または追加する必要があるものです。
プログラム チェンジ イベントがまったくない場合、チャネルはアコースティック グランド ピアノであるプログラム番号 (ボイス番号) 0 を使用します。このようなチャンネルのインストゥルメントを変更したい場合は、このチャンネルの新しいプログラム チェンジ イベントをトラックの先頭に追加するだけです。
ただし、チャンネルにすでにプログラム チェンジ イベントがある場合、最初に新しいイベントを追加しても効果はありません。これは、既存のイベントによってすぐに上書きされるためです。この場合、必要なインストゥルメントを使用するには、既存のイベントのパラメーターを変更する必要があります。
1 つのチャンネルにもともと複数のプログラム チェンジ イベントがあり、楽器がトラック全体で変化する場合、事態はさらに複雑になる可能性があります。これは珍しいことですが、このようなファイルに遭遇した場合は、どのように変更するかを決定する必要があります。
トラックが 1 つ、チャンネルが 1 つしかなく、プログラム チェンジ イベントが存在しない非常に単純な midi ファイルがあるとします。このプログラムはMIDI::Opus
、ファイルから新しいオブジェクトを作成し、トラックのリスト (単一のメンバーのみ) にアクセスし、最初のトラックのイベントのリストへの参照を取得します。patch_change
次に、チャンネル 0の新しいプログラム チェンジ イベント (このモジュールがそれを呼び出します)が、イベント リストの先頭にシフト解除されます。新しいイベントのプログラム番号は 40 (バイオリン) であるため、このチャンネルはピアノではなくバイオリンで演奏されます。
複数のトラック、複数のチャンネル、および既存のプログラム変更イベントがあると、タスクはより複雑になりますが、原則は同じです。何を行う必要があるかを決定し、必要に応じてイベントのリストを変更します。
use strict;
use warnings;
use MIDI;
my $opus = MIDI::Opus->new( { from_file => 'song.mid' } );
my $tracks = $opus->tracks_r;
my $track0_events = $tracks->[0]->events_r;
unshift @$track0_events, ['patch_change', 0, 0, 40];
$opus->write_to_file('newsong.mid');
music21 ライブラリを使用します(自分のシステムをプラグインします。問題ないことを願っています)。パーツにパッチが定義されている場合は、次のようにします。
from music21 import converter,instrument # or import *
s = converter.parse('/Users/cuthbert/Desktop/oldfilename.mid')
for el in s.recurse():
if 'Instrument' in el.classes: # or 'Piano'
el.activeSite.replace(el, instrument.Violin())
s.write('midi', '/Users/cuthbert/Desktop/newfilename.mid')
または、現在定義されているパッチの変更がない場合:
from music21 import converter,instrument # or import *
s = converter.parse('/Users/cuthbert/Desktop/oldfilename.mid')
for p in s.parts:
p.insert(0, instrument.Violin())
s.write('midi', '/Users/cuthbert/Desktop/newfilename.mid')