我生成了正弦波并使用源数据线发出声音。
采样率为44100, block 大小为441。
如果我播放 0.1 秒,则生成 4410 短正弦波并发出如下声音。
ByteBuffer cBuf = ByteBuffer.allocate(Constants.BLOCK_SIZE);
for(int i=0; i<SamplesTotal; i++){
if(!cBuf.hasRemaining()){
cBuf.putShort((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * time)));
time += samplingInterval;
}else{
line.write(cBuf.array(), 0, cBuf.position());
cBuf.clear();
cBuf.putShort((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * time)));
time += samplingInterval;
}
}
line.write(cBuf.array(), 0, cBuf.position());
现在的问题是,当我用智能手机从这个声音中读取数据时,找到使用 fftpack 读取 441 短类型数据并进行转换的频率。如下面的源码。
while (started) {
int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
toTransform[i] = (double) buffer[i] / (Short.MAX_VALUE);
}
transformer.ft(toTransform);
publishProgress(toTransform);
}
为了找到特定频率 19000 和 20000,我像这样进行了过滤,并打印了如下频率。
int temp = 0;
int temp_idx=0;
double freq=0;
int testFreq_19 = 380;
int testFreq_20 = 400;
for (int i = 0; i < toTransform[0].length; i++) {
int x = i;
int downy = (int) (100 - (toTransform[0][i] * 10));
int upy = 100;
if(i>testFreq_19-1 && downy<99){
if(temp<downy){
temp=downy;
temp_idx=i;
}
}
canvas.drawLine(x/2, downy, x/2, upy, paint);
}
if(temp_idx>testFreq_19-10 && temp_idx<testFreq_19+10){
freq = testFreq_19*(frequency/882);
}else if(temp_idx>testFreq_20-10 && temp_idx<testFreq_20+10){
freq = testFreq_20*(frequency/882);
}else{
freq= -1;
}
Log.d("frequency log", "frequency: " + String.valueOf(freq));
问题是当我生成 0.1 秒时,就会写入 10 个 block (4410)。 当我从智能手机上读取时,我以为我会收到 4410 block ,这意味着使用上述源打印 19000 10 次。
然而,结果却很糟糕。有时即使收到5次也会收到20或30次。数据之间有空白(没有数据)我得到的结果示例如下:
frequency: -1
frequency: -1
frequency: 19000.0
frequency: 19000.0
frequency: 19000.0
frequency: -1
frequency: -1
frequency: -1
frequency: 19000.0
frequency: -1
frequency: -1
frequency: -1
frequency: -1
frequency: -1
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: -1
frequency: -1
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: -1
frequency: 20000
frequency: 20000
frequency: 20000
frequency: 20000
frequency: -1
frequency: -1
frequency: -1
frequency: -1
这段代码有什么问题?
最佳答案
当您生成声波时,您正在以 16 位样本的形式写出数据。但是,当您再次读回数据时,您一次处理一个字节的数据(但仍将值除以 Short.MAX_VALUE
),这似乎不正确。
AudioRecord
的音频数据格式是什么?对象-ENCODING_PCM_8BIT
或ENCODING_PCM_16BIT
?如果它是 8 位,那么您肯定应该除以 127 ( Byte.MAX_VALUE
)。如果它是 16 位,那么您应该一次处理两个字节并将它们转换为短字节。
更新
如果buffer
变量实际上是一个短数组而不是字节数组,那么您读取的代码可能就这样,您可以忽略我上面的评论。但是,我刚刚注意到您编写的代码中有一些奇怪的地方。在本节中:
if(!cBuf.hasRemaining()){
cBuf.putShort((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * time)));
time += samplingInterval;
}else{
line.write(cBuf.array(), 0, cBuf.position());
cBuf.clear();
cBuf.putShort((short) (Short.MAX_VALUE * Math.sin(2 * Math.PI * time)));
time += samplingInterval;
}
假设条件是if
应该是cBuf.hasRemaining()
没有 !
运算符(operator)。如果缓冲区有剩余空间,您想写入它。如果没有,您需要刷新缓冲区中已经积累的内容,然后在尝试写入之前清除它。
但是,一旦您修复了该问题,我预计您将收到 BufferOverflowException。正如我在评论中提到的,您正在使用 ByteBuffer
大小为奇数字节,但一次写出两个字节。假设声明实际上应该是:
ByteBuffer cBuf = ByteBuffer.allocate(Constants.BLOCK_SIZE*2);
我不确定这是否是您其他问题的原因,但值得修复,看看是否有任何区别。
关于java - Android 缓冲区大小和频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16907980/