java - Java Audio SourceDataLine不支持PCM_FLOAT

标签 java audio javasound pcm java-audio

我正在尝试在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 音频转换为适当的格式。同样,这种假设是不正确的?

我必须将我的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

最佳答案

我不知道我能回答您的直接问题。但是也许我可以向您展示的代码(我知道它可以工作)(包括在Linux上)可以帮助您找到可行的解决方案。我有一些程序通过传入的提示生成音频信号,也有定制的Synths,并且我使用-1至1范围内的PCM浮点数进行所有混合和效果。要输出,我将这些浮点数转换为标准的“CD质量Java支持的格式。

这是我用于输出SourceDataLine的格式:

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

您可能需要将此单声道而不是立体声。但是我应该说,在我看来,如果您能够读取具有不同格式的传入wav文件,则可以假定以逆转将传入数据转换为PCM的所有步骤来播放相同格式的文件。 。

对于标准的“CD质量”格式,要从pcm带符号的浮点数转换为字节,有一个中间步骤,将其扩展到带符号的short范围(-32768至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;
}

这取自我编写并发布在github上的AudioCue库。

我发现,仅处理一种AudioFormat,将Audacity转换为一种格式,而不是尝试提供多种格式,就可以减轻麻烦。但这只是个人喜好,我不知道该策略是否适合您的情况。

希望这里能有所帮助!

关于java - Java Audio SourceDataLine不支持PCM_FLOAT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50672068/

相关文章:

java.lang.NoClassDefFoundError : okhttp3. OkHttpClient$Builder

java - 由 : javax.naming.NamingException 引起

java - 没有 @EndConversation 的 Struts 2 Conversation Scope 插件

html - 音频标签自动播放在安卓浏览器中不起作用

java - 哪些 JFrame 对象支持音高变化?

java - 如何解决Java中POST和GET不支持警告?

安卓录音外接插孔

unix - 在 macOS 上使用 ffmpeg 将音频文件拆分为多个文件

java - 为什么 java AudioSystem.getTargetEncodings( AudioFormat ) 返回的 Encoding 与我们提供的 AudioFormat 的编码不同?

java - Java 中的 JComboBox