2016-06-29 16 views
2

Ich benutze Android AudioRecord, um das Audio aufzunehmen und es in einer WAV-Datei zu speichern. Das Problem ist, dass wenn ich das Audio von der WAV-Datei abspiele, es klingt, als wäre es schnell weitergeleitet (spielt zu schnell). In der Klasse, die ich gepostet habe, habe ich auch Spracherkennung eingerichtet. Die Spracherkennung funktioniert und die Audioaufnahmen, aber es ist die Rate, mit der die Audiowiedergabe nicht stimmt.Android AudioRecord WAV-Audiowiedergabegeschwindigkeit ist zu schnell

Ich denke, es könnte ein Problem sein, wie ich die WAV-Datei schreibe, aber ich bin mir nicht sicher. Welche Einstellungen könnten im WAV-Header geändert werden oder das Audio in die WAV-Datei geschrieben werden, wodurch die Audiowiedergabe langsamer wird?

Hier ist die Klasse, die ich verwende. Ich habe einige Methoden aus der Klasse weggelassen, um den Code lesbarer zu halten.

public class SpeechRecognizer { 

protected static final String TAG = SpeechRecognizer.class.getSimpleName(); 

private final Decoder decoder; 

private final int sampleRate; 
private int bufferSize; 
private final AudioRecord recorder; 
private boolean record; 
private boolean is_recording; 

/* Files to record the audio into */ 
public File pcm_sound_file; 
public File wav_sound_file; 

private Thread recognizerThread; 
public Thread recorder_thread; 

private final Handler mainHandler = new Handler(Looper.getMainLooper()); 

private final Collection<RecognitionListener> listeners = new HashSet<RecognitionListener>(); 

/** 
* Creates speech recognizer. Recognizer holds the AudioRecord object, so you 
* need to call {@link release} in order to properly finalize it. 
* 
* @param config The configuration object 
* @throws IOException thrown if audio recorder can not be created for some reason. 
*/ 
protected SpeechRecognizer(Config config, boolean record) throws IOException { 
    this.record = record; 
    decoder = new Decoder(config); 
    sampleRate = (int)decoder.getConfig().getFloat("-samprate"); 
    bufferSize = AudioRecord.getMinBufferSize(sampleRate, 
      AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 
    recorder = new AudioRecord(
      AudioSource.VOICE_RECOGNITION, sampleRate, 
      AudioFormat.CHANNEL_IN_MONO, 
      AudioFormat.ENCODING_PCM_16BIT, bufferSize); 

    if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) { 
     recorder.release(); 
     throw new IOException(
       "Failed to initialize recorder. Microphone might be already in use."); 
    } 
} 

/** 
* Stops recognition. All listeners should receive final result if there is 
* any. Does nothing if recognition is not active. 
* 
* @return true if recognition was actually stopped 
*/ 
public boolean stop() { 
    boolean result = stopRecognizerThread(); 
    if (result) { 
     Log.i(TAG, "Stop recognition"); 
     is_recording = false; 
     recorder_thread = null; 

     try { 
      wav_sound_file = getOutputMediaFile("wav"); 
      copyWaveFile(pcm_sound_file, wav_sound_file); 
     } 
     catch (Exception e){ 
      Log.d("COS", "Failed to convert PCM to WAV"); 
     } 

     final Hypothesis hypothesis = decoder.hyp(); 
     mainHandler.post(new ResultEvent(hypothesis, true)); 
    } 
    return result; 
} 


private void copyWaveFile(File inFilename,File outFilename){ 
    FileInputStream in; 
    FileOutputStream out; 
    long totalAudioLen; 
    long totalDataLen; 
    long longSampleRate = sampleRate; 
    int channels = 1; 
    long byteRate = 16 * sampleRate * channels/8; 

    byte[] data = new byte[bufferSize]; 

    try { 
     in = new FileInputStream(inFilename); 
     out = new FileOutputStream(outFilename); 
     totalAudioLen = in.getChannel().size(); 
     totalDataLen = totalAudioLen + 36; 


     WriteWaveFileHeader(out, totalAudioLen, totalDataLen, 
       longSampleRate, channels, byteRate); 

     while(in.read(data) != -1){ 
      out.write(data); 
     } 

     in.close(); 
     out.close(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

private void WriteWaveFileHeader(
     FileOutputStream out, long totalAudioLen, 
     long totalDataLen, long longSampleRate, int channels, 
     long byteRate) throws IOException { 

    byte[] header = new byte[44]; 

    header[0] = 'R'; // RIFF/WAVE header 
    header[1] = 'I'; 
    header[2] = 'F'; 
    header[3] = 'F'; 
    header[4] = (byte) (totalDataLen & 0xff); 
    header[5] = (byte) ((totalDataLen >> 8) & 0xff); 
    header[6] = (byte) ((totalDataLen >> 16) & 0xff); 
    header[7] = (byte) ((totalDataLen >> 24) & 0xff); 
    header[8] = 'W'; 
    header[9] = 'A'; 
    header[10] = 'V'; 
    header[11] = 'E'; 
    header[12] = 'f'; // 'fmt ' chunk 
    header[13] = 'm'; 
    header[14] = 't'; 
    header[15] = ' '; 
    header[16] = 16; // 4 bytes: size of 'fmt ' chunk 
    header[17] = 0; 
    header[18] = 0; 
    header[19] = 0; 
    header[20] = 1; // format = 1 
    header[21] = 0; 
    header[22] = (byte) channels; 
    header[23] = 0; 
    header[24] = (byte) (longSampleRate & 0xff); 
    header[25] = (byte) ((longSampleRate >> 8) & 0xff); 
    header[26] = (byte) ((longSampleRate >> 16) & 0xff); 
    header[27] = (byte) ((longSampleRate >> 24) & 0xff); 
    header[28] = (byte) (byteRate & 0xff); 
    header[29] = (byte) ((byteRate >> 8) & 0xff); 
    header[30] = (byte) ((byteRate >> 16) & 0xff); 
    header[31] = (byte) ((byteRate >> 24) & 0xff); 
    header[32] = (byte) (16/8); // block align 
    header[33] = 0; 
    header[34] = 16; // bits per sample 
    header[35] = 0; 
    header[36] = 'd'; 
    header[37] = 'a'; 
    header[38] = 't'; 
    header[39] = 'a'; 
    header[40] = (byte) (totalAudioLen & 0xff); 
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff); 
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff); 
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff); 

    out.write(header, 0, 44); 
} 

private void writeAudioDataToFile() { 

    byte sData[] = new byte[bufferSize]; 

    FileOutputStream os = null; 
    try { 
     pcm_sound_file = getOutputMediaFile("pcm"); 
     os = new FileOutputStream(pcm_sound_file); 
    } catch (Exception e) {e.printStackTrace();} 

    while (is_recording) { 
     recorder.read(sData, 0, bufferSize); 
     try { 
      os.write(sData); 
     } catch (Exception e) {e.printStackTrace();} 
    } 

    try { 
     os.close(); 
    } catch (Exception e) {e.printStackTrace();} 
} 


private File getOutputMediaFile(String format){ 
    // To be safe, you should check that the SDCard is mounted 
    // using Environment.getExternalStorageState() before doing this. 

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
      Environment.DIRECTORY_PICTURES), "SafePhrase"); 
    // This location works best if you want the created images to be shared 
    // between applications and persist after your app has been uninstalled. 

    // Create the storage directory if it does not exist 
    if (! mediaStorageDir.exists()){ 
     if (! mediaStorageDir.mkdirs()){ 
      Log.d("COS", "failed to create directory"); 
      return null; 
     } 
    } 

    // Create a media file name 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    File mediaFile; 
    mediaFile = new File(mediaStorageDir.getPath() + File.separator + 
       "SOUND_"+ timeStamp + "." + format); 

    return mediaFile; 
} 


