Как мне конвертировать аудио из одного формата в формат wav или raw в Java? - PullRequest
0 голосов
/ 11 марта 2020

Я пытаюсь выяснить, как использовать java .sound api для преобразования файла WAV в формат RAW / PCM. Мне нужно преобразовать WAV-файл из некоторого заданного аудиоформата в RAW-файл, закодированный следующим образом:

  • 16 кГц
  • 16 бит
  • Mono
  • Подпись
  • Little endian

Многие из постов, которые я нашел здесь, предназначены для обратного пути, как go из RAW и получить WAV. Будучи новичком в аудио, я надеялся, что кто-нибудь может опубликовать пример, показывающий, как это сделать.

Ответы [ 2 ]

0 голосов
/ 11 марта 2020

Вы можете легко получить данные PCM (в необработанных байтах) из файла WAV, прочитав его с AudioInputStream, сохранив данные в ByteBuffer, возможно.

Java действительно имеет некоторые встроенные конвертеры формата. Я не уверен, поддерживаются ли нужные вам конверсии. Документация о поддерживаемых преобразованиях форматов приведена на Аудио-трейл: Использование файлов и преобразователей форматов

Если вам нужно выполнить какое-либо прореживание, например, до go из wav с 44,1 кГц частота дискретизации до 16 кГц, я бы предположил, что с помощью линейной интерполяции было бы хорошо.

  1. преобразовать входящие байты в значения данных PCM (возможно, нормализуя до значений с плавающей запятой)
  2. итерация по полученному массиву с шагом 2.76625 (получено из 44.1 / 16) с использованием линейной интерполяции для получения новых значений
  3. преобразование новых значений PCM обратно в байты

Полученный байтовый массив можно записать в файл, использующий FileOutputStream, если заголовок отсутствует. Java Обучающие программы: Потоки байтов

Линейная интерполяция с точностью с плавающей запятой обычно считается достаточно хорошей для сохранения достоверности звука.

0 голосов
/ 11 марта 2020

Насколько я знаю, звуковой интерфейс Java не конвертируется в RAW-аудио. Он конвертирует в WAV, который является RAW аудио с 44-байтовым заголовком . Когда вы поймете это, вы сможете разбить проблему на 2 части:

1. Конвертируйте аудио из любого формата в формат WAV.

Приведенный ниже пример кода был протестирован только из WAV в WAV (другой формат аудио), но теоретически при вызове AudioSystem.getAudioInputStream(audioFormat, originalAudioStream); должен быть найден соответствующий код c, если он есть.

Этот метод преобразует аудиобайты в заданный формат и выдает результат байта [] в виде WAV.

 private static final AudioFormat EXAMPLE_FORMAT = new AudioFormat(
        16_000,
        16,
        1,
        true,
        false
    );

    public byte[] formatAudioToWav(@NotNull final byte[] audioFileContent,
                                   @NotNull final AudioFormat audioFormat) throws
                                                                           IOException,
                                                                           UnsupportedAudioFileException {

        try (
            final AudioInputStream originalAudioStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(audioFileContent));
            final AudioInputStream formattedAudioStream = AudioSystem.getAudioInputStream(audioFormat, originalAudioStream);
            final AudioInputStream lengthAddedAudioStream = new AudioInputStream(formattedAudioStream, audioFormat, audioFileContent.length);
            final ByteArrayOutputStream convertedOutputStream = new ByteArrayOutputStream()
        ) {
            AudioSystem.write(lengthAddedAudioStream, AudioFileFormat.Type.WAVE, convertedOutputStream);
            return convertedOutputStream.toByteArray();
        }
    }

2. Уберите заголовок из файла WAV, созданного на шаге 1.

   public byte[] formatWavToRaw(@NotNull final byte[] audioFileContent) {
        return Arrays.copyOfRange(audioFileContent, 44, audioFileContent.length);
    }

Примечания

  • Преимущество кода заключается в правильном закрытии всех потоков, но у него есть недостаток в работе с byte [] напрямую, поэтому он не будет хорошо работать с большими файлами. Его можно преобразовать в чистые потоки, но обратите внимание, что вам нужна длина одного из потоков в вызове new AudioInputStream(formattedAudioStream, audioFormat, audioFileContent.length);.
  • Другим недостатком является то, что, даже если код разборчив, есть 3 AudioInputStream, которые необходимо создать / обернуть, чтобы сделать эту работу, что несколько запутанно. Мне не удалось найти лучшего решения.

Дальнейшее чтение

...