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 .