我必须做些啥来改变我的音频可视化器的视觉效果?
Posted
技术标签:
【中文标题】我必须做些啥来改变我的音频可视化器的视觉效果?【英文标题】:What do I have to do to change the visuals of my audio visualizer?我必须做些什么来改变我的音频可视化器的视觉效果? 【发布时间】:2021-08-08 15:22:28 【问题描述】:我在 rust 中创建了自己的音频可视化器,其中每个频率的幅度存储为 [f32;第3750章
我使用 cpal 作为音频后端,具有 f32 个音频样本、2 个通道和 44.1khz 采样率。
我使用rustfft 转换了这些样本,如下所示:
pub fn convert_buffer(input_buffer: [f32; 3750]) -> [f32; 3750]
let mut planner = FftPlanner::new();
let fft = planner.plan_fft_forward(3750);
let mut buffer: Vec<Complex<f32>> = Vec::new();
for i in 0..3750
buffer.push(Complex re: input_buffer[i], im: 0.0 );
fft.process(&mut buffer[..]);
let mut output_buffer: [f32; 3750] = [0.0; 3750];
for i in 0..buffer.len()
output_buffer[i] = buffer[i].norm()
output_buffer
但在可视化 15.000hz 正弦波时,它看起来像这样:
我对音频一无所知,所以我不知道为什么它会像这样反映自己以及为什么低于 500hz 的频率几乎被切断了。
我必须做些什么才能使它的行为方式在没有这种镜像的情况下可视化从 0hz 到 20khz 的频率
【问题讨论】:
【参考方案1】:从某种意义上说,您的代码很好;您所看到的是解释 FFT 的基本问题,而不是计算它。
首先,FFT自然是一个从复杂样本到复杂样本的函数。当您从实值输入信号开始并通过添加零虚部(或任何其他简单值,甚至复制实数 input_buffer[i]
)将其转换为复数时,输出将始终是镜像频谱强>。
(复值信号可以具有任意不对称频谱,将正频率与负频率区分开来。这在音频中没有广泛使用,但它是 FFT 和其他 DSP 操作的软件定义无线电 (SDR) 应用的基础。)
为了不得到镜像,你必须丢弃一半的输出。 (如果我没记错的话,它的效率略高——虽然不是 50%——跳过计算那一半,但看起来 rustfft
不提供该选项。)
如果你丢弃输出的上半部分(就数组索引而言),那么你会发现剩余的“频率区间”排列在从 0 Hz 到 22.05 kHz 的范围内。图书馆文档说明了这一点:
输出顺序
输出中的元素按频率升序排列,第一个元素对应于频率 0。
确实使用频谱后半部分的应用程序经常交换两半部分,因此它们的范围不是从 0 Hz 到 [采样频率]/2,而是从 -[采样频率]/2 到 +[采样频率频率] / 2。但是因为你是从一个真实的而不是复杂的信号开始的,所以这不适用于你;我只是提到它,因为您可能已经在其他以 0 Hz 为中心的图中看到它。
您的图像中心可见的衰减对应于任何数字信号处理所需的高通抗锯齿滤波器。丢弃右半部分后,它应该出现在右边缘。
最后,您的代码似乎没有对输入信号应用任何窗口。开窗是一个复杂的话题,但有必要考虑这样一个事实,即 FFT 假定一个周期性信号在输入缓冲区的长度上完全重复,但我们实际上是在给它一个周期为 not 输入缓冲区的偶数分割;加窗通过衰减信号的开始和结束部分来抑制这种影响。
您应该查找标准window function 并将其应用于 FFT 之前的输入数据;这应该会减少您观察到的次要峰值。
【讨论】:
哇,谢谢,现在效果很好。但我无法解决一个低频不可见的问题。有没有推荐的方法来操纵频率相对于彼此的水平大小?就像有一个像[0.5, 0.25, 0.125, 0.125]
这样的数组,其中每个值代表 eq 中四分之一的水平大小?
@BrunoWallner 不,任何这样的改变都会使情节不正确——当然,如果这纯粹是装饰性的,你可以随意调整它。如果缺少低频,那么它一定与输入信号有关 — 在大多数音频信号中,低频在 FFT 图中往往会更加突出。以上是关于我必须做些啥来改变我的音频可视化器的视觉效果?的主要内容,如果未能解决你的问题,请参考以下文章
GDI +游戏引擎(我可以做些啥来让我的引擎运行得更快?)[重复]