2013-10-02 19 views
6

Ho trovato questo codice Android per registrare l'audio dell'utente quando inizia a parlare e interrompe la registrazione quando si arresta. Ma il problema è che la registrazione si interrompe molto rapidamente. Se uno vuole dire due parole, registra solo il primo.Rilevamento silenzio acquisizione audio Android

In che modo è possibile modificare il seguente codice per rendere meno sensibile al silenzio momentaneo il processo di registrazione?

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    final int RECORDER_BPP = 16; 
    int RECORDER_SAMPLERATE = 8000; 
    int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO; 
    int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; 

    // Get the minimum buffer size required for the successful creation of 
    // an AudioRecord object. 
    int bufferSizeInBytes = AudioRecord 
      .getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, 
        RECORDER_AUDIO_ENCODING); 
    // Initialize Audio Recorder. 
    AudioRecord audioRecorder = new AudioRecord(
      MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, 
      RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSizeInBytes); 
    // Start Recording. 
    audioRecorder.startRecording(); 

    int numberOfReadBytes = 0; 
    byte audioBuffer[] = new byte[bufferSizeInBytes]; 
    boolean recording = false; 
    float tempFloatBuffer[] = new float[3]; 
    int tempIndex = 0; 
    int totalReadBytes = 0; 
    byte totalByteBuffer[] = new byte[60 * 44100 * 2]; 

    // While data come from microphone. 
    while (true) { 
     float totalAbsValue = 0.0f; 
     short sample = 0; 

     numberOfReadBytes = audioRecorder.read(audioBuffer, 0, 
       bufferSizeInBytes); 

     // Analyze Sound. 
     for (int i = 0; i < bufferSizeInBytes; i += 2) { 
      sample = (short) ((audioBuffer[i]) | audioBuffer[i + 1] << 8); 
      totalAbsValue += Math.abs(sample)/(numberOfReadBytes/2); 
     } 

     // Analyze temp buffer. 
     tempFloatBuffer[tempIndex % 3] = totalAbsValue; 
     float temp = 0.0f; 
     for (int i = 0; i < 3; ++i) 
      temp += tempFloatBuffer[i]; 

     if ((temp >= 0 && temp <= 350) && recording == false) { 
      Log.i("TAG", "1"); 
      tempIndex++; 
      continue; 
     } 

     if (temp > 350 && recording == false) { 
      Log.i("TAG", "2"); 
      recording = true; 
     } 

     if ((temp >= 0 && temp <= 350) && recording == true) { 
      Log.i("TAG", "Save audio to file."); 

      // Save audio to file. 
      String filepath = Environment.getExternalStorageDirectory() 
        .getPath(); 
      File file = new File(filepath, "AudioRecorder"); 
      if (!file.exists()) 
       file.mkdirs(); 

      String fn = file.getAbsolutePath() + "/" 
        + System.currentTimeMillis() + ".wav"; 

      long totalAudioLen = 0; 
      long totalDataLen = totalAudioLen + 36; 
      long longSampleRate = RECORDER_SAMPLERATE; 
      int channels = 1; 
      long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels 
        /8; 
      totalAudioLen = totalReadBytes; 
      totalDataLen = totalAudioLen + 36; 
      byte finalBuffer[] = new byte[totalReadBytes + 44]; 

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

      for (int i = 0; i < totalReadBytes; ++i) 
       finalBuffer[44 + i] = totalByteBuffer[i]; 

      FileOutputStream out; 
      try { 
       out = new FileOutputStream(fn); 
       try { 
        out.write(finalBuffer); 
        out.close(); 
       } catch (IOException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

      } catch (FileNotFoundException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } 

      // */ 
      tempIndex++; 
      break; 
     } 

     // -> Recording sound here. 
     Log.i("TAG", "Recording Sound."); 
     for (int i = 0; i < numberOfReadBytes; i++) 
      totalByteBuffer[totalReadBytes + i] = audioBuffer[i]; 
     totalReadBytes += numberOfReadBytes; 
     // */ 

     tempIndex++; 

    } 
} 

risposta

-6

