5

Android MIC からオーディオをキャプチャし、入力に対して FFT を実行してから、グラフをユーザーにグラフ表示する小さなアプリを作成しています。記録とグラフ化を同時に実行しようとしています (明らかに、記録されてからグラフ化されるまでにわずかな遅延があります)。読み取り用と処理用の 2 つのスレッドを起動しようとしています。ただし、処理時に同期の問題が発生し、ゼロしか受信していないように見えます (または受信していないようです)。どんなアドバイスでも大歓迎です。:)

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

編集:完全な定義を追加しました。

4

1 に答える 1

2
  • いくつかの考え...

同様のサンプル コード、Audalyzer

残念ながら、作者はこのプロジェクトの開発を中止しましたが、ソース tarball はオンラインで引き続き入手できます。特に注意: 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()ますか?私は 2 倍の minBufferSize を使用しましたが、これは計算を行わずに行いました (読み取り/書き込みのみ)。

Handler思考

私はまだコードを見直していますが、スレッドがどのように通信するかは不明です。しかし、あなたの問題は、スレッドがHandler.

Handler以下は、 s を使用してスレッド間で効果的に通信する方法を把握するために確認したリンクです。

于 2012-12-04T23:51:31.117 に答える