1

我正在尝试在 Linux 上使用 Java 播放音频缓冲区。

尝试打开线路时出现以下异常(而不是在我向其写入音频时)...

Exception in thread "main" java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_FLOAT 44100.0 Hz, 16 bit, mono, 2 bytes/frame,  is supported.

    public boolean open()
{
    try {

        int smpSizeInBits = bytesPerSmp * 8;
        int frameSize = bytesPerSmp * channels; // just an fyi, frameSize does not always == bytesPerSmp * channels for non PCM encodings
        int frameRate = (int)smpRate; // again this might not be the case for non PCM encodings.
        boolean isBigEndian = false;

        AudioFormat af = new AudioFormat(AudioFormat.Encoding.PCM_FLOAT , smpRate, smpSizeInBits, channels, frameSize, frameRate, isBigEndian);

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
        int bufferSizeInBytes = bufferSizeInFrames * channels * bytesPerSmp;
        line = (SourceDataLine) AudioSystem.getLine(info);
        line.open(af, bufferSizeInBytes);
        open = true;
    }
    catch(LineUnavailableException e) {
        System.out.println("PcmFloatPlayer: Unable to open, line unavailble.");
    }

    return open;
}

我想知道我对 PCM_FLOAT 编码是什么的假设实际上是不正确的。

我有一些读入 wav 文件的代码。wavfile 是单声道、16 位、未压缩格式。然后我将音频转换为 -1.0 到 1.0 范围内的浮点数进行处理。

我假设 PCM_FLOAT 编码只是原始 PCM 数据,已转换为 -1.0 和 1.0 之间的浮点值。这个对吗?

然后我假设 SourceDataLine 会根据我传递的格式信息(单声道、16 位、2 字节/帧)将浮动音频转换为适当的格式。这个假设又是不正确的吗?

我必须将我的 float -1.0 到 1.0 音频转换回我想要的输出格式,并将 SourceDataLine 设置为 PCM_SIGNED(假设这是我想要的格式)吗?

编辑:

另外,当我使用 PCM_FLOAT 调用 AudioSystem.getTargetEncodings() 时,它会返回三个编码。这是否意味着它将接受 PCM_FLOAT,并能够根据底层音频系统支持的内容转换为返回的编码?

        AudioFormat.Encoding[] encodings = AudioSystem.getTargetEncodings(AudioFormat.Encoding.PCM_FLOAT);
    for(AudioFormat.Encoding e : encodings)
        System.out.println(e);

结果是...

PCM_SIGNED PCM_UNSIGNED PCM_FLOAT

4

2 回答 2

1

I don't know that I'll be able to answer your direct questions. But maybe the code I can show you, which I know works (including on Linux), will help you arrive at a workable solution. I have programs that generate audio signals via incoming cues, but also custom-made Synths, and I do all the mixing and effects with PCM floats in the range -1 to 1. To output, I convert the floats to a standard "CD Quality" format that Java supports.

Here is the format I use for the outputting SourceDataLine:

AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);

You'll probably want to make this mono instead of stereo. But I should say, it seems to me that if you are able to read an incoming wav file with a different format, you should be able to play back that same format, assuming you reverse all the steps taken to convert the incoming data to PCM.

For the standard "CD Quality" format, to go from pcm signed floats to bytes, there is an intermediate step of inflating to the range of a signed short (-32768 to 32767).

public static byte[] fromBufferToAudioBytes(byte[] audioBytes, float[] buffer)
{
    for (int i = 0, n = buffer.length; i < n; i++)
    {
        buffer[i] *= 32767;
        audioBytes[i*2] = (byte) buffer[i];
        audioBytes[i*2 + 1] = (byte)((int)buffer[i] >> 8 );
    }
    return audioBytes;
}

This is taken from the AudioCue library that I wrote and posted on github.

I find it reduces headaches to just deal with the one AudioFormat, to make conversions with Audacity to the one format, and not try make provisions for multiple formats. But that is just a personal preference, and I don't know if that strategy would work for your situation or not.

Hope there is something here that helps!

于 2018-06-04T11:55:59.283 回答
0
public class Main {    
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread2();
        t1.start(); 
        Thread t2 = new thread3();  
        t2.start();
        Thread.sleep(5000);  
    }  
}

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Thread2 extends Thread implements Runnable {

   @Override 
   public void run() { 
      playWav("C:/Windows/Media/feel_good_x.wav");
    }

   private static void playWav(String soundFilePath) {
      File sFile = new File(soundFilePath); 
      if (!sFile.exists()) {

         String ls = System.lineSeparator();
         System.err.println("немає в директорії»+
               ls + "(" + soundFilePath + ")" + ls);
         return;
      }

      try {
         Clip clip;

         try (AudioInputStream audioInputStream = AudioSystem.

               getAudioInputStream(sFile.getAbsoluteFile())) { 
            clip = AudioSystem.getClip();
            clip.setFramePosition(0);
            clip.open(audioInputStream);
         }
         clip.start();
      }

      catch (UnsupportedAudioFileException | IOException | LineUnavailableException ex) {

         Logger.getLogger("playWav()").log(Level.SEVERE, null, ex);
      }
   }


}
于 2018-06-05T23:01:24.510 回答