音声認識の目的で生の音声データをあるフォーマットから別のフォーマットに変換しようとしています。 48Khz, 16-bit stereo signed BigEndian PCM
:Raw PCMデータをRIFF WAVに変換する
- オーディオフォーマットで
20ms
チャンクにDiscordサーバから受信されます。 - 私は
InputStream
RIFF (little-endian) WAVE audio, 16-bit, mono 16,000Hz
オーディオデータは、長さ3840
とbyte[]
に受信されるオーディオかかる音声認識のためのCMU's Sphinxを使用しています。このbyte[]
アレイは、前述のフォーマット1のオーディオの20ms
を含みます。これは、このオーディオの1秒が3840 * 50
であることを意味します。これは192,000
です。つまり、毎秒192,000
サンプルです。これは、バイトが8ビットであり、オーディオが16ビットであり、ステレオに対して2倍の時間がかかるため、48KHz
サンプルレート、2倍(96Kサンプル)の意味があります。だから48,000 * 2 * 2 = 192,000
。 (576000を
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;
}
これは単なるバイト[]オーディオデータの3秒を含むまで一つの大きなバイト[]に新しいパケットを追加します。
だから私は最初にこのメソッドに音声パケットを受信するたびに呼び出しますサンプル、または192000 * 3)。オーディオデータの3秒間は、ユーザーがボットの起動ホットワードを "hey computer"と言ったかどうかを検出するのに十分な時間(推測)です。ここで私は、サウンドデータを変換する方法は次のとおりです。
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\n", result.getHypothesis());
}
recognizer.stopRecognition();
}
私がいる問題は、CMUSphinx
にエラー・メッセージがクラッシュしたり、提供していないということです3秒ごとに空の仮説が出てくるだけです。なぜ私は正確にはわかりませんが、私の推測は、私が正しく音を変換していないということです。何か案は?どんな助けでも大歓迎です。
ルック。デバッガで実行します。何が起こるか見る。あなたが他のすべての価値を望むなら、なぜ私は1つずつ増やすのですか?また、常に新しいバッファを作成してデータをコピーしないでください。これはGCに対する膨大なストレスであり、まったく役に立たないものです。あなたが最後にしたいサイズの1つのバッファは、それにデータをコピーします。 –