リアルタイムで操作できるJavaで基本的なトーンジェネレーターを作成したいと思います(最初はピッチだけです)。
シンプルなものから始めて、より複雑なトーン生成とエフェクトを追加して、ある種の基本的なシンセサイザーに仕上げたいと考えています。
このサイトで、アプレット Beeper.java のサンプル コードを取り上げた役立つ投稿を見つけました。
トーンを生成し、クリップに保存しました。その後、必要に応じてそのクリップをループで再生しました。関連する発音ビット:
/** Generates a tone, and assigns it to the Clip. */
public void generateTone()
throws LineUnavailableException {
if ( clip!=null ) {
clip.stop();
clip.close();
} else {
clip = AudioSystem.getClip();
}
boolean addHarmonic = harmonic.isSelected();
int intSR = ((Integer)sampleRate.getSelectedItem()).intValue();
int intFPW = framesPerWavelength.getValue();
float sampleRate = (float)intSR;
// oddly, the sound does not loop well for less than
// around 5 or so, wavelengths
int wavelengths = 20;
byte[] buf = new byte[2*intFPW*wavelengths];
AudioFormat af = new AudioFormat(
sampleRate,
8, // sample size in bits
2, // channels
true, // signed
false // bigendian
);
int maxVol = 127;
for(int i=0; i<intFPW*wavelengths; i++){
double angle = ((float)(i*2)/((float)intFPW))*(Math.PI);
buf[i*2]=getByteValue(angle);
if(addHarmonic) {
buf[(i*2)+1]=getByteValue(2*angle);
} else {
buf[(i*2)+1] = buf[i*2];
}
}
try {
byte[] b = buf;
AudioInputStream ais = new AudioInputStream(
new ByteArrayInputStream(b),
af,
buf.length/2 );
clip.open( ais );
} catch(Exception e) {
e.printStackTrace();
}
}
ループビット:
/** Loops the current Clip until a commence false is passed. */
public void loopSound(boolean commence) {
if ( commence ) {
clip.setFramePosition(0);
clip.loop( Clip.LOOP_CONTINUOUSLY );
} else {
clip.stop();
}
}
バックグラウンドで別のクリップを作成し、ピッチを変更したいときに別のクリップをすばやく変更できるように、これを論争しようとしましたが、もちろん、1 つのクリップが開始され、もう 1 つのクリップが停止すると、顕著なクリック音が発生します。
それで、これを行うには、あるウェーブの終わりを別のウェーブの終わりとシームレスに一致させる、ある種の巧妙なバッファリングが必要だと思いますか?
それとも、事前に生成されたクリップでは不可能なのでしょうか? もしそうなら、どうすればいいですか?
関連する余談ですが、ソフトウェア シンセサイザーはどのように機能しますか? それらはすべてのサウンドとエフェクトを継続的に生成しますか、それとも「クリップ」と Beeper.java のようなループを事前に生成しますか?
ありがとう!