我正在尝试在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);
结果是...
最佳答案
我不知道我能回答您的直接问题。但是也许我可以向您展示的代码(我知道它可以工作)(包括在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转换为一种格式,而不是尝试提供多种格式,就可以减轻麻烦。但这只是个人喜好,我不知道该策略是否适合您的情况。
希望这里能有所帮助!