周期的に音色を変化させるためのクラスを作ります。ビブラートやトレモロといった周期的な音色の変化をこれによって表現できるようになります。
実装内容
およそ以下のような内容を実現できるようにします。
- 変調させるオシレーターを選択できる
- 変調をかける周期の変化を周波数エンベロープとして保持する
- 変調をかける量の変化をエンベロープで保持する
- 変調をかける量を保持する
3と4は同じ値を操作するのですが例えばオンオフのスイッチみたいな使い方をしたい場合には4の方を0に設定すれば3で複雑な設定をしていたとしてもすぐにモジュレーターを無効にすることができます。
モジュレーターの実装
ではクラスを実装します。
フィールド変数
実装内容で想定したものをフィールド変数として宣言します。
package mocha.sound; public class Modulator { Oscillatable oscillatable; DoubleMap freqMap; DoubleMap envMap; double volume;
コンストラクタ
外部からフィールド変数を受け取るようにします。
public Modulator(Oscillatable oscillatable, DoubleMap freqMap, DoubleMap envMap, double volume) { this.oscillatable = oscillatable; this.freqMap = freqMap; this.envMap = envMap; this.volume = volume; }
変調メソッド
変調する周波数と量を読み取って変調させる量を計算します。その後引数で指定された原音に加算して返します。
public double modulate(double value) { double mod = oscillatable.read(freqMap.next(), 0, envMap.next()) * volume; return value + mod; }
ローパスフィルターへのモジュレーターの追加
ローパスフィルターで使えるようにします。
フィールド変数への追加
フィールド変数に2つ追加します。遮断周波数用とクオリティファクター用のモジュレーターです。
public class LowPassFilterModule implements SoundReadable{ IIRLowPassFilter filter; SoundReadable source; DoubleMap cutoff; DoubleMap quality; Modulator cutoffModulator; Modulator qualityModulator;
設定メソッドの追加
public void setCutoffModulator(Modulator cutoffModulator) { this.cutoffModulator = cutoffModulator; } public void setQualityModulator(Modulator qualityModulator) { this.qualityModulator = qualityModulator; }
読み込み処理への処理追加
モジュレーターがある場合にのみ変調をかけます。
@Override public double read() { double nextCutoff = cutoffModulator == null?cutoff .next():cutoffModulator.modulate(cutoff .next()); double nextQuality = qualityModulator == null?quality.next():qualityModulator.modulate(quality.next()); filter.set(nextCutoff, nextQuality); return filter.process(source.read()); }
動作確認
4種類音を出します。
- 遮断周波数をサイン波で変調
- クオリティフィルターをサイン波で変調
- 遮断周波数を矩形波で変調
- クオリティフィルターを矩形波で変調
TimeLine tl = new TimeLine(); //tl.addReadable(0, getOscillatorReader()); DoubleMap cutoff1 = new DoubleMap(4000); DoubleMap quality1 = new DoubleMap(IIRLowPassFilter.DEFAULT_QUALITY); LowPassFilterModule lpf1 = new LowPassFilterModule(getOscillatorReader(), cutoff1, quality1); Modulator mod1 = new Modulator(new SineOscillator(), new DoubleMap(5), new DoubleMap(1), 2000); lpf1.setCutoffModulator(mod1); tl.addReadable(0, lpf1); DoubleMap cutoff2 = new DoubleMap(2000); DoubleMap quality2 = new DoubleMap(1.8); LowPassFilterModule lpf2 = new LowPassFilterModule(getOscillatorReader(), cutoff2, quality2); Modulator mod2 = new Modulator(new SineOscillator(), new DoubleMap(5), new DoubleMap(1), 1.5); lpf2.setQualityModulator(mod2); tl.addReadable(5, lpf2); DoubleMap cutoff3 = new DoubleMap(4000); DoubleMap quality3 = new DoubleMap(IIRLowPassFilter.DEFAULT_QUALITY); LowPassFilterModule lpf3 = new LowPassFilterModule(getOscillatorReader(), cutoff3, quality3); Modulator mod3 = new Modulator(new SquareOscillator(), new DoubleMap(5), new DoubleMap(1), 2000); lpf3.setCutoffModulator(mod3); tl.addReadable(10, lpf3); DoubleMap cutoff4 = new DoubleMap(2000); DoubleMap quality4 = new DoubleMap(1.8); LowPassFilterModule lpf4 = new LowPassFilterModule(getOscillatorReader(), cutoff4, quality4); Modulator mod4 = new Modulator(new SquareOscillator(), new DoubleMap(5), new DoubleMap(1), 1.5); lpf4.setQualityModulator(mod4); tl.addReadable(15, lpf4); WavFileWriter.create(tl, new File("wav/filter2.wav")); WavFilePlayer.playFile(new File("wav/filter2.wav"));
実行結果です。音色の変化が最初の二つはサイン波で滑らかに変わりますがあとの二つは矩形波による変調のため極端に変わるようになっています。