private final class RecognizerThread extends Thread { 

    private int remainingSamples; 
    private int timeoutSamples; 
    private final static int NO_TIMEOUT = -1; 

    public RecognizerThread(int timeout) { 
     if (timeout != NO_TIMEOUT) 
      this.timeoutSamples = timeout * sampleRate/1000; 
     else 
      this.timeoutSamples = NO_TIMEOUT; 
     this.remainingSamples = this.timeoutSamples; 
    } 

    public RecognizerThread() { 
     this(NO_TIMEOUT); 
    } 

    @Override 
    public void run() { 

     recorder.startRecording(); 

     /* If the user has asked to record, then create a new recorder thread where the audio 
     * will be recorded. */ 
     if(record) { 
      recorder_thread = new Thread(new Runnable() { 
       @Override 
       public void run() { 
        Log.d("COS", "RECORDING!"); 
        writeAudioDataToFile(); 
       } 
      }, "Audio Recorder Thread"); 
      recorder_thread.start(); 
     } 
     else{ 
      Log.d("COS", "NOT RECORDING!"); 
     } 

     /* SPEECH RECOGNITION BELOW */ 

     if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) { 
      recorder.stop(); 
      IOException ioe = new IOException(
        "Failed to start recording. Microphone might be already in use."); 
      mainHandler.post(new OnErrorEvent(ioe)); 
      return; 
     } 

