## 自己紹介
                    - 仕事: .NETでGUIアプリ
                    - Twitter: @techno_neko
                    - 所属: Hokkaido.pm
                
                
                
                    ## 例えば・・・?
                    - 車のハンドルと実際の動き
                    - 電子楽器
                    - 画像の輪郭抽出
                
                
                    ## アクセスログに使うと・・・?
                    - スパイク(突発的なアクセス)の除去
                    - スパイクの生じた日時の抽出
                    (位相のずれを考えると、FIRの方が良いかと・・・。)
                
                
                    スパイク(突発的なアクセス)の除去
                    低域通過フィルタ(長い周期の信号を通過させる)
                     
                
                
                    スパイクの生じた日時の抽出
                    高域通過フィルタ(短い周期の信号を通過させる)
                     ## これ、どうやって描いたの?
                    - Imager
                    - Cassis  
                    https://github.com/techno-cat/p5-Cassis
                
                
                    ## Cassisを使って、ディタルフィルタが学べる!!1
                
                
                    ## 試してみよう!
                    1. 波形の生成
                    1. 波形の足し算
                    1. フィルタを通す
                
                
                    ## その前に
                    - 波形を描いてみる
                    - WAVファイルで出力
                
                
                    ## 波形を描いてみる(1/5)
                    グラフの余白をあらかじめ決めると、後が楽になる
                    ```perl
# 目盛の色
use constant TICK_COLOR => Imager::Color->new( 80, 80, 80 );
use constant TICK_X => 20; # x軸方向の目盛の間隔
use constant TICK_Y => 50; # y軸方向の目盛の間隔
use constant STEP_X => 5;  # プロット間隔
use constant MARGIN => 20; # グラフ領域と画像サイズの隙間
use constant N => 80;      # プロット数
                    ```
                
                
                    ## 波形を描いてみる(2/5)
                    原点の計算を済ませると描画処理が簡単になる
                    ```perl
# グラフ領域の計算
my $graph_width = (STEP_X * N) + 1;
my $graph_height = 200;
# 原点
my $x0 = MARGIN;
my $y0 = MARGIN + $graph_height - 1;
# 波形データの生成
my @src = map {
    0.5 + sin($_ * 0.1) * 0.25
} 0..(N - 1);
draw_graph( 'my_graph.png', \@src );
                    ```
                
                
                    ## 波形を描いてみる(3/5)
                    グラフ描画の手続き
                    ```perl
sub draw_graph {
    my ( $path, $src ) = @_;
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, \@src, 'red' );
    $img->write( file => $path ) or die $img->errstr;
}
                    ```
                
                
                    ## 波形を描いてみる(4/5)
                    目盛を描画
                    ```perl
sub draw_graduation {
    my ( $img, $color ) = @_;
    my $x = 0;
    while ( $x <= $graph_width ) {
        $img->line( color => $color,
            x1 => $x0 + $x, y1 => $y0,
            x2 => $x0 + $x, y2 => $y0 - $graph_height - 1 );
        $x += (TICK_X * STEP_X);
    }
    my $y = 0;
    while ( $y <= $graph_height ) {
        $img->line( color => $color,
            x1 => $x0,                    y1 => $y0 - $y,
            x2 => $x0 + $graph_width - 1, y2 => $y0 - $y );
        $y += TICK_Y;
    }
}
                    ```
                
                
                    ## 波形を描いてみる(5/5)
                    データをプロット
                    ```perl
sub draw_wave {
    my ( $img, $data, $color ) = @_;
    my $y0 = int($img->getheight() / 2);
    my $xmax = scalar(@{$data}) - 1;
    my @points = map {
        my $gain = TICK_Y * $data->[$_];
        [ $_, $y0 - int(($gain < .0) ? ($gain - .5) : ($gain + .5)) ];
    } 0..$xmax;
    $img->polyline( points => \@points, color => $color );
}
                    ```
                
                
                    ## WAVファイルで出力
                    ```perl
use Cassis;
use Math::Trig ':pi';
use constant SAMPLING_RATE => 44100;
my @src = map { sin(440 * 2.0 * pi * ($_ / SAMPLING_RATE)) } 0..(SAMPLING_RATE - 1);
Cassis::File::write( 
    file        => '440.wav',
    sf          => SAMPLING_RATE,
    channels    => [ \@src ] );
                    ```
                
                
                    ## 波形の生成(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $osc1_out, 'red' );
    draw_wave( $img, $osc2_out, 'green' );
    $img->write( file => '01.png' ) or die $img->errstr;
}
                    ```
                
                
                    ## これ、どうやって描いたの?
                    - Imager
                    - Cassis  
                    https://github.com/techno-cat/p5-Cassis
                
                
                    ## Cassisを使って、ディタルフィルタが学べる!!1
                
                
                    ## 試してみよう!
                    1. 波形の生成
                    1. 波形の足し算
                    1. フィルタを通す
                
                
                    ## その前に
                    - 波形を描いてみる
                    - WAVファイルで出力
                
                
                    ## 波形を描いてみる(1/5)
                    グラフの余白をあらかじめ決めると、後が楽になる
                    ```perl
