2012-12-04 7 views
5

Piszę małą aplikację, która przechwytuje dźwięk z mikrofonu android, wykonuje FFT na wejściu, a następnie wykresy wykresu dla użytkownika. Próbuję jednocześnie nagrywać i tworzyć wykresy (oczywiście z niewielkim opóźnieniem od zapisania do wykreślenia). Próbuję uruchomić dwa wątki, jeden do odczytu i jeden do przetworzenia. Jednak mam problemy z synchronizacją, gdy przetwarzam, wydaje się, że tylko otrzymują (lub nie) zera. Wszelkie rady będą mile widziane. :)Nagrywanie i przetwarzanie audio jednocześnie z wątkiem w Androidzie

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

Edytuj: Dodano pełne definicje.

+0

Piszesz dane niezerowe w pierwszej kolejności? Czy nagrywarka działa? Czy możesz wysłać swoją deklarację "przedmiotów"? – emrys57

+0

Nagrywarka działa, przetestowałem ją bez przetwarzania. Nie piszę wcześniej niezerowych danych do tablicy. – user1877132

Odpowiedz

2
  • kilka myśli ...

podobny kod przykład Audalyzer

Niestety autor zatrzymał rozwój tego projektu, ale tarball źródłem jest nadal dostępna w Internecie. W szczególności uwaga: org.hermit.android.io.AudioReader.java. Odczytujesz dźwięk i przekazujesz go za pomocą obiektu Stack, autor korzysta z tablic short []. (Jeszcze, że nie wydaje się, że powinna być źródło problemu ...) http://code.google.com/p/moonblink/downloads/detail?name=SourceTarball.zip

myśli BUF_SIZE

swój bufor audio (BUF_SIZE = 8192) czuje się trochę małe. Jak to się ma do AudioRecord.getMinBufferSize()? Użyłem 2x minBufferSize, a to bez wykonywania jakichkolwiek obliczeń (tylko odczyt/zapis).

Handler myśli

ja wciąż przeglądając kod, jasne, w jaki sposób komunikować się nici. Ale twój problem brzmi, jakby potrzebował sposobu, aby wątki komunikowały się z Handler.

Poniżej znajdują się linki Byłem recenzowanie zrozumieć, jak korzystać Handler S i skutecznie komunikować się między wątków:

Powiązane problemy