3

博客新址,这里更有趣

目录

  1. 声音信号相关知识

  2. 声音采集过程

  3. 乐音识别

之前在SF上回答了一个关于乐音识别相关的问题,自己课余时间也看了一些声音信号处理方面的书籍同时也有一个相关的小项目正在进展,写篇博客来分享一下学习的过程和收获。由于本身不是通信相关专业的学生,所以对于这方面没有学习过,所以一切都是从基础开始,通过谷歌,一步一步的向下走,同时也要吐槽下看到几篇论文,中国海洋大学,硕士论文也是关于乐音识别的一篇,把各种吊炸天的技术介绍一篇,然后却一点没用,呵呵,然后对于实验数据,完全不对,整个思路上就存在严重问题,被带入了坑。一点启示是找相关专业的大牛咨询要比自己一步步探索着去做,效率会高很多。

声音信号相关知识

音频信号:语音,乐音和音效的有规律的声波的频率,幅度变化的信息载体。音频信号又分为规则音频,不规则音频,规则音频是一段连续变化的模拟信号

响度,音高,音色是声音的三要素

响度取决于声音的振幅,音高取决于声音的频率,音色是产生的泛音不同所带来的差距,泛音是和基频成正整数倍关系,我们做乐音识别,所要采取的方式就是通过我们对于声音频率的提取,不同的音阶其频率是不相同的,获取了其频率,我们也就可以得到当前声音的一个曲谱。

声音采集过程

我们通过mic是如何得到一个可以播放的文件的呢?提到声音信号方面,采样,量化,编码。这个大家一定是听说过,这三个过程有什么作用呢?先从几个概念入手。

模拟信号:通过连续变化的物理量描述某一个信息,一般是信息的相关数据随着时间的变化

我们的声音就是属于模拟信号,是其幅度虽时间变化的一个信息,而对于模拟信号,我们是无法对其进行相应的处理的,因此需要将其转化为数字信号,如何转化呢?就是通过我们之前的三个步骤,采样,量化,编码。这三个步骤下来,我们就可以实现将模拟信号转化为数字信号。具体怎么转化呢?

抽样就是在指定的时间内,抽取的样本数,量化即为对抽样的物理量的数据表示,量化的数据越高,表示的越真实,编码就是按着某种规则,生成相应的二进制代码。由于我们的模拟信号在时间上是连续的,我们通过采样的方式,从其中每隔一定的时间采一个点,每秒采取的点数,即为我们的采样频率,然后是对于量化的过程,我们通过采样得到的确定了x轴上的量,我们还是需要来确定y轴上的量,此时我们通过量化的方式,把采样得到的声音信号幅度转化为数字值,是声音信号在幅度上被离散化,量化位数是每个采样点能够表示的数据范围。再通过相应的编码方式生成我们相应格式的音频文件。

关于采样的一些问题,录音设备在一秒钟内对声音信号的采样次数,声音是一种能量波,波形是由很多点构成的,所以对这些点进行采样,采样越多,对原型的还原越好,根据奈魁斯特(NYQUIST)采样定理,用2倍于一个正弦波的频率进行采样就能完全真实地还原该波形。

乐音识别大致流程

我们通过采样,量化,编码得到了相应的音频文件,现在我们要根据该音频文件来得到我们这个音频文件的曲调,也就是谱子。大致是通过以下几个步骤。

  1. 分帧处理

  2. 基音切割

  3. 提取基频

我们的一个音频文件,为了能够应用音频的一些特性,我们要利用其短时不变特性,通过做一个分帧处理,将我们的音频分割成一段一段,假设其在该段上是不变的,我们便可以利用某一些特性来进行分析,此后的处理都是基于分好的每一帧。有静音段,有有声段,所以我们需要做的是将静音段切除,保留出有声段,然后再确定该有声段的频率是多少,再和我们一直各个音调的频率对比,从而确定出来,我们的音频的曲调。

加窗分帧处理

对于信号的加窗,我采取的是一个矩形窗,采样频率为44100Hz,帧长为1024,帧移为512,帧移的目的是为了使得我们的每一帧之间的过渡更平滑。matalb代码如下

y=wavread('C:\Users\Administrator\Desktop\fourblow.wav');
framelength = 1024;
step = 512;
frameNum = (length(y)-framelength)/step;

这样我们实现了对于我们的音频的一个分帧处理,同时计算出了帧的数量。通过wavread我们来获取我们的音频信号,下面第一个图便是我们通过matlab得到的图形

图片描述

通过波形,按我们常识可以去判断,中间的蓝色较为粗部分即为我们的有声段,而两端比较细的地方即为静音段,中间的刺即为噪音。

基音切割

我们做分帧处理的目的即为来使用其短时不变的特性来进行相应的处理,基音的切割,我们要如何进行呢?常用的一种方式,通过能量来进行计算,静音段的能量比较低,而有声段的能量相对比较高,所以我们需要对其能量进行计算,通过该帧的幅度值绝对值的累计作为我们这一帧的能量,matlab代码如下

for i=1:frameNum;
      E(1)=0;
      for j=(i-1)*step+1:(i-1)*step+framelength
          E(1)=E(1)+abs(y(j));
      end
     E2(i) = E(1);
end

得到的图像为
图片描述

通过上图,我们可以区分出有声段和无声段,由于一些细小噪音的存在,我们可以将能量的值设置为一个界限,这个界限作为我们的进入有声段的一个判别。当然对于这种细小噪音的处理,也可以通过平均过零率来去掉。
对于噪音,其平均过零率要高于我们的基音阶段,同时对于一些细小的噪音,我们可以设置一个略大于零的数据来将微小的噪音过滤掉,对于噪音过大的环境此处就先不再考虑了。
此处将过零率设置为0.1,通过这种分析可以看出分析的效果比较好。matlab代码如下

for i=1:frameNum;
     S(1)=0;
   for j=(i-1)*step+2:(i-1)*step+frameNum;
   if(y(j)>=0.1)
       last=1;
     else
      last=-1;
   end
  if(y(j-1)>=0.1)
    first=1;
  else
    first=-1;
  end;
  S(1)=S(1)+abs(last-first);
end 
S2(i)=S(1)/2;
end

由此可以得到的分析图像如下图所示
图片描述

结合能量图分析和平均过零率我们就可以得到了我们的有声段,我们就可以进入该阶段,对该阶段在进行分析。

下篇更新对于基频提取,后续更新通过Android设备来实现的对于音频的一个实时识别的demo和具体实现


Jensen95
2.9k 声望534 粉丝

连续创业者。