     Log.d(TAG, "Starting decoding"); 

     decoder.startUtt(); 
     short[] buffer = new short[bufferSize]; 
     boolean inSpeech = decoder.getInSpeech(); 

     // Skip the first buffer, usually zeroes 
     recorder.read(buffer, 0, buffer.length); 

     while (!interrupted() 
       && ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) { 
      int nread = recorder.read(buffer, 0, buffer.length); 

      if (-1 == nread) { 
       throw new RuntimeException("error reading audio buffer"); 
      } else if (nread > 0) { 
       decoder.processRaw(buffer, nread, false, false); 

       // int max = 0; 
       // for (int i = 0; i < nread; i++) { 
       //  max = Math.max(max, Math.abs(buffer[i])); 
       // } 
       // Log.e("!!!!!!!!", "Level: " + max); 

       if (decoder.getInSpeech() != inSpeech) { 
        inSpeech = decoder.getInSpeech(); 
        mainHandler.post(new InSpeechChangeEvent(inSpeech)); 
       } 

       if (inSpeech) 
        remainingSamples = timeoutSamples; 

       final Hypothesis hypothesis = decoder.hyp(); 
       mainHandler.post(new ResultEvent(hypothesis, false)); 
      } 

      if (timeoutSamples != NO_TIMEOUT) { 
       remainingSamples = remainingSamples - nread; 
      } 
     } 

     recorder.stop(); 
     decoder.endUtt(); 

     // Remove all pending notifications. 
     mainHandler.removeCallbacksAndMessages(null); 

     // If we met timeout signal that speech ended 
     if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) { 
      mainHandler.post(new TimeoutEvent()); 
     } 
    } 
} 

Antwort

0

Die Mediaplayer Klasse verfügt nicht über diese Funktion aber Soundpool diese Funktionalität. Die SoundPool-Klasse hat eine Methode namens setRate(int streamID, float rate). Wenn Sie sich für die API interessieren, schauen Sie hier nach.

wird dieser Code-Schnipsel arbeiten:

float playbackSpeed=1.5f; 
SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100); 

soundId = soundPool.load(Environment.getExternalStorageDirectory() 
         + "/sample.wav", 1); 
AudioManager manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 
final float volume = manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 

soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() 
{ 
    @Override 
    public void onLoadComplete(SoundPool arg0, int arg1, int arg2) 
    { 
     soundPool.play(soundId, volume, volume, 1, 0, playbackSpeed); 
    } 
}); 
+0

Aber ich möchte die Rate machen, an dem es permanent spielt. Ich nehme Audiodateien auf und der Benutzer kann wählen, ob er die Datei von überall abspielen möchte, was bedeutet, dass er nicht von meiner App abgespielt wird. Wenn ich die Datei in der WAV-Datei aufnehme, dann möchte ich die Rate ändern. – Cyogenos