Получить AudioInputStream из FloatBuffer

У меня есть обратный вызов, который получает входящие аудиоданные как FloatBuffer содержит 1024 числа с плавающей точкой, которые вызываются несколько раз в секунду. Но мне нужно AudioInputStream моя система работает только с ними.

Преобразование поплавков в 16-битные звуковые данные, записанные в формате PCM, не является проблемой, но я не могу создать InputStream из них. Конструктор AudioInputStream принимает только данные известной длины, но у меня постоянный поток. AudioSystem.getAudioInputStream выдает "java.io.IOException: пометка / сброс не поддерживается", если я передаю его с помощью PipedInputStream, содержащего аудиоданные.

Есть идеи?


Вот мой текущий код:

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,

1 ответ

Решение

AudioSystem.getAudioInputStream ожидает поток, который соответствует поддерживаемому AudioFileFormat, что означает, что он должен соответствовать известному типу. Из документации:

Поток должен указывать на действительные данные аудиофайла.

А также из этой документации:

Реализация этого метода может потребовать, чтобы несколько парсеров исследовали поток, чтобы определить, поддерживают ли они его. Эти парсеры должны иметь возможность пометить поток, прочитать достаточно данных, чтобы определить, поддерживают ли они поток, и сбросить указатель чтения потока в исходное положение. Если входной поток не поддерживает эти операции, этот метод может завершиться с ошибкой IOException,

Вы можете создать свой собственный AudioInputStream, используя конструктор с тремя аргументами. Если длина не известна, она может быть указана как AudioSystem.NOT_SPECIFIED. К сожалению, ни документация конструктора, ни документация класса не упоминают об этом, но документация другого конструктора делает это.

Другие вопросы по тегам