绘制可缩放音频波形的正确方法

信息处理 声音的 音频处理
2022-01-27 23:05:49

我正在尝试实现平滑的可缩放音频波形,但对实现缩放的正确方法感到困惑。我搜索了互联网,但信息很少或没有。

所以这就是我所做的:

  1. 从文件中读取音频样本并使用 samplesPerPixel = 10, 20, 40, 80, ....,10240 计算波形点。存储每个比例的数据点(此处总共 11 个)。Max 和 min 也与每个 samplesPerPixel 的点一起存储。

  2. 缩放时,切换到最近的数据集。因此,如果当前宽度的 samplesPerPixel 为 70,则使用对应于 samplesPerPixel = 80 的数据集。使用 log2(samplesPerPixel) 很容易找到正确的数据集索引。

  3. 使用数据集的二次采样来绘制波形点。因此,如果我们 samplesPerPixel = 41 并且我们使用数据集进行缩放 80,那么我们使用缩放因子 80/41 进行子采样。

     let scaleFactor = 80.0/41.0
     x = waveformPointX[i*scaleFactor]
    

我还没有找到更好的方法,也不太确定上述二次采样方法是否正确,但可以肯定的是,这种方法会消耗大量内存,并且在开始时加载数据也很慢。音频编辑器如何实现波形放大,有没有有效的方法?

1个回答

这似乎与音频采样率转换和 D/A 转换有关。您可以将其视为两个子问题:

  1. 如何最大限度地了解源波形
  2. 如何通过离散像素显示器传达最大的视觉信息

1 在放大时特别重要(来源受限),而 2 在缩小时特别重要(显示受限)。我将在这里主要介绍 1。

将解析 sinc 函数直接拟合到样本的局部邻域并直接在目标像素网格处离散化它们怎么样?或者一些实际的 sinc 近似值(窗口?样条?)

类似于模拟波形重建的标准可视化,如这篇文章: Matlab 中的信号采样和重建

在某些时候,您的波形将被过采样到简单的线性插值应该足以进一步上采样的程度。我不认为真的需要每个样本有 10000 个点的预先计算的向量吗?

编辑:纯代码来表达我的想法

N = 10;
x = 2*rand(N,1)-1;
us = 50;
grd = 1:(1/us):N;
y = x.*sinc(grd-(1:N)');
z = sum(y);

请注意,总和波形沿边缘将不准确。为了改善这一点,您可以总结显示区域之外的贡献。和/或尝试将 sinc 窗口化以限制其范围(会有一些妥协)

在此处输入图像描述

即使使用分析探测函数生成的离散波形,您也可能希望改进渲染。如果样本在垂直维度上大约位于两个像素之间,您可能希望将其分配给这两个(或更多)像素,而不是选择最近的邻居。

我猜这个解决方案可以很好地缩放到,比如说,100 个样本和每个维度上 1000 或 3000 个像素的显示。如果您显示的样本比一次裁剪中的样本多得多,那么您可能无法欣赏到太多的视觉效果,同时计算成本会增加。通过简单的静态重采样和更多的渲染工作(“克服显示的限制而不是源数据的限制”)可能会更好地创建这种视图。

上面的解决方案依赖于 MATLAB 绘图渲染来进行抗锯齿。下面显示了一个粗略的渲染尝试,其中垂直偏移由最近的邻居选择。这导致可见的楼梯:

vgrid = linspace(-2, 2, N*us);
[mv, mvi] = min(abs(z-vgrid'), [], 1, 'linear');
M = zeros(length(vgrid), length(grd));
M(mvi) = 1;
imwrite(M, 'test.bmp')

在此处输入图像描述

我不是图形专家,但我假设 MATLAB 和他们的基于 Open GL (?) 的渲染器有一个关于“线粗”的概念,并且应该使用抗锯齿将离散向量绘制为连续波形以将局部权重分配给离散像素邻域?