在音频文件中检测低频音调

3
我知道这个问题已经被问了很多次...但是我对我的结果感到沮丧,所以我想再次询问。在深入研究fft之前,我需要解决这个简单的任务。
我需要检测音频文件中的20赫兹音调。我像图片中那样自己插入了20赫兹音调。(它可以是任何频率,只要听众听不到,所以我认为我应该选择一个大约在20赫兹至50赫兹左右的频率)
关于音频文件的信息。
afinfo 1.m4a 
File:           1.m4a
File type ID:   adts
Num Tracks:     1
----
Data format:     1 ch,  22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
estimated duration: 8.634043 sec
audio bytes: 42416
audio packets: 219
bit rate: 33364 bits per second
packet size upper bound: 768
maximum packet size: 319
audio data file offset: 0
optimized
format list:
[ 0] format:      1 ch,  22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
----

我跟着这三个教程,编写了一个可以读取音频缓冲区并给出fft doubles的工作代码。 http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html
https://github.com/alexbw/iPhoneFFT
如何获取FFT中每个值的频率?

我按照以下方式读取数据:
// If there's more packets, read them
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        CheckError(AudioQueueEnqueueBuffer(inAQ,
                                           inCompleteAQBuffer,
                                           (sound->packetDescs?nPackets:0),
                                           sound->packetDescs),
                   "couldn't enqueue buffer");
        sound->packetPosition += nPackets;


        int numFrequencies=2048;
        int kNumFFTWindows=10;

        SInt16 *testBuffer = (SInt16*)inCompleteAQBuffer->mAudioData; //Read data from buffer...!

        OouraFFT *myFFT = [[OouraFFT alloc] initForSignalsOfLength:numFrequencies*2 andNumWindows:kNumFFTWindows];
        for(long i=0; i<myFFT.dataLength; i++)
        {
            myFFT.inputData[i] = (double)testBuffer[i];

        }
        [myFFT calculateWelchPeriodogramWithNewSignalSegment];
        for (int i=0;i<myFFT.dataLength/2;i++) {
            NSLog(@"the spectrum data %d is  %f ",i,myFFT.spectrumData[i]);
}

而我的输出日志则类似于:
Everything checks out for 4096 samples of data
Set up all values, about to init window type 2
the spectrum data 0 is  42449.823771 
the spectrum data 1 is  39561.024361 
.
.
.
.
the spectrum data 2047 is  -42859933071799162597786649755206634193030992632381393031503716729604050285238471034480950745056828418192654328314899253768124076782117157451993697900895932215179138987660717342012863875797337184571512678648234639360.000000

我知道我还没有计算幅度,但是如何检测声音中是否有20 Hz?我需要学习Goertzel算法吗?


从您的图片中,我无法确定您是在低频率下爆发了一个20Hz正弦爆发,还是在20Hz下爆发了一个更高频率的正弦爆发。 - jaket
1
首先进行低通滤波。然后使用自相关,对于嘈杂的信号来说,它通常比FFT中的谐波更好。 - Sten
如果底部图中的脉冲是20Hz的单个周期,那么您将无法使用FFT或Goertzel算法可靠地实时捕获它们。如果您将它们用作文件中的隐藏标记,则我建议对数据进行低通滤波,然后自相关或仅在某些阈值以上的正确宽度的部分进行观察。(编辑:自相关无法很好地捕获这些单个周期) - Katie
我看到你正在使用AAC进行工作 - 你可能需要在Audacity中压缩后查看最终文件,以确认添加的音调是否显示出来。音频压缩通过丢弃听不到的信号部分来工作,因此在你处理它之前,它可能会删除20Hz的音调。 - Katie
@Katie 是的,我使用了几个程序来检查音频,并确保低频未被削减。我的初始想法是在20z中插入5个幅度很大的周期,所以当我获得5次正布尔值时,就可以直接应用我的逻辑,这是个坏主意吗? - Mord Fustang
显示剩余3条评论
1个回答

1
有许多方法可以传达信息,这些信息被插入并从一些现有的波形中检索。输入的信息可以改变幅度(幅度调制)或频率(频率调制)等内容。你有策略吗?请注意,你希望传达的信息密度可能会受到诸如调制频率之类的因素的影响(更高的频率自然可以传递更多的信息,因为它可以每秒解决更多的变化)。
如果发送方和接收方都有源音频(参考),则还有另一种方法。在这种情况下,接收方可以对比参考音频和实际接收到的音频来解析出传输的额外信息。这种方法的一个变化是,发送方首先发送未经处理的参考音频,然后再发送该参考音频的调制版本,这样接收方只需在这两个听起来相同的片段之间进行对比,就可以解析出嵌入的音频。

回到你最初的问题...如果发件人和收件人达成协议......比如在某个时间段 X 内,先发送基准的 20 Hz 纯音,然后再跟着另一个时间段 X,在这个时间段内,20 Hz 音调会被你输入的信息调制以改变其振幅或频率......然后就这样重复......在接收端,他们只需要在每一对这样的时间段之间做差值以解析出你的调制信息......为了使它工作,源音频不能有任何低于某个频率(比如 100 Hz)的音调(如果需要,可以去除这样的频带),以消除来自源音频的干扰......你没有提到你想要传输什么数据......如果是语音,你首先需要将它拉长,实际上降低其频率范围,从 1 kHz 范围降至你的低 20 Hz 范围......一旦在接收端得到差异的结果,你就可以将这条曲线压缩回正常的 1kHz 语音范围......可能需要更多的工作,但这可能会起作用......真正的 AM/FM 无线电使用调制将声音传送到百万赫兹的载波频率上,因此它能够运行


感谢您提供的建议,但接收方没有音频文件可供比较。我们正在尝试从HTTP服务器上进行流媒体传输。如果使用更高的频率,听者不会察觉到吗?文件格式必须是22050 Hz AAC。 - Mord Fustang

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