2012-12-04 8 views
5

Ich schreibe eine kleine App, die Audio von der Android-MIC erfassen, führt eine FFT auf der Eingabe und dann die Grafik für den Benutzer. Ich versuche, die Aufnahme und die Graphik gleichzeitig zu machen (offensichtlich mit einer kleinen Verzögerung von der Aufzeichnung bis zur graphischen Darstellung). Ich versuche, zwei Threads zu starten, einen zu lesen und einen zu verarbeiten. Allerdings habe ich Probleme mit der Synchronisierung, wenn ich sie verarbeitet habe, scheint es nur Nullen zu empfangen (oder nicht). Jede Beratung würde sehr geschätzt werden. :)Aufnahme und Verarbeitung von Audio gleichzeitig mit Thread in Android

public class Plotter extends Activity { 

/* plotting objects */ 
private static GraphicalView mView; 
private LineGraph line = new LineGraph(); 

private boolean recordAudio = true; // record? 
private AudioRecord mRecorder = null; // audio object 
private Menu mMenu; // app menu 

private static final String LOG_TAG = "Frequency Plotter"; // debug tag 

private Mfft mfft = null; // FFT class 
private static final int BUF_SIZE = 8192; // amount to read in 

private Thread listener = null; 
private Thread processor = null; 

Stack<Float> items = new Stack<Float>(); 

/* colors for line */ 
private int[] colors = {Color.BLUE,Color.CYAN,Color.DKGRAY,Color.GRAY, 
     Color.GREEN,Color.LTGRAY,Color.MAGENTA,Color.RED,Color.WHITE,Color.YELLOW}; 

private void processAudio(){ 

    ArrayList<Double> real = new ArrayList<Double>(); 

    try{ 

     Random randomGenerator = new Random(); 
     float[] in = new float[2048]; 
     Arrays.fill(in,1); 

     while(true){ 

      synchronized(items){ 

       while(items.size() < 2048) 
        items.wait(); 

       items.notifyAll(); 

       for(int i=0; i < 2048; i++){ 

        in[i] = items.pop();  
       } 
      } 

      double[] ret = mfft.fft(2048,44100,in); // get FFT of data 
      TimeSeries dataset = new TimeSeries((real.size()+1)/2048 + ""); 
      XYSeriesRenderer renderer = new XYSeriesRenderer(); // customized renderer 

      // Customization time 
      renderer.setColor(colors[randomGenerator.nextInt(10)]); 
      renderer.setPointStyle(PointStyle.SQUARE); 
      renderer.setFillPoints(true); 
      line.addRenderer(renderer); // add custom renderer 

      for(int i = 0; i < 2048; i++){ 
       real.add(ret[i]); 
       dataset.add(real.size()-1,ret[i]); // Add it to our graph 
      } 

      line.addDataset(dataset); // add data to line 
      mView.repaint(); // render lines 
     } 

    }catch(Exception e){ 
     Log.e(LOG_TAG, e + " "); 
    } 
} 

private void writeToBuffer(short[] in) { 

    synchronized(items){ 

     for(int i = 0; i < BUF_SIZE; i++){ // copy to create float 
      items.push((float)in[i]); 
     } 
     items.notifyAll(); 
    } 
} 

private void listen(){ 

    final short[] in = new short[BUF_SIZE]; 
    mRecorder = new AudioRecord(
      MediaRecorder.AudioSource.MIC, // source 
      44100, // frequency (HERTZ) 
      AudioFormat.CHANNEL_IN_MONO, // channel 
      AudioFormat.ENCODING_PCM_16BIT, // format 
      BUF_SIZE // size data packet 
      ); 

    mRecorder.startRecording(); 

    while(recordAudio){ 
     try{  
      /* read next part */ 
      mRecorder.read(in,0,BUF_SIZE); // read from device 
      writeToBuffer(in); 

     }catch(Exception t){ 
      /* something went horribly wrong!!!*/ 
      recordAudio = false; 
      Log.e(LOG_TAG, "Failure reading" + t.getMessage()); 
     } 
    } 
} 

private void startRecording(){ 

    /* create a new thread that will run the recording in the background */ 

    listener = new Thread(
     new Runnable(){ 

      public void run(){ 
       listen(); 
      } 
    }); 
    listener.start(); 

    /* small delay to produce */ 
    try { 
     Thread.sleep(100); 
    } catch (InterruptedException e1) { 
     e1.printStackTrace(); 
    } 

    /* create a thread to process the audio */ 
    processor = new Thread(
     new Runnable(){ 
      public void run(){ 
       processAudio(); 
      } 
    }); 
    processor.start(); 
} 

private void stopRecording(){ 

    recordAudio = false; 
    mRecorder.stop(); 
    mRecorder.release(); 
    mRecorder = null; 
} 

/** clear the current chart */ 
private void clearChart(){ 

    line = new LineGraph(); 
    this.onStart(); 
} 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
} 

