音の作り方[入門編]
波形の生成
任意の周波数を持った波形データを生成するには、

リスト3は、
sub create_modulator { # (1)
my $samples_per_sec = shift;
my $arg_ref = shift;
my $freq = $arg_ref->{freq};
my $osc_func = create_mod_func( $arg_ref->{waveform} );
my $t = 0.0;
my $samples_per_cycle = $samples_per_sec / $freq; # (2)
return sub {
my $mod = shift;
my $ret = $osc_func->(
$t / $samples_per_cycle # (3)
);
my $dt = 1.0 + $mod;
if ( 0.0 < $dt ) {
$t += $dt;
while ( $samples_per_cycle <= $t ) {
$t -= $samples_per_cycle;
}
}
return $ret;
};
}
# 1秒間分の440Hzのサイン波を生成する
my $osc = create_modulator( # (4)
44100, # サンプリング周波数
{
freq => 440, # 周波数
waveform => 'sin' # 波形の種類
}
);
my @sin_samples = map {
$osc->( 0 ); # (5)
} 1..44100;
周波数変調
ここでは、

図4は、
Perlによる実装
リスト4は周波数変調を実装したコードです。
sub create_pitch_modulator { # (1)
my $samples_per_sec = shift;
my $arg_ref = shift;
my $waveform = $arg_ref->{waveform};
my $depth = $arg_ref->{depth};
if ( $waveform eq 'env' ) {
my $curve = 1.0;
if ( exists $arg_ref->{curve} ) {
$curve = $arg_ref->{curve};
}
my $env = create_envelope(
$samples_per_sec,
{ sec => $arg_ref->{speed}, curve => $curve } );
return sub { $env->() * $depth };
}
else {
my $osc = create_modulator(
$samples_per_sec,
{
freq => (1.0 / $arg_ref->{speed}),
waveform => $waveform
}
);
return sub { $osc->(0) * $depth };
}
}
# 周波数変調用の関数の取得
my $mod = create_pitch_modulator(
44100, # サンプリング周波数
{
speed => 0.5, # 変調する速度
depth => 0.5, # 変調の度合い
waveform => 'pulse' # 矩形波
}
);
# リスト3で定義した波形を周波数変調する
my @sin_with_mod_samples = map {
$osc->( $mod->() ); # (2)
} 1..44100;
減衰音
太鼓や鐘の音のように、

Perlによる実装
リスト5は、
sub create_envelope {
my $samples_per_sec = shift;
my $arg_ref = shift;
my $curve = 1.0;
if ( exists $arg_ref->{curve} ) {
$curve = $arg_ref->{curve};
}
my $mod_func = sub { return ( 1.0 - $_[0] ); };
my $t = 0.0;
my $interval = $samples_per_sec * $arg_ref->{sec};
return sub {
if ( $t < $interval ) {
my $ret = $mod_func->( $t / $interval );
$t += 1.0;
return $ret ** $curve; # (1)
}
else {
return 0.0;
}
};
}
音の作り方[実践編]
次はドラムマシンのように、
キック
バスドラムのような低い音程で
Perlによる実装
リスト6はキックのパラメータです。まずはoscで定義しているパラメータですが、
my $kick = {
osc => {
freq => 25, # (1)
waveform => 'sin', # (2)
mod => {
speed => 0.25, ┓
depth => 3.5, ┃
waveform => 'env',┃(3)
curve => 1.8 ┛
}
},
amp => {
sec => 0.25, # (4)
waveform => 'env', # (5)
curve => 1.4 # (6)
}
};
スネア
スネアドラムは太鼓の一種ですが、

サンプリング&ホールドとは、
Perlによる実装
リスト7はスネアのパラメータです。バスドラムのように低い音ではないので
my $snare = {
osc => {
freq => 400, # (1)
waveform => 'tri',
mod => {
speed => 0.08, depth => 9.0, waveform => 'noise'
}
},
amp => { sec => 0.16, waveform => 'env', curve => 2.2 }
};
ハイハット
ハイハットはシンバルを2つ組み合わせた楽器で、
Perlによる実装
リスト8はオープンハイハットとクローズハイハットの2つのパラメータです。両者の違いはampに定義している音の鳴っている時間だけです。オープンハイハットは時間を長く、
# オープンハイハット
my $o_hat = {
osc => {
freq => 16000,
waveform => 'tri',
mod => {
speed => 0.06, depth => 6.0, waveform => 'noise'
}
},
amp => { sec => 0.15, waveform => 'env', curve => 2.7 }
};
# クローズハイハット
my $c_hat = {
osc => {
freq => 16000,
waveform => 'tri',
mod => {
speed => 0.06, depth => 6.0, waveform => 'noise'
}
},
amp => { sec => 0.08, waveform => 'env', curve => 2.7 }
};
波形データの生成
次に、
リスト9は、
sub create_oneshot {
my $samples_per_sec = 44100;
my $arg_ref = shift;
my $osc = create_modulator(
$samples_per_sec, $arg_ref->{osc} ); # (1)
my $env = create_envelope(
$samples_per_sec, $arg_ref->{amp} ); # (2)
my $mod = sub { return 0.0; }; # pitch modulator
if ( exists $arg_ref->{osc}->{mod} ) {
$mod = create_pitch_modulator(
$samples_per_sec, $arg_ref->{osc}->{mod} );
}
my $amp = $arg_ref->{amp};
my $gate_time = int( $samples_per_sec * $amp->{sec} );
my @samples = map {
$osc->( $mod->() ) * $env->(); # (3)
} 0..($gate_time - 1);
return \@samples;
}
my $samples_kick_ref = create_oneshot( $kick );
my $samples_snare_ref = create_oneshot( $snare );
my $samples_o_hat_ref = create_oneshot( $o_hat );
my $samples_h_hat_ref = create_oneshot( $c_hat );