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

Android音频降采样:将44100Hz录制音频转512Hz用于卷积运算

Got it, let's break down how to solve this problem—whether you need to downsample your 44100Hz recording after capturing it or do it in real-time while recording for immediate convolution. Here's practical, self-contained code and guidance tailored for Android:

1. Offline Post-Recording Downsampling

If you're recording first and processing later, this approach is straightforward. The key steps are: apply a low-pass filter to avoid aliasing (critical per Nyquist's theorem), then resample to 512Hz using interpolation for better quality than just skipping samples.

Code Implementation

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Paths;

// Step 1: Read your 44100Hz 16-bit mono PCM recording
File inputPcmFile = new File(getFilesDir(), "recording_44100.pcm");
byte[] inputBytes = Files.readAllBytes(inputPcmFile.toPath());
short[] inputSamples = new short[inputBytes.length / 2];
ByteBuffer.wrap(inputBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(inputSamples);

// Step 2: Apply low-pass filter to remove frequencies above 256Hz (Nyquist for 512Hz)
short[] filteredSamples = applyLowPassFilter(inputSamples);

// Step 3: Downsample to 512Hz using linear interpolation
int targetSampleRate = 512;
int sourceSampleRate = 44100;
double resampleRatio = (double) sourceSampleRate / targetSampleRate;
short[] downsampledSamples = new short[(int) Math.floor(inputSamples.length / resampleRatio)];

for (int i = 0; i < downsampledSamples.length; i++) {
    double sourceIndex = i * resampleRatio;
    int lowerIdx = (int) Math.floor(sourceIndex);
    int upperIdx = Math.min(lowerIdx + 1, filteredSamples.length - 1);
    
    double fraction = sourceIndex - lowerIdx;
    downsampledSamples[i] = (short) ((1 - fraction) * filteredSamples[lowerIdx] + fraction * filteredSamples[upperIdx]);
}

// Use downsampledSamples for your convolution operation here!

// Helper: Simple 7-point FIR low-pass filter (adjust kernel for better quality if needed)
private short[] applyLowPassFilter(short[] input) {
    float[] filterKernel = {0.05f, 0.1f, 0.2f, 0.3f, 0.2f, 0.1f, 0.05f};
    int kernelSize = filterKernel.length;
    int halfKernel = kernelSize / 2;
    short[] output = new short[input.length];
    
    for (int i = 0; i < input.length; i++) {
        float sum = 0;
        for (int j = 0; j < kernelSize; j++) {
            int sampleIdx = i + j - halfKernel;
            sampleIdx = Math.max(0, Math.min(sampleIdx, input.length - 1)); // Handle edge cases
            sum += input[sampleIdx] * filterKernel[j];
        }
        output[i] = (short) Math.round(sum);
    }
    return output;
}
2. Real-Time Downsampling During Recording

If you need to use the 512Hz signal immediately for convolution while recording, you can process AudioRecord's input buffer in real-time:

Code Implementation

import android.media.AudioRecord;
import android.media.MediaRecorder;
import java.util.ArrayList;
import java.util.List;

private AudioRecord audioRecord;
private int sourceSampleRate = 44100;
private int targetSampleRate = 512;
private double resampleRatio = (double) sourceSampleRate / targetSampleRate;
private List<Short> sampleBuffer = new ArrayList<>();

// Initialize and start recording with real-time processing
private void startRealTimeRecording() {
    int minBufferSize = AudioRecord.getMinBufferSize(
        sourceSampleRate,
        android.media.AudioFormat.CHANNEL_IN_MONO,
        android.media.AudioFormat.ENCODING_PCM_16BIT
    );
    
    audioRecord = new AudioRecord(
        MediaRecorder.AudioSource.MIC,
        sourceSampleRate,
        android.media.AudioFormat.CHANNEL_IN_MONO,
        android.media.AudioFormat.ENCODING_PCM_16BIT,
        minBufferSize * 2 // Use larger buffer to avoid underruns
    );
    
    // Set up periodic callback to process incoming samples
    audioRecord.setRecordPositionUpdateListener(new AudioRecord.OnRecordPositionUpdateListener() {
        @Override
        public void onPeriodicNotification(AudioRecord recorder) {
            short[] rawBuffer = new short[minBufferSize / 2]; // 16-bit samples
            int bytesRead = recorder.read(rawBuffer, 0, rawBuffer.length);
            
            if (bytesRead > 0) {
                // Add new samples to buffer
                for (short s : rawBuffer) sampleBuffer.add(s);
                
                // Generate 512Hz samples as soon as we have enough data
                while (sampleBuffer.size() >= resampleRatio) {
                    double sourceIndex = 0;
                    int lowerIdx = (int) Math.floor(sourceIndex);
                    int upperIdx = Math.min(lowerIdx + 1, sampleBuffer.size() - 1);
                    
                    double fraction = sourceIndex - lowerIdx;
                    short downsampledSample = (short) ((1 - fraction) * sampleBuffer.get(lowerIdx) + fraction * sampleBuffer.get(upperIdx));
                    
                    // Remove processed samples from buffer
                    sampleBuffer.subList(0, (int) Math.ceil(resampleRatio)).clear();
                    
                    // Pass this sample directly to your convolution function
                    runConvolution(downsampledSample);
                }
            }
        }

        @Override
        public void onMarkerReached(AudioRecord recorder) {}
    });
    
    audioRecord.setPositionNotificationPeriod(minBufferSize / 2);
    audioRecord.startRecording();
}

// Replace this with your actual convolution logic
private void runConvolution(short sample) {
    // Your convolution code here
}
Key Notes
  • Don't skip low-pass filtering: Without it, high-frequency content from the 44100Hz signal will alias into the 512Hz bandwidth, causing distortion. For better quality, use a more sophisticated FIR/IIR filter (you can generate filter kernels using window functions like Hann).
  • Interpolation matters: Linear interpolation is a good balance between quality and performance; for higher fidelity, you can use cubic spline interpolation (but it's more compute-heavy).
  • Convolution efficiency: If doing real-time convolution, consider using FFT-based convolution instead of direct convolution to reduce computation time.

内容的提问来源于stack exchange,提问作者Igor Vurdelja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:32:20