passa attraverso questo la documentazione di CAPTURE

quindi seguire questi pochi link che questo potrebbe essere utile per scoprire il vostro errore.

http://www.devlper.com/2010/12/android-audio-recording-part-1/

http://www.devlper.com/2010/12/android-audio-recording-part-2/

anche finalmente, fornisci le applicazioni delle autorizzazioni che avrà bisogno. Per lo meno avrà bisogno di RECORD_AUDIO e WRITE_EXTERNAL_STORAGE.

+0

non ho alcun problema con la registrazione, il mio problema è che voglio interrompere la registrazione quando l'utente smette di parlare, ma non così veloce, per esempio se il microfono non ottiene alcun suono per 1 secondo poi la registrazione si interrompe –

19

Non mi piace il modo in cui hai scritto il tuo codice. Usa il mio. È possibile modificare la variabile di soglia in base al volume della voce. In questa app di esempio non è presente alcun pulsante. Quando si avvia l'app, inizia ad ascoltare, quando si preme il pulsante Indietro, l'acquisizione viene interrotta e il file viene archiviato nella memoria del telefono, cartella AudioRecorder, con un nuovo file ogni volta che viene eseguito. legge anche commenti e codice commentato. Nota: la voce viene aggiunta ad un file temporaneo ogni volta che la voce supera la soglia. L'intestazione wav viene aggiunta quando si arresta manualmente la registrazione premendo indietro (il file wav viene creato dal file temporaneo, con un nuovo nome univoco). Se è necessario creare un nuovo file ogni volta che viene rivelata la voce, è possibile modificarla facilmente in base alle proprie esigenze, ma è sempre necessario passare attraverso il salvataggio temporaneo dei file. Se hai bisogno di una sorta di ritardo, per registrare altro, anche quando non c'è voce (dopo la voce), continua a salvare i dati mentre il tuo ritardo è trascorso. È possibile creare il ritardo, contando il tempo trascorso (System.nanotime) dall'ultimo picco rilevato (che indica la presenza vocale).

Non dimenticare di contrassegnare la soluzione accettata (l'ho testata).

package com.example.testaudiocapturewiththreshold; 

import android.os.Bundle; 
import android.app.Activity; 
import android.view.Menu; 


import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 

import android.media.AudioFormat; 
import android.media.AudioRecord; 
import android.media.MediaRecorder; 
import android.os.AsyncTask; 
import android.os.Environment; 
import android.os.Handler; 
import android.util.Log; 

public class TestAudioCaptureWithThreshold extends Activity { 

private static final String TAG = TestAudioCaptureWithThreshold.class.getSimpleName(); 
private static final int RECORDER_BPP = 16; 
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav"; 
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder"; 
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw"; 

FileOutputStream os = null; 

int bufferSize ; 
int frequency = 44100; //8000; 
int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
boolean started = false; 
    RecordAudio recordTask; 

short threshold=15000; 

boolean debug=false; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    Log.w(TAG, "onCreate"); 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_test_audio_capture_with_threshold); 

    startAquisition(); 
} 


@Override 
protected void onResume() { 
    Log.w(TAG, "onResume"); 
    super.onResume(); 


} 

@Override 
protected void onDestroy() { 
    Log.w(TAG, "onDestroy"); 
    stopAquisition(); 
    super.onDestroy(); 

} 

public class RecordAudio extends AsyncTask<Void, Double, Void> { 

