前回サイン波のオシレーターをつくりました。矩形波もファイルは作りましたがファイル作成ロジックとオシレータ部分が混ざった状態で作っていました。ここではオシレーター部分を分けたいとおもます。ここでの狙いはサイン波のオシレータと矩形波のオシレータを必要に応じて付け替えられるようにできることです。このためまずオシレータであることを担保するインタフェースから作りたいと思います。
インタフェースの定義
インタフェースは「なにができるか」を定義します。このため英語で命名する場合は「〜できうるもの」を意味する語尾-ableを動詞の後ろにつけます。オシレーターはoscillate「リズムを持って揺らす」という動詞から来ています。
今回のインタフェースはこの動詞に-ableをつけてoscillatableという名前にします。これは通常の英単語ではない造語ですが通常の英語の知識があれば理解されうる単語です。
サイン波で実装したreadメソッドは矩形波でも同様に使えるものなのでこれをインタフェイスで定義するメソッドとします。
package mocha.sound; public interface Oscillatable { public double read(double freq, double volume); }
オシレータの実装
クラス定義
先ほどのインタフェースを実装implementします。
public class SquareOscillator implements Oscillatable {
フィールド変数とコンストラクタ
double t; double delta_t; public SquareOscillator(double sample_rate) { t = 1.0 / sample_rate; delta_t = 0; }
今回はsin関数は使いません。まずサンプル周期tを求めます。サンプル周期とはサンプリング周波数の逆数です。
delta_tが何周期目かを表します。1Hzの周波数であれば1秒後に1になりますし100Hzであれば0.01秒後に1になります。1周に満たない位置は小数点以下で表されます。
readメソッドの実装
1周期の前半の音量は1、後半を-1とします。上記のdelta_tの小数点の部分を求めそれが0.5未満であれば1、そうでなければ-1とします。その値に引数のボリュームを掛け合わせた結果を返します。
@Override public double read(double freq, double volume) { double x = delta_t - Math.floor(delta_t); double point = x < 0.5 ? 1 : -1; delta_t += freq * t; return point * volume; }
次回はこのオシレータを使ってファイルを出力する処理を書きます
コード
今回作ったコードです。
package mocha.sound; public class SquareOscillator implements Oscillatable { double t; double delta_t; public SquareOscillator(double sample_rate) { t = 1.0 / sample_rate; delta_t = 0; } @Override public double read(double freq, double volume) { double x = delta_t - Math.floor(delta_t); double point = x < 0.5 ? 1 : -1; delta_t += freq * t; return point * volume; } }