コーラスっぽいエフェクトを実装してみる

Detuneが出来たので、簡単に出来るかなーって思ったら、
ディレイを実装しなきゃいけないことを知って、
だいぶ無理矢理ですが、それっぽい音が出来ました。

use v5.14;
use strict;
use warnings;

use Cassis;
use constant SAMPLING_RATE => 44100;

my $dco1 = Cassis::DCO::Saw->new( fs => SAMPLING_RATE );
my $dco2 = Cassis::DCO::Saw->new( fs => SAMPLING_RATE );
my $lfo = Cassis::Osc::Tri->new( fs => SAMPLING_RATE, freq => 30 );
my $filter1 = Cassis::Iir2::LPF->new( cutoff => 0.3, q => 1.0 );
my $filter2 = Cassis::Iir2::LPF->new( cutoff => 0.3, q => 1.0 );

my $eg = Cassis::EG->new(
    fs      => SAMPLING_RATE,
    adsr    => [ 0.03, 0.1, 0.9, 0.3 ],
    curve   => 0.5
);

my @wav = ();
my $depth = 0.02;
foreach my $delay ( 0.0, 0.001, 0.01 ) {
    my @pitch_table = (
        -9 / 12, # C
        -7 / 12, # D
        -5 / 12, # E
        -4 / 12, # F
        -2 / 12, # G
         0 / 12, # A
         2 / 12, # B
        (-9 / 12) + 1.0 # C(ここから1オクターブ上がる)
    );

    my @wav1 = ();
    my @wav2 = ();
    while ( @pitch_table ) {
        my $pitch = shift @pitch_table;
        $dco1->set_pitch( 4.0 + $pitch );
        $dco2->set_pitch( 4.0 + $pitch );
        $lfo->set_freq( 10 );

        my $eg_out;
        if ( @pitch_table ) {
            $eg->trigger( gatetime => 0.05 );
            $eg_out = $eg->exec( num => SAMPLING_RATE * 0.3 );
        }
        else {
            $eg_out = $eg->one_shot( gatetime => 0.05 );
        }

        my $dco1_out = $dco1->exec( num => scalar(@{$eg_out}) );
        my $dco2_out = $dco2->exec(
            num => scalar(@{$eg_out}),
            mod_pitch => {
                src => $lfo->exec( num => scalar(@{$eg_out}) ),
                depth => $depth
            }
        );

        my $amp = Cassis::Amp->new();
        my $amp1_out = $amp->exec(
            src => $filter1->exec( src => $dco1_out ),
            mod_volume => {
                src => $eg_out,
                depth => 1.0
            }
        );
        my $amp2_out = $amp->exec(
            src => $filter2->exec( src => $dco2_out ),
            mod_volume => {
                src => $eg_out,
                depth => 1.0
            }
        );

        push @wav1, @{$amp1_out};
        push @wav2, @{$amp2_out};
    }

    my $n = int(SAMPLING_RATE * $delay);
    if ( 0 < $n ) {
        my @tmp = map { 0.0; } 1..$n;
        push @wav1, @tmp;
        unshift @wav2, @tmp;

        my $mixer_out = Cassis::Mixer::mix(
            { src => \@wav1, volume => 0.5 },
            { src => \@wav2, volume => 0.5 }
        );

        push @wav, @{$mixer_out};
    }
    else {
        push @wav, @wav1;
    }
}

Cassis::File::write(
    file => 'chorus.wav',
    fs => SAMPLING_RATE, channels => [ \@wav ] );

Detuneのように、
単にpitchを揺らしたものをミックスするだけじゃダメで、
少し遅らせた音をミックスするのがポイントのようです。
なので、ミックスする前に無音期間を追加して、
それっぽい効果を得ています。

パラメーターを変えると、フランジャーにもなるそうですよ。

おしまい。

Leave a Comment