Получать входной сигнал с микрофона от 2 процессов одновременно - PullRequest
1 голос
/ 06 мая 2020

Я работал над распознаванием речи java с использованием sphynx4, и в настоящее время у меня есть и проблема.

У меня есть приложение, которое распознает ввод микрофона с использованием класса LiveSpeechRecognizer Sphynx4, которое отлично работает. Проблема в том, что после того, как я добавил класс, который также слушает микрофон, преобразует и визуализирует вывод.

По отдельности оба класса работают нормально. Но при объединении в одном приложении я получаю сообщение об ошибке:

LineUnavailableException: строка с форматом PCM_SIGNED 44100.0 Гц, 8 бит, моно, 1 байт / кадр, не поддерживается.

Я проверил проблему, похоже, она вызвана одновременным доступом к микрофону. У меня была идея использовать StreamSpeechRecognizer вместо Live, но мне не удалось получить поток со входа микрофона. Пробовал AudioInputStream для этой цели.

Не могли бы вы подсказать, как я могу настроить свой код, чтобы и SpeechRecognition, и осциллограф использовали микрофон одновременно?

Заранее спасибо.

UPD:

Это моя попытка разделить вход микрофона для использования в обоих приложениях.

....
     byte[] data = new byte[dataCaptureSize];   
            line.read(data, 0, data.length);

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            out.write(data);
            byte audioData[] = out.toByteArray();
            InputStream byteArrayInputStream = new ByteArrayInputStream(audioData);
            AudioInputStream audioInputStream = new AudioInputStream(byteArrayInputStream,
                    inputFormat,
                    audioData.length / inputFormat.getFrameSize());
....

Вот как я конвертирую его во входной поток, который затем передается в StreamSpeechRecognizer, а массив байтов преобразуется с помощью быстрого преобразования Фурье и передается на график. Это не работает, так как график постоянно замораживается, поэтому отображаемые данные не соответствуют действительности.

Я попытался запустить распознавание в отдельном потоке, но это не увеличило производительность вообще.

Мой код разбиения на потоки ниже:

Thread recognitionThread = new Thread(new RecognitionThread(configuration,data));
    recognitionThread.join();
    recognitionThread.run();

UPD 2: Вход с микрофона. Вышеупомянутый AudioInputStream передается в StreamSpeechRecognizer:

StreamSpeechRecognizer nRecognizer = new StreamSpeechRecognizer(configuration); nRecognizer.startRecognition(audioStream);

И массив байтов передается преобразованным методом БПФ и передается графу: `double [] arr = FastFourierTransform.TransformRealPart (data );

for (int i = 0; i < arr.length; i++) { 
    series1.getData().add(new XYChart.Data<>(i*22050/(arr.length), arr[i]));

`

1 Ответ

1 голос
/ 07 мая 2020

Вот возможный подход, который следует рассмотреть.

Во-первых, напишите свой собственный микрофонный считыватель. (Существуют учебные пособия о том, как это сделать.) Затем переупакуйте эти данные в виде двух параллельных строк, которые могут читать другие приложения.

Другой подход - проверить, имеет ли какое-либо приложение какую-либо возможность «сквозной передачи» включен.

РЕДАКТИРОВАТЬ: добавлено для уточнения

Этот Java пример кода утилиты записи звука открывает TargetDataLine микрофону и сохраняет данные с него в массив (строки 69, 70). Вместо того, чтобы хранить данные в массиве, я предлагаю вам создать два объекта SourceDataLine и записать данные для каждого из них.

recordBytes = new ByteArrayOutputStream();
secondStreamBytes = new ByteArrayOutputStream();

isRunning = true;

while (isRunning) {
    bytesRead = audioLine.read(buffer, 0, buffer.length);
    recordBytes.write(buffer, 0, bytesRead);
    secondStreamBytes.write(buffer, 0, bytesRead);
}

Надеюсь, не составит труда понять, как чтобы настроить две программы для чтения из созданных строк, а не из линии микрофона. Я не могу дать указания, как это сделать.

РЕДАКТИРОВАТЬ 2: Я хочу, чтобы sh другие люди присоединились к нему. Я немного не в себе, делая что-нибудь необычное с потоками. И код, который вы даете, настолько минимален, что я до сих пор не понимаю, что происходит или как что-то соединяется.

FWTW: (1) Данные, которые вы добавляете в "series1", являются потоковыми данными? Если да, можете ли вы добавить строку в этот for l oop и записать те же данные в поток, используемый другим классом? (Это был бы способ использования данных микрофона «последовательно», а не «параллельно».)

(2) Потоки данных часто включают код, который блокируется или выполняется с различной скоростью из-за непредсказуемости способ переключения процессора между задачами. Поэтому, если вы напишете «разделитель» (как я пытался проиллюстрировать, изменив код чтения микрофона, который я связал ранее), может возникнуть ситуация, когда код будет работать только с такой скоростью, как более медленное из двух «разделений» при заданном момент. Возможно, вам потребуется включить какую-то буферизацию и использовать отдельные потоки для двух получателей данных с микрофона.

Недавно я написал свой первый код буферизации для ситуации, когда линия считывания микрофона отправляет поток на функция микширования звука в другом потоке. Я написал это всего несколько недель go, и это первый раз, когда я имел дело с попыткой запустить поток через потоки барьера потока, поэтому я не знаю, является ли идея, которую я придумал, лучший способ сделать это Такие вещи. Но ему удается поддерживать постоянный поток от микрофона к микшеру без выпадений и потерь.

Считывающее устройство микрофона считывает буфер данных, а затем добавляет этот byte[] буфер в ConcurrentLinkedQueue<Byte[]> .

Из другого потока код микширования звука опрашивает ConcurrentLinkedQueue на предмет данных.

Я немного поэкспериментировал, и в настоящее время размер буфера byte [] равен 512 байтам, а ConcurrentLinkedQueue настроен на хранение до 12 «буферов», прежде чем он начнет отбрасывать самые старые буферы (структура это FIFO). Кажется, этих небольших буферов достаточно, чтобы приспособиться, когда код обработки микрофона временно опережает микшер.

В ConcurrentLinkedQueue есть встроенные средства, позволяющие добавлять и опрашивать одновременно из двух потоков без создания исключения. Я не могу сказать, нужно ли вам это написать, чтобы помочь с раздачей рук, и какой может быть лучший размер буфера. Может быть, лучше будет иметь буфер гораздо большего размера с меньшим количеством буферов, содержащихся в Очереди. это лучшее, что я могу сделать, учитывая мой ограниченный опыт в этом. Надеюсь, у вас получится что-нибудь придумать.

...