# 目盛の色
use constant TICK_COLOR => Imager::Color->new( 80, 80, 80 );
use constant TICK_X => 20; # x軸方向の目盛の間隔
use constant TICK_Y => 50; # y軸方向の目盛の間隔
use constant STEP_X => 5;  # プロット間隔
use constant MARGIN => 20; # グラフ領域と画像サイズの隙間
use constant N => 80;      # プロット数
                    ```
                
                
                    ## 波形を描いてみる(2/5)
                    原点の計算を済ませると描画処理が簡単になる
                    ```perl
# グラフ領域の計算
my $graph_width = (STEP_X * N) + 1;
my $graph_height = 200;
# 原点
my $x0 = MARGIN;
my $y0 = MARGIN + $graph_height - 1;
# 波形データの生成
my @src = map {
    0.5 + sin($_ * 0.1) * 0.25
} 0..(N - 1);
draw_graph( 'my_graph.png', \@src );
                    ```
                
                
                    ## 波形を描いてみる(3/5)
                    グラフ描画の手続き
                    ```perl
sub draw_graph {
    my ( $path, $src ) = @_;
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, \@src, 'red' );
    $img->write( file => $path ) or die $img->errstr;
}
                    ```
                
                
                    ## 波形を描いてみる(4/5)
                    目盛を描画
                    ```perl
sub draw_graduation {
    my ( $img, $color ) = @_;
    my $x = 0;
    while ( $x <= $graph_width ) {
        $img->line( color => $color,
            x1 => $x0 + $x, y1 => $y0,
            x2 => $x0 + $x, y2 => $y0 - $graph_height - 1 );
        $x += (TICK_X * STEP_X);
    }
    my $y = 0;
    while ( $y <= $graph_height ) {
        $img->line( color => $color,
            x1 => $x0,                    y1 => $y0 - $y,
            x2 => $x0 + $graph_width - 1, y2 => $y0 - $y );
        $y += TICK_Y;
    }
}
                    ```
                
                
                    ## 波形を描いてみる(5/5)
                    データをプロット
                    ```perl
sub draw_wave {
    my ( $img, $data, $color ) = @_;
    my $y0 = int($img->getheight() / 2);
    my $xmax = scalar(@{$data}) - 1;
    my @points = map {
        my $gain = TICK_Y * $data->[$_];
        [ $_, $y0 - int(($gain < .0) ? ($gain - .5) : ($gain + .5)) ];
    } 0..$xmax;
    $img->polyline( points => \@points, color => $color );
}
                    ```
                
                
                    ## WAVファイルで出力
                    ```perl
