音频记录缓冲区大小

3

我按照以下方式初始化我的AudioRecord实例:

// TODO: remember to add RECORD_AUDIO permission
int audioSource = MediaRecorder.AudioSource.MIC;

// TODO: I should consider Nyquist frequency and tell the user if her device can correctly detect frequencies in the range of her instrument
int sampleRateInHz = getDeviceSampleRate(context);

int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

// TODO: bufferSizeInBytes should be set according to minimum detectable frequency in order to have at least three periods
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);

AudioRecord audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);

以下是我的问题:

  • 因为我指定了ENCODING_PCM_16BIT,所以我必须从缓冲区中读取短语。这样做对吗?
  • 如果最小缓冲区大小为1000字节,则我将拥有500个短语。因此,如果我需要4096个样本,则必须将bufferSizeInBytes设置为8192。这样做对吗?

谢谢。

1个回答

5
我必须从缓冲区中读取shorts,因为我指定了ENCODING_PCM_16BIT。这是正确的吗?
是的,但不一定非要这样做。您可以将样本读入byte[]中,但在将byte转换为short时,您需要处理字节序。
如果最小缓冲区大小为1000个字节,则会有500个shorts。因此,如果我需要4096个样本,则必须将bufferSizeInBytes设置为8192。这是正确的吗?
实际上不是这样的。
最小缓冲区大小是AudioRecord实例接受的最小大小。它就像一个阈值。 AudioRecord constructor documentation说:
使用小于getMinBufferSize()的值将导致初始化失败。
在某些情况下,您可能希望使用比最小值更大的缓冲区大小。AudioRecord.getMinBufferSize()文档中写道:
请注意,此大小不能保证在负载下平稳录音,应根据预期以新数据轮询AudioRecord实例的频率选择更高的值。
以下是读取4096个16位样本的算法:
ByteArrayOutputStream mainBuffer = new ByteArrayOutputStream();

int minimumBufferSize = AudioRecord.getMinBufferSize(...);

byte[] readBuffer = new byte[minimumBufferSize];

AudioRecord recorder = new AudioRecord(..., minimumBufferSize);

recorder.startRecording();

while (mainBuffer.size() < 8192) {

    // read() is a blocking call
    int bytesRead = recorder.read(readBuffer, 0, minimumBufferSize);

    mainBuffer.write(readBuffer, 0, bytesRead);
}

recorder.stop();

recorder.release();

感谢您的回复。根据AudioRecord文档,应该将数据以小于总录制缓冲区大小的块的形式从音频硬件中读取。因此,如果我需要分析4096个样本,并且我知道我将要读取shorts,则必须使用bufferSizeInBytes为8192个单位来初始化我的AudioRecord实例。这样正确吗? - Adriano Di Giovanni
为什么我必须实现你发布的算法?如果我调用AudioRecord#read,操作会一直阻塞直到所有样本都被读取。这是正确的吗? - Adriano Di Giovanni
@AdrianoDiGiovanni 我认为8192对于bufferSizeInBytes来说太大了。我会使用getMinBufferSize()创建一个AudioRecord,或者使用它的几倍。 - nandsito
为什么太大?我不关心延迟和响应速度:这是一个吉他调音器,录音/分析是在后台任务中执行的。还有其他标准吗? - Adriano Di Giovanni
@AdrianoDiGiovanni 那个算法当然不是必须的。是的,read() 是一个阻塞调用。 - nandsito
@AdrianoDiGiovanni 看一下 read() 的文档。关键在于 read() 不一定会在单次调用中返回所有所需的样本。它可能会返回较少的样本。因此建议您读取样本,直到您有足够的数量。 - nandsito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接