Перейти к основному содержимому

Java Sound API — захват микрофона

· 5 мин. чтения

1. Обзор

В этой статье мы увидим, как захватить микрофон и записать входящий звук на Java, чтобы сохранить его в файл WAV. Для захвата входящего звука с микрофона мы используем Java Sound API, часть экосистемы Java.

Java Sound API — это мощный API для захвата, обработки и воспроизведения звука, состоящий из 4 пакетов. Мы сосредоточимся на пакете javax.sound.sampled , который предоставляет все интерфейсы и классы, необходимые для захвата входящего звука .

2. Что такое TargetDataLine ?

TargetDataLine — это тип объекта DataLine , который мы используем для захвата и чтения данных, связанных со звуком, и он собирает данные с устройств захвата звука, таких как микрофоны. `` Интерфейс предоставляет все методы, необходимые для чтения и захвата данных, а также считывает данные из буфера целевой строки данных.

Мы можем вызвать метод getLine () AudioSystem и предоставить ему объект DataLine.Info , который предоставляет все методы управления транспортом для аудио. Документация Oracle подробно объясняет, как работает Java Sound API.

Давайте рассмотрим шаги, необходимые для захвата звука с микрофона в Java.

3. Шаги для захвата звука

Для сохранения захваченного звука Java поддерживает следующие форматы файлов: AU, AIFF, AIFC, SND и WAVE. Мы будем использовать формат файла WAVE (.wav) для сохранения наших файлов.

Первым шагом в этом процессе является инициализация экземпляра AudioFormat . AudioFormat уведомляет Java о том , как интерпретировать и обрабатывать биты информации во входящем звуковом потоке. В нашем примере мы используем следующий конструктор класса AudioFormat :

AudioFormat(AudioFormat.Encoding encoding, float sampleRate, int sampleSizeInBits, int channels, int frameSize, float frameRate, boolean bigEndian)

После этого открываем объект DataLine.Info . Этот объект содержит всю информацию, относящуюся к строке данных (ввод). Используя объект DataLine.Info , мы можем создать экземпляр TargetDataLine , который будет считывать все входящие данные в аудиопоток. Для генерации экземпляра TargetDataLine мы используем метод AudioSystem.getLine() и передаем объект DataLine.Info :

line = (TargetDataLine) AudioSystem.getLine(info);

Строка является экземпляром TargetDataLine , а информация — экземпляром DataLine.Info . ``

После создания мы можем открыть линию для чтения всех входящих звуков. Мы можем использовать AudioInputStream для чтения входящих данных. В заключение мы можем записать эти данные в файл WAV и закрыть все потоки.

Чтобы понять этот процесс, мы рассмотрим небольшую программу для записи входного звука.

4. Пример приложения

Чтобы увидеть Java Sound API в действии, давайте создадим простую программу. Мы разобьем его на три части: сначала создадим AudioFormat , затем создадим TargetDataLine и, наконец, сохраним данные в виде файла.

4.1. Создание аудиоформата

Класс AudioFormat определяет, какие данные могут быть захвачены экземпляром TargetDataLine . Итак, первый шаг — инициализировать экземпляр класса AudioFormat еще до того, как мы откроем новую строку данных. Класс App является основным классом приложения и выполняет все вызовы. Мы определяем свойства AudioFormat в классе констант с именем ApplicationProperties . Мы создаем экземпляр AudioFormat в обход всех необходимых параметров:

public static AudioFormat buildAudioFormatInstance() {
ApplicationProperties aConstants = new ApplicationProperties();
AudioFormat.Encoding encoding = aConstants.ENCODING;
float rate = aConstants.RATE;
int channels = aConstants.CHANNELS;
int sampleSize = aConstants.SAMPLE_SIZE;
boolean bigEndian = aConstants.BIG_ENDIAN;

return new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize / 8) * channels, rate, bigEndian);
}

Теперь, когда у нас есть готовый AudioFormat , мы можем двигаться дальше и создать экземпляр TargetDataLine .

4.2. Построение TargetDataLine

Мы используем класс TargetDataLine для чтения аудиоданных с нашего микрофона. В нашем примере мы получаем и запускаем TargetDataLine в классе SoundRecorder. Метод getTargetDataLineForRecord() создает экземпляр TargetDataLine .

Мы прочитали и обработали ввод аудио и выгрузили его в объект AudioInputStream . Мы создаем экземпляр TargetDataLine следующим образом :

private TargetDataLine getTargetDataLineForRecord() {
TargetDataLine line;
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
if (!AudioSystem.isLineSupported(info)) {
return null;
}
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format, line.getBufferSize());
return line;
}

4.3. Создание и заполнение AudioInputStream

Пока что в нашем примере мы создали экземпляр AudioFormat и применили его к TargetDataLine, а также открыли строку данных для чтения аудиоданных. Мы также создали поток для помощи в автоматическом запуске экземпляра <em>SoundRecorder</em>. Сначала мы создаем поток вывода байтов при запуске потока, а затем преобразовываем его в экземпляр AudioInputStream . Параметры, которые нам нужны для создания экземпляра AudioInputStream :

int frameSizeInBytes = format.getFrameSize();
int bufferLengthInFrames = line.getBufferSize() / 8;
final int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;

Обратите внимание, что в приведенном выше коде мы уменьшили размер буфера на 8. Мы сделали это, чтобы сделать буфер и массив одинаковой длины, чтобы устройство записи могло затем доставить данные в строку, как только они будут прочитаны.

Теперь, когда мы инициализировали все необходимые параметры, следующим шагом будет создание потока вывода байтов. Следующим шагом является преобразование сгенерированного выходного потока (захваченных звуковых данных) в экземпляр AudioInputStream .

buildByteOutputStream(out, line, frameSizeInBytes, bufferLengthInBytes);
this.audioInputStream = new AudioInputStream(line);

setAudioInputStream(convertToAudioIStream(out, frameSizeInBytes));
audioInputStream.reset();

Прежде чем установить InputStream , мы создадим byte OutputStream :

public void buildByteOutputStream(final ByteArrayOutputStream out, final TargetDataLine line, int frameSizeInBytes, final int bufferLengthInBytes) throws IOException {
final byte[] data = new byte[bufferLengthInBytes];
int numBytesRead;

line.start();
while (thread != null) {
if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
break;
}
out.write(data, 0, numBytesRead);
}
}

Затем мы преобразуем байт Outstream в AudioInputStream следующим образом:

public AudioInputStream convertToAudioIStream(final ByteArrayOutputStream out, int frameSizeInBytes) {
byte audioBytes[] = out.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
AudioInputStream audioStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);
long milliseconds = (long) ((audioInputStream.getFrameLength() * 1000) / format.getFrameRate());
duration = milliseconds / 1000.0;
return audioStream;
}

4.4. Сохранение AudioInputStream в файл Wav

Мы создали и заполнили AudioInputStream и сохранили его как переменную- член класса SoundRecorder . Мы получим этот AudioInputStream в классе App , используя свойство получателя экземпляра SoundRecorder , и передадим его классу WaveDataUtil :

wd.saveToFile("/SoundClip", AudioFileFormat.Type.WAVE, soundRecorder.getAudioInputStream());

Класс WaveDataUtil имеет код для преобразования AudioInputStream в файл .wav:

AudioSystem.write(audioInputStream, fileType, myFile);

5. Вывод

В этой статье показан краткий пример использования Java Sound API для захвата и записи звука с помощью микрофона. Весь код этого руководства доступен на GitHub .