Android 录音问题?

发布于 2024-10-12 10:44:02 字数 1188 浏览 6 评论 0原文

我一直在摆弄 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 数据似乎是一个 8 位签名波形。我得到的值从 -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

I have been messing around with the AudioRecord feature of the Android API and found some strange behaviors with it.

Background info:
My phone is a HTC Incredible
I am using the Eclipse plugin for Android development with the emulator.
Targeted platform or OS is 2.2... Since it is what my phone uses.

Some code:

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

This is the code I use to setup the AudioRecord API with. Now, for the emulator it likes FREQUENCY to be set to 8000 for it to work. Comes back with a buffer size 640. For the phone I use 44100. One issue here is it seems the resulting PCM data for the wave seems to be an eight bit signed wave. I get values from -127 to 128. I thought the value AudioFormat.ENCODING_PCM_16BIT would produce something different.

I process the audio with a thread,

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

I have a way to graphically display to corresponding wave in real time using a SurfaceView. There seems to be a lot of noise coming from the MIC. I get this noise from the emulator and the phone as well. Do I need to run the data through some sort of filter(s)? I would like to use this data to calculate some fun FFT and stuff just to play around with the wave. But I need to reduce the noise somehow.

Has anyone else experience this as well. Does anyone have a solution?

I appreciated your time and responses,
thanks,
dk

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

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

发布评论

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

评论(4

醉酒的小男人 2024-10-19 10:44:02

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

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

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

When you read bytes from a "AudioFormat.ENCODING_PCM_16BIT" stream, it actually gives you both the upper and lower bytes of each sample as 2 sequential bytes. This will seem extremely noisy if you just take each byte to be a sample (instead of the half sample it actually is), plus the signing will be wrong for the first byte (it's in little endian order).

To get meaningful data out of the stream, read via shorts, e.g.

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();
}
疧_╮線 2024-10-19 10:44:02

自从问这个问题以来已经有一段时间了,所以我不知道回答它是否还有意义。

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

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

It's been a while since this question was asked, so I don't know if answering it is relevant any more.

The reason you're getting values from -127 to 128 is that you're reading into an array of bytes, each of which hold a signed 8-bit number. For 16-bit audio, read into an array of shorts.

I'm afraid I can't help with the noise issue.

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

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

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

16 位编码模式是唯一适用于 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. 为什么监听器方法从未被调用?

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

I might be able to help a tiny bit. However, I am in the same situation as you so I can only tell you about my experiences.

I believe you can get your device's preferred sampleRate like so:

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

The 16Bit encoding mode is the only one that works with AudioRecord. I am unsure why you are getting 8Bit like output (right?). Maybe someone knows.

I am also unsure how you pull the amplitude from the retrieved bytes, did you do this?

Finally, I believe you need to use the periodic listener functions, like so:

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

There are two big questions here which I cannot answer and want to know the answer of myself as well:

  1. What should be set as intervalFrames?
  2. Why are the listener methods never called?

I wish I could help more.

醉生梦死 2024-10-19 10:44:02

这个开源项目有大量的帮助器类来帮助您获取音频数据并进行分析实验:

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

它有一个 AsyncTask

它有一些控制 AudioRecorder

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

This open source project has a good amount of helper classes to help you acquire the audio data and experiment with analyzing it:

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

It has an AsyncTask

It has something that controls AudioRecorder

It even has a simple frequency estimation algorithm

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