2012-12-04 49 views
5

我正在寫一個小應用程序,它捕獲來自android MIC的音頻,對輸入執行FFT,然後將圖表繪製到用戶圖表。我正在嘗試同時進行記錄和繪圖(顯然,從記錄到繪圖都有一小段延遲)。我試圖啓動兩個線程,一個讀取和一個處理。但是,當我處理它時,我遇到了同步問題,似乎只能接收(或不)零。任何意見將不勝感激。 :)與Android中的Thread同時記錄和處理音頻

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; 
} 
} 

編輯:添加完整的定義。

+0

你在第一時間寫非零數據?錄音機是否在工作?你可以發佈你的「物品」聲明嗎? – emrys57

+0

錄音機正在工作,我已經測試過,沒有經過處理。我以前不會寫非零數據到數組。 – user1877132

回答

2
  • 幾個想法...

類似的例子代碼,Audalyzer

不幸的是,筆者已經停止了對這個項目的發展,但源碼包仍然可在網上。特別注意:org.hermit.android.io.AudioReader.java。您讀取音頻並通過一個Stack對象傳遞它,該作者使用short []數組。 (仍然是似乎並不像它應該是你的問題的根源...) http://code.google.com/p/moonblink/downloads/detail?name=SourceTarball.zip

BUF_SIZE想法

你的音頻緩衝(BUF_SIZE = 8192)感覺有點小。這與AudioRecord.getMinBufferSize()有什麼關係?我使用了2x minBufferSize,並且沒有對它進行任何計算(只讀/寫)。

Handler想法

我還在審覈您的代碼,你還不清楚如何線程溝通。但是,你的問題聽起來像是它需要一種方式讓線程溝通Handler

下面是我一直在檢討,以掌握如何使用Handler S和有效的線程間通信鏈接: