获取 FloatBuffer 的 AudioInputStream

Get AudioInputStream of FloatBuffer

我有一个回调函数,它以 FloatBuffer 的形式获取传入的音频数据,其中包含 1024 个每秒被调用多次的浮点数。但我需要一个 AudioInputStream,因为我的系统只适用于它们。

将浮点数转换为 16 位 PCM isgned 音频数据不是问题,但我无法从中创建 InputStream。 AudioInputStream 构造函数只接受已知长度的数据,但我有一个恒定的流。如果我用包含音频数据的 PipedInputStream 为它提供 AudioSystem.getAudioInputStream 抛出 "java.io.IOException: mark/reset not supported"。

有什么想法吗?


这是我当前的代码:

Jack jack = Jack.getInstance();
JackClient client = jack.openClient("Test", EnumSet.noneOf(JackOptions.class), EnumSet.noneOf(JackStatus.class));
JackPort in = client.registerPort("in", JackPortType.AUDIO, EnumSet.of(JackPortFlags.JackPortIsInput));

PipedInputStream pin = new PipedInputStream(1024 * 1024 * 1024);
PipedOutputStream pout = new PipedOutputStream(pin);
client.setProcessCallback(new JackProcessCallback() {
public boolean process(JackClient client, int nframes) {
    FloatBuffer inData = in.getFloatBuffer();
    byte[] buffer = new byte[inData.capacity() * 2];
    for (int i = 0; i < inData.capacity(); i++) {
        int sample = Math.round(inData.get(i) * 32767);
        buffer[i * 2] = (byte) sample;
        buffer[i * 2 + 1] = (byte) (sample >> 8);
    }
    try {
        pout.write(buffer, 0, buffer.length);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return true;
}
});
client.activate();
client.transportStart();

Thread.sleep(10000);
client.transportStop();
client.close();

AudioInputStream audio = AudioSystem.getAudioInputStream(new BufferedInputStream(pin, 1024 * 1024 * 1024));
AudioSystem.write(audio, Type.WAVE, new File("test.wav"));

它使用 JnaJack 库,但数据来自何处并不重要。顺便说一句,转换为字节很好:将数据直接写入 SourceDataLine 将正常工作。但我需要数据作为 AudioInputStream.

AudioSystem.getAudioInputStream 期望流符合支持的 AudioFileFormat, which means it must conform to a known type. From the documentation:

The stream must point to valid audio file data.

以及该文档中的内容:

The implementation of this method may require multiple parsers to examine the stream to determine whether they support it. These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and reset the stream's read pointer to its original position. If the input stream does not support these operation, this method may fail with an IOException.

您可以使用 three-argument 构造函数创建自己的 AudioInputStream。如果不知道长度,可以指定为 AudioSystem.NOT_SPECIFIED. Frustratingly, neither the constructor documentation nor the class documentation mentions this, but the other constructor’s documentation