MIDI
包可以帮您实现此功能,但确切的处理方法取决于midi文件的原始内容。
一个midi文件由一个或多个轨道组成,每个轨道都是十六个通道中的任何一个上的事件序列,例如
音符关闭,
音符开启,
程序更改等。这些事件中的最后一个将更改分配给通道的乐器,这就是您需要更改或添加的乐器。
如果一个通道根本没有任何程序更改事件,它将使用程序号(声音号)为零的钢琴声。如果您想更改此类频道的乐器,则只需在轨道开头为该频道添加一个新的程序更改事件即可。
然而,如果通道已经有程序更改事件,则在开头添加一个新的事件将不起作用,因为它会立即被现有的事件覆盖。在这种情况下,您必须更改现有事件的参数以使用所需的乐器。
如果原来某个通道有多个程序更改事件,那么意味着乐器在整个轨道中换了几次。虽然这很少见,但如果你遇到这样的文件,你就必须决定如何改变它。
假设您有一个非常简单的midi文件,只有一个轨道,一个通道和没有现有的程序更改事件。该程序从文件中创建一个新的
MIDI::Opus
对象,访问轨道列表(只有一个成员),并获取对第一个轨道事件列表的引用。然后,在事件列表的开头
插入了一个新的频道0的程序更改事件(此模块称其为
patch_change
)。新事件的程序号为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');