首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用javax.sound.sampled生成声音

用javax.sound.sampled生成声音
EN

Stack Overflow用户
提问于 2011-02-04 01:55:11
回答 2查看 4K关注 0票数 1

我正在尝试用Java生成声音。最后,我愿意不断地向声卡发送声音,但现在我可以发送一个独特的声波。

所以,我用44100个有符号的整数填充了一个数组,表示一个简单的正弦波,我想把它发送到我的声卡上,但我就是不能让它工作。

代码语言:javascript
复制
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));
}

我把它发送到一条声音线路上,使用:

代码语言:javascript
复制
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[]转换成输入流!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-02-04 02:03:49

首先,我认为您需要的是short样本而不是int

代码语言:javascript
复制
short[] data = new short[samples];

因为您的AudioFormat指定了16位样本。short是16位宽,但int是32位。

将其转换为流的一种简单方法是:

和Allocate a ByteBuffer

  • Populate it using putShort calls

  • ByteArrayInputStream

  • Create中包装生成的

  • byte[]并格式化AudioInputStream < ByteArrayInputStream >F221<

>

示例:

代码语言:javascript
复制
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可以正常工作。我还引入了一些变量,以使计算更加清晰。

票数 6
EN

Stack Overflow用户

发布于 2015-04-13 00:46:20

如果你想播放一个简单的声音,你应该使用SourceDataLine。

下面是一个例子:

代码语言:javascript
复制
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();
  }
}

在本例中,您将连续生成一个正弦波,但您可以使用此代码播放来自任何源的声音。您只需确保样例格式正确即可。在本例中,我使用的是未压缩的原始16位样本,采样率为44100 Hz。但是,如果要播放文件中的音频,则可以使用Clip对象

代码语言:javascript
复制
public void play(File file){
  Clip clip=AudioSystem.getClip();
  clip.open(AudioSystem.getAudioInputStream(file));
  clip.loop(1);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4889750

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档