生成特定分贝的音频波形

https://www.cnblogs.com/wangguchangqing/p/6197590.html

在处理音频的时候的有时候需要特定分贝(如-10dB)的音频波形,本文主要介绍如何生成特定分贝数的音频文件。有以下几个方面:

  • 简单的生成特定分贝的波形

    • 模拟频率和数字频率
    • 波形生成
  • 代码的封装
    • 正弦波、方形波、锯齿波、三角波的生成
    • 生成特定分贝特定形状的波形

简单的生成特定分贝的波形

波形可以通过一个周期内幅度值的变化来描述,所以要生成指定的波形就要知道两个量:周期(频率)和幅度的变化值。数字信号通常由模拟信号采样得到,而通常所说的频率也是模拟频率,所以首先要搞清楚模拟频率、数字频率,采样率这些量之间的关系。

数字频率和模拟频率

通常所说的频率为模拟频率,其单位为赫兹Hz,表示每秒信号变化的周期数。以单位圆为例,旋转一圈表示信号变化一个周期(产生一个正弦或者余弦波形),则模拟频率指的是每秒钟圆旋转的圈数。1000Hz,就是1秒钟圆旋转了1000圈(1秒钟有1000个正弦或者余弦曲线)。如下图:

单位圆旋转一周,在水平方向产生一个正弦波;竖直方向产生一个余弦波。

模拟角频率,仍然以单位圆为例,频率是单位时间内单位圆旋转的圈数,每旋转一圈单位圆旋转的角度是 2∗π

。 频率为f的波,表示一秒钟旋转f圈,角度变化就是 2∗f∗π,故模拟角频率就是 2∗f∗πrad/s

数字信号通常有模拟信号采样而来,采样频率 指的是单位时间内提取到的样本的个数,由奈奎斯特采样定理知道,要完全的保留模拟信号的信息,就需要采样频率大于等于模拟信号中最高频率的2倍。

数字频率,更准确叫法应该是归一化角频率,其单位为弧度(rad),表达式为:2∗π∗f/fs

,其中f为频率,fs为采样率。物理意义为相邻两个采样点之间变化的弧度数。

现在假设有个模拟的正弦信号x[t],其模拟频率为f=1000Hz,幅度为A,初始相位为0,则该信号的表达式为:x[t]=A∗sin(2π∗f∗t)=Asin(2000∗π∗t)

以采样率fs = 5000对其进行采样,得到数字信号x[n],则采样得到的数字信号的表达式i为:x[n]=A∗sin(2π∗f/fs∗t)=Asin(0.4pi∗n)。可以看出数字频率为0.4pi,也就是每隔0.4pi弧度取得一个sample。初始相位为0,则该数字信号的幅度序列为:Asin(0),Asin(0.4π),Asin(0.4∗2∗π),Asin(0.4∗3∗π),...,Asin(0.4∗n∗π)。这一系列离散的点组成的数字信号其对应的模拟的信号就是x[t]=Asin(2000∗π∗t)

。也就说,要想生成特定频率,特定幅度(幅度和分贝有转换关系)的波形,只需要知道其数字频率就可以了。

总结:
模拟频率f表示单位时间内信号变化的周期数,单位是赫兹Hz;模拟角频率$\Omega = 2f \pi ,表示单位时间内信号变化的角度,单位是rad/s;采样率fs表示单位时间内采样得到的样本数;数字频率,归一化角频率

\omega=2f\pi/fs$,表示采样时相邻两个样本间变化的弧度数。
由以上可知,即使两个数字频率完全相同的数字信号,其对应的模拟信号缺不一定相同,还需要考虑到采样率。而且采样率是模拟信号和数字信号之间进行转换的桥梁。

生成特定分贝的波形

从上面可以知道,要生成指定频率和分贝的波形,需要两个量:

  • 数字频率,相邻两个采样点之间变化的弧度数。 该值可以由模拟频率和采样率得到 2fπ/fs
  • 幅度值,幅度值可通过分贝dB换算得到。 dB=20∗log(A)→A=10db/20
  • ,这里幅值A归一化到[-1,1]。关于分贝和幅值之间的关系可以参考声音分贝的概念,dBSPL.dBm,dBu,dBV,dBFS

现假设要生成-10dB,频率为1000Hz的正弦波形,其采样率为48000,有下面代码:

double f = 1000;
double fs = 48000
double db = -10.0f;
double duration = 10;
double incr = 2 * pi * f / fs ;// 数字频率,也是相邻两个采样点的变化的弧度
double A = powf(10,db / 20); // 波形的最大幅度值
float* frame = new float[static_cast<int>(duration * fs)];
for(int i=0; i < static_cast<int>(duration * fs); i ++)frame[i] = A * sin(i * incr);

