0

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

采样率为 44100,块大小为 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 个块(4410)。当我从智能手机阅读时,我以为我会收到 4410 块,这意味着使用上述源打印 19000 10 次。

然而,结果是可怕的。有时收到 20 或 30 次,即使我收到了 5 次。数据之间有空白(没有数据)我得到了如下结果示例:

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

这段代码有什么问题?

4

1 回答 1

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()没有!操作员。如果缓冲区有剩余空间,您想写入它。如果没有,您想刷新缓冲区中已经累积的内容,然后在尝试写入之前将其清除。

但是,一旦你解决了这个问题,我希望你会得到一个 BufferOverflowException。正如我在评论中提到的,您使用的ByteBuffera 大小为奇数字节,但一次写出两个字节。假设声明确实应该是:

ByteBuffer cBuf = ByteBuffer.allocate(Constants.BLOCK_SIZE*2);

我不确定这是否是您其他问题的原因,但值得修复看看它是否有任何区别。

于 2013-06-04T00:43:44.940 回答