以编程方式实时更改音频文件的速度 [英] Programmatically change the speed of an audio file in real-time

查看:110
本文介绍了以编程方式实时更改音频文件的速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

环境

  • 硬件: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毫秒是可以接受的.

一些思想

QpMultimedia中的

QMediaPlayer具有应执行此操作的playingRate属性.不幸的是,我无法使QtMultimedia在我的系统中正常工作.

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

您将如何实现这一目标?

解决方案

我不知道有多少可以转换为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的float足以满足此目的.

为使动态变化的速度增量保持平稳,我将通过一系列4096步(大约为44100 fps,大约1/10秒)扩展对新速度的更改.变更请求通常是异步的,例如来自GUI,并且以某种无法预测的方式随时间分布.平滑算法应能够根据每个新的速度请求重新计算并更新自身.

下面的链接演示了两种策略,其中,通过滑块控件实时更改声音的播放速度.

SlidersTest.jar

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

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

AudioCue.java是一个长文件.相关部分位于文件末尾的内部类中:class AudioCuePlayer ,对于平滑算法,请检查设置方法 setSpeed ,该方法大约为3/4的下来的路.抱歉,我没有行号.

Environment

  • Hardware: Raspberry Pi x
  • O.S.: Raspbian Jessie Lite
  • Language: Qt5 / C++

Goal

Execute an audio file (wav or better mp3) changing its speed smoothly and countinuosly. The pitch should change according to the speed (playback rate). My application updates several times per second a variable that contains the desired speed: i.e. 1.0 = normal speed. Required range is about 0.2 .. 3.0, with a resolution of 0.01.

The audio is likely music, expected format: mono, 16-bit, 11.025 Hz. No specific constraints about latency: below 500 ms is acceptable.

Some thougths

QMediaPlayer in QtMultimedia has the playbackRate property that should do exactly this. Unfortunately I have never be able to make QtMultimedia work in my systems.

It's ok to use also an external player, and send data using pipes or any IPC.

How would you achieve this?

解决方案

I don't know how much of this translates to C++. The work I did on this problem uses Java. Still, something of the algorithm should be of help.

Example data (made up):

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

With normal speed, we send the output line a series of values where the sample number increments by 1 per output frame.

If we were going slower, say half speed, we should output twice as many values before reaching the same point in the media data. In other words, we need to include, in our output, values that are at the non-existent, intermediate sample frame locations 0.5, 1.5, 2.5, ...

To do this, it turns out that linear interpolation works quite well for audio. It is possible to use a more sophisticated curve fitting algorithm but the increase in fidelity is not considered to be worth the trouble.

So, we end up with a stream as follows (for half speed):

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.

If you want to play back 3/4 speed, then the positions and values used in the output would be this:

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.

I code this via a "cursor" that is incremented each sample frame, where the increment amount determines the "speed" of the playback. The cursor points into an array, like an integer index would, but instead, is a float (or double). If there is a fractional part to the cursor's value, the fraction is used to interpolate between sample values pointed to by the integer part and the integer part plus one.

For example, if the cursor was 6.25, and the value of soundData[6] was A and the value of soundData[6+1] was B, the sound value would be:

audioValue = A * 0.75 + B * 0.25

The degree of precision with which you can define your speed increment is quite high. I think Java's floats are considered sufficient for this purpose.

As for keeping a dynamically changing speed increment smooth, I am spreading out the changes to new speeds over a series of 4096 steps (roughly 1/10th of a second, at 44100 fps). Change requests are often asynchronous, e.g., from a GUI, and are spread out over time in a somewhat unpredictable way. The smoothing algorithm should be able to recalculate and update itself with each new speed request.

Following is a link that demonstrates both strategies, where a sound's playback speed is altered in real time via a slider control.

SlidersTest.jar

This is a runnable copy of the jar file that also contains the source code, and executes via Java 8. You can also rename the file SlidersTest.zip and then drill in to view the source code, in context.

But links to the source files can also be navigated to directly in the two following sections of a page I posted for this code I recently wrote and made open source: see AudioCue.java see SlidersTest.java

AudioCue.java is a long file. The relevant parts are in the inner class at the end of the file: class AudioCuePlayer, and for the smoothing algorithm, check the setter method setSpeed which is about 3/4's of the way down. Sorry I don't have line numbers.

这篇关于以编程方式实时更改音频文件的速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