IIRローパスフィルタの作成(3)

スポンサーリンク

前回作ったのはフィルターのロジック部分ですが今回はこれをコントロールするクラスを作ります。遮断周波数やクオリティファクターを変えると音色も変わるのでこれを自由に変更できるようにしたいというのがここでの狙いです。

IIRローパスフィルタの作成(1)
IIRローパスフィルタの作成(2)

実装内容

クラス名はLowPassFilterModuleとしました。以下のような要件が必要と考えています。

  • SoundReadableを実装した音源クラスを保持する
  • 自身もSoundReadableを実装する
  • 遮断周波数をエンベロープとして保持する
  • クオリティファクターをエンベロープとして保持する

エンベロープは以前作ったDoubleMapクラスを使います。このクラスを使うと設定値を時間の変化と共に変えていくことができます。

実装

では実装をしていきます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public class LowPassFilterModule implements SoundReadable{
IIRLowPassFilter filter;
SoundReadable source;
DoubleMap cutoff;
DoubleMap quality;
public class LowPassFilterModule implements SoundReadable{ IIRLowPassFilter filter; SoundReadable source; DoubleMap cutoff; DoubleMap quality;
public class LowPassFilterModule implements SoundReadable{
  IIRLowPassFilter filter;
  SoundReadable source;
  DoubleMap cutoff;
  DoubleMap quality;

コンストラクタ

エンベロープの最初の値を元にIIRローパスフィルターを作成します。今のところは音源はモノラルのみとします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public LowPassFilterModule(SoundReadable source, DoubleMap cutoff, DoubleMap quality){
this.filter = new IIRLowPassFilter(cutoff.getInitial(), quality.getInitial());
this.source = source;
if(source.getChannel() != 1){
throw new IllegalArgumentException("monoral only");
}
this.cutoff = cutoff;
this.quality = quality;
}
public LowPassFilterModule(SoundReadable source, DoubleMap cutoff, DoubleMap quality){ this.filter = new IIRLowPassFilter(cutoff.getInitial(), quality.getInitial()); this.source = source; if(source.getChannel() != 1){ throw new IllegalArgumentException("monoral only"); } this.cutoff = cutoff; this.quality = quality; }
public LowPassFilterModule(SoundReadable source, DoubleMap cutoff, DoubleMap quality){
  this.filter = new IIRLowPassFilter(cutoff.getInitial(), quality.getInitial());
  this.source = source;
  if(source.getChannel() != 1){
    throw new IllegalArgumentException("monoral only");
  }
  this.cutoff = cutoff;
  this.quality = quality;
}

SoundReadableに対する実装

SoundReadableインタフェースで要求される実装をします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Override
public long length() {
return source.length();
}
@Override
public int getChannel() {
return source.getChannel();
}
@Override public long length() { return source.length(); } @Override public int getChannel() { return source.getChannel(); }
@Override
public long length() {
  return source.length();
}

@Override
public int getChannel() {
  return source.getChannel();
}

遮断周波数とクオリティファクターの値をエンベロープから取得しフィルターを更新します。フィルター側では現在の値と更新する値が同じ場合には計算処理はしないように作られています。そのあとで音源から読み出したものをフィルタリングして戻り値として返します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@Override
public double read() {
double nextCutoff = cutoff .next();
double nextQuality = quality.next();
filter.set(nextCutoff, nextQuality);
return filter.process(source.read());
}
@Override public double read() { double nextCutoff = cutoff .next(); double nextQuality = quality.next(); filter.set(nextCutoff, nextQuality); return filter.process(source.read()); }
@Override
public double read() {
  double nextCutoff  = cutoff .next();
  double nextQuality = quality.next();
  filter.set(nextCutoff, nextQuality);
  return filter.process(source.read());
}

検査

実装内容が正しく実装されているか検査します。以下のような音を作ることにします。

  • 440Hzの矩形波を5秒間3回鳴らす
  • 最初のものはフィルターなし
  • 2番目は遮断周波数が5秒間で500Hzから10000Hzまで変化、クオリティファクターはデフォルト値のまま変化なし
  • 3番目は遮断変数は2000Hzのまま変化なし、クオリティファクターは5秒間で0.2から3まで変化する

実装します。
まず5秒間の矩形波を作るメソッドを作っておきます。これを3回呼び出します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public static OscillatorReader getOscillatorReader() {
DoubleMap freq = new DoubleMap(440);
DoubleMap env = new DoubleMap(1);
env.putSecondValue(4.5, 1);
env.putSecondValue(5, 0);
return new OscillatorReader(new SquareOscillator(), freq, env, 5);
}
public static OscillatorReader getOscillatorReader() { DoubleMap freq = new DoubleMap(440); DoubleMap env = new DoubleMap(1); env.putSecondValue(4.5, 1); env.putSecondValue(5, 0); return new OscillatorReader(new SquareOscillator(), freq, env, 5); }
public static OscillatorReader getOscillatorReader() {
  DoubleMap freq = new DoubleMap(440);
  DoubleMap env = new DoubleMap(1);
  env.putSecondValue(4.5, 1);
  env.putSecondValue(5, 0);
  return new OscillatorReader(new SquareOscillator(), freq, env, 5);
}

次にメインの処理です。まずタイムラインを作ります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
TimeLine tl = new TimeLine();
TimeLine tl = new TimeLine();
TimeLine tl = new TimeLine();

最初は矩形波そのままを書き出します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
tl.addReadable(0, getOscillatorReader());
tl.addReadable(0, getOscillatorReader());
tl.addReadable(0, getOscillatorReader());

つぎに遮断周波数を初期値500、5秒後の値が10000になるようにしてフィルタリングします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DoubleMap cutoff1 = new DoubleMap(500);
cutoff1.putSecondValue(5, 10000);
DoubleMap quality1 = new DoubleMap(IIRLowPassFilter.DEFAULT_QUALITY);
LowPassFilterModule lpf1 = new LowPassFilterModule(getOscillatorReader(), cutoff1, quality1);
tl.addReadable(5, lpf1);
DoubleMap cutoff1 = new DoubleMap(500); cutoff1.putSecondValue(5, 10000); DoubleMap quality1 = new DoubleMap(IIRLowPassFilter.DEFAULT_QUALITY); LowPassFilterModule lpf1 = new LowPassFilterModule(getOscillatorReader(), cutoff1, quality1); tl.addReadable(5, lpf1);
DoubleMap cutoff1 = new DoubleMap(500);
cutoff1.putSecondValue(5, 10000);
DoubleMap quality1 = new DoubleMap(IIRLowPassFilter.DEFAULT_QUALITY);
LowPassFilterModule lpf1 = new LowPassFilterModule(getOscillatorReader(), cutoff1, quality1);
tl.addReadable(5, lpf1);

最後にクオリティファクターを0.2から3に変化させるように設定してフィルタリングします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DoubleMap cutoff2 = new DoubleMap(2000);
DoubleMap quality2 = new DoubleMap(0.2);
quality2.putSecondValue(5, 3);
LowPassFilterModule lpf2 = new LowPassFilterModule(getOscillatorReader(), cutoff2, quality2);
tl.addReadable(10, lpf2);
DoubleMap cutoff2 = new DoubleMap(2000); DoubleMap quality2 = new DoubleMap(0.2); quality2.putSecondValue(5, 3); LowPassFilterModule lpf2 = new LowPassFilterModule(getOscillatorReader(), cutoff2, quality2); tl.addReadable(10, lpf2);
DoubleMap cutoff2 = new DoubleMap(2000);
DoubleMap quality2 = new DoubleMap(0.2);
quality2.putSecondValue(5, 3);
LowPassFilterModule lpf2 = new LowPassFilterModule(getOscillatorReader(), cutoff2, quality2);
tl.addReadable(10, lpf2);

ファイルに書き出します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
WavFileWriter.create(tl, new File("wav/filter.wav"));
WavFileWriter.create(tl, new File("wav/filter.wav"));
WavFileWriter.create(tl, new File("wav/filter.wav"));

以下のようになりました。

ソースの細かい点はGithubにあげていますので確認してください。

Githubのソース

スポンサーリンク

シェアする

フォローする

%d人のブロガーが「いいね」をつけました。