2

リアルタイムで操作できる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 のようなループを事前に生成しますか?

ありがとう!

4

1 に答える 1

1

Java で、位相アキュムレータを使用して実装された数値制御発振器 (NCO)を実装したいようです。

基本的に、必要な周波数のデルタ位相を計算し、これをモジュロ 2pi でアキュムレータに追加し続ける必要があります。アキュムレータの値はsin()、サンプル値を生成するための値として使用されます。

周波数を変更したい場合は、デルタ位相を更新します。これにより、サンプルの連続性が保証されます (波が突然途切れることはありません)。これがクリックの原因であると思われます。より良い変更が必要な場合は、一連のサンプルでデルタ フェーズを徐々に変更する必要があります。

于 2012-04-28T01:08:40.263 に答える