本文部分知识从以下文章学习:

https://zhuanlan.zhihu.com/p/19763358 傅里叶变换的知识

https://www.cnblogs.com/RabbitHu/p/FFT.html FFT的知识

最近工作上在做关于音乐游戏的内容,其中需要分析音频找节奏点(或者说是重音点)。

学习了一系列相关知识后,了解到一段音乐的波形图可以分解成不同频率的波形图,也就是由时域到频域的转换。

借用其他博主的图就比较容易理解了,如下所示。

波从时域到频域的转换可以通过傅里叶变换实现,关于傅里叶变换的知识可以从最上面的链接学习或者自行查找(傅里叶真厉害!!!)。

计算机处理的音频在时域上是离散的数据,我们可以使用离散傅里叶变换DFT(傅里叶变换在时域和频域上都呈离散的形式)获得频域上的离散数据。

快速傅立叶变换FFT是DFT的快速算法,其核心思路就是分治法的DFT,具体推导可以查看上面的第二个链接。

FFT 代码如下:

     static void BitReverse(Complex[] cpData, int n)
{
Complex temp;
int lim = ;
while (( << lim) < n) lim++;
for (int i = ; i < n; i++)
{
int t = ;
for (int j = ; j < lim; j++)
{ if (((i >> j) & ) != )
t |= ( << (lim - j - ));
}
if (i < t)
{
temp = cpData[i];
cpData[i] = cpData[t];
cpData[t] = temp;
} // i < t 防止交换两次
}
} static void FFT1(Complex[] cpData, bool forward)
{
var n = cpData.Length; BitReverse(cpData, n);//位反转 Complex[] omg = new Complex[n];
for (int i = ; i < n; i++)
{
omg[i] = new Complex((float)Math.Cos( * Math.PI * i / n), (float)Math.Sin( * Math.PI * i / n));
}
Complex temp ;
for (int step = ; step <= n; step *= )
{
int m = step / ;
for (int j = ; j < n; j += step)
for (int i = ; i < m; i++)
{//蝶形运算
if(forward)
temp = omg[n / step * i] * cpData[j + i + m];
else
temp = omg[n / step * i].Conjugate() * cpData[j + i + m];
cpData[j + i + m] = cpData[j + i] - temp;
cpData[j + i] = cpData[j + i] + temp;
}
}
}

Complex是封装的复数类,偷懒不是自己写的,来自这位老哥https://blog.csdn.net/u011583927/article/details/46974341

这个FFT,new了好多对象,效率不是很高。。。

再贴一个直接把复数的实部虚部轮流放在一个数组里直接算的,能快一些。

     static void Reverse(float[] data, int n)
{ int j = , k = ;
var top = n / ;
while (true)
{ var t = data[j + ];
data[j + ] = data[k + n];
data[k + n] = t;
t = data[j + ];
data[j + ] = data[k + n + ];
data[k + n + ] = t;
if (j > k)
{
t = data[j];
data[j] = data[k];
data[k] = t;
t = data[j + ];
data[j + ] = data[k + ];
data[k + ] = t; t = data[j + n + ];
data[j + n + ] = data[k + n + ];
data[k + n + ] = t;
t = data[j + n + ];
data[j + n + ] = data[k + n + ];
data[k + n + ] = t;
} k += ;
if (k >= n)
break; var h = top;
while (j >= h)
{
j -= h;
h /= ;
}
j += h;
}
}
static void FFT2(float[] data, bool forward)
{
var n = data.Length;
n /= ; Reverse(data, n); float sign = forward ? : -;
var mmax = ;
while (n > mmax)
{
var istep = * mmax;
var theta = sign * (float)Math.PI / mmax;
float wr = , wi = ;
var wpr = (float)Math.Cos(theta);
var wpi = (float)Math.Sin(theta);
for (var m = ; m < istep; m += )
{
for (var k = m; k < * n; k += * istep)
{
var j = k + istep;
var tempr = wr * data[j] - wi * data[j + ];
var tempi = wi * data[j] + wr * data[j + ];
data[j] = data[k] - tempr;
data[j + ] = data[k + ] - tempi;
data[k] = data[k] + tempr;
data[k + ] = data[k + ] + tempi;
}
var t = wr;
wr = wr * wpr - wi * wpi;
wi = wi * wpr + t * wpi;
}
mmax = istep;
} }
     static void Main(string[] args)
{ int n =*;
float[] data = new float[ * n];
for (int i = ; i < n; i++)
{
data[ * i] = i;
data[ * i + ] = ;
} Complex[] cpData = new Complex[n];
for (int i = ; i < n; i++)
{
cpData[i] = new Complex(data[ * i], data[ * i + ]);
} long s = DateTime.Now.Ticks;
FFT1(cpData, true);
Console.WriteLine("time:" + (DateTime.Now.Ticks - s) / ); s = DateTime.Now.Ticks;
FFT2(data, true);
Console.WriteLine("time:" + (DateTime.Now.Ticks - s) / ); Console.Read();
}

