それなりに音を作れるようになってきたので今後はエフェクターを作りたいと思います。エフェクターは読み込んだ音に「何かしらの影響」を与えるものです。処理には読み込んだその場のサンプルだけでなく過去のサンプルも使うことがあります。そのために過去のサンプルを貯めておくバッファを作りたいと思います。
バッファに必要な要件
処理に時間をかけないために固定の配列を使います。以下のことができるようなクラスにします。
- 読み込んだバッファを決められた数の履歴分保持することができる。
- 一番最新の値と過去のすべての履歴を簡単に取得できる。
実装
double値のためのバッファクラスDoubleBufferを作成します。
必要なものはデータを保持するための配列valuesとその長さlengthと現在どこを指しているかを示すindexです。
package mocha.sound;
public class DoubleBuffer {
double[] values;
int length;
int index;
コンストラクタです。配列の長さを指定するとその長さの配列を作ります。indexは配列の最後を指すように初期化しておきます。
public DoubleBuffer(int length) {
values = new double[length];
this.length = length;
index = length - 1;
}
長さを返すメソッドを作ります。
public int length() {
return length;
}
indexを次に進めるためのメソッドです。インクリメントした後配列の長さで割った剰余を計算します。これで配列の範囲からはみ出すことはなくなります。
void next() {
index = ++index % length;
}
現在の値を取得するメソッドです。
public double current() {
return values[index];
}
過去の履歴を返すメソッドです。shiftは過去の履歴を指すインデックスで0は最新つまり現在の値で1は一つ前の値になります。shiftが負数であったり保持できる以上の過去のインデックスを指定した場合は0を返します。
public double get(int shift) {
if (shift >= length || shift < 0) {
return 0;
}
int get_index = (index + length - shift) % length;
return values[get_index];
}
値を設定するメソッドです。インデックスを次に進めてから値を設定します。過去の履歴を返します。
public double put(double value) {
next();
double old = values[index];
values[index] = value;
return old;
}
実装の検証
うまく実装できたか検証します。順々に値を設定していきその後履歴を取得します。
public static void main(String[] args) {
DoubleBuffer buf = new DoubleBuffer(5);
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println("put 1");
System.out.println("old=" + buf.put(1));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("put 2");
System.out.println("old=" + buf.put(2));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("put 3");
System.out.println("old=" + buf.put(3));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("put 4");
System.out.println("old=" + buf.put(4));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("put 5");
System.out.println("old=" + buf.put(5));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("put 6");
System.out.println("old=" + buf.put(6));
System.out.println("index=" + buf.index + ":value=" + buf.values[buf.index]);
System.out.println();
System.out.println("confirmation");
System.out.println(buf.current());
System.out.println("[-1]=" + buf.get(-1));
System.out.println("[0]=" + buf.get(0));
System.out.println("[1]=" + buf.get(1));
System.out.println("[2]=" + buf.get(2));
System.out.println("[3]=" + buf.get(3));
System.out.println("[4]=" + buf.get(4));
System.out.println("[5]=" + buf.get(5));
System.out.println("[6]=" + buf.get(6));
System.out.println();
}
以下実行結果です。
index=4:value=0.0 put 1 old=0.0 index=0:value=1.0 put 2 old=0.0 index=1:value=2.0 put 3 old=0.0 index=2:value=3.0 put 4 old=0.0 index=3:value=4.0 put 5 old=0.0 index=4:value=5.0 put 6 old=1.0 index=0:value=6.0 confirmation 6.0 [-1]=0.0 [0]=6.0 [1]=5.0 [2]=4.0 [3]=3.0 [4]=2.0 [5]=0.0 [6]=0.0