有了上面模拟频率和数字频率之间的转换关系后,上面代码还是比较简单明了的。首先通过模拟频率和采样率计算出数字频率,也就是相邻两个采样点之间的变化的弧度;然后,根据分贝数和幅度之间关系计算出波形的最大幅度值(这里说明下,音频的分贝计算通常取一段时间内(例如50ms)样本值的最大值(Peak值)。关于音频音量的度量,有机会会单独介绍)。最后,for循环计算各个sample的值,生成波形。如下图得到一个周期内的样本值:

代码封装

使用上面不到10行的代码就可以生成一个指定频率,指定分贝的正弦波形了。但是,上述代码实在太简单,下面就使用C++的类,将上面不到10行的代码编变成200行。

生成各种形状的波

标准的波形除了正弦波外,还有方形波、三角波、锯齿波等。如下图:

首先,声明一个classOscillator,其功能就是根据频率和采样率以及选择的波形形状,连续的产生波形的sample值。有以下的字段:

    double sampleRate; // 采样率double twoPIdivSamplerate; // 2 * pi / sampleRatedouble curFreq; // 当前频率double curPhase; // 当前相位double incrSample; // 每个sample增长的值// 正弦波double sinetick(double freq){auto val = sin(curPhase);updateFreq(freq);updatePhase();return val;}

sinetick生成正弦波的sample。该函数需要波形的频率作为参数,在生成返回当前的sample后。根据传入的频率不同,更新相邻sample的变化值,为生成下一个sample做准备。

   void updateFreq(double freq){if (curFreq != freq){curFreq = freq;incrSample = twoPIdivSamplerate * freq;}}void updatePhase(){curPhase += incrSample;if (curPhase >= 2 * pi)curPhase -= 2 * pi;else if (curPhase < 0.0)curPhase += 2 * pi;}

除了sinetick外,还有squaretick生成方形波的sample;triangletick,生成三角波的sample;sawtoothDownTick,生成向下的锯齿波的sample;sawtoothUpTick生成向上的锯齿波的sample。

生成特定分贝的波形

使用class Oscillator可以生成诸如sin(2f/fs⋅π)

的波形,但是还缺少一个对波形幅值的缩放系数,来生成特定分贝的波形。下面再定一个class AudioGenerator,该类的主要功能是能够 生成不同形状的指定分贝的波形,对于sample的类型也有三种选择:16位的有符号整型、32位有符号整型以及单精度浮点数。

    float GenerateFloat_32(double decibel, double freq, WavformType wavType = WavformType::SIN){auto amplitude = powf(10.0, decibel / 20); // 幅度double val;val = value(freq, wavType);amplitude *= val;if (amplitude > 1.0f)amplitude = 1.0f;else if (amplitude < -1.0f)amplitude = -1.0f;return static_cast<float>(amplitude);}

上面方法是生成单精度浮点数的sample。首先根据分贝数,计算得到波形的最大幅度值;value函数根据选择波形形状的不同,调用Oscialltor中的不同波形的生成方法,对得到的sample使用前面最大幅值进行缩放。

使用以及wav文件的保存

代码基本已经完成了,接下来就是将生成的波形保存为wav文件了。对于wav文件读写,在前面有个介绍C++标准库实现WAV文件读写,但是后来在使用SoundTouch这个变调变速的库的时候,发现其带的WavOutFileWavInFile用着挺方便的,这是就是用其来保存wav文件 。

   int db = -10;float amplitude = powf(10.0, static_cast<float>(db) / 20);int f = 1000; // 信号的模拟频率为1000Hzint fs = 48000; // 采样频率为48000Hzint duration = 10; //生成10s的信号AudioGenerator gen(fs);WavOutFile *outFile;float *outFrame = new float[duration * fs];outFile = new WavOutFile("-10db_sin.wav", fs, 32, 1);for (int i = 0; i < fs * duration; i++)outFrame[i] = gen.GenerateFloat_32(-10, f);outFile->write(outFrame, fs * duration);delete outFile;

代码很简单,就不做过多的解释了。生成-10dB各种波形的结果

总结

本文主要介绍了如何生成指定分贝的标准信号,正弦波、方形波、三角波、锯齿波等。对于波形的生成,首先要弄清楚模拟频率和数字频率之间的关系。

  • 模拟频率f,单位时间内信号变化的周期数
  • 模拟角频率,单位时间内信号变化的弧度,单位 rad/s
  • 采样率fs,单位时间内采样得到的样本数
  • 数字频率 2f/fs⋅π
  • ,相邻两个样本间变化的弧度数。

本文使用的源代码 http://download.csdn.net/detail/brookicv/9715390


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。

生成特定分贝的音频波形相关推荐

  1. DeepMind发布最新原始音频波形深度生成模型WaveNet,将为TTS带来无数可能

    WaveNets是一种卷积神经网络,能够模拟任意一种人类声音,生成的语音听起来比现存的最优文本-语音系统更为自然,将模拟生成的语音与人类声音之间的差异降低了50%以上. 我们也将证明,同一种网络能够合 ...

  2. 百度推出完全端到端的并行音频波形生成模型,比WaveNet快千倍 | 论文

    稿件来源:百度硅谷研究院 量子位授权转载 | 公众号 QbitAI 语音合成(Text-to-Speech,TTS)是将自然语言文本转换成语音音频输出的技术,在AI时代的人机交互中扮演至关重要的角色. ...

  3. 详细介绍Audition输出一个周期2khz的正弦波(循环)。将一段数字音频歌曲数据转换为模拟音频波形输出(循环)。

    详细介绍Audition输出一个周期2khz的正弦波(循环).将一段数字音频歌曲数据转换为模拟音频波形输出(循环) 序 言 1)STM32 的 DAC简介 2)DAC基本原理 2)DAC数字信号格式 ...

  4. OpenGL 绘制音频波形

    一.音频采样数据的获取 二 .音频采样数据的处理 三.使用OpenGL来绘制波形 3.1 准备三种方法的音频采样数据 3.2 绘制音频波形   在音视频编辑软件中直观的看到一个素材的音频波形后,就可以 ...

  5. Nat. Mach. Intell. | 利用条件循环神经网络生成特定性质分子

    作者 | 陆丰庆 今天给大家介绍瑞士知名药企阿斯利康和伯尔尼大学的 Esben Jannik Bjerrum团队在Nature Machine Intelligence上的一篇论文.该研究提出基于分子 ...

  6. 如何在Java中生成特定范围内的随机整数?

    如何生成特定范围内的随机int数值? 我已经尝试了以下方法,但是这些方法不起作用: 尝试1: randomNum = minimum + (int)(Math.random() * maximum); ...

  7. C/C++ 中生成特定范围内的随机数

    大家在写 C/C++ 程序时,难免会遇到要求获取某个范围内的随机数,我查阅了一些资料后,总结如下.本文分两部分,先介绍 C 语言中与随机数相关的两个函数 srand 和 rand,后介绍 C++ 中的 ...

  8. 阿里云移动端播放器高级功能---截图和音频波形

    基本介绍 如果用户对视频播放中的某一帧画面特别感兴趣,可以使用截图功能将这一帧视频保存起来.另外有一种场景想知道是否有声音,或者想感知声音的大小震动频率等,可以通过显示一个声音的波形来形象的表示.如下 ...

  9. python 如何生成特定间隔数列?range()、numpy.arange()

    方法1: >>> range(0,10,2)[0,2,4,6,8] 方法2: >>> numpy.arange(1, 10, 2)[1 3 5 7 9] 参考文章: ...

