Perlでミョンミョンした音を作る
今日はCassisを開発するときに使ってるスクリプトを公開します。
あとはパラメータをファイルから入力できるようにして、
サンプルスクリプトとしてリポジトリに追加する予定です。
package MySynth;
use strict;
use warnings;
use Cassis;
sub new {
my $class = shift;
my %args = @_;
my $fs = ( exists $args{fs} ) ? $args{fs} : 44100;
bless {
samples => [],
fs => $fs,
modules => {
DCO1 => Cassis::DCO::Saw->new( fs => $fs ),
DCO2 => Cassis::DCO::Tri->new( fs => $fs ),
LPF => Cassis::Iir2::LPF->new( cutoff => 0.01, q => 6.0 ),
LFO1 => Cassis::Osc::Pulse->new( fs => $fs ),
LFO2 => Cassis::Osc::Sin->new( fs => $fs ),
AMP => Cassis::Amp->new(),
EG1 => Cassis::EG->new(
fs => $fs,
adsr => [ 0.03, 0.1, 0.5, 0.5 ],
curve => 0.5
),
EG2 => Cassis::EG->new(
fs => $fs,
adsr => [ 0.03, 0.4, 0.2, 0.5 ],
curve => 0.5
)
}
}, $class;
}
sub exec {
my $self = shift;
my %args = @_;
my ( $dco1, $dco2, $lpf, $lfo1, $lfo2, $amp, $env1, $env2 ) = map {
$self->{modules}->{$_};
} qw(DCO1 DCO2 LPF LFO1 LFO2 AMP EG1 EG2);
$dco1->set_pitch( $args{pitch} - 0.01) if ( exists $args{pitch} );
$dco2->set_pitch( $args{pitch} - 1.0 ) if ( exists $args{pitch} );
$lfo1->set_freq( 2000 );
$lfo2->set_freq( 2200 );
$amp->set_volume( 0.5 );
$env1->trigger( gatetime => 1.0 );
$env2->trigger( gatetime => 0.5 );
my $lfo1_out = $lfo1->exec( num => $args{num} );
my $lfo2_out = $lfo2->exec( num => $args{num} );
my $dco1_out = $dco1->exec( num => $args{num}, mod_pitch => {
src => $lfo1_out, depth => 0.2
} );
my $dco2_out = $dco2->exec( num => $args{num}, mod_pitch => {
src => $lfo2_out, depth => 0.1
} );
my $filter_out = $lpf->exec( src => mix($dco1_out, $dco2_out, 0.5), mod_cutoff => {
src => $env2->exec( num => $args{num} ), depth => 0.5
} );
my $amp_out = $amp->exec( src => $filter_out, mod_volume => {
src => $env1->exec( num => $args{num} ), depth => 1.0
} );
push @{$self->{samples}}, @{$amp_out};
}
sub write {
my $self = shift;
my %args = @_;
$args{sf} = $self->{sf};
$args{channels} = [ $self->{samples} ];
Cassis::File::write( %args );
}
sub mix {
my ( $src1, $src2, $gain ) = @_;
my $n = scalar( @{$src1} );
my @dst = map { ($src1->[$_] + $src2->[$_]) * $gain; } 0..($n - 1);
return \@dst;
}
package main;
use strict;
use warnings;
my %NOTE_TO_PITCH = (
C => -9 / 12,
D => -7 / 12,
E => -5 / 12,
F => -4 / 12,
G => -2 / 12,
A => 0 / 12,
B => 2 / 12
);
my $s = MySynth->new();
foreach ( qw(C4 D4 E4 F4 G4 A4 B4 C5) ) {
if ( my ( $note, $octave ) = m/([\w])(\d)/i ) {
print 'pitch: ', $octave + $NOTE_TO_PITCH{$note}, "\n";
$s->exec(
pitch => $octave + $NOTE_TO_PITCH{$note},
num => 44100 * 0.5
);
}
else {
warn 'cannot parse => ', $_;
}
}
$s->write( file => 'sample.wav' );
まだ、音作りのコツがつかめてないのですが、
実際は、ランダムパラメータでWAVとパラメータと出力して、
気に入った音が見つかったら詰めていこうと思っています。
個人的に、非常に満足しております。
おしまい。
Leave a Comment