    @Override 
    protected Void doInBackground(Void... arg0) { 
     Log.w(TAG, "doInBackground"); 
     try { 

       String filename = getTempFilename(); 

      try { 
         os = new FileOutputStream(filename); 
      } catch (FileNotFoundException e) { 
         e.printStackTrace(); 
      } 


      bufferSize = AudioRecord.getMinBufferSize(frequency, 
      channelConfiguration, audioEncoding); 

      AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, 
        channelConfiguration, audioEncoding, bufferSize); 

      short[] buffer = new short[bufferSize]; 

      audioRecord.startRecording(); 

      while (started) { 
       int bufferReadResult = audioRecord.read(buffer, 0,bufferSize); 
       if(AudioRecord.ERROR_INVALID_OPERATION != bufferReadResult){ 
         //check signal 
        //put a threshold 
         int foundPeak=searchThreshold(buffer,threshold); 
         if (foundPeak>-1){ //found signal 
               //record signal 
          byte[] byteBuffer =ShortToByte(buffer,bufferReadResult); 
         try { 
           os.write(byteBuffer); 
         } catch (IOException e) { 
           e.printStackTrace(); 
         } 
         }else{//count the time 
          //don't save signal 
         } 


           //show results 
         //here, with publichProgress function, if you calculate the total saved samples, 
         //you can optionally show the recorded file length in seconds:  publishProgress(elsapsedTime,0); 


       } 
      } 

      audioRecord.stop(); 


      //close file 
       try { 
        os.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

       copyWaveFile(getTempFilename(),getFilename()); 
       deleteTempFile(); 


     } catch (Throwable t) { 
      t.printStackTrace(); 
      Log.e("AudioRecord", "Recording Failed"); 
     } 
     return null; 

    } //fine di doInBackground 

     byte [] ShortToByte(short [] input, int elements) { 
     int short_index, byte_index; 
     int iterations = elements; //input.length; 
     byte [] buffer = new byte[iterations * 2]; 

     short_index = byte_index = 0; 

     for(/*NOP*/; short_index != iterations; /*NOP*/) 
     { 
     buffer[byte_index]  = (byte) (input[short_index] & 0x00FF); 
     buffer[byte_index + 1] = (byte) ((input[short_index] & 0xFF00) >> 8); 

     ++short_index; byte_index += 2; 
     } 

     return buffer; 
    } 


    int searchThreshold(short[]arr,short thr){ 
     int peakIndex; 
     int arrLen=arr.length; 
     for (peakIndex=0;peakIndex<arrLen;peakIndex++){ 
      if ((arr[peakIndex]>=thr) || (arr[peakIndex]<=-thr)){ 
       //se supera la soglia, esci e ritorna peakindex-mezzo kernel. 

       return peakIndex; 
      } 
     } 
     return -1; //not found 
    } 

    /* 
    @Override 
    protected void onProgressUpdate(Double... values) { 
     DecimalFormat sf = new DecimalFormat("000.0000");   
     elapsedTimeTxt.setText(sf.format(values[0])); 

    } 
    */ 

    private String getFilename(){ 
     String filepath = Environment.getExternalStorageDirectory().getPath(); 
     File file = new File(filepath,AUDIO_RECORDER_FOLDER); 

     if(!file.exists()){ 
       file.mkdirs(); 
     } 

     return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV); 
    } 


    private String getTempFilename(){ 
     String filepath = Environment.getExternalStorageDirectory().getPath(); 
     File file = new File(filepath,AUDIO_RECORDER_FOLDER); 

     if(!file.exists()){ 
       file.mkdirs(); 
     } 

     File tempFile = new File(filepath,AUDIO_RECORDER_TEMP_FILE); 

     if(tempFile.exists()) 
       tempFile.delete(); 

     return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE); 
    } 





    private void deleteTempFile() { 
      File file = new File(getTempFilename()); 

      file.delete(); 
    } 

    private void copyWaveFile(String inFilename,String outFilename){ 
     FileInputStream in = null; 
     FileOutputStream out = null; 
     long totalAudioLen = 0; 
     long totalDataLen = totalAudioLen + 36; 
     long longSampleRate = frequency; 
     int channels = 1; 
     long byteRate = RECORDER_BPP * frequency * 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 (FileNotFoundException e) { 
       e.printStackTrace(); 
     } catch (IOException 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) (channels * 16/8); // block align 
      header[33] = 0; 
      header[34] = RECORDER_BPP; // 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); 
    } 

} //Fine Classe RecordAudio (AsyncTask) 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.test_audio_capture_with_threshold, 
      menu); 
    return true; 

} 


public void resetAquisition() { 
    Log.w(TAG, "resetAquisition"); 
    stopAquisition(); 
    //startButton.setText("WAIT"); 
    startAquisition(); 
} 

