a-record

In this post, I show you how to plot a graph in real time while acquiring raw data using AudioRecord. Iwould like to highlight the section where the async task is, since it is the most important part. I will also add the button for starting the async task and the variables that are related with it.

The key of this program is in understanding the following sections of the  code. For instance:

  • Understanding the order which the task are executed in the loop (while) for acquiring the audio into the async task.
  • Reading the hardware for polling the audio from the buffer to the array.
  • Shifting to the left the values within the array that is going to be plotted.
  • Adding the new generated value in the buffer (raw audio) to the last index or position of the shifted vector.
  • Checking where to write the publishProgress() line, since within the loop where the data is polled , the code doesn´t perform so good. For that reason, I wrote the code out of that loop and it seems to work well. However, it would be good to check how does it work with lower frequency signals since the only thing used to test performace are voice signals.

Now I show you the variables.

RecordAudio recordTask;
Button startStopButton, decreaseButton, increaseButton, playButton,
 but_minusTime, but_plusTime;
File recordingFile;
int frequency = 48000;
int channelConfiguration1 = AudioFormat.CHANNEL_IN_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(frequency,
        channelConfiguration1, audioEncoding);
short[] buffer = new short[bufferSize];
Number[] grafica = new Number[bufferSize];
boolean started = false;//recording

After that I show you what is into the onCreate method :

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sounds);

//---------Casting de objetos de la interfaz----------------------
startStopButton = (Button) this.findViewById(R.id.StartStopButton);//Botón inic

File path = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/Android/data/com.example.android.nameOfTheProject/files/");
path.mkdirs(); //Path within smartphone
try {
recordingFile = File.createTempFile("recording", ".pcm", path);
} catch (IOException e) {
throw new RuntimeException("Couldn't create file on SD card", e);
}

startStopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (started) {
started = false;
startStopButton.setText("Start");
recordTask.cancel(true);
} else {
started = true;
startStopButton.setText("Stop");
recordTask = new RecordAudio();
recordTask.execute();
}
}
}) ;

Then I show you what the async task contains.


private class RecordAudio extends AsyncTask<Void, Number, Void> {

 @Override
 protected Void doInBackground(Void... params) {

 try {
 //Alamacenamiento datos
 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream
 (new FileOutputStream(recordingFile)));

 //Constructor AudioRecord
 AudioRecord audioRecord = new AudioRecord(
 MediaRecorder.AudioSource.MIC, frequency,
 channelConfiguration1, audioEncoding, bufferSize);
 //Crea array para guardar datos del buffer(hardware) y poder leerlos

 //Método inicio de grabación
 audioRecord.startRecording();

//Probablemente meter aqui el vector con zeros.

 while (started) {
 int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
 for (int i = 0; i < bufferReadResult; i++) {
 dos.writeShort ( buffer[i] );

 for (int a = 0; a < grafica.length - 1; a++) {
 //movemos todos los numeros una posicion a la izquierda
 grafica[a] = grafica[a + 1];
 }
 grafica [grafica.length-1] = buffer[i] ;
 }
 publishProgress(grafica); //Solo se ve bien fuera del for previo si no se traba o la tarea es muy lenta
 }
 //Método para detener grabación de audio
 audioRecord.stop();
 // ¿Finalizar stream?
 dos.close();
 } catch (Throwable t) {
 Log.e("AudioRecord", "Recording Failed");
 }
 return null;
 }

 @Override
 protected void onProgressUpdate(Number ... buffer) {
 //Cargamos el nuevo array en la clase XYSERIES / Cuantitativo
 series = new SimpleXYSeries(Arrays.asList(grafica), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Signal");
 //Limpiamos la gráfica
 plot.clear();
 //Añadimos la nueva gráfica
 plot.addSeries(series, seriesFormat) ;
 plot.redraw();

 }

 @Override
 protected void onCancelled() {

 Toast.makeText(Sounds.this, "Tarea finalizada!",
 Toast.LENGTH_SHORT).show();

 }
 }

Understanding how an async task works is really important for those who are interested in real time plotting, communication protocols and the exchange of data. Either with a bluetooth tranmission, or sampling some signals using the USB interface, you are very likely to use an async task.

modifcation

Soruces and helpful material:

[1] http://stackoverflow.com/questions/10992806/how-to-have-a-moving-graph-or-chart-in-android

Anuncios