use Cassis;
use Math::Trig ':pi';
use constant SAMPLING_RATE => 44100;
my @src = map { sin(440 * 2.0 * pi * ($_ / SAMPLING_RATE)) } 0..(SAMPLING_RATE - 1);
Cassis::File::write( 
    file        => '440.wav',
    sf          => SAMPLING_RATE,
    channels    => [ \@src ] );
                    ```
                
                
                    ## 波形の生成(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $osc1_out, 'red' );
    draw_wave( $img, $osc2_out, 'green' );
    $img->write( file => '01.png' ) or die $img->errstr;
}
                    ```
                
                
                    波形の生成(2/2)
                     ## 波形の足し算(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $mixer_out = Cassis::Mixer::mix(
        { src => $osc1_out, volume => 0.2 },
        { src => $osc2_out, volume => 0.1 }
    );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $mixer_out, 'orange' );
    draw_wave( $img, $osc1_out, 'red' );
    draw_wave( $img, $osc2_out, 'green' );
    $img->write( file => '02.png' ) or die $img->errstr;
}
                    ```
                
                
                    ## 波形の足し算(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $mixer_out = Cassis::Mixer::mix(
        { src => $osc1_out, volume => 0.2 },
        { src => $osc2_out, volume => 0.1 }
    );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $mixer_out, 'orange' );
    draw_wave( $img, $osc1_out, 'red' );
    draw_wave( $img, $osc2_out, 'green' );
    $img->write( file => '02.png' ) or die $img->errstr;
}
                    ```
                
                
                    波形の足し算(2/2)
                     ## フィルタを通す(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $mixer_out = Cassis::Mixer::mix(
        { src => $osc1_out, volume => 0.2 },
        { src => $osc2_out, volume => 0.1 }
    );
    # "linear => 1"を設定すると、一般的な方法で計算が使われる(音楽用途だと使いにくい)
    my $q = 1.0 / sqrt(2.0);
    my $lpf = Cassis::Iir2::LPF->new( cutoff => 0.04, q => $q, linear => 1 );
    my $hpf = Cassis::Iir2::HPF->new( cutoff => 0.015, q => $q, linear => 1 );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $mixer_out, 'orange' );
    draw_wave( $img, $lpf->exec( src => $mixer_out ), 'red' );
    draw_wave( $img, $hpf->exec( src => $mixer_out ), 'green' );
    $img->write( file => '03.png' ) or die $img->errstr;
}
                    ```
                
                
                    ## フィルタを通す(1/2)
                    ```perl
{
    my $osc1_out = Cassis::Osc::Pulse->new( fs => N, freq => 2 )->exec( num => N );
    my $osc2_out = Cassis::Osc::Sin->new( fs => N, freq => 4 )->exec( num => N );
    my $mixer_out = Cassis::Mixer::mix(
        { src => $osc1_out, volume => 0.2 },
        { src => $osc2_out, volume => 0.1 }
    );
    # "linear => 1"を設定すると、一般的な方法で計算が使われる(音楽用途だと使いにくい)
    my $q = 1.0 / sqrt(2.0);
    my $lpf = Cassis::Iir2::LPF->new( cutoff => 0.04, q => $q, linear => 1 );
    my $hpf = Cassis::Iir2::HPF->new( cutoff => 0.015, q => $q, linear => 1 );
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + 100 + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, $mixer_out, 'orange' );
    draw_wave( $img, $lpf->exec( src => $mixer_out ), 'red' );
    draw_wave( $img, $hpf->exec( src => $mixer_out ), 'green' );
    $img->write( file => '03.png' ) or die $img->errstr;
}
                    ```
                
                
                    フィルタを通す(2/2)
                     ## まとめ
                    - 使い道はいろいろ
                    - Cassisは難しい
                    - でも、Imagerは便利だよ!
                
                
                    ## おまけ
                    アクセスログのグラフに使ったスクリプト
                    ```perl
#!perl
use strict;
use warnings;
use Cassis;
use Imager;
use constant TICK_COLOR => Imager::Color->new( 80, 80, 80 );
use constant TICK_X => 20;
use constant TICK_Y => 50;
use constant STEP_X => 5;
use constant MARGIN => 20;
use constant N => 80;
my $graph_width = (STEP_X * N) + 1;
my $graph_height = 200;
my $x0 = MARGIN;
my $y0 = MARGIN + $graph_height - 1;
my @src = map {
    (sin($_ * 0.1) * 0.01) + ($_ * 0.005);
} 0..(N - 1);
# スパイクの追加
$src[20] += 0.3;
$src[50] += 0.1;
$src[60] += 0.2;
my $q = 1.0 / sqrt(2.0);
{
    my $f = Cassis::Iir2::LPF->new( cutoff => 0.04, q => $q, linear => 1 );
    my $dst = $f->exec( src => \@src );
    draw_graph( 'sample_lpf.png', \@src, $dst );
}
{
    my $f = Cassis::Iir2::HPF->new( cutoff => 0.015, q => $q, linear => 1 );
    my $dst = $f->exec( src => \@src );
    draw_graph( 'sample_hpf.png', \@src, $dst );
}
sub draw_graph {
    my ( $path, $src, $dst ) = @_;
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, \@src, 'red' );
    draw_wave( $img, $dst, 'green' );
    $img->write( file => $path ) or die $img->errstr;
}
sub draw_graduation {
    my ( $img, $color ) = @_;
    my $x = 0;
    while ( $x <= $graph_width ) {
        $img->line( color => $color,
            x1 => $x0 + $x, y1 => $y0,
            x2 => $x0 + $x, y2 => $y0 - $graph_height - 1 );
        $x += (TICK_X * STEP_X);
    }
    my $y = 0;
    while ( $y <= $graph_height ) {
        $img->line( color => $color,
            x1 => $x0,                    y1 => $y0 - $y,
            x2 => $x0 + $graph_width - 1, y2 => $y0 - $y );
        $y += TICK_Y;
    }
}
sub draw_wave {
    my ( $img, $data, $color ) = @_;
    my $y1;
    my $n = scalar( @{$data} );
    for (my $i=0; $i<$n; $i++) {
        my $x = $x0 + ($i * STEP_X);
        my $y = $y0 - ($graph_height * $data->[$i]);
        $y = int( ($y < .0) ? ($y - .5) : ($y + .5) );
        if ( 0 < $i ) {
            my $x1 = $x - STEP_X;
            $img->line(
                x1 => $x1, y1 => $y1,
                x2 => $x , y2 => $y,
                color => $color )
        }
        $img->box(
            xmin => $x - 1, ymin => $y - 1, xmax => $x + 1, ymax => $y + 1,
            color => $color, filled => 0 );
        $y1 = $y;
    }
}
                    ```
                
                
                    ## まとめ
                    - 使い道はいろいろ
                    - Cassisは難しい
                    - でも、Imagerは便利だよ!
                
                
                    ## おまけ
                    アクセスログのグラフに使ったスクリプト
                    ```perl
