非常に基本的なサウンド合成を使用して、ゲームのオーディオとエフェクトをオンザフライで作成しています。基本的に、周波数と振幅と持続時間を指定してサウンドを再生できるメソッドがいくつかあります。
短いフレーズとメロディーについては、簡単に書き直したり新しいメロディーをコードに追加したりできるように、基本的な記譜法を考案したいと思います (最終的にはファイルから読み取ることができるかもしれませんが、それはおそらくやり過ぎです)。
ただし、これを実装する方法がわかりません。
私は、MIDI # フィールドと周波数フィールドを持つ 88 の基本的なピアノの音符すべてを含む列挙型 EqualTemperamentTuning を作成することから始めました。これは少なくとも、周波数ではなく音名を扱うことができることを意味します。
public enum EqualTemperamentTuning {
A_0 (1, 27.5),
A_SHARP_0 (2, 29.1352),
...
C_8 (88, 4186.01);
private int num;
private double frequency;
EqualTemperamentTuning(int num, double frequency){
this.num = num;
this.frequency = frequency;
}
public double getFrequency(){
return frequency;
}
public double getNum(){
return num;
}
}
次に、さらにオブジェクトを作成し始めました。最初は、EqualTemperamentTuning、振幅、および長さを保持する Note です。
public class Note {
/** Note frequency */
private double frequency;
/** Note Amplitude */
private double amplitude;
/** Note length */
private int length;
public Note(EqualTemperamentTuning tuning, double amplitude, int length){
this.frequency = tuning.getFrequency();
this.amplitude = amplitude;
this.length = length;
}
public double getFrequency(){
return frequency;
}
public double getAmplitude(){
return amplitude;
}
public int getLength(){
return length;
}
}
最後に、演奏したいメロディーを定義するために、NotePhrase クラスを作成しました。
public class NotePhrase {
/** The arrayList of notes*/
private Note[] notes;
public NotePhrase(Note[] notes){
this.notes = notes;
}
public double getFrequency(int counter){
// for each note in the array
for (int i = 0; i< notes.length; i++){
// for each unit of length per note
for (int j=0; j<notes[i].getLength(); j++){
counter--;
// return the frequency at this point
if (counter <= 0) return notes[i].getFrequency();
}
}
return -1;
}
}
次に、オーディオ生成クラスに、ウェーブ ジェネレーターからサンプルを生成するループ (カウンター付き) があります。再生する新しいサンプルが必要になるたびに、上記の NotePhrase.getFrequency(int counter) メソッドに従ってウェーブの周波数を設定します。これは (実際にはまだテストしていません!) 周波数と振幅 (追加予定) に従って NotePhrase メロディーを再生するだけです。
問題は、あまりエレガントに見えないことです。具体的には、メロディーを読みやすい方法で「書く」のが非常に難しいことです。たくさんの新しい Note オブジェクトをコーディングしてから、それらの配列を使用して NotePhrase オブジェクトを作成する必要があります...これらのメロディーの束をハードコーディングして、後でそれらを簡単に切り替える方法は明らかではありません。
本当に私は、メロディーの列挙型などを作成したいと思います。ここでは、異なるメロディーごとに人間が判読できる構成を簡単にハードコーディングできます。次に、それらを使用したいときに、列挙型をオーディオプレーヤーに渡すだけです.. .
私が持っている最高のものは次のとおりです。
private static enum Melody {
NOKIA_RINGTONE ( new Note(EqualTemperamentTuning.E_5, 0.5, 1), new Note(EqualTemperamentTuning.D_5, 0.5, 1))
;
private Note[] notes = new Note[2];
Melody (Note note1, Note note2){
this.notes[0] = note1;
this.notes[1] = note2;
}
}
これを実行時に NotePhrase オブジェクトにロードします。異なる量の音符を持つメロディー用に新しいコンストラクターを作成する必要があるため、これはあまり良くありません。逆に、音符の配列で列挙型を作成すると、別の場所で 2 つの部分に分けてメロディーを「書いている」だけで、さらに混乱するように見えます...
だから私はこれを適切に構造化する方法について行き詰まっていますか? つまり、どのクラスを作成し、どの情報を保持する必要があるか...これを「正しく」取得したいのは、将来、表記法を拡張してエフェクト (エコーなど) を含めたいと思うかもしれません。適切なクラス、構造、および関係 (名前でさえも) によって、私のプログラムが非常に理解しやすくなったり、理解しにくくなったりする可能性があるという経験はほとんどありません。
エッセイで申し訳ありませんが、これは非常によく表現された (エヘム) 質問ではないかもしれませんが、Java と OOP の初心者として、ヒントは大歓迎です!
編集* *
回答と提案をありがとう、とても役に立ちました。このケースで与えられた答えを考えてみると、一般的なオーディオの実装を再考するきっかけになりましたが、これは現在かなり不安定です。ただし、誰を正しいとマークする必要があるかはわかりません。実際には、すべての推奨事項を取り入れて、そこから試してみるつもりです.