使用 Android FFT 获取声音频率

发布于 2025-01-06 16:49:37 字数 3081 浏览 0 评论 0原文

下面的代码仅显示一个图表,但我想要声音的频率。我正在尝试录制语音并获取实时频率,以便我可以弹奏钢琴或吉他声音并找到频率。

public class AudioProcessing extends Activity implements OnClickListener {

int frequency = 8000;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

private RealDoubleFFT transformer;
int blockSize = 256;

Button startStopButton;
boolean started = false;

RecordAudio recordTask;

ImageView imageView;
Bitmap bitmap;
Canvas canvas;
Paint paint;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    startStopButton = (Button) this.findViewById(R.id.StartStopButton);
    startStopButton.setOnClickListener(this);

    transformer = new RealDoubleFFT(blockSize);

    imageView = (ImageView) this.findViewById(R.id.ImageView01);
    bitmap = Bitmap.createBitmap((int) 256, (int) 100,
            Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);
    paint = new Paint();
    paint.setColor(Color.GREEN);
    imageView.setImageBitmap(bitmap);
}



private class RecordAudio extends AsyncTask<Void, double[], Void> {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            int bufferSize = AudioRecord.getMinBufferSize(frequency,
                    channelConfiguration, audioEncoding);

            AudioRecord audioRecord = new AudioRecord(
                    MediaRecorder.AudioSource.MIC, frequency,
                    channelConfiguration, audioEncoding, bufferSize);

            short[] buffer = new short[blockSize];
            double[] toTransform = new double[blockSize];

            audioRecord.startRecording();

            while (started) {
                int 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);
            }

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

        return null;
    }

    protected void onProgressUpdate(double[]... toTransform) {
        canvas.drawColor(Color.BLACK);

        for (int i = 0; i < toTransform[0].length; i++) {
            int x = i;
            int downy = (int) (100 - (toTransform[0][i] * 10));
            int upy = 100;

            canvas.drawLine(x, downy, x, upy, paint);
        }
        imageView.invalidate();
    }
}

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

如何从这段代码中获取频率?

The following code just shows a graph, but I want the sound's frequency. I am trying to record voice and get real-time frequency, so that I can play a piano or guitar sound and find the frequency.

public class AudioProcessing extends Activity implements OnClickListener {

int frequency = 8000;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

private RealDoubleFFT transformer;
int blockSize = 256;

Button startStopButton;
boolean started = false;

RecordAudio recordTask;

ImageView imageView;
Bitmap bitmap;
Canvas canvas;
Paint paint;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    startStopButton = (Button) this.findViewById(R.id.StartStopButton);
    startStopButton.setOnClickListener(this);

    transformer = new RealDoubleFFT(blockSize);

    imageView = (ImageView) this.findViewById(R.id.ImageView01);
    bitmap = Bitmap.createBitmap((int) 256, (int) 100,
            Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);
    paint = new Paint();
    paint.setColor(Color.GREEN);
    imageView.setImageBitmap(bitmap);
}



private class RecordAudio extends AsyncTask<Void, double[], Void> {
    @Override
    protected Void doInBackground(Void... params) {
        try {
            int bufferSize = AudioRecord.getMinBufferSize(frequency,
                    channelConfiguration, audioEncoding);

            AudioRecord audioRecord = new AudioRecord(
                    MediaRecorder.AudioSource.MIC, frequency,
                    channelConfiguration, audioEncoding, bufferSize);

            short[] buffer = new short[blockSize];
            double[] toTransform = new double[blockSize];

            audioRecord.startRecording();

            while (started) {
                int 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);
            }

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

        return null;
    }

    protected void onProgressUpdate(double[]... toTransform) {
        canvas.drawColor(Color.BLACK);

        for (int i = 0; i < toTransform[0].length; i++) {
            int x = i;
            int downy = (int) (100 - (toTransform[0][i] * 10));
            int upy = 100;

            canvas.drawLine(x, downy, x, upy, paint);
        }
        imageView.invalidate();
    }
}

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

How can I get frequency from this code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黎歌 2025-01-13 16:49:37

您的 FFT 代码不会给您频率。它为您提供了一组不同频率的复数值。如果您只是查看 FFT 结果的“实数”或余弦分量,而不是每个复数分量的矢量幅度,那么您的代码中可能存在错误。

FFT 后的 toTransform[i] 数组的每个元素都会为您提供一个围绕或接近 (i * sampleRate / blockSize) 的频率的复数值。您可以找到该数组幅度的最大值来估计幅度最大时的近似频率。您还可以对最大值进行插值以改进此频率估计。

但如果您正在寻找音高估计(例如吉他音符),这可能与峰值频率估计有很大不同。也许您可能想研究一些音高估计算法。

Your FFT code doesn't give you frequency. It gives you an array of complex values at a bunch of different frequencies. And there may be a bug in your code if you are just looking at the "real" or cosine component of the FFT result instead of the vector magnitude of each complex component.

Each element of your toTransform[i] array after the FFT gives you a complex value for frequencies around or near (i * sampleRate / blockSize). You could find the maxima of the magnitudes of this array to estimate the approximate frequency at which the magnitude was greatest. You could also interpolate the maxima to improve this frequency estimate.

But if you are looking for a pitch estimate (of a guitar note for instance), that can be very different from a peak frequency estimate. Perhaps you might want to look into some pitch estimation algorithms instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文