首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WAV-文件分析C (libsndfile,fftw3)

我正在尝试开发一个简单的C应用程序,它可以在WAV文件中给定时间戳的某个频率范围内给出0到100的值。

示例:我的频率范围为44.1kHz (典型的MP3文件),我希望将该范围拆分为n个范围(从0开始)。然后我需要得到每个范围的振幅,从0到100。

到目前为止我所做的:

使用libsndfile,我现在能够读取WAV-文件的数据。

代码语言:javascript
运行
AI代码解释
复制
infile = sf_open(argv [1], SFM_READ, &sfinfo);

float samples[sfinfo.frames];

sf_read_float(infile, samples, 1);

然而,我对FFT的理解是相当有限的。但我知道要在我需要的范围内获得振幅是必需的。但我该怎么从这里开始呢?我找到了FFTW-3图书馆,它似乎适合这个用途。

我在这里找到了一些帮助:https://stackoverflow.com/a/4371627/1141483

在这里查看FFTW教程:2.html

但是,由于我不确定自由工联的行为,我不知道从这里取得什么进展。

还有另一个问题,假设您使用libsndfile:如果您强迫读取单通道(使用立体声文件),然后读取示例。那么,您实际上只读取了整个文件的一半样本吗?其中一半来自第一频道,还是自动过滤掉?

非常感谢你的帮助。

编辑:我的代码可以在这里看到:

代码语言:javascript
运行
AI代码解释
复制
double blackman_harris(int n, int N){
double a0, a1, a2, a3, seg1, seg2, seg3, w_n;
a0 = 0.35875;
a1 = 0.48829;
a2 = 0.14128;
a3 = 0.01168;

seg1 = a1 * (double) cos( ((double) 2 * (double) M_PI * (double) n) / ((double) N - (double) 1) );
seg2 = a2 * (double) cos( ((double) 4 * (double) M_PI * (double) n) / ((double) N - (double) 1) );
seg3 = a3 * (double) cos( ((double) 6 * (double) M_PI * (double) n) / ((double) N - (double) 1) );

w_n = a0 - seg1 + seg2 - seg3;
return w_n;
}

int main (int argc, char * argv [])
{   char        *infilename ;
SNDFILE     *infile = NULL ;
FILE        *outfile = NULL ;
SF_INFO     sfinfo ;


infile = sf_open(argv [1], SFM_READ, &sfinfo);

int N = pow(2, 10);

fftw_complex results[N/2 +1];
double samples[N];

sf_read_double(infile, samples, 1);


double normalizer;
int k;
for(k = 0; k < N;k++){
    if(k == 0){

        normalizer = blackman_harris(k, N);

    } else {
        normalizer = blackman_harris(k, N);
    }

}

normalizer = normalizer * (double) N/2;



fftw_plan p = fftw_plan_dft_r2c_1d(N, samples, results, FFTW_ESTIMATE);

fftw_execute(p);


int i;
for(i = 0; i < N/2 +1; i++){
    double value = ((double) sqrtf(creal(results[i])*creal(results[i])+cimag(results[i])*cimag(results[i]))/normalizer);
    printf("%f\n", value);

}



sf_close (infile) ;

return 0 ;
} /* main */
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-05-17 14:00:13

这完全取决于你所追求的频率范围。FFT的工作原理是获取2^n样本,并为你提供2^(n-1)实数和虚数。我不得不承认,我对这些价值观到底代表了什么(我有一个朋友承诺要和我一起度过这一切,而不是在他有财务问题时我给他的一笔贷款),我很模糊),而不是一个圆圈的角度。有效地,他们提供了一个arccos的角度参数的正弦和余弦的每一个频率宾,其中原始的2^n样本,可以完美地,重建。

