エンベロープ・ジェネレータ

雲仙用のドッグ・フードを食べる企画として作成しているシンセサイザー。Youtubeではすでに音が出る様子を公開していますが、ブログでは粛々と個々のモジュールを紹介していきます。

エンベロープ・ジェネレータは音の特徴を左右する重要なブロックです。ある意味シンセサイザーの顔とも言えるでしょう。VFOの周波数変調に使うやりかたもあるのですが、お試しシンセとしてひねらずに振幅制御に使うことにします。

クラス宣言

このシリーズを読んでいる方がどれだけいるかはわかりませんが、最初から読み続けている人なら、クラス宣言の形にはそろそろ想像がつくころあいでしょう。コンストラクタで処理ブロックのサイズを設定し、run()メソッドでは与えられたバッファに振幅データを格納して返しています。

amakusa::AbstractFilterから派生させても良かったのですが、気の迷いで周波数変調に使うことになった場合にそなえ、内部で余計なことをせずに包絡線のみ出力させています。

class EG {
public:
    EG ( int32_t a_block_size );
    virtual void run( float *pEnvelope );
    void on(void);
    void off(void);
    void set_attack( float attack );                // [0,1.0]
    void set_decay( float attack );                 // [0,1.0]
    void set_sustain( float sustain );              // [0,1.0]
    void set_release ( float attack );              // [0,1.0]
private:
    float current_level, sustain_level;
    float attack_time_constant, decay_time_constant, release_time_constant;
    eg_state  state;
    int32_t block_size;
};

 

実装

内部では、外部からのキーのオン、オフをトリガーにAttack, Decay, Release の間で状態遷移させています。唯一、Attackだけは包絡線が所定の値になったときに自動的にDecayへと状態遷移させています。

包絡線の曲線は1-exp(-At)とすべきですが、ここは手を抜いて1-A^tとしています(1.0>A)。

void EG::run( float32_t *pEnvelope )
{
    if ( this->state == release )
        for ( int i= 0; i< this->block_size; i++ )
            pEnvelope[i] = this->current_level = 
                this->current_level * this->release_time_constant;
    else if ( this->state == decay )
        for ( int i= 0; i< this->block_size; i++ )
            pEnvelope[i] = this->current_level = 
                ( this->current_level - this->sustain_level ) * this->decay_time_constant
                + this->sustain_level;
    else // attack
    {
        for ( int i= 0; i< this->block_size; i++ )
            pEnvelope[i] = this->current_level = 
                1.5f - 
                ( 1.5f - this->current_level ) * this->attack_time_constant;
        if ( this->current_level >= 1.0f )
            this->state = decay;
     }               
    
}

void EG::on(void)
{
    this->state = attack;
}

void EG::off(void)
{
    this->state = release;
}

 

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください