Androidでノイズとローパスフィルタなど
風邪引きまして少し手抜きで。前回はオシレータを4つ作りまして今回はフィルタとノイズです。
ノイズ行きます。
class Noise extends Snd{ public double amp; public Noise(double a){ amp = a; } public double updata(){ return (2*Math.random() - 1) * amp; } }
randomが0から1までで、それを2倍して1を引けば-1から1までのランダムを生成できます。
さあフィルタです。
説明
・ローパスフィルタは高い周波数のサウンドを遮断します、ローをパスするわけですから。
・ハイパスフィルタは低い周波数のサウンドを遮断する。
・バンドパスは指定した周波数付近のサウンドだけを通過させます。
実装
・ローパスは単純に言うと今現在の音波の1点と1つ前に通過した1点を足し算する。
・ハイパスはその引き算
・バンドパスは上2つを融合したものと考えればいいでしょう。
本当は前の音波の1点と今の点をどのような割合で足すとかあるわけですが、これらは先人がどういう割合がいいかなど研究されていますので、以下のサイトを参考にします。
http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
http://www.geidai.ac.jp/~marui/matlab/node8.html
ローパスフィルタですが、それらが継承するクラスを作ります。
class Filter extends Snd{ public double b0 = 0; public double b1 = 0; public double b2 = 0; public double a0 = 0; public double a1 = 0; public double a2 = 0; public Snd input; public double cf; public double q; public Snd addcf = new Snd(); public Snd addq = new Snd(); public double forder = 0; public double sorder = 0; public Filter(Snd ii, double cc, double qq){ input = ii; cf = cc; q = qq; } public Filter(Snd ii, double cc, double qq, Snd ac){ input = ii; cf = cc; q = qq; addcf = ac; } public Filter(Snd ii, double cc, double qq, Snd ac, Snd aq){ input = ii; cf = cc; q = qq; addcf = ac; addq = aq; } public void connect(Snd n){ input = n; } }
b0からa2の変数ですがこれは前の音波の1点と今の1点の割合になるものです。cfはカットオフ周波数で、その周波数付近から例えばローパスなら高い周波数を遮断します。qが高くなると共振します。分かりづらいかもしれないのでsynth tvを見てください。cfのdddスライダーでqはeeeです。雰囲気つかめますかね。 addcfやaddqはここでモジュレーションです。1つ前の音波の1点がforderでもう1つ前のsorderとなります。今と以前だけじゃなくもう一つ前も計算するということです。複雑です。
class LowPass extends Filter{ //improve (http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt) public LowPass(Snd ii, double cc, double qq){ super(ii, cc, qq); } public LowPass(Snd ii, double cc, double qq, Snd ac){ super(ii, cc, qq, ac); } public LowPass(Snd ii, double cc, double qq, Snd ac, Snd aq){ super(ii, cc, qq, ac, aq); } public void calc(){ double omega = 2 * Math.PI * (cf + addcf.updata()) / sampleRate; double alpha = Math.sin(omega) / (2 * (q + addq.updata())); double cs = Math.cos(omega); b0 = (1 - cs) / 2; b1 = 1 -cs; b2 = (1 - cs) / 2; a0 = 1 + alpha; a1 = -2 * cs; a2 = 1 - alpha; } public double updata(){ calc(); double temp = (b0/a0)*input.updata() + (b1/a0)*forder + (b2/a0)*sorder - (a1/a0)*forder - (a2/a0)*sorder; sorder = forder; forder = temp; return temp; } } class HighPass extends Filter{ //improve (http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt) public HighPass(Snd ii, double cc, double qq){ super(ii, cc, qq); } public HighPass(Snd ii, double cc, double qq, Snd ac){ super(ii, cc, qq, ac); } public HighPass(Snd ii, double cc, double qq, Snd ac, Snd aq){ super(ii, cc, qq, ac, aq); } public void calc(){ double omega = 2 * Math.PI * (cf + addcf.updata()) / sampleRate; double alpha = Math.sin(omega) / (2 * (q + addq.updata())); double cs = Math.cos(omega); b0 = (1 + cs) / 2; b1 = -(1 + cs); b2 = (1 + cs) / 2; a0 = 1 + alpha; a1 = -2 * cs; a2 = 1 - alpha; } public double updata(){ calc(); double temp = (b0/a0)*input.updata() + (b1/a0)*forder + (b2/a0)*sorder - (a1/a0)*forder - (a2/a0)*sorder; sorder = forder; forder = temp; return temp; } } class BandPass extends Filter{ //improve (http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt) public BandPass(Snd ii, double cc, double qq){ super(ii, cc, qq); } public BandPass(Snd ii, double cc, double qq, Snd ac){ super(ii, cc, qq, ac); } public BandPass(Snd ii, double cc, double qq, Snd ac, Snd aq){ super(ii, cc, qq, ac, aq); } public void calc(){ double omega = 2 * Math.PI * (cf + addcf.updata()) / sampleRate; double alpha = Math.sin(omega) * Math.sinh(Math.log(2) / 2 *(q + addq.updata()) * omega / Math.sin(omega)); double cs = Math.cos(omega); b0 = alpha; b1 = 0; b2 = -alpha; a0 = 1 + alpha; a1 = -2 * cs; a2 = 1 - alpha; } public double updata(){ calc(); double temp = (b0/a0)*input.updata() + (b1/a0)*forder + (b2/a0)*sorder - (a1/a0)*forder - (a2/a0)*sorder; sorder = forder; forder = temp; return temp; } }
、、、、。ぐ、具合が悪くなってきたのでこの辺で逃げます。コードとにらめっこしてください。
エンベロープ、オシレータ、フィルタと作ったので次は安いシンセぐらいはいけそうです。