フェイザーペダルとオールパスフィルタについての覚書を読んで勉強になったし、実際自分でも試してみて、「お、フェイザーなかなか良いじゃん!」と思い、自分好みのを作ってみました。
変更点
自作の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に書き出してみました。
追記:なぜか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) ) ;