4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FAUST:自分好みのフェイザーを作ってみた

Last updated at Posted at 2018-02-14

フェイザーペダルとオールパスフィルタについての覚書を読んで勉強になったし、実際自分でも試してみて、「お、フェイザーなかなか良いじゃん!」と思い、自分好みのを作ってみました。

変更点

自作のbiquad filter用のライブラリを使う

せっかく作ったし、二次の方が何かと都合がいいらしいので。

MIDI noteに変換してモデュレーションする

周波数リニアでなく、音階にそった方が自然な感じがするので。

LRに位相差をつけられるようにする

広がりがでるし、何かもやもやしていい感じ。

使いやすいインターフェイス

あくまで自分好みに。他の人が使いやすいかは知らん。

こうなりました

myPhaser.dsp

declare name "myPhaser";
import("stdfaust.lib");
import("RBJ.lib");

process = phaserMono(0.0), phaserMono(phaseDiff) ;
phaserMono(phaseDiff) = _
  <: _ , apfSeq
  : *(1 - wet), *(wet)
  :> _
    with{
      apfSeq = _, stage
        : seq( i, 12, bypassIfZero( APF( F, Q ) ) )
        : _, ! ;
      F = ba.midikey2hz( note ) ;
      note = centerNote + ampMod * os.oscp(modF, phaseDiff * ma.PI) ;
      centerNote = (hz2midi(ceilingF) + hz2midi(floorF)) / 2.0 ;
      ampMod = ( hz2midi(ceilingF) - hz2midi(floorF)) / 2.0 ;
    };

bypassIfZero( func, x, stage ) =
  ( x : ba.bypass1( stage == 0, func ) ), max( 0, stage - 1 ) ;

hz2midi(f) = 12*ma.log2(f/440.0) + 69.0;

phaserGrp( x ) = hgroup("[0]Phaser", x ) ;
stage     = phaserGrp( hslider("[0]Stage[style:knob]", 6, 1, 12, 1 ) ) ;
Q         = phaserGrp( hslider("[1]Q[style:knob]",0.7,0.1,4.5,0.1) ) ;
modF      = phaserGrp( hslider("[2]modFreq[style:knob][unit:Hz]", 1.0, 0.01, 5.0, 0.01)) ;
floorF    = phaserGrp( hslider("[3]Floor[style:knob][unit:Hz]", 440, 100, 5000, 0)) ;
ceilingF  = phaserGrp( hslider("[4]Ceiling[style:knob][unit:Hz]", 880, 440, 5000, 0)) ;
phaseDiff = phaserGrp( hslider("[5]phaseDiff[style:knob]", 0.5, -1.0, 1.0, 0.1)) ;
wet       = phaserGrp( hslider("[6]Wet[style:knob]", 0.5, 0.0, 0.5, 0.001) ) ;

これを 自作のbiquad filter用のライブラリ"RBJ.lib"と同階層においてFaustLiveでvstに書き出してみました。

スクリーンショット 2018-02-14 17.00.13.png
いい感じで使えてます。

追記:なぜかba.hz2midikey()が使えない...

FaustLiveからだとなぜか駄目なのです。何でだろ?
しょうがないので、自前で hz2midi() というのを定義してます。元からコピペしてるので、同じものです。
うーん、謎...
ひとつのファイルにまとめればオンラインエディタも使えるので、RBJ.libからAPFに関係するところをコピペしてエディタにかけてみたら、そっちはうまくいきました。さらに謎...

myPhaser2.dsp
declare name "myPhaser2";
import("stdfaust.lib");
//import("RBJ.lib");

process = phaserMono(0.0), phaserMono(phaseDiff) ;
phaserMono(phaseDiff) = _
  <: _ , apfSeq
  : *(1 - wet), *(wet)
  :> _
  with{
    apfSeq = _, stage
      : seq( i, 12, bypassIfZero( APF( F, Q ) ) )
      : _, ! ;
    F = ba.midikey2hz( note ) ;
    note = centerNote + ampMod * os.oscp(modF, phaseDiff * ma.PI) ;
    centerNote = (ba.hz2midikey(ceilingF) + ba.hz2midikey(floorF)) / 2.0 ;
    ampMod = ( ba.hz2midikey(ceilingF) - ba.hz2midikey(floorF)) / 2.0 ;
  };

bypassIfZero( func, x, stage ) =
  ( x : ba.bypass1( stage == 0, func ) ), max( 0, stage - 1 ) ;

