Displaying a double (frequency) that is updated constantly while recording with Android

若如初见. 提交于 2019-12-18 18:32:27

问题


I am building an android application that displays the Frequency of a sustained note with the FFT algorithm. I am using Jtransform methods. My issue currently is that I can't display the frequency on screen. The following code is the fft freqency calculation and the AsynchTask which should display the frequency in a text box

import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;

public class Tuning extends Activity implements OnClickListener{

    int audioSource = MediaRecorder.AudioSource.MIC;    // Audio source is the device mic
    int channelConfig = AudioFormat.CHANNEL_IN_MONO;    // Recording in mono
    int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit


    private DoubleFFT_1D fft;                           // The fft double array
    int blockSize = 1024;                               // deal with this many samples at a time
    int sampleRate = 44100;                             // Sample rate in Hz
    public double frequency = 0.0;                      // the frequency given

    RecordAudio recordTask;                             // Creates a Record Audio command
    TextView tv;                                        // Creates a text view for the frequency


    // On Start Up
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tuning);

        tv = (TextView) findViewById(R.id.lbl1);

    }


    // The Record and analysis class
    private class RecordAudio extends AsyncTask<Void, Double, Void>{
    @Override
    protected Void doInBackground(Void... params){      

        /*Calculates the fft and frequency of the input*/
        try{
            int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding);                // Gets the minimum buffer needed
            AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize);   // The RAW PCM sample recording

            short[] buffer = new short[blockSize];          // Save the raw PCM samples as short bytes
            double[] audioDataDoubles = new double[(blockSize*2)]; // Same values as above, as doubles

            double[] re = new double[blockSize];
            double[] im = new double[blockSize];
            double[] magnitude = new double[blockSize];

            audioRecord.startRecording();                   // Start working

            fft = new DoubleFFT_1D(blockSize);

            while(started){
                /* Reads the data from the microphone. it takes in data 
                 * to the size of the window "blockSize". The data is then
                 * given in to audioRecord. The int returned is the number
                 * of bytes that were read*/

                int bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                // Read in the data from the mic to the array
                for(int i = 0; i < blockSize && i < bufferReadResult; i++) {

                    /* dividing the short by 32768.0 gives us the 
                     * result in a range -1.0 to 1.0.
                     * Data for the compextForward is given back 
                     * as two numbers in sequence. Therefore audioDataDoubles
                     * needs to be twice as large*/

                    audioDataDoubles[2*i] = (double) buffer[i]/32768.0; // signed 16 bit
                    audioDataDoubles[(2*i)+1] = 0.0;
                }

                //audiodataDoubles now holds data to work with
                fft.complexForward(audioDataDoubles);

                // Calculate the Real and imaginary and Magnitude.
                for(int i = 0; i < blockSize; i++){
                    // real is stored in first part of array
                    re[i] = audioDataDoubles[i*2];
                    // imaginary is stored in the sequential part
                    im[i] = audioDataDoubles[(i*2)+1];
                    // magnitude is calculated by the square root of (imaginary^2 + real^2)
                    magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i]*im[i]));
                }

                double peak = -1.0;
                // Get the largest magnitude peak
                for(int i = 0; i < blockSize; i++){
                    if(peak < magnitude[i])
                        peak = magnitude[i];
                }
                // calculated the frequency
                frequency = (sampleRate * peak)/blockSize;

                /* calls onProgressUpdate
                 * publishes the frequency
                 */
                publishProgress(frequency);
            }

        } catch(Throwable t){
            Log.e("AudioRecord", "Recording Failed");
        }
        return null;
    }


    // This should display the Frequency
    protected void onProgressUpdate(Double value){

        //print the frequency 
        setContentView(R.layout.tuning);
        String info = Double.toString(value);

        //TextView doubleView = (TextView) findViewById(R.id.DoubleView);
        tv.setText(info);
    }

    // For the click of the button
   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();
       }
   }

I have checked other similar questions and I can't find the fault in my code.

EDIT: added onClick() to code. I know that the frequency is being calculated, and according to Eclipse, at no point is the onProgressUpdate() being called.


回答1:


In addition to what Alexei said, in his answer, I think you have also incorrectly coded the method signature of onProgressUpdate():

protected void onProgressUpdate(Double value){

This means that your version of onProgressUpdate() is actually not overriding anything from AsyncTask, and will never be called.

So, including the point about not calling setContentView() repeatedly, your final method should look like this:

protected void onProgressUpdate(Double... frequencies){
    //print the frequency 
    String info = Double.toString(frequencies[0]);
    tv.setText(info);
}



回答2:


SetContentView in onProgressUpdate is an error. You really do not want to change layout xml




回答3:


Try replace

protected void onProgressUpdate(Double value){

        //print the frequency 
        setContentView(R.layout.tuning);
        String info = Double.toString(value);

with

protected void onProgressUpdate(Double... value){

        //print the frequency             
        String info = Double.toString(value[0]);

For others not having jtransforms.jar, refer to http://sourceforge.net/projects/jtransforms/



来源:https://stackoverflow.com/questions/16652999/displaying-a-double-frequency-that-is-updated-constantly-while-recording-with

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!