public void stopAquisition() { 
    Log.w(TAG, "stopAquisition"); 
    if (started) { 
     started = false; 
     recordTask.cancel(true); 
    } 
} 

public void startAquisition(){ 
    Log.w(TAG, "startAquisition"); 
    Handler handler = new Handler(); 
    handler.postDelayed(new Runnable() { 
     public void run() { 

      //elapsedTime=0; 
      started = true; 
      recordTask = new RecordAudio(); 
      recordTask.execute(); 
      //startButton.setText("RESET"); 
     } 
    }, 500); 
} 


} 

Non dimenticate di aggiungere le autorizzazioni a manifestare il file:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
package="com.example.testaudiocapturewiththreshold" 
android:versionCode="1" 
android:versionName="1.0" > 
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> 
<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

<uses-sdk 
    android:minSdkVersion="8" 
    android:targetSdkVersion="17" /> 

<application 
    android:allowBackup="true" 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme" > 
    <activity 
     android:name="com.example.testaudiocapturewiththreshold.TestAudioCaptureWithThreshold" 
     android:label="@string/app_name" > 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 

      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
</application> 

</manifest> 
+0

Grazie! Ho modificato il codice un po 'per adattarlo al mio caso d'uso. Rilevo il silenzio e se rimane silenzioso per X secondi smetto di registrare. – SjoerdvGestel

+0

@Gaucho Ho usato il tuo codice. Ma puoi dirmi come smettere di registrare e riprodurre suoni se non c'è audio? – Sunny

+0

@Gaucho: Grazie per il fantastico codice ... Ho un requisito nella mia applicazione .. Devo rilevare una voce da un utente e se non ci sono dati da parte dell'utente per X no. di secondi di quanto dovrebbe fornire un errore all'utente. Quali cambiamenti devo fare per riuscirci? –

1

Per chi non ha trovato una risposta yet.It è possibile rilevare il silenzio e interrompere la registrazione quando l'utente hasn Si parla per alcuni secondi.

Per calcolare se l'utente ha smesso di parlare possiamo prendere i dati dall'ultimo secondo della registrazione, mapparlo su un numero e confrontare questo numero con i numeri ottenuti in precedenza. Sono stati girati un punteggio di confidenza (0-INF) di una pausa più lunga che si è verificata nell'input vocale.

Segui questo link tutto è spiegato lì. https://github.com/Kaljurand/speechutils/blob/master/app/src/main/java/ee/ioc/phon/android/speechutils/AbstractAudioRecorder.java grazie a Kaljurand e al suo meraviglioso codice.

È possibile trovare l'intero progetto in questo collegamento. https://github.com/Kaljurand/K6nele.

1

Il codice da questo post funziona. Ma ha qualche problema. Il fatto è che il disco si sta interrompendo troppo bruscamente. E il suono sta suonando con la balbuzie. Per risolvere ho creato conter silenceDegree.

Vedi il mio codice Kotlin:

var threshold: Short = 5000 
    val SILENCE_DEGREE = 15 

     //buffer size - need be fixed, established value for IOS compatibility 
       val buffer = ShortArray(MIN_SIZE) 
       var silenceDegree = 0 

       while (record) { 
        val bytesRead = audioRecord?.read(buffer, 0, MIN_SIZE) 

        if (bytesRead != null) { 
         if (bytesRead > 0) { 

           val foundPeak = searchThreshold(buffer, threshold) 

          if (foundPeak == -1) { 
           if (silenceDegree <= SILENCE_DEGREE) { 
            silenceDegree++ 
           } 

          } else { 
           silenceDegree = 0 
          } 

          //stoping to send, only when counter became equals SILENCE_DEGREE 
          if (silenceDegree < SILENCE_DEGREE) { 
          //SEND USEFUL DATA 

         handler.sendDataOnRecord(INSTANCE.shorts2Bytes(buffer)) 
          } 

         } else { 
          if (bytesRead == AudioRecord.ERROR_INVALID_OPERATION) { 
           // This can happen if there is already an active 
           // AudioRecord (e.g. in another tab). 
           record = false; 
          } 
         } 
        }