平均律クラヴィーアBWV846プレリュードの最後の和音をアルペジオのように少しづつずらして各音を鳴らすことがありました。和音をならす処理が洗練されていなかったのでここに手を入れます。
前回の処理
前回の実装をまず見てみましょう。
leftHand.play(notes3[0], 4, 1, 0.7); leftHand.setBeat(0.0625); leftHand.play(notes3[1], 4, 1, 0.5); rightHand.setBeat(0.125); rightHand.play(notes3[2], 4, 1, 0.5); rightHand.setBeat(0.1875); rightHand.play(notes3[3], 4, 1, 0.5); rightHand.setBeat(0.25); rightHand.play(notes3[4], 4, 1, 0.5);
単音をならす前にsetBeatメソッドを使って拍の微妙な位置調整をしてから演奏していました。これを一度の処理でできるように新規にメソッドを作りましょう。
和音を鳴らす処理
大体以下のようなメソッドを作ろうと思います。
- 演奏者クラスに和音を鳴らすメソッドを追加する
- メソッドには演奏する音を配列で渡す
- アルペジオにかかる時間tをメソッドに渡す
- 時間tが正の場合には最初の音は時間通りに、最後の音は時間t後に演奏される
- 時間tが負の場合には最初の音は時間t前に、最後の音は時間通りに演奏される
実装する
和音notesは配列でアルペジオ時間は引数の最後に指定します。他の引数、音の長さdurationと長さの比率ratioと音の速さvelocityは単音を演奏する時と同じです。
public void play(double[] notes, double duration, double ratio, double velocity, double arpegio) {
音の数分繰り返しをします。
for(int i = 0;i < notes.length;i++){
配列の長さが2以上の時に以下を行います。1の時に実行すると0乗算が発生するためです。アルペジオ時間が正の場合は最初の音が指定の時間通りに、最後の音がアルペジオ時間後になるようにします。負の場合には最初の音がアルペジオ時間前に、最後の音が時間通りになるようにします。
if(notes.length > 1){ if(arpegio > 0){ gap = arpegio / (double)(notes.length - 1) * (double)i; }else{ gap = arpegio / (double)(notes.length - 1) * (double)(notes.length - 1 - i); } }
始まりの時間を上で計算した通りにずらします。音の終わりは変更はなく全ての音が同時に鳴り止むことになります。
double time = measures.getTime(measure, beat + gap); double realDuration = measures.getTime(measure, beat + duration * ratio) - time; played.addReadable(time, inst.play(notes[i], realDuration, velocity)); }
全ての処理が終わったら音の長さぶん演奏者の時間を後ろにします。これは単音のときと同じです。
beat += duration; }
次回通奏低音のサンプル演奏をします。