#!perl
use strict;
use warnings;
use Cassis;
use Imager;
use constant TICK_COLOR => Imager::Color->new( 80, 80, 80 );
use constant TICK_X => 20;
use constant TICK_Y => 50;
use constant STEP_X => 5;
use constant MARGIN => 20;
use constant N => 80;
my $graph_width = (STEP_X * N) + 1;
my $graph_height = 200;
my $x0 = MARGIN;
my $y0 = MARGIN + $graph_height - 1;
my @src = map {
    (sin($_ * 0.1) * 0.01) + ($_ * 0.005);
} 0..(N - 1);
# スパイクの追加
$src[20] += 0.3;
$src[50] += 0.1;
$src[60] += 0.2;
my $q = 1.0 / sqrt(2.0);
{
    my $f = Cassis::Iir2::LPF->new( cutoff => 0.04, q => $q, linear => 1 );
    my $dst = $f->exec( src => \@src );
    draw_graph( 'sample_lpf.png', \@src, $dst );
}
{
    my $f = Cassis::Iir2::HPF->new( cutoff => 0.015, q => $q, linear => 1 );
    my $dst = $f->exec( src => \@src );
    draw_graph( 'sample_hpf.png', \@src, $dst );
}
sub draw_graph {
    my ( $path, $src, $dst ) = @_;
    my $img = Imager->new(
        xsize => MARGIN + $graph_width + MARGIN,
        ysize => MARGIN + $graph_height + MARGIN );
    $img->box( filled => 1, color => 'black' );
    draw_graduation( $img, TICK_COLOR );
    draw_wave( $img, \@src, 'red' );
    draw_wave( $img, $dst, 'green' );
    $img->write( file => $path ) or die $img->errstr;
}
sub draw_graduation {
    my ( $img, $color ) = @_;
    my $x = 0;
    while ( $x <= $graph_width ) {
        $img->line( color => $color,
            x1 => $x0 + $x, y1 => $y0,
            x2 => $x0 + $x, y2 => $y0 - $graph_height - 1 );
        $x += (TICK_X * STEP_X);
    }
    my $y = 0;
    while ( $y <= $graph_height ) {
        $img->line( color => $color,
            x1 => $x0,                    y1 => $y0 - $y,
            x2 => $x0 + $graph_width - 1, y2 => $y0 - $y );
        $y += TICK_Y;
    }
}
sub draw_wave {
    my ( $img, $data, $color ) = @_;
    my $y1;
    my $n = scalar( @{$data} );
    for (my $i=0; $i<$n; $i++) {
        my $x = $x0 + ($i * STEP_X);
        my $y = $y0 - ($graph_height * $data->[$i]);
        $y = int( ($y < .0) ? ($y - .5) : ($y + .5) );
        if ( 0 < $i ) {
            my $x1 = $x - STEP_X;
            $img->line(
                x1 => $x1, y1 => $y1,
                x2 => $x , y2 => $y,
                color => $color )
        }
        $img->box(
            xmin => $x - 1, ymin => $y - 1, xmax => $x + 1, ymax => $y + 1,
            color => $color, filled => 0 );
        $y1 = $y;
    }
}
                    ```