我一直在使用sphynx4
进行java语音识别,目前有问题。
我有一个应用程序,可以使用Sphynx4的LiveSpeechRecognizer类识别麦克风输入,效果很好。问题是,在我添加了同样监听麦克风并转换和可视化输出的类之后。
另外,这两个类都可以正常工作。但当组合在一个应用程序中时,我会得到错误:
线路不可用异常:线路格式为PCM_SIGNED 44100.0 Hz,8位,单声道,1字节/帧,不受支持。
我已经检查了这个问题,它似乎是由同时访问麦克风引起的。我曾想过使用StreamSpeechRecognizer而不是Live,但我未能从麦克风输入中检索到流。为此目的尝试了AudioInputStream。
你能建议我如何调整我的代码以同时使用麦克风:语音识别和示波器吗?
提前谢谢。
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();
更新2:输入来自麦克风。上述AudioInputStream被传递到StreamSpeechRecognizer:
StreamSpeechRecognizer nRecognizer = new StreamSpeechRecognizer(configuration);
nRecognizer.startRecognition(audioStream);
字节数组通过FFT进行传递变换并传递到图形中:`double[]arr=FastFourierTransform.TransformRealPart(数据);
for (int i = 0; i < arr.length; i++) {
series1.getData().add(new XYChart.Data<>(i*22050/(arr.length), arr[i]));
`
这里有一个合理的方法可以考虑。
首先,编写自己的麦克风阅读器。(有关于如何做到这一点的教程。)然后将数据重新打包为两条平行线,其他应用程序可以读取。
另一种方法是检查任一应用程序是否启用了某种"传递"功能。
编辑:添加以澄清
这个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:我希望其他人也能加入进来。我对用流做任何花哨的事情都有点不知所措。你给出的代码太少了,我仍然不明白发生了什么,也不明白事情是如何联系的。
FWTW:(1)您添加到"系列1"中的数据是流数据吗?如果是这样的话,你能在for
循环中添加一行,并将相同的数据写入另一个类消耗的流中吗?(这将是一种"串联"使用麦克风数据的方式,而不是"并联"使用。)
(2) 由于cpu在任务之间切换的方式不可预测,数据流通常涉及阻塞或以不同速度运行的代码。因此,如果你真的写了一个"拆分器"(正如我试图通过修改我之前链接的麦克风读取代码来说明的那样),可能会出现这样的情况,即代码在给定时刻的运行速度只能与两个"拆分"中较慢的一个一样快。您可能需要合并某种缓冲,并为mike数据的两个接收者使用单独的线程。
我最近写了我的第一个缓冲代码,用于麦克风读取行向另一个线程上的音频混合函数发送流的情况。我几周前才写这篇文章,这是我第一次尝试在线程屏障线程上运行流,所以我不知道我提出的想法是否是做这类事情的最佳方式。但它确实设法保持了从麦克风到混音器的馈送稳定,没有脱落和损失。
麦克风读取器读取一个数据缓冲区,然后将这个byte[]
缓冲区添加到ConcurrentLinkedQueue<Byte[]>
中。
音频混合代码从另一个线程轮询ConcurrentLinkedQueue
以获取数据。
我做了一点实验,目前字节[]缓冲区的大小为512字节,ConcurrentLinkedQueue
设置为最多可容纳12个"缓冲区",然后才开始丢弃最旧的缓冲区(结构为FIFO)。当麦克风处理代码暂时领先于混音器时,这些小缓冲区似乎已经足够容纳了。
ConcurrentLinkedQueue
内置了一些规定,允许在不引发异常的情况下同时从两个线程进行添加和轮询。这是否是你必须写的东西来帮助切换,以及最好的缓冲区大小是多少,我不能说。也许一个更大的缓冲区,队列中的缓冲区更少会更好。
也许其他人会参与进来,或者这个建议值得尝试。
不管怎样,这是我能做的最好的事情,因为我在这方面的经验有限。我希望你能解决一些问题。