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