5

我一直在搞乱 Android API 的 AudioRecord 功能,并发现了一些奇怪的行为。

背景信息:我的手机是 HTC Incredible 我正在使用 Eclipse 插件与模拟器一起进行 Android 开发。目标平台或操作系统是 2.2... 因为这是我的手机使用的。

一些代码:

bufferSize = AudioRecord.getMinBufferSize(FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);

这是我用来设置 AudioRecord API 的代码。现在,对于模拟器来说,它喜欢将 FREQUENCY 设置为 8000 以使其工作。返回缓冲区大小 640。对于手机,我使用 44100。这里的一个问题是,波形的结果 PCM 数据似乎是八位有符号波形。我得到从 -127 到 128 的值。我认为该值AudioFormat.ENCODING_PCM_16BIT会产生不同的结果。

我用线程处理音频,

public void run() {
  while(isRecording) {
    audioRecord.startRecording();
    byte[] data = new byte[bufferSize];
    audioRecord.read(data, 0, bufferSize);
    listener.setData(data);
    handleData(data);
  }
  audioRecord.release();
}

我有一种方法可以使用SurfaceView. MIC 似乎有很多噪音。我也从模拟器和手机中得到这种噪音。我是否需要通过某种过滤器运行数据?我想用这些数据来计算一些有趣的 FFT 和一些东西,只是为了玩波。但我需要以某种方式减少噪音。

有没有其他人也经历过这种情况。有没有人有办法解决吗?

感谢您的时间和回复,谢谢,dk

4

4 回答 4

12

当您从“AudioFormat.ENCODING_PCM_16BIT”流中读取字节时,它实际上为您提供了每个样本的高字节和低字节作为 2 个连续字节。如果您只是将每个字节作为样本(而不是实际上的一半样本),这看起来会非常嘈杂,而且第一个字节的签名将是错误的(它是小端顺序)。

要从流中获取有意义的数据,请通过短裤读取,例如

public void run() {
  while(isRecording) {
    audioRecord.startRecording();
    short[] data = new short[bufferSize/2];
    audioRecord.read(data, 0, bufferSize/2);
    listener.setData(data);
    handleData(data);
  }
  audioRecord.release();
}
于 2011-11-30T04:43:26.237 回答
9

自从提出这个问题以来已经有一段时间了,所以我不知道回答这个问题是否相关。

您获得从 -127 到 128 的值的原因是您正在读取一个字节数组,每个字节都包含一个有符号的 8 位数字。对于 16 位音频,读入一个 short 数组。

恐怕我无法解决噪音问题。

于 2011-06-28T09:34:59.067 回答
3

我也许能帮上一点忙。不过,我的情况和你一样,所以我只能告诉你我的经历。

我相信您可以像这样获得设备的首选 sampleRate:

int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);

16Bit 编码模式是唯一适用于 AudioRecord 的编码模式。我不确定你为什么会得到类似 8Bit 的输出(对吗?)。也许有人知道。

我也不确定你是如何从检索到的字节中提取振幅的,你这样做了吗?

最后,我相信您需要使用周期性侦听器函数,如下所示:

int sampleRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
int channelMode = AudioFormat.CHANNEL_IN_MONO;
int encodingMode = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelMode, encodingMode);

AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelMode, encodingMode, bufferSize);

recorder.setPositionNotificationPeriod(intervalFrames);
recorder.setRecordPositionUpdateListener(recordListener);
recorder.startRecording();

private RecordListener recordListener = new RecordListener();
private class RecordListener implements AudioRecord.OnRecordPositionUpdateListener {
    public void onMarkerReached(AudioRecord recorder) {
        Log.v("MicInfoService", "onMarkedReached CALL");
    }

    public void onPeriodicNotification(AudioRecord recorder) {
        Log.v("MicInfoService", "onPeriodicNotification CALL");
    }
}

这里有两个大问题我无法回答,也想知道自己的答案:

  1. 应该将什么设置为 intervalFrames?
  2. 为什么从不调用侦听器方法?

我希望我能提供更多帮助。

于 2011-01-24T15:58:27.560 回答
2

这个开源项目有大量的帮助类来帮助你获取音频数据并尝试分析它:

https://github.com/gast-lib/gast-lib

它有一个AsyncTask

它有一些东西可以控制AudioRecorder

它甚至有一个简单的频率估计算法

于 2012-06-07T12:42:34.573 回答