Audio::PortAudio(入門編)
あらかじめ断っておくと、
MacOS Xを使っていて、homebrewでportaudioをインストール出来て、
cpanmでAudio::PortAudioをインストールできることを前提に書いています。
use strict;
use warnings;
use Cassis;
use Audio::PortAudio;
use constant SAMPLING_RATE => 44100;
use constant INT16_MAX => 0x7FFF;
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オクターブ上がる)
);
play();
sub play {
my ( $frames_per_buffer, $stream_flags ) = ( 512, undef );
my $api = Audio::PortAudio::default_host_api();
printf STDERR "Going to play via %s\nCtrl+c to stop...", $api->name;
my $device = $api->default_output_device;
my $stream = $device->open_write_stream( {
channel_count => 1, # 1:mono, 2:stereo
sample_format => 'int16' # 'float32', 'int16', 'int32', 'int24', 'int8', 'uint8'
},
SAMPLING_RATE,
$frames_per_buffer,
$stream_flags,
);
my $dco = Cassis::DCO::Tri->new( fs => SAMPLING_RATE );
my $interval = int( SAMPLING_RATE * 0.5 );
my $i = $interval;
# Infinite loop...
while ( 1 ) {
my $wa = $stream->write_available;
if ( $interval <= $i ) {
my $pitch = shift @pitch_table;
$dco->set_pitch( 4.0 + $pitch );
push @pitch_table, $pitch;
$i -= $interval;
}
my $dco_out = $dco->exec( num => $wa );
my $buf = pack( 's*', map {
int( (($_ < -1.0) ? -1 : ((1.0 < $_) ? +1 : $_)) * INT16_MAX );
} @{$dco_out} );
$stream->write( $buf );
$i += $wa;
}
}
コードの説明をする前に、PortAudioを使用する準備をします。
cpanmでテストが走った際にも音が出るので、
インストール前にスピーカーの音量は小さめにしておくと良いです。
$ brew install portaudio
$ cpanm Audio::PortAudio
そしてコードの方ですが、あんまり単純だと面白くないので、
約0.5秒ごとに音程が変わるようにしました。
ポイントとしては、
Cassisのモジュールはサンプル数を指定して波形を生成できるので、
Port::Audioとの相性が良いという事です。
でも、効果音を作る時は時間を指定したいですよね。。。
なので、issueを登録した次第。
おしまい。
Leave a Comment