Android Studio实现了FFT,但无法检测到低频

时间:2017-09-13 12:41:37

标签: java android fft frequency

我正在尝试使用可以检测钢琴频率的应用。 我已经看到了这个

How to calculate sound frequency in android?

FFT类:https://github.com/fjfdeztoro/fftpack

并使用示例代码 https://github.com/sommukhopadhyay/FFTBasedSpectrumAnalyzer/tree/master/

这是我的代码:

package com.somitsolutions.android.spectrumanalyzer;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import ca.uol.aig.fftpack.RealDoubleFFT;


public class SoundRecordAndAnalysisActivity extends Activity implements OnClickListener{

    //code by yu-che
    int display_width = 600;//the result of display_width/5 and display_width/50 must be integer
    int frequency = 44100;
    //code by yu-che
    int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
    //origin code
    //int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

    AudioRecord audioRecord;
    private RealDoubleFFT transformer;
    int blockSize;// = 256;
    Button startStopButton;
    boolean started = false;
    boolean CANCELLED_FLAG = false;


    RecordAudio recordTask;
    ImageView imageViewDisplaySpectrum;
    MyImageView imageViewScale;
    Bitmap bitmapDisplaySpectrum;

    Canvas canvasDisplaySpectrum;

    Paint paintSpectrumDisplay;

    SoundRecordAndAnalysisActivity mainActivity;
    LinearLayout main;
    int width;
    int height;
    int left_Of_BitmapScale;
    int left_Of_DisplaySpectrum;
    private final static int ID_BITMAPDISPLAYSPECTRUM = 1;
    private final static int ID_IMAGEVIEWSCALE = 2;
    TextView tv;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Display display = getWindowManager().getDefaultDisplay();
        //Point size = new Point();
        //display.get(size);
        //code by yu-che
        Point size = new Point();
        display.getSize(size);
        width = size.x;
        height = size.y;
        //origin code
        //width = display.getWidth();
        //height = display.getHeight();