//hz2midi(f) = 12*ma.log2(f/440.0) + 69.0;

phaserGrp( x ) = hgroup("[0]Phaser", x ) ;
stage     = phaserGrp( hslider( "[0]Stage[style:knob]", 6, 1, 12, 1 ) ) ;
Q         = phaserGrp( hslider("[1]Q[style:knob]",0.7,0.1,4.5,0.1) ) ;
modF      = phaserGrp( hslider("[2]modFreq[style:knob][unit:Hz]", 1.0, 0.01, 5.0, 0.01)) ;
floorF    = phaserGrp( hslider("[3]Floor[style:knob][unit:Hz]", 440, 100, 5000, 0)) ;
ceilingF  = phaserGrp( hslider("[4]Ceiling[style:knob][unit:Hz]", 880, 440, 5000, 0)) ;
phaseDiff = phaserGrp( hslider("[5]phaseDiff[style:knob]",0.5, -1.0, 1.0, 0.1)) ;
wet       = phaserGrp( hslider("[6]Wet[style:knob]",0.5, 0.0, 0.5, 0.001) ) ;

// 以下、RBJ.libからコピペ

APF( F, Q ) = biquad( b0/a0, b1/a0, b2/a0, a1/a0, a2/a0 )
  with{
    b0 =   1 - alpha ;
    b1 =  -2 * cos( w0 ) ;
    b2 =   1 + alpha ;
    a0 =   1 + alpha ;
    a1 =  -2 * cos( w0 ) ;
    a2 =   1 - alpha ;

    w0 = f_w0( F ) ;
    alpha = f_alpha( w0, Q ) ;
  } ;

biquad  = fi.tf2;

f_A( G ) = 10 ^ ( G / 40 ) ;
f_w0( F ) = 2 * ma.PI * F / ma.SR ;
f_alpha( w0, Q ) = sin( w0 ) / ( 2 * max( 0.001, Q )) ;

追記2:ついでにNFBも載せてみました

これもまた癖があって良い感じ。
もしかして再帰はじめてかも(自前では)。書いてみたら意味やら使い勝手やらが分かってきた。

myPhaserFB.dsp
declare name "myPhaserFB";
import("stdfaust.lib");
import("RBJ.lib");

process = phaserMono(0.0), phaserMono(phaseDiff) ;
phaserMono(phaseDiff) = _
  <: _ , ( + : apfSeq) ~ *( 0 - nfb )
  : *(1 - wet), *(wet)
  :> _
    with{
      apfSeq = _, stage
        : seq( i, 12, bypassIfZero( APF( F, Q ) ) )
        : _, ! ;
      F = ba.midikey2hz( note ) ;
      note = centerNote + ampMod * os.oscp(modF, phaseDiff * ma.PI) ;
      centerNote = (hz2midi(ceilingF) + hz2midi(floorF)) / 2.0 ;
      ampMod = ( hz2midi(ceilingF) - hz2midi(floorF)) / 2.0 ;
    };

bypassIfZero( func, x, stage ) =
  ( x : ba.bypass1( stage == 0, func ) ), max( 0, stage - 1 ) ;

hz2midi(f) = 12*ma.log2(f/440.0) + 69.0;

phaserGrp( x ) = hgroup("[0]Phaser", x ) ;
stage     = phaserGrp( hslider("[0]Stage[style:knob]", 6, 1, 12, 1 ) ) ;
Q         = phaserGrp( hslider("[1]Q[style:knob]",0.7,0.1,4.5,0.1) ) ;
modF      = phaserGrp( hslider("[2]modFreq[style:knob][unit:Hz]", 1.0, 0.01, 5.0, 0.01)) ;
floorF    = phaserGrp( hslider("[3]Floor[style:knob][unit:Hz]", 440, 100, 5000, 0)) ;
ceilingF  = phaserGrp( hslider("[4]Ceiling[style:knob][unit:Hz]", 880, 440, 5000, 0)) ;
phaseDiff = phaserGrp( hslider("[5]phaseDiff[style:knob]", 0.5, -1.0, 1.0, 0.1)) ;
nfb       = phaserGrp( hslider("[6]NFB[style:knob]", 0.0, 0.0, 1.0, 0.01));
wet       = phaserGrp( hslider("[7]Wet[style:knob]", 0.5, 0.0, 0.5, 0.001) ) ;

スクリーンショット 2018-02-14 18.50.02.png

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?