以编程方式实时更改音频文件的速度

时间:2017-06-29 07:22:27

标签: c++ audio

环境

  • 硬件:Raspberry Pi x
  • O.S。:Raspbian Jessie Lite
  • 语言:Qt5 / C ++

目标

执行音频文件(wav或更好的mp3),平滑地改变它的速度。音高应根据速度(播放速率)而变化。 我的应用程序每秒更新一次包含所需速度的变量:即1.0 =正常速度。要求的范围约为0.2 .. 3.0,分辨率为0.01。

音频可能是音乐,预期格式:单声道,16位,11.025 Hz。 没有关于延迟的具体限制:低于500毫秒是可以接受的。

有些人

QtMultimedia中的QMediaPlayer具有应该完成此操作的playbackRate属性。不幸的是,我无法让QtMultimedia在我的系统中运行。

也可以使用外部播放器,并使用管道或任何IPC发送数据。

你将如何实现这一目标?

1 个答案:

答案 0 :(得分:1)

我不知道这有多少转化为C ++。我在这个问题上所做的工作使用Java。不过,算法中的某些东西应该有所帮助。

示例数据(组成):

sample    value
0          0.0
1          0.3
2          0.5
3          0.6
4          0.2
5         -0.1
6         -0.4

在正常速度下,我们向输出线发送一系列值,其中每个输出帧的采样数递增1。

如果我们走得更慢,比如半速,我们应该在到达媒体数据中的相同点之前输出两倍的值。换句话说,我们需要在输出中包含不存在的中间样本帧位置0.5,1.5,2.5,...的值

为此,事实证明线性插值对于音频非常有效。可以使用更复杂的曲线拟合算法,但保真度的提高并不值得给它带来麻烦。

因此,我们最终得到如下流(半速):

sample    value
0          0.0
0.5        0.15
1          0.3
1.5        0.4
2          0.5
2.5        0.55
3          0.6
etc.

如果你想回放3/4速度,那么输出中使用的位置和值将是:

sample    value
0          0.0
0.75       0.225
1.5        0.4
2.25       0.525
3          0.6
3.75       0.525
etc.

我通过"光标"进行编码。每个样本帧递增,其中增量量确定"速度"的回放。光标指向一个数组,就像一个整数索引,但相反,是一个浮点数(或双精度数)。如果光标的值有小数部分,则该分数用于在整数部分指向的样本值和整数部分加1之间进行插值。

例如,如果光标为6.25,并且soundData [6]的值为A且soundData [6 + 1]的值为B,则声音值为:

audioValue = A * 0.75 + B * 0.25

您可以定义速度增量的精度非常高。我认为Java的浮动被认为足以达到此目的。

至于保持动态变化的速度增量平滑,我正在通过一系列4096步(大约1/10秒,44100 fps)展开新速度的变化。变更请求通常是异步的,例如来自GUI,并且以某种不可预测的方式随时间展开。平滑算法应该能够使用每个新的速度请求重新计算和更新自己。

以下是一个演示两种策略的链接,其中声音的播放速度通过滑块控件实时更改。

SlidersTest.jar

这是一个jar文件的可运行副本,它也包含源代码,并通过Java 8执行。您还可以重命名文件SlidersTest.zip,然后在上下文中查看源代码。

但是源代码文件的链接也可以直接导航到我为最近编写的这段代码发布并开源的页面的以下两个部分: 见AudioCue.javaSlidersTest.java

AudioCue.java是一个长文件。相关部分位于文件末尾的内部类中:class AudioCuePlayer ,对于平滑算法,请检查setter方法 setSpeed ,大约是3/4&# 39;顺便说一句对不起,我没有行号。