如何在 Android 中以更好的质量录制声音并降低噪音

Posted

技术标签:

【中文标题】如何在 Android 中以更好的质量录制声音并降低噪音【英文标题】:How To Record Sound in Android with Better Quality and Reduce Noise 【发布时间】:2014-04-12 12:06:48 【问题描述】:

我正在尝试为安卓平台构建一个音乐分析应用程序。

该应用正在使用MediaRecorder.Audiosource.MIC 录制来自 MIC 的音乐并将其编码为 11025 频率的 PCM 16BIT,但录制的音频样本质量非常低,有什么办法可以让它变得更好,降低噪音?

mRecordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC,FREQUENCY, CHANNEL,ENCODING, minBufferSize);

mRecordInstance.startRecording();

do 



samplesIn += mRecordInstance.read(audioData, samplesIn, bufferSize - samplesIn);

if(mRecordInstance.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED)

break;

 

while (samplesIn < bufferSize);

提前致谢

【问题讨论】:

这能回答你的问题吗? Appropriate audio capture and noise reduction 【参考方案1】:

上面的解决方案对我不起作用。

所以,我四处寻找,发现this article。

长话短说,我使用了MediaRecorder.AudioSource.VOICE_RECOGNITION 而不是AudioSource.MIC,这给了我非常好的结果,并且背景中的噪音确实减少了很多。

这个解决方案的伟大之处在于,它可以与 AudioRecord 和 MediaRecorder 类一起使用。

【讨论】:

【参考方案2】:

SR 和缓冲区大小的最佳组合非常依赖于设备,因此您的结果会因硬件而异。我使用这个实用程序来找出运行 android 4.2 及更高版本的设备的最佳组合;

public static DeviceValues getDeviceValues(Context context) 
    try 
        AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        try 
            Method getProperty = AudioManager.class.getMethod("getProperty", String.class);
            Field bufferSizeField = AudioManager.class.getField("PROPERTY_OUTPUT_FRAMES_PER_BUFFER");
            Field sampleRateField = AudioManager.class.getField("PROPERTY_OUTPUT_SAMPLE_RATE");
            int bufferSize = Integer.valueOf((String)getProperty.invoke(am, (String)bufferSizeField.get(am)));
            int sampleRate = Integer.valueOf((String)getProperty.invoke(am, (String)sampleRateField.get(am)));
            return new DeviceValues(sampleRate, bufferSize);
         catch(NoSuchMethodException e) 
            return selectBestValue(getValidSampleRates(context));
        
     catch(Exception e) 
        return new DeviceValues(DEFAULT_SAMPLE_RATE, DEFAULT_BUFFER_SIZE);
    

这使用反射来检查 getProperty 方法是否可用,因为此方法是在 API 级别 17 中引入的。如果您正在为特定的设备类型进行开发,您可能希望尝试各种缓冲区大小和采样率。我用作后备的默认值是;

private static final int DEFAULT_SAMPLE_RATE = 22050; private static final int DEFAULT_BUFFER_SIZE = 1024;

此外,我通过查看 getMinBufferSize 是否返回合理的使用值来检查各种 SR;

private static List<DeviceValues> getValidSampleRates(Context context) 
    List<DeviceValues> available = new ArrayList<DeviceValues>();
    for (int rate : new int[] 8000, 11025, 16000, 22050, 32000, 44100, 48000, 96000)   // add the rates you wish to check against
        int bufferSize = AudioRecord.getMinBufferSize(rate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
        if (bufferSize > 0 && bufferSize < 2048) 
            available.add(new DeviceValues(rate, bufferSize * 2));
        
    
    return available;

这取决于如果 getMinBufferSize 返回 0,则设备中的采样率不可用的逻辑。您应该针对您的特定用例试验这些值。

【讨论】:

嗨@Bartol,请帮助提供 selectBestValue() 方法。谢谢【参考方案3】:

虽然这是一个老问题,但以下解决方案会有所帮助。 我们可以使用MediaRecorder轻松录制音频。

  private void startRecording() 
    MediaRecorder recorder = new MediaRecorder();
    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    recorder.setAudioEncodingBitRate(96000)
    recorder.setAudioSamplingRate(44100)
    recorder.setOutputFile(".../audioName.m4a");

    try 
        recorder.prepare();
     catch (IOException e) 
        Log.e(LOG_TAG, "prepare() failed");
    

    recorder.start();

注意:

MediaRecorder.AudioEncoder.AAC 用作 MediaRecorder.AudioEncoder.AMR_NB 编码在 iOS 中不再支持。 Reference AudioEncodingBitRate 应根据需要使用 96000 或 128000 以确保声音清晰。

【讨论】:

以上是关于如何在 Android 中以更好的质量录制声音并降低噪音的主要内容,如果未能解决你的问题,请参考以下文章

如何在iPhone中以mp3格式录制声音[重复]

使用如何在 iPhone 中以 mp3 格式录制声音的音频队列服务示例

如何在 VB6 中从麦克风录制声音?

录制/播放声音时音质不佳 - Android SDK

Android 录制音频没有 SDCARD

如何在 Android 应用中录制声音