2017-12-19 21 views
1

音声認識の目的で生の音声データをあるフォーマットから別のフォーマットに変換しようとしています。 48Khz, 16-bit stereo signed BigEndian PCMRaw PCMデータをRIFF WAVに変換する

  • オーディオフォーマットで20msチャンクにDiscordサーバから受信されます。
  • 私はInputStream

RIFF (little-endian) WAVE audio, 16-bit, mono 16,000Hzオーディオデータは、長さ3840byte[]に受信されるオーディオかかる音声認識のための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秒ごとに空の仮説が出てくるだけです。なぜ私は正確にはわかりませんが、私の推測は、私が正しく音を変換していないということです。何か案は?どんな助けでも大歓迎です。

+0

ルック。デバッガで実行します。何が起こるか見る。あなたが他のすべての価値を望むなら、なぜ私は1つずつ増やすのですか?また、常に新しいバッファを作成してデータをコピーしないでください。これはGCに対する膨大なストレスであり、まったく役に立たないものです。あなたが最後にしたいサイズの1つのバッファは、それにデータをコピーします。 –

答えて

0

実際、オーディオをbyte[]から変換するための、より優れた社内ソリューションがあります。

は、ここで私はかなりよく作品を見つけたものです:あなたのステレオ滴下ループ条件で

 // 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) {} 
関連する問題