最新文章

  1. Intersection of Two Linked Lists——经典问题
  2. C#中的参数传递(转)
  3. java6打印机不能用_高分求解:java中调用的打印机在什么情况下不可用?
  4. 已有Unity工程升级到LWRP/HDRP后材质都变洋红色了,怎么办?
  5. uvccamera 后台服务_UVCCamera的一些坑
  6. JAVA环境变量的配置方法【希望可以帮助你】【个人实测没问题】
  7. MATLAB遍历文件夹
  8. java messagebox_由MessageBox透视Win32 API的调用 | 学步园
  9. 黑客之门的魅力:感染与加载 [转]
  10. Java - 使用Cipher类实现加密(RSA)
  11. 五个核心能力打造普惠金融商业化发展模式
  12. 你还记得当年上课天天玩 JAVA游戏吗
  13. 计算机网络路由器和交换机之间该如何配置,交换机怎么配置?交换机和路由器有什么区别?...
  14. 上海高考惊现0分作文 只因描写同性恋题材
  15. 一、软著专利查询网站
  16. 禁用服务器网络协议怎么设置,如何在Windows操作系统中启用和禁用DHCP?
  17. slogan - 构建认知价值
  18. win10修复tcp驱动服务器,高手亲自解决win10系统tcpip.sys蓝屏的详尽解决教程
  19. 百年奥运是一部科技史,智能奥运在平昌冬奥会浮出水面
  20. MCU独立看门狗 vs 窗口看门狗

热门文章

  1. 中国“量子霸权”成果:比最快超级计算机快一百万亿倍
  2. 【招聘推荐】启元世界招聘深度强化学习算法工程师
  3. struts2 lebel标签失效问题
  4. Smart3D输出Orthophoto(正射影像)和DSM(数字地表模型)+ArcGIS拼接TIFF/GeoTIFF文件
  5. 概率论笔记1.1.3事件间的关系
  6. (十八)师大放假了 - 7
  7. OPenGL 内部摄像机(Inside out:Camera)
  8. ESXi 镜像添加驱动
  9. Python中ArcPy实现对大量长时间序列栅格遥感影像批量逐像元求取像素平均值
  10. 迅为RK3568开发板Android11修改开机动画