速度上还是差挺多的。。。

好了获得频率数据之后的流程就不再那么烧脑了(都怪自己早早把傅里叶变换还给课本了)。。。

找节奏点的逻辑大概如下(代码有点多就不贴了):

1.根据采样率依次获取数据,每次通过FFT得到一组复数数组。

2.计算出复数的模长,可以表示此频率下的声音大小,可以把一定范围的声音累加起来,可以用来表示低音、中音、高音。

3.对比每一帧的数据变化就可以判断出节奏点(声音变化大,可以表示是一个节奏点)。

其实能得到频域的值,针对不同的功能,大家后面就可以自由发挥了。

关于FFT分析音频的学习的更多相关文章

  1. I2S音频总线学习

    IIS音频总线学习(一)数字音频技术 一.声音的基本概念 声音是通过一定介质传播的连续的波. 图1 声波 重要指标: 振幅:音量的大小 周期:重复出现的时间间隔 频率:指信号每秒钟变化的次数 声音按频 ...

  2. LINUX内核分析第一周学习总结——计算机是如何工作的

    LINUX内核分析第一周学习总结——计算机是如何工作的 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/ ...

  3. LINUX内核分析第二周学习总结——操作系统是如何工作的

    LINUX内核分析第二周学习总结——操作系统是如何工作的 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

  4. LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”

    LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...

  5. linux内核分析第四周学习笔记

    linux内核分析第四周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  6. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  7. linux内核分析第一周学习笔记

    linux内核分析第一周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  8. Linux内核分析第一周学习博客 --- 通过反汇编方式学习计算机工作过程

    Linux内核分析第一周学习博客 通过反汇编方式学习计算机工作过程 总结: 通过这次对一个简单C程序的反汇编学习,我了解到计算机在实际工作工程中要涉及大量的跳转指针操作.计算机通常是顺序执行一条一条的 ...

  9. Linux内核分析第二周学习博客——完成一个简单的时间片轮转多道程序内核代码

    Linux内核分析第二周学习博客 本周,通过实现一个简单的操作系统内核,我大致了解了操作系统运行的过程. 实验主要步骤如下: 代码分析: void my_process(void) { int i = ...

随机推荐

  1. 【设计模式】【最后一个】结构型07适配器模式(Adapter Pattern)

    适配器模式(Adapter Pattern) 推荐一个很全面的博客:https://blog.csdn.net/zxt0601/article/details/52848004 定义:将一个类的接口转 ...

  2. C# Redis分布式锁(基于ServiceStack.Redis)

    相关的文章其实不少,我也从中受益不少,但是还是想自己梳理一下,毕竟自己写的更走心! 首先给出一个拓展类,通过拓展方法实现加锁和解锁. 注:之所以增加拓展方法,是因为合理使用拓展类(方法),可以让程序更 ...

  3. epoll使用详解:epoll_create、epoll_ctl、epoll_wait、close

    epoll - I/O event notification facility 在linux的网络编程中,很长的时间都在使用select来做事件触发.在linux新的内核中,有了一种替换它的机制,就是 ...

  4. 蓝桥杯:最大的算式(爆搜 || DP)

    http://lx.lanqiao.cn/problem.page?gpid=T294 题意:中文题意. 思路:1.一开始想的是,乘号就相当于隔板,把隔板插入到序列当中,同一个隔板的就是使用加法运算, ...

  5. Azkaban 3.73.1 使用简介

    本文上接<Azkaban 3.73.1 集群搭建(Multiple Executor)>,对Azkaban的使用做简单说明 目录 目录 简介 1. 登录 2. 创建工程 3. 创建job ...

  6. 56. Merge Interval

    56. Merge Interval 0. 参考文献 序号 文献 1 花花酱 LeetCode 56. Merge Intervals 2 [LeetCode] Merge Intervals 合并区 ...

  7. ABP开发框架前后端开发系列---(15)ABP框架的服务端和客户端缓存的使用

    缓存在一个大型一点的系统里面是必然会涉及到的,合理的使用缓存能够给我们的系统带来更高的响应速度.由于数据提供服务涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发 ...

  8. 前端从零开始学习Graphql

    学习本姿势需要电脑装有node,vue-cli相关环境,以及要有node,express,koa,vue相关基础 本文相关demo的github地址: node服务:https://github.co ...

  9. C#如何加载程序运行目录外的程序集 (转)

    ---恢复内容开始--- 尼玛,为了这个问题,纠结到差点吐出干血,赶紧记下来! 源地址:http://blog.csdn.net/dyllove98/article/details/9391325 我 ...

  10. 基于SpringBoot-Dubbo的微服务快速开发框架

    简介: 基于Dubbo的分布式/微服务基础框架,为前端提供脚手架开发服务,结合前一篇--Web AP快速开发基础框架,可快速上手基于Dubbo的分布式服务开发,项目代码: https://github ...