@Override 
protected void onStart() { 

    super.onStart(); 

    /* instantiate */ 
    mfft = new Mfft(); // instance of the FFT class 
    mView = line.getView(this); // get the chart view 

    /* new horizontal layout */ 
    LinearLayout ll = new LinearLayout(this); 
    ll.setOrientation(LinearLayout.HORIZONTAL); 

    ll.addView(mView); // add chart to layout 

    setContentView(ll); // set layout 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 

    // Handle item selection 

    switch (item.getItemId()) { 
     case R.id.record: 

      startRecording(); 

      item.setEnabled(false); // disable start 
      mMenu.findItem(R.id.stop).setEnabled(true); // enable stop 

      return true; 
     case R.id.stop: 

      stopRecording(); 

      item.setEnabled(false); // disable stop 
      mMenu.findItem(R.id.clear).setEnabled(true); // enable stop 

      return true; 
     case R.id.clear: 

      clearChart(); // clear chart 

      item.setEnabled(false); // disable clear 
      mMenu.findItem(R.id.record).setEnabled(true); // enable stop 

      return true; 
     default: 
      return super.onOptionsItemSelected(item); 
    } 

} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 

    mMenu = menu; 
    MenuInflater inflater = getMenuInflater(); 
    inflater.inflate(R.menu.my_menu, menu); 
    return true; 
} 
} 

Edit: Vollständige Definitionen hinzugefügt.

+0

Schreibst du von Null verschiedene Daten in erster Linie? Funktioniert der Recorder tatsächlich? Und kannst du bitte deine "Items" deklarieren? – emrys57

+0

Der Recorder funktioniert, ich habe es ohne die Verarbeitung getestet. Ich schreibe nicht ungleiche Daten vorher in das Array. – user1877132

Antwort

2
  • mehr Gedanken ...

ähnlicher Beispiel-Code, Audalyzer

Leider hat der Autor der Entwicklung auf diesem Projekt gestoppt, aber der Quell-Tarball ist noch online verfügbar. Insbesondere zu beachten: org.hermit.android.io.AudioReader.java. Sie lesen das Audio und übergeben es über ein Stack Objekt, dieser Autor verwendet short [] Arrays. (Immer noch, dass scheint nicht, wie es Ihr Problem Quelle sein sollte ...) http://code.google.com/p/moonblink/downloads/detail?name=SourceTarball.zip

buf_size Gedanken

Ihre Audio-Puffer (buf_size = 8192) fühlt sich ein bisschen klein. Wie verhält es sich mit AudioRecord.getMinBufferSize()? Ich habe 2x minBufferSize benutzt, und das ohne Berechnungen darauf (nur lesen/schreiben).

Handler Gedanken

Ich bin der Überprüfung noch Ihren Code, unklar, wie Threads kommunizieren. Aber Ihr Problem klingt wie es eine Möglichkeit für die Threads benötigt, um eine Handler zu kommunizieren.

Im Folgenden sind die Links, die ich habe die Überprüfung zu begreifen, wie Handler s zu nutzen und effektiv zwischen Threads kommunizieren:

Verwandte Themen