java - Android 缓冲区大小和频率

标签 java android audio frequency

我生成了正弦波并使用源数据线发出声音。

采样率为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_8BITENCODING_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/

相关文章:

java - 命令行参数显示 0?

android - 在 Android 中更改方向时布局会损坏

android - 如何加快android中的缩放

flash - 如何在闪光灯上合成准确的频率?

java - 扩展另一个类的类,如何将其作为异常类?

java - 在迭代长列表时跳过项目,什么更有效率?

ios - AVAudioPlayer Swift 3 不播放声音

audio - FFMPEG - 将 DTS-Audio 转换为 AC3 - 但保留原始视频和音频文件

java - 需要生成QueryParam的getter和setter

android - SQLite 问题 : Program Crash When Try a Query