无论如何,这有一个巨大的优势,你可以通过取实部和虚部(sqrtf( (实*实)+ (imag * imag ) )的欧几里得距离来计算震级。这为您提供了一个未规范化的距离值。然后,该值可用于为每个频带构建一个幅度。

因此,让我们采用10 FFT (2^10)的顺序。你输入了1024个样本。您可以对这些样本进行FFT处理,得到512个假想值和实数(这些值的特殊顺序取决于您使用的FFT算法)。这意味着,对于一个44.1Khz音频文件,每个bin代表44100/512 Hz或~86 Hz/ bin。

有一点值得注意的是,如果您使用更多的样本(在处理多维信号(如图像)时,使用更多的样本(从所谓的时间域或空间域),则可以获得更好的频率表示(在所谓的频域中)。不管你为了另一个牺牲一个。事情就是这样进行的,你必须接受它。

基本上,您将需要调整频率箱和时间/空间分辨率,以获得您需要的数据。

首先来点命名。我前面提到的1024个时域示例称为“您的窗口”。通常,在执行这类处理时,您需要在窗口上滑动一定数量的窗口,以获得下一个1024个样本(您的FFT )。最明显的做法是取样本0->1023,然后1024->2047,以此类推。不幸的是,这并没有给出最好的结果。理想情况下,您希望在一定程度上重叠窗口,以便随着时间的推移,您的频率变化会更平稳。最常见的情况是,人们把窗户滑动到半个窗口大小。你的第一个窗口是0->1023,第二个512->1535等等。

现在,这就引出了另一个问题。虽然这一信息提供了完美的逆FFT信号重建,它给你留下了一个问题,频率泄漏到环抱箱在一定程度上。为了解决这个问题,一些数学家(比我聪明得多)提出了窗口函数的概念。窗口函数在频域中提供了更好的频率隔离,尽管它会导致时域信息的丢失(即在使用窗口函数AFAIK之后不可能完美地重新构造信号)。

现在有各种类型的窗口函数,从矩形窗口(实际上对信号没有任何作用)到提供更好频率隔离的各种功能(尽管有些函数还可能扼杀您可能感兴趣的周围频率!!)唉,没有一个尺寸适合所有的人,但我是一个狂热的球迷(谱图)的黑曼-哈里斯窗口功能。我认为它能给出最好看的结果!

然而,正如我前面提到的,FFT为你提供了一个未正常化的光谱。要使光谱正常化(在欧几里德距离计算之后),您需要将所有值除以一个归一化因子(我将详细介绍这里)。

这种标准化将为您提供一个介于0到1之间的值。因此,您可以轻松地将此值乘以100,以获得0到100的比例。

然而,这并不是它的终点。你从这得到的光谱是相当不令人满意的。这是因为你用线性尺度来观察震级。不幸的是,人类耳朵听到的是对数音阶。这就导致了光谱图/光谱的外观问题。

为了解决这个问题,您需要将这0到1的值(我称之为'x')转换为分贝标度。标准转换是log10f( X)。然后,这将为您提供一个值,其中1已转换为0,0已转换为-infinity。你的震级现在在适当的对数尺度上。然而,这并不总是那么有帮助。

此时,您需要查看原始示例位深度。在16位抽样时,得到一个介于32767到-32768之间的值。这意味着您的动态范围为fabsf( 20.0f * log10f( 1.0f / 65536.0f ))或~96.33dB。所以现在我们有了这个价值。

取我们从上面的dB计算中得到的值。加上这个-96.33的价值。显然,最大振幅(0)现在是96.33。现在除以相同的值,您就没有一个从-infinity到1.0f的值。夹紧下端到0,你现在有一个范围从0到1,乘以100,你就有了最后的0到100范围。

这是一个怪物的帖子,比我原来的打算,但应该给你一个良好的基础如何产生一个良好的光谱/光谱图的输入信号。

呼吸

进一步阅读(供已发现原海报的人参考):

将FFT转换为平面图

编辑:顺便提一下,我发现kiss使用起来容易得多,我执行前向FFT的代码如下:

代码语言:javascript
运行
AI代码解释
复制
CFFT::CFFT( unsigned int fftOrder ) :
    BaseFFT( fftOrder )
{
    mFFTSetupFwd    = kiss_fftr_alloc( 1 << fftOrder, 0, NULL, NULL );
}

bool CFFT::ForwardFFT( std::complex< float >* pOut, const float* pIn, unsigned int num )
{
    kiss_fftr( mFFTSetupFwd, pIn, (kiss_fft_cpx*)pOut );
    return true;
}
票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10627517

复制
相关文章
NaN和Infinity,null和undefined
看到这个标题,大家对这4个变量应该都不陌生,但若说起他们的差别或者是举个小栗子判断结果,估计就有点晕乎乎的了。
jojo
2022/04/01
1.2K0
原 NaN和Infinity,null和u
作者:汪娇娇 日期:2016.10.10 看到这个标题,大家对这4个变量应该都不陌生,但若说起他们的差别或者是举个小栗子判断结果,估计就有点晕乎乎的了。 1、NaN和Infinity 那先来说说JavaScript的数据类型,有Number、字符串、布尔值、对象等等,而NaN和Infinity就属于Number类型。先说说它俩的差别: NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示 Infinity; // Infinity表示无限大,当数值超过了JavaScript的Nu
jojo
2018/05/03
1.1K0
java中double的NAN和INFINITY
在开发中double的处理时会出现NAN(无穷小)和INFINITY(无穷大)的情况,所以我们需要在这种情况时加一下处理
余生大大
2022/10/25
1.2K0
[C] C语言中的nan和inf使用
本文总结nan和inf在C语言当中的含义、产生和判定方法。 C语言当中的nan 表示not a number,等同于 #IND:indeterminate (windows) 产生: 对浮点数进行了未定义的操作;
轻舞飞扬SR
2021/02/24
3.5K0
C语言中switch语句_switch在c语言中
本篇文章帮大家学习c语言switch语句,包含了C语言switch语句使用方法、操作技巧、实例演示和注意事项,有一定的学习价值,大家可以用来参考。
全栈程序员站长
2022/09/27
2.7K0
ValueError: Input contains NaN, infinity or a value too large for dtype(‘float64’).
笔者在使用LogisticRegression模型进行预测时,报错 Traceback (most recent call last): File “D:/软件(学习)/Python/MachineLearing/taitannike/train.py”, line 55, in predicted_np = clf.predict(test_np) File “D:\Python\Anaconda\lib\site-packages\sklearn\linear_model\base.py”, line 281, in predict scores = self.decision_function(X) File “D:\Python\Anaconda\lib\site-packages\sklearn\linear_model\base.py”, line 257, in decision_function X = check_array(X, accept_sparse=‘csr’) File “D:\Python\Anaconda\lib\site-packages\sklearn\utils\validation.py”, line 573, in check_array allow_nan=force_all_finite == ‘allow-nan’) File “D:\Python\Anaconda\lib\site-packages\sklearn\utils\validation.py”, line 56, in _assert_all_finite raise ValueError(msg_err.format(type_err, X.dtype)) ValueError: Input contains NaN, infinity or a value too large for dtype(‘float64’). Age False
全栈程序员站长
2022/09/03
1.6K0
ValueError: Input contains NaN, infinity or a value too large for dtype(‘float64’).
从Ndom语浅谈语言中的进制
这题粗看复杂,其实不然。首先不难看出,abo、an并不是数字,所以不是加法就是乘法。因为abo出现的十分多,所以我们可以简单地假设abo是加法。接下来需要确定进制。我们知道1-10的乘方之间,出现了三个单独的词。不难得出,肯定1个是1,一个是基数的平方。除了这两个,只剩一个单独的词,那么这个词只可能是2^2=4。由此我们可以确定,Ndom语言的数字表达的基数肯定大于4且小于9。因为nif为很多长词的开头,所以nif应该是基数的平方。在题2的等式我们发现meregh乘上sas结尾的词,结果竟然还是以meregh尾!所以很明显sas就是1,于是thonith就是4。接着找,就找到了余下几个小于基数的词(于abo、an之后的较小):ithin、meregh、thef(可能是2、3、5)。剩下的mer、nif、tondor估计就是基数的倍数了,通过观察nif abo tondor abo mer abo thonith,发现nif>tondor>mer。按照推论,mer abo ithin应该是第三小的数字——9,那么mer应该就是基数了。ithin肯定不是1、4,所以排除5、8进制可能。那么就只剩下6、7进制两种可能了。分析得mer an thef abo thonith是第4小的,即16。mer*thef+4=16⇒mer*thef=12。所以只有一种可能:Ndom语言的数字是6进制。所以mer为6,thef为2,nif是mer的平方即36,ithin是9-6=3。排除法得,meregh是5。最后还有一个tondor,通过推断tondor abo mer abo sas≥6*2+6+1=19最近的平方数是25,可以判断tondor是18。至此,我们已经推断完成所有的词。剩下就是一些小小的规则,比如表示72,并不是nif an thef,而是直接nif thef。还有就是大的数字一定会在前。所以我们就能写出:58=36+18+4也就是nif abo tondor abo thonith,而87=36*2+6*2+3即nif thef abo mer an thef abo ithin。参考答案:
KAAAsS
2022/01/13
11.3K0
从Ndom语浅谈语言中的进制
为什么在Go语言中要慎用interface{}
在掘金上看到一篇从java转Go思想上的变化以及对go语言思考的文章,写的很透彻,我也推敲了一遍。这里也分享给大家,或许对将要或者已经学习golang的同学有所帮助。提示:代码块可以左右拖动哦~~
我的小碗汤
2018/08/22
1.4K0
为什么在Go语言中要慎用interface{}
void loop在c语言中什么意思,C语言中的loop是什么意思,在C语言中loop是什么意思?…[通俗易懂]
另附上goto,break, continue和return用法:=========================================== 程序中的语句通常总是按顺序方向, 或按语句功能所定义的方向执行的。
全栈程序员站长
2022/08/30
2.7K0
GCC在C语言中内嵌汇编-转载
在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作。 1、简单的内嵌汇编 例:
战神伽罗
2019/07/24
2.9K0
为什么不带参数的 Math.max() 返回-Infinity
Math.max() 是 JS 内置的方法,可以从传入的参数中,返回最大的一个。例如:
前端小智@大迁世界
2022/06/15
1.1K0
system在c语言中_c语言system返回值
C 库函数 int system(const char *command) 把 command 指定的命令名称或程序名称传给要被命令处理器执行的主机环境,并在命令完成后返回。
全栈程序员站长
2022/09/29
1.9K0
在c语言中,数组 a[i++] 和数组 a[++i] 有区别吗? && 在c语言中,数组 a[0]++; 又是什么意思?
b = a++;    //先计算表达式的值,即先把a赋值给了b;然后a再自加1。 b = ++a;    //先a自加1后;然后把a自加后得到的赋值给b。
黑泽君
2018/10/11
3.4K0
JavaScript面向对象编程指南 第一、二章知识点整理
第一章、 面向对象的JavaScript 面向对象程序设计(OOP,Object -Oriented Programming)中最常用到的概念: 对象:是指"事物"在程序设计语言中的表现形式。 这里的"事物"可以是任何东西。例如,对于猫这种常见对象来说,我们可以看到它们具有某些明确的特征(如颜色、名字、体型等),能执行某些动作(如喵喵叫、睡觉等)。在OOP语义中,这些对象特征都叫做属性,而那些动作则被称为方法。 类:在面向对象编程中,类(class)是对象(object)的模板,定义了同一组对象(又称
小胖
2018/06/27
4050
0.1+0.2=0.30000000000000004问题的探究
首先声明这不是bug,原因在与十进制到二进制的转换导致的精度问题!其次这几乎出现在很多的编程语言中:C/C++,Java,Javascript中,准确的说:“使用了IEEE 754浮点数格式”来存储浮点类型(float 32,double 64)的任何编程语言都有这个问题!
mmzhou
2018/08/01
6990
c/c++ -nan(ind) NAN
nan -- 表示 出错,“不是一个数” not a number 的缩写。 按 IEEE 754 国际标准,当运算中出现无效数据时,给出 NaN. 许多情况会出现,例如 0 除 0,负数开平方,...
acoolgiser
2019/01/17
3.5K0
C语学习之 getchar() putchar()
// 使用getchar() 和puchar()演示 #include "stdafx.h" int main(int argc, char* argv[]) { char a,b,c,d,e; printf("请输入5个字符:\n"); a=getchar(); b=getchar(); c=getchar(); d=getchar(); e=getchar(); putchar(a); putchar(b); putchar(c); putchar(d); putchar(e)
明明如月学长
2021/08/27
1.7K0
lodash源码分析之NaN不是NaN
暗恋之纯粹,在于不求结果,完全把自己锁闭在一个单向的关系里面。 ——梁文道《暗恋到偷窥》 本文为读 lodash 源码的第五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitbook也会同步仓库的更新,gitbook地址:pocket-lodash 本篇分析的是 eq 函数。 作用与用法 eq 函数用来比较两个值是否相等。遵循的是 SameValueZero 规范。 var obj1 = {test: 1} var obj2 = {test: 1} var obj3 =
对角另一面
2018/03/30
1.9K0
lodash源码分析之NaN不是NaN
本文为读 lodash 源码的第五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
对角另一面
2018/01/17
1.8K0
原 三、基本概念
作者:汪娇娇 时间:2017年11月4日 一、语法 1、区分大小写 2、标识符 指变量、函数、属性的名字,采用驼峰大小写格式。 3、注释 单行:// 多行:/*  */ 4、严格模式 "use strict" 5、语句 以一个分号结尾,代码块用{}包起来。 二、关键字和保留字 关键字有指定用途; break do instanceof typeof case else new var catch finally return void continue for switch whil
jojo
2018/05/03
9460

相似问题

C语言中带有NAN、INFINITY和-INFINITY的冒泡排序

113

java NaN和-infinity

215

为什么我的代码返回NAN和Infinity?

16

为什么Math.pow(1,Infinity)返回NaN?

42

禁用Infinity和NaN异常

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档