本文介紹了將原始PCM數(shù)據(jù)轉換為RIFF波的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在嘗試將原始音頻數(shù)據(jù)從一種格式轉換為另一種格式,以便進行語音識別。
從Discord服務器以20ms
塊的格式接收音頻:48Khz, 16-bit stereo signed BigEndian PCM
。
我使用CMU’s Sphinx進行語音識別,它將音頻作為RIFF (little-endian) WAVE audio, 16-bit, mono 16,000Hz
中的InputStream
音頻數(shù)據(jù)在byte[]
中接收,長度3840
。該byte[]
數(shù)組包含上述格式1的音頻的20ms
。這意味著1秒的音頻是3840 * 50
,也就是192,000
。這就是每秒192,000
個樣本。這是有意義的,48KHz
采樣率,乘以2(96K采樣),因為一個字節(jié)是8比特,我們的音頻是16比特,并且是立體聲的另外兩倍。所以48,000 * 2 * 2 = 192,000
。
所以每次收到音頻包時,我首先調用此方法:
private void addToPacket(byte[] toAdd) {
if(packet.length >= 576000 && !done) {
System.out.println("Processing needs to occur...");
getResult(convertAudio());
packet = null; // reset the packet
return;
}
byte[] newPacket = new byte[packet.length + 3840];
// copy old packet onto new temp array
System.arraycopy(packet, 0, newPacket, 0, packet.length);
// copy toAdd packet onto new temp array
System.arraycopy(toAdd, 0, newPacket, 3840, toAdd.length);
// overwrite the old packet with the newly resized packet
packet = newPacket;
}
這只會將新數(shù)據(jù)包添加到一個大字節(jié)[]上,直到該字節(jié)[]包含3秒的音頻數(shù)據(jù)(576,000個樣本,或192000*3)。3秒的音頻數(shù)據(jù)足以(只是猜測)檢測用戶是否說了機器人的激活熱詞,如”嘿,電腦。”下面是我如何轉換聲音數(shù)據(jù):
private byte[] convertAudio() {
// STEP 1 - DROP EVERY OTHER PACKET TO REMOVE STEREO FROM THE AUDIO
byte[] mono = new byte[96000];
for(int i = 0, j = 0; i % 2 == 0 && i < packet.length; i++, j++) {
mono[j] = packet[i];
}
// STEP 2 - DROP EVERY 3RD PACKET TO CONVERT TO 16K HZ Audio
byte[] resampled = new byte[32000];
for(int i = 0, j = 0; i % 3 == 0 && i < mono.length; i++, j++) {
resampled[j] = mono[i];
}
// STEP 3 - CONVERT TO LITTLE ENDIAN
ByteBuffer buffer = ByteBuffer.allocate(resampled.length);
buffer.order(ByteOrder.BIG_ENDIAN);
for(byte b : resampled) {
buffer.put(b);
}
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.rewind();
for(int i = 0; i < resampled.length; i++) {
resampled[i] = buffer.get(i);
}
return resampled;
}
最后,嘗試識別講話:
private void getResult(byte[] toProcess) {
InputStream stream = new ByteArrayInputStream(toProcess);
recognizer.startRecognition(stream);
SpeechResult result;
while ((result = recognizer.getResult()) != null) {
System.out.format("Hypothesis: %s
", result.getHypothesis());
}
recognizer.stopRecognition();
}
我遇到的問題是CMUSphinx
沒有崩潰或提供任何錯誤消息,它只是每隔3秒提出一個空的假設。我不確定為什么,但我猜我沒有正確轉換聲音。有什么主意嗎?如有任何幫助,將不勝感激。
推薦答案
因此,實際上有一個更好的內部解決方案來轉換來自byte[]
的音頻。
以下是我發(fā)現(xiàn)非常有效的方法:
// Specify the output format you want
AudioFormat target = new AudioFormat(16000f, 16, 1, true, false);
// Get the audio stream ready, and pass in the raw byte[]
AudioInputStream is = AudioSystem.getAudioInputStream(target, new AudioInputStream(new ByteArrayInputStream(raw), AudioReceiveHandler.OUTPUT_FORMAT, raw.length));
// Write a temporary file to the computer somewhere, this method will return a InputStream that can be used for recognition
try {
AudioSystem.write(is, AudioFileFormat.Type.WAVE, new File("C:\filename.wav"));
} catch(Exception e) {}
這篇關于將原始PCM數(shù)據(jù)轉換為RIFF波的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,