You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中基于MediaRecorder按时间间隔同步获取音频振幅(分贝)与频率的实现方案咨询

Hey there! Let's break down how to add frequency detection alongside your existing amplitude/decibel tracking when recording audio.

First off, the key thing to note is that MediaRecorder is a high-level wrapper that gives you encoded audio output (like MP3 or AAC), but it doesn't expose the raw PCM sample data you need for frequency analysis. So we'll need to switch to using AudioRecord instead—it lets you access the raw time-domain audio samples required to run a Fast Fourier Transform (FFT) and extract frequency information.

Here's a step-by-step approach:

1. Switch to AudioRecord for Raw PCM Data

AudioRecord directly captures unprocessed audio samples from the microphone, which is essential for frequency calculation. Here's how to initialize it:

private AudioRecord audioRecord;
private static final int SAMPLE_RATE = 44100; // Common high-quality sample rate
private int bufferSize;

// Calculate the minimum buffer size, then round up to a power of 2 for efficient FFT
bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, 
    AudioFormat.CHANNEL_IN_MONO, 
    AudioFormat.ENCODING_PCM_16BIT);
// Adjust buffer size to nearest power of 2 (e.g., 1024, 2048) for better FFT performance
bufferSize = (int) Math.pow(2, Math.ceil(Math.log(bufferSize) / Math.log(2)));

audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
    SAMPLE_RATE,
    AudioFormat.CHANNEL_IN_MONO,
    AudioFormat.ENCODING_PCM_16BIT,
    bufferSize);

2. Capture Samples at Your Desired Interval and Run FFT

In the same loop where you're tracking amplitude, you'll read PCM samples, then run an FFT to convert the time-domain data into frequency-domain data. We'll use a reliable third-party library like JTransforms for FFT (it's lightweight and easy to use).

First, add the JTransforms dependency to your build.gradle (Module level):

implementation 'com.github.wendykierp:JTransforms:3.1'

Then, here's the recording loop that handles both amplitude/decibel and frequency calculation:

private boolean isRecording = false;
private static final long PROCESS_INTERVAL_MS = 100; // Match your amplitude interval

public void startRecording() {
    isRecording = true;
    new Thread(() -> {
        audioRecord.startRecording();
        short[] pcmBuffer = new short[bufferSize];
        long lastProcessedTime = System.currentTimeMillis();

        while (isRecording) {
            int bytesRead = audioRecord.read(pcmBuffer, 0, bufferSize);
            if (bytesRead > 0) {
                long currentTime = System.currentTimeMillis();
                if (currentTime - lastProcessedTime >= PROCESS_INTERVAL_MS) {
                    lastProcessedTime = currentTime;
                    
                    // Calculate amplitude and decibels
                    int maxAmplitude = getMaxAmplitude(pcmBuffer);
                    double decibels = calculateDecibels(maxAmplitude);
                    
                    // Calculate dominant frequency
                    double dominantFreq = calculateDominantFrequency(pcmBuffer, SAMPLE_RATE);
                    
                    // Update UI or process results (run on UI thread if updating views)
                    runOnUiThread(() -> {
                        // Example: Update text views with decibels and frequency
                        // tvDecibels.setText(String.format("%.1f dB", decibels));
                        // tvFrequency.setText(String.format("%.1f Hz", dominantFreq));
                    });
                }
            }
        }
        audioRecord.stop();
        audioRecord.release();
    }).start();
}

3. Helper Methods for Amplitude, Decibels, and Frequency

  • Get Max Amplitude:
private int getMaxAmplitude(short[] buffer) {
    int max = 0;
    for (short sample : buffer) {
        int absSample = Math.abs(sample);
        if (absSample > max) {
            max = absSample;
        }
    }
    return max;
}
  • Calculate Decibels:
private double calculateDecibels(int maxAmplitude) {
    // For 16-bit PCM, max amplitude is 32767 (0 dB reference)
    double reference = 32767.0;
    if (maxAmplitude == 0) return -Double.MAX_VALUE; // Avoid log(0)
    return 20 * Math.log10(maxAmplitude / reference);
}
  • Calculate Dominant Frequency with FFT:
import org.jtransforms.fft.DoubleFFT_1D;

private double calculateDominantFrequency(short[] pcmBuffer, int sampleRate) {
    // Convert short PCM samples to double array for FFT (complex format: real + imaginary)
    double[] fftInput = new double[pcmBuffer.length * 2];
    for (int i = 0; i < pcmBuffer.length; i++) {
        fftInput[2 * i] = pcmBuffer[i]; // Real part
        fftInput[2 * i + 1] = 0; // Imaginary part (set to 0 for real input)
    }

    // Run FFT
    DoubleFFT_1D fft = new DoubleFFT_1D(pcmBuffer.length);
    fft.complexForward(fftInput);

    // Calculate magnitude for each frequency bin (only first half is useful, FFT is symmetric)
    double[] magnitudes = new double[pcmBuffer.length / 2];
    double maxMagnitude = 0;
    int dominantBinIndex = 0;

    for (int i = 0; i < magnitudes.length; i++) {
        double real = fftInput[2 * i];
        double imaginary = fftInput[2 * i + 1];
        magnitudes[i] = Math.sqrt(real * real + imaginary * imaginary);
        
        if (magnitudes[i] > maxMagnitude) {
            maxMagnitude = magnitudes[i];
            dominantBinIndex = i;
        }
    }

    // Convert bin index to actual frequency: frequency = (index * sampleRate) / bufferSize
    return (double) dominantBinIndex * sampleRate / pcmBuffer.length;
}

Key Notes to Keep in Mind

  • Permissions: Don't forget to request the RECORD_AUDIO permission (and post Android 6.0, request it dynamically).
  • Frequency Precision: The precision of your frequency measurement depends on the sample rate and buffer size. Higher sample rates and larger buffers give better precision but lower time resolution. For example, 44100 Hz sample rate with a 2048-size buffer gives ~21.5 Hz precision.
  • Noise Handling: Real-world audio has noise—you might want to add logic to ignore low-magnitude frequency bins, or apply a smoothing filter to the frequency results to avoid jitter.
  • Power of 2 Buffer: FFT runs much faster on buffer sizes that are powers of 2 (1024, 2048, etc.), which is why we rounded up the buffer size earlier.

内容的提问来源于stack exchange,提问作者Shubham Mogarkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:02:39