显示在使用 Android 录制时不断更新的双倍(频率) [英] Displaying a double (frequency) that is updated constantly while recording with Android

查看:24
本文介绍了显示在使用 Android 录制时不断更新的双倍(频率)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个使用 FFT 算法显示持续音符频率的 android 应用程序.我正在使用 Jtransform 方法.我目前的问题是我无法在屏幕上显示频率.以下代码是 fft 频率计算和应在文本框中显示频率的 AsynchTask

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:将 onClick() 添加到代码中.我知道正在计算频率,并且根据 Eclipse,在任何时候都不会调用 onProgressUpdate().

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.

推荐答案

除了 Alexei 所说的在他的回答中,我认为你也错误地编码了onProgressUpdate()的方法签名:

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){

这意味着您的 onProgressUpdate() 版本实际上并没有覆盖任何内容 来自 AsyncTask,并且永远不会被调用.

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

所以,包括关于不要重复调用setContentView()的点,你的最终方法应该是这样的:

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

这篇关于显示在使用 Android 录制时不断更新的双倍(频率)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