#この記事は4月頃書かれたものを再投稿したものです。
前のエントリで正変換と逆変換の間に関数を入れるのにpvcalcと言うのを紹介したが、 他にも2つのchainを処理できるpvcalc2や、関数内でindex(bin数)を利用できるpvcollectがある。pvcollectが便利そう。
UnpackFFT
UnpackFFTはFFTの吐いたchainの中身をDemand rateのストリームで吐き出す。
UnpackFFT(chain, numFrames, frombin, tobin )
これもfrombin, tobin引数によって必要なbin数を指定できる。
出てくる数値はDemand rateのストリームなのでこれにDemand UGenで処理を加えることができる。
出てくるストリームはリアルパートとイマジナリパートが分かれていないので、そこは適せん自分で分ける式を書く。
(あとpvcalcやpvcollectも関数内でDemand UGenで処理を加える事ができる。つまりDemand UGenはサンプル毎に処理ができるってこと。?これってなんかスパコの時間概念って実は結構フレキシブルなんじゃないだろかと思ってしまう。もししたらChuckみたいにサンプルレベルの波形処理も別に普通のことなのかもしれない。このへん後で調べたい)
あとヘルプに注意があるように今の時点でDemand UGenは32のインプットしか処理できないのでbin数はfrombin, tobinでそれ以内に抑えなければいけないようだ。
以下ヘルプから( s.boot.doWhenBooted{ ~fftsize = 1024; b = Buffer.alloc(s, ~fftsize, 1); c = Buffer.read(s,"sounds/a11wlk01.wav"); } )
// ポストウィンドにMagnitude、Phaseとストリームをポストする ( x = { var sig, chain, unp; sig = SinOsc.ar; sig = PlayBuf.ar(1, c, BufRateScale.kr(c), loop: 1); chain = FFT(b, sig);
// frombin と tobin 引数で必要なbinを制限 unp = UnpackFFT(chain, b.numFrames, frombin: 0, tobin: 4); // アンパックしてDemand rateに // 時点でDemand UGenは32のインプットしか処理できない
//なのでbin数はfrombin, tobinでそれ以内に抑える Demand.kr(chain>=0, 0, unp).collect{|anunp, index| anunp.poll(chain>=0, if(index % 2 == 0, "Magnitude", "Phase")+(index/2).floor); };
(sig*0.1).dup;
}.play(s); ) x.free;
またDemand rateのFFTデータをchainバッファに束ねて戻すPackFFTもある。
#この記事は4月頃書かれたものを再投稿したものです。 FFT出来無いとか馬鹿にされた(マジむかつく)のでFFTの事をちょっと。
スパコにもフーリエ変換、正変換FFT逆変換IFFTのクラスが用意されている。
FFT
FFTクラスはデカルト座標で配列をずらっと吐いてくるのでその配列を操作する事でスペクトル解析、フィルタリングなど各操作をする。 出てくる配列はこんな感じ。order: DC, nyquist, real 1f, imag 1f, real 2f, imag 2f, ... real (N-1)f, imag (N-1)f
また窓の種類が選べてrectangular、Welch、Hannの三つ。デフォルトではWelch。(レクトアングルとハニングはわかるけど、ウェルチとはどんな窓なんですか?) またIFFTに突っ込む前にデータ変換するためのPV UGensというクラス郡も用意されていて、各種比較、演算オンセット・ディテクトなどいろいろある。 詳しくは FFT Overview.html
では一つヘルプから例を、
周波数成分をプロットしてグラフを見る。スペクトルアナライズ。b = Buffer.alloc(s,1024);
a = { FFT(b, LFSaw.ar(400)); 0.0 }.play; ( b.getn(0, 1024, { arg buf; var z, x; z = buf.clump(2).flop; z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])]; x = Complex(z[0], z[1]); {x.magnitude.plot}.defer }) ) a.free; b.free;
[説明]
b = Buffer.alloc(s,1024); //FFTデータを書き込むバッファが必要。
z = buf.clump(2).flop;
//clumpしてflopすると奇数、偶数つまり振幅成分と位相成分のデータ配列に分ける(clump(2)はサイズが2のセルを配列の先頭から順番に作っていく、結果2DArrayになる。flopは2DArrayの行と列をひっくり返す)
z = [Signal.newFrom(z[0]), Signal.newFrom(z[1])];
//newFromは別の配列から新たに配列を作る(でもこれzの要素をまたzの要素に入れ子にして意味あるんかなこれ)
x = Complex(z[0], z[1]);
//パワースペクトルを対数表示するのでComplexを使って
x.magnitude.plot
//実部と虚部から距離を取って最後にプロット
追記: ウェルチ窓についてSignal.htmlヘルプにグラフ見るコードが。
Signal.welchWindow(1024).plot;
上がハニングで下がウェルチ。なるほどね。
追記2:
スパコのFFTでは窓かけやオーバーラップを自動でやってくれていて、 オーバーラップの深度はFFTの引数"hop"で0~ 1のunipolarでこれは0~100のパーセンテージ。 wintypeが窓の種類で -1 rectangular, 0 Welch, 1 Hannとなっている。
FFT.new(buffer, input, hop, wintype, active)