2011-02-03 10 views
1

Javaでサウンドを生成しようとしています。最後に、私はサウンドカードにサウンドを継続的に送ろうとしていますが、今のところ私はユニークなサウンドウェーブを送ることができます。javax.sound.sampledでサウンドを生成する

私はシンプルな正弦波を表す44100符号付き整数で配列を埋めましたが、それをサウンドカードに送信したいのですが、動作させることができません。

int samples = 44100; // 44100 samples/s 
int[] data = new int[samples]; 

// Generate all samples 
for (int i=0; i<samples; ++i) 
{ 
    data[i] = (int) (Math.sin((double)i/(double)samples*2*Math.PI)*(Integer.MAX_VALUE/2)); 
} 

は、私は使用して音のラインに送っ:

AudioFormat format = new AudioFormat(Encoding.PCM_SIGNED, 44100, 16, 1, 1, 44100, false); 

Clip clip = AudioSystem.getClip(); 
AudioInputStream inputStream = new AudioInputStream(ais,format,44100); 
clip.open(inputStream); 
clip.start(); 

私の問題は、コードスニペットにこれらの間に存在します。 int[]を入力ストリームに変換する方法が見つかりません。あなたのAudioFormatは、16ビットのサンプルを指定しているため

short[] data = new short[samples]; 

答えて

5

まず私はあなたではなくintよりshortサンプルをしたいと思います。 shortは16ビット幅ですが、intは32ビットです。

ストリームに変換する簡単な方法は次のとおりです。

  • ラップがByteArrayInputStream
  • で結果byte[]はからAudioInputStreamを作成putShort呼び出し
  • を使用してそれを読み込む ByteBuffer
  • を割り当てByteArrayInputStreamおよびフォーマット

例:

float frameRate = 44100f; // 44100 samples/s 
int channels = 2; 
double duration = 1.0; 
int sampleBytes = Short.SIZE/8; 
int frameBytes = sampleBytes * channels; 
AudioFormat format = 
    new AudioFormat(Encoding.PCM_SIGNED, 
        frameRate, 
        Short.SIZE, 
        channels, 
        frameBytes, 
        frameRate, 
        true); 
int nFrames = (int) Math.ceil(frameRate * duration); 
int nSamples = nFrames * channels; 
int nBytes = nSamples * sampleBytes; 
ByteBuffer data = ByteBuffer.allocate(nBytes); 
double freq = 440.0; 
// Generate all samples 
for (int i=0; i<nFrames; ++i) 
{ 
    double value = Math.sin((double)i/(double)frameRate*freq*2*Math.PI)*(Short.MAX_VALUE); 
    for (int c=0; c<channels; ++ c) { 
     int index = (i*channels+c)*sampleBytes; 
     data.putShort(index, (short) value); 
    } 
} 

AudioInputStream stream = 
    new AudioInputStream(new ByteArrayInputStream(data.array()), format, nFrames*2); 
Clip clip = AudioSystem.getClip(); 
clip.open(stream); 
clip.start(); 
clip.drain(); 

注:私は、モノラインを要求したときに例外を投げたので、私は、ステレオにあなたのAudioFormatを変更しました。私はまたあなたの波形の周波数を可聴範囲の何かに増やしました。


更新 - (データラインに直接書き込む)前の変更が必要ではなかった - Clipが正常に動作します使用します。計算をより明確にするためにいくつかの変数を導入しました。

+0

素晴らしいです。私の一日を保存:) – NewbiZ

0

単純なサウンドを再生する場合は、SourceDataLineを使用する必要があります。

ここでは例を示します。この例では

import javax.sound.sampled.*; 
public class Sound implements Runnable { 

    //Specify the Format as 
    //44100 samples per second (sample rate) 
    //16-bit samples, 
    //Mono sound, 
    //Signed values, 
    //Big-Endian byte order 
    final AudioFormat format=new AudioFormat(44100f,16,2,true,true); 

    //Your output line that sends the audio to the speakers 
    SourceDataLine line; 

    public Sound(){ 
    try{ 
     line=AudioSystem.getSourceDataLine(format); 
     line.open(format); 
    }catch(LineUnavailableExcecption oops){ 
     oops.printStackTrace(); 
    } 
    new Thread(this).start(); 
    } 

    public void run(){ 
    //a buffer to store the audio samples 
    byte[] buffer=new byte[1000]; 
    int bufferposition=0; 

    //a counter to generate the samples 
    long c=0; 

    //The pitch of your sine wave (440.0 Hz in this case) 
    double wavelength=44100.0/440.0; 

    while(true){ 
     //Generate a sample 
     short sample=(short) (Math.sin(2*Math.PI*c/wavelength)*32000); 

     //Split the sample into two bytes and store them in the buffer 
     buffer[bufferposition]=(byte) (sample>>>8); 
     bufferposition++; 
     buffer[bufferposition]=(byte) (sample & 0xff); 
     bufferposition++; 

     //if the buffer is full, send it to the speakers 
     if(bufferposition>=buffer.length){ 
     line.write(buffer,0,buffer.length); 
     line.start(); 
     //Reset the buffer 
     bufferposition=0; 
     } 
    } 
    //Increment the counter 
    c++; 
    } 

    public static void main(String[] args){ 
    new Sound(); 
    } 
} 

あなたがに常時正弦波を生成している、しかし、あなたが望む任意のソースからサウンドを再生するには、このコードを使用することができます。あなたは、サンプルを正しくフォーマットすることを確認する必要があります。この場合、44100 Hzのサンプルレートで未圧縮の16ビットサンプルをそのまま使用しています。ただし、ファイルからオーディオを再生する場合は、Clipオブジェクトを使用できます。

public void play(File file){ 
    Clip clip=AudioSystem.getClip(); 
    clip.open(AudioSystem.getAudioInputStream(file)); 
    clip.loop(1); 
}