        blockSize = 8196;



    }

    @Override
    public void onWindowFocusChanged (boolean hasFocus) {
        //left_Of_BitmapScale = main.getC.getLeft();
        MyImageView  scale = (MyImageView)main.findViewById(ID_IMAGEVIEWSCALE);
        ImageView bitmap = (ImageView)main.findViewById(ID_BITMAPDISPLAYSPECTRUM);
        left_Of_BitmapScale = scale.getLeft();
        left_Of_DisplaySpectrum = bitmap.getLeft();
    }
    private class RecordAudio extends AsyncTask<Void, double[], Boolean> {

        @Override
        protected Boolean doInBackground(Void... params) {

            int bufferSize = AudioRecord.getMinBufferSize(frequency,
                    channelConfiguration, audioEncoding);
            audioRecord = new AudioRecord(
                    MediaRecorder.AudioSource.DEFAULT, frequency,
                    channelConfiguration, audioEncoding, bufferSize);
            int bufferReadResult;
            short[] buffer = new short[blockSize];
            double[] toTransform = new double[blockSize];
            try {
                audioRecord.startRecording();
            } catch (IllegalStateException e) {
                Log.e("Recording failed", e.toString());

            }
            while (started) {

                if (isCancelled() || (CANCELLED_FLAG == true)) {

                    started = false;
                    //publishProgress(cancelledResult);
                    Log.d("doInBackground", "Cancelling the RecordTask");
                    break;
                } else {
                    bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                    for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                        toTransform[i] = (double) buffer[i] / 32768.0; // signed 16 bit
                    }

                    transformer.ft(toTransform);

                    publishProgress(toTransform);

                }

            }
            return true;
        }
        @Override
        protected void onProgressUpdate(double[]...progress) {
            Log.e("RecordingProgress", "Displaying in progress");

            Log.d("Test:", Integer.toString(progress[0].length));


            if (width > 512) {
                int i = 0;
                int intensity = 0;
                double scale =0;
                while (true){

                    //scale = 1600/(2000/50)*(display_width/50);
                    //canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-50 , paintSpectrumDisplay);
                    if ( 0 == i){
                        intensity = (int)(progress[0][0]* progress[0][0]);
                        canvasDisplaySpectrum.drawLine(0, 150, 0,150-intensity , paintSpectrumDisplay);
                        i++;
                    } else if ( (blockSize-1) == i) {
                        intensity = (int)(progress[0][(blockSize-1)]* progress[0][(blockSize-1)]);
                        scale = (i/2+0.5)*frequency/(blockSize-1)/(2000/50)*(display_width/50);
                        canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-intensity , paintSpectrumDisplay);
                        break;
                    } else{
                        intensity = (int)(progress[0][i]*progress[0][i]+ progress[0][(i+1)]*progress[0][(i+1)]);
                        scale = (i/2+0.5)*frequency/(blockSize-1)/(2000/50)*(display_width/50);
                        canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-intensity , paintSpectrumDisplay);
                        i = i +2;
                    }

                }
                /*
                for (int i = 0; i < progress[0].length; i++) {

                    //int x = 2 * i;
                    //int downy = (int) (150 - (progress[0][i] * 10));
                    //int upy = 150;
                    //canvasDisplaySpectrum.drawLine(x, downy, x, upy, paintSpectrumDisplay);


                    canvasDisplaySpectrum.drawLine(0, 120, 0, 150, paintSpectrumDisplay);

                    canvasDisplaySpectrum.drawLine(display_width/50*10, 170, display_width/50*10, 150, paintSpectrumDisplay);
                }
                */

                imageViewDisplaySpectrum.invalidate();
            } else {
                for (int i = 0; i < progress[0].length; i++) {
                    int x = i;
                    int downy = (int) (150 - (progress[0][i] * 10));
                    int upy = 150;
                    canvasDisplaySpectrum.drawLine(x, downy, x, upy, paintSpectrumDisplay);
                }

                imageViewDisplaySpectrum.invalidate();
            }



        }
        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            try{
                audioRecord.stop();
            }
            catch(IllegalStateException e){
                Log.e("Stop failed", e.toString());

            }

            canvasDisplaySpectrum.drawColor(Color.BLACK);
            imageViewDisplaySpectrum.invalidate();

        }
    }

    protected void onCancelled(Boolean result){

        try{
            audioRecord.stop();
        }
        catch(IllegalStateException e){
            Log.e("Stop failed", e.toString());

        }
           /* //recordTask.cancel(true);
            Log.d("FFTSpectrumAnalyzer","onCancelled: New Screen");
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_HOME);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
*/
    }

    public void onClick(View v) {
        if (started == true) {
            //started = false;
            CANCELLED_FLAG = true;
            //recordTask.cancel(true);
            try{
                audioRecord.stop();
            }
            catch(IllegalStateException e){
                Log.e("Stop failed", e.toString());

            }
            startStopButton.setText("Start");

            canvasDisplaySpectrum.drawColor(Color.BLACK);

        }

        else {
            started = true;
            CANCELLED_FLAG = false;
            startStopButton.setText("Stop");
            recordTask = new RecordAudio();
            recordTask.execute();
        }

    }
    //code by yu-che
    /*
    static SoundRecordAndAnalysisActivity getMainActivity(){

        return mainActivity;
    }
    */
    public void onStop(){
        super.onStop();
            /* try{
                 audioRecord.stop();
             }
             catch(IllegalStateException e){
                 Log.e("Stop failed", e.toString());

             }*/
        recordTask.cancel(true);
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

    public void onStart(){

        super.onStart();
        main = new LinearLayout(this);
        main.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,android.view.ViewGroup.LayoutParams.MATCH_PARENT));
        main.setOrientation(LinearLayout.VERTICAL);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        transformer = new RealDoubleFFT(blockSize);

        imageViewDisplaySpectrum = new ImageView(this);
        if(width > 512){
            bitmapDisplaySpectrum = Bitmap.createBitmap((int)512,(int)300,Bitmap.Config.ARGB_8888);
        }
        else{
            bitmapDisplaySpectrum = Bitmap.createBitmap((int)256,(int)150,Bitmap.Config.ARGB_8888);
        }
        LinearLayout.LayoutParams layoutParams_imageViewScale = null;
        //Bitmap scaled = Bitmap.createScaledBitmap(bitmapDisplaySpectrum, 320, 480, true);
        canvasDisplaySpectrum = new Canvas(bitmapDisplaySpectrum);
        //canvasDisplaySpectrum = new Canvas(scaled);
        paintSpectrumDisplay = new Paint();
        paintSpectrumDisplay.setColor(Color.GREEN);
        imageViewDisplaySpectrum.setImageBitmap(bitmapDisplaySpectrum);
        if(width >512){
            //imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
            LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            ((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(100, 600, 0, 0);
            imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);
            layoutParams_imageViewScale= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            //layoutParams_imageViewScale.gravity = Gravity.CENTER_HORIZONTAL;
            ((MarginLayoutParams) layoutParams_imageViewScale).setMargins(100, 20, 0, 0);

        }

        else if ((width >320) && (width<512)){
            LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            ((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(60, 250, 0, 0);
            //layoutParams_imageViewDisplaySpectrum.gravity = Gravity.CENTER_HORIZONTAL;
            imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);

            //imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
            layoutParams_imageViewScale=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            ((MarginLayoutParams) layoutParams_imageViewScale).setMargins(60, 20, 0, 100);
            //layoutParams_imageViewScale.gravity = Gravity.CENTER_HORIZONTAL;
        }

        else if (width < 320){
                /*LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                ((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(30, 100, 0, 100);
                imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);*/
            imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
            layoutParams_imageViewScale=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            //layoutParams_imageViewScale.gravity = Gravity.CENTER;
        }
        imageViewDisplaySpectrum.setId(ID_BITMAPDISPLAYSPECTRUM);
        main.addView(imageViewDisplaySpectrum);

        imageViewScale = new MyImageView(this);
        imageViewScale.setLayoutParams(layoutParams_imageViewScale);
        imageViewScale.setId(ID_IMAGEVIEWSCALE);

        //imageViewScale.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
        main.addView(imageViewScale);

        tv=new TextView(this);
        tv.setText("frequency");
        tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));


        startStopButton = new Button(this);
        startStopButton.setText("Start");
        startStopButton.setOnClickListener(this);
        startStopButton.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));

        main.addView(startStopButton);
        main.addView(tv);
        setContentView(main);

        mainActivity = this;

    }
    @Override
    public void onBackPressed() {
        super.onBackPressed();

        try{
            audioRecord.stop();
        }
        catch(IllegalStateException e){
            Log.e("Stop failed", e.toString());

        }
        recordTask.cancel(true);
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        try{
            audioRecord.stop();
        }
        catch(IllegalStateException e){
            Log.e("Stop failed", e.toString());

        }
        recordTask.cancel(true);
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
    //Custom Imageview Class
    //底下的座標軸
    public class MyImageView extends ImageView {
        Paint paintScaleDisplay;
        Bitmap bitmapScale;
        Canvas canvasScale;
        public MyImageView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            if(width >display_width){
                bitmapScale = Bitmap.createBitmap(display_width,50,Bitmap.Config.ARGB_8888);
            }
            else{
                bitmapScale =  Bitmap.createBitmap(256,50,Bitmap.Config.ARGB_8888);
            }
            //坐標軸
            paintScaleDisplay = new Paint();
            paintScaleDisplay.setColor(Color.BLUE);
            paintScaleDisplay.setStyle(Paint.Style.FILL);

            canvasScale = new Canvas(bitmapScale);

            setImageBitmap(bitmapScale);
            invalidate();
        }
        @Override
        protected void onDraw(Canvas canvas)
        {
            // TODO Auto-generated method stub
            super.onDraw(canvas);

            if(width > 512){
                canvasScale.drawLine(0, 30,  display_width, 30, paintScaleDisplay);
                for(int i = 0,j = 0; i< display_width; i=i+display_width/5, j++){
                    for (int k = i; k<(i+display_width/5); k=k+display_width/50){
                        canvasScale.drawLine(k, 30, k, 23, paintScaleDisplay);
                    }
                    canvasScale.drawLine(i, 40, i, 20, paintScaleDisplay);
                    String text = Integer.toString(j*400) + " Hz";
                    canvasScale.drawText(text, i, 45, paintScaleDisplay);
                }
                canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
            }
            else if ((width >320) && (width<512)){
                canvasScale.drawLine(0, 30, 0 + 256, 30, paintScaleDisplay);
                for(int i = 0,j = 0; i<256; i=i+64, j++){
                    for (int k = i; k<(i+64); k=k+8){
                        canvasScale.drawLine(k, 30, k, 25, paintScaleDisplay);
                    }
                    canvasScale.drawLine(i, 40, i, 25, paintScaleDisplay);
                    String text = Integer.toString(j) + " KHz";
                    canvasScale.drawText(text, i, 45, paintScaleDisplay);
                }
                canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
            }

            else if (width <320){
                canvasScale.drawLine(0, 30,  256, 30, paintScaleDisplay);
                for(int i = 0,j = 0; i<256; i=i+64, j++){
                    for (int k = i; k<(i+64); k=k+8){
                        canvasScale.drawLine(k, 30, k, 25, paintScaleDisplay);
                    }
                    canvasScale.drawLine(i, 40, i, 25, paintScaleDisplay);
                    String text = Integer.toString(j) + " KHz";
                    canvasScale.drawText(text, i, 45, paintScaleDisplay);
                }
                canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
            }
        }
    }
}

但是当频率低于A3(220Hz)时。

根本无法抓住。只是抓住了它的泛音。

我尝试更改采样率和阻止,但我没有得到更好的结果。

我的代码有问题吗?或者我找不到一些细节? 有人可以教我,我会受到赞赏&gt;。&lt;

1 个答案:

答案 0 :(得分:0)

峰值幅度频率估计器不是音高检测器/估计器。所以不正确的结果与代码无关。除了它是OP目的的错误算法选择。