C++ 从音频中提取波形的算法

C++ 从音频中提取波形的算法,c++,algorithm,audio,ffmpeg,C++,Algorithm,Audio,Ffmpeg,我试图从原始音频文件中提取波形。我使用FFmpeg对一个音频文件进行了解复用/解码,并获得了以下信息:采样缓冲区、采样缓冲区的大小、音频文件的持续时间(以秒为单位)、采样率(44100、48000等)、采样大小、采样格式(uint8、int16、int32、float、double)以及原始音频数据本身 在互联网上挖掘我发现了这个算法(更多): 白噪声: 算法 您只需将每个样本从–振幅随机分配到 振幅在大多数情况下,我们并不关心频道的数量,所以 我们只是用一个新的随机数填充每个样本 Rando

我试图从原始音频文件中提取波形。我使用FFmpeg对一个音频文件进行了解复用/解码,并获得了以下信息:采样缓冲区、采样缓冲区的大小、音频文件的持续时间(以秒为单位)、采样率(44100、48000等)、采样大小、采样格式(uint8、int16、int32、float、double)以及原始音频数据本身

在互联网上挖掘我发现了这个算法(更多):

白噪声:

算法

您只需将每个样本从–振幅随机分配到 振幅在大多数情况下,我们并不关心频道的数量,所以 我们只是用一个新的随机数填充每个样本

Random rnd=new Random();
短随机值=0;
对于(int i=0;i
这真的很好,但我不想那样画,但这样:


是否有任何算法或想法可以让我使用我所掌握的信息进行绘图?

底部的图形只是包含了更长的时间跨度,因此如果您增加了numsample,您将得到更紧凑的图形。但是在白噪声中,你看不到正常声音/音乐中的波峰和波谷


因此,如果您可以增加样本量,或者至少增加样本周期(x轴),您将开始模拟底部图表。使用其中两个来获得立体效果。

首先,您需要确定每个样本将在屏幕上的何处结束

int x = x0 + sample_number * (xn - x0) / number_of_samples;
现在,对于具有相同
x
的所有样本,分别确定正值和负值的最小值和最大值。画一条垂直线,一条从负最大值到正最大值的暗线,然后在上面画一条从负最小值到正最小值的浅线


编辑:再想一想,你可能想用平均值而不是最小值作为内线。

英国广播公司研发部有一个很好的节目,你可以参考他们的来源。

我想你指的是这里描述的波形


我没有读完整页。但每个垂直条代表一个波形样本窗口。深蓝色是该窗口中的最大正值和最小负值(我认为)。浅蓝色是均方根。(基本上是将每个窗口内的值平方,取平均值,然后求平方根

希望这能有所帮助。

showwavespic
ffmpeg
可以使用滤波器绘制波形

有关选项,请参阅

炫耀 您还可以使用过滤器制作实时波形的视频


有关选项,请参阅。

第二个波形可能是简单之字形图形的近似列

每列都是前一个采样振幅到当前采样振幅之间的一条线

因此,将所有样本读入画布或纹理作为点的预测试,然后,一旦你完成了,你可以做两种情况,用条代替点,向上画到最后一个样本或向上画到这个样本,取决于哪个更高,只要你在到两个之间画一条线。这确保波形小,能量低下一个样品和高能量样品之间

您可以对其进行别名并测量多个样本,这取决于您正在运行的硬件,如果您想读取1000个样本并制作一个巨大的二维阵列表示波,然后将其向下别名为一个较小的可显示图像,或者如果您只想运行512个样本并快速更新,则应在程序中使用二维画布快速制作超过512个样本的详细波形

…另一个选项与另一个答案中的灰色波形相同,将绝对值绘制为从+电流采样到-电流采样的直线

它有助于平均多个样本,即每4个样本或每4个样本的最大值,以减少不稳定的图形,这是一个快速混叠的孩子。

为大家解释 我是一个dj应用程序的开发者,一直在寻找类似的答案。 因此,我将解释所有你可能在任何软件中看到的音乐波形,包括audacity

在任何音乐软件中,都有3种类型的波形用于显示。 即样本、平均值和均方根值

1) 示例是图形中显示的实际音乐点,可以是原始音频数据数组(在audacity中缩放波形时看到的点)

2) 平均值:最常用的是,假设您在屏幕上显示3分钟的歌曲,那么屏幕上的一个点必须至少显示100毫秒(约)的歌曲,其中包含许多原始音频点,因此在显示时,我们计算100毫秒持续时间内所有点的平均值,以此类推,以显示剩余的曲目(大胆的深蓝色大波形)

3) RMS:与平均值类似,但此处不是平均值,而是取特定持续时间的均方根(蓝色波形中的浅蓝色小波形是audacity中的RMS波形)

现在如何计算波形

1) 当您使用任何获得原始样本/点的技术解码歌曲时,样本是原始数据。现在根据点的格式将其转换为范围-1到1,例如,如果格式为16位,则将所有点除以32768(16位数字的最大范围),然后绘制点

2) 对于平均波形-首先将所有点相加,将负值转换为正值,然后乘以2,然后取平均值

//samples is the array and nb_samples is the length of array
float sum = 0;
for(int i = 0 ; i < nb_samples ; i++){
    if(samples[i] < 0)
        sum += -samples[i];
    else
        sum += samples[i];
}
float average_point = (sum * 2) / nb_samples; //average after multiplying by 2
//now draw this point
//samples是数组,nb\u samples是数组的长度
浮点数和=0;
对于(int i=0;i
3) RMS:简单的方法是取平方根的平均值-所以先取每个样本的平方,然后求和,然后计算
ffmpeg -i input -filter_complex "showwavespic=split_channels=1" output.png
ffmpeg -i input -filter_complex \
"showwaves=s=600x240:mode=line:split_channels=1,format=yuv420p[v]"  \
-map "[v]" -map 0:a -movflags +faststart output.mp4
//samples is the array and nb_samples is the length of array
float sum = 0;
for(int i = 0 ; i < nb_samples ; i++){
    if(samples[i] < 0)
        sum += -samples[i];
    else
        sum += samples[i];
}
float average_point = (sum * 2) / nb_samples; //average after multiplying by 2
//now draw this point
//samples is the array and nb_samples is the length of array
float squaredsum = 0;
for(int i = 0 ; i < nb_samples ; i++){
    squaredsum += samples[i] * samples[i]; // square and sum
}
float mean = squaredsum / nb_samples; // calculated mean
float rms_point = Math.sqrt(mean); //now calculate square root in last
//now draw this point