我该如何可视化音频数据?

11

我希望有一个类似这样的东西,两种不同的颜色并非必需。

Mac 上的 Audacity
(来源: sourceforge.net)

我已经有了来自立体声wav文件的音频数据(每毫秒一个样本),分别用于左右声道的两个int数组。我尝试过几次,但它们看起来远不如这个清晰,我的尝试结果变得太尖锐或者是一团紧密的块。

有什么好的建议吗?我在使用c#工作,但伪代码也可以。

假设我们有

  • 一个函数DrawLine(color, x1, y1, x2, y2)
  • 两个长度为L的int数组right[]和left[]
  • 数据值在32767和-32768之间

如果你有其他假设,请在你的答案中写下它们。

for(i = 0; i < L - 1; i++) {
  // What magic goes here?
}

当我应用Han提供的解决方案时,它变成了这样(只有一个频道)
替代文本 http://www.imagechicken.com/uploads/1245877759099921200.jpg


Audacity是开源的,所以你可以查看代码。我假设像以下这样... func getHeight(v) { return abs(v) * 32767 / viewArea.height / 2); samplesPerPixelColumn = samples.len/viewArea.width; for i = 1 to viewArea.width {avgV = Avg(samples[i-i+samplesPerPixelColumn]); colHeight = getHeight(avgV); if avgV >= 0 DrawLine(black, i, viewArea.height /2, i, (viewArea.height / 2) + colHeight) else DrawLine(black, i, viewArea.height /2, i, (viewArea.height / 2) - colHeight); 你可能需要在其中进行一些舍入/范围处理,但那应该就是要点了。 - steamer25
为什么不把那个放到一个答案里呢? - Nifle
1
我想给你一些可能会立即有用但不会因为其中的某部分而被踩的东西。更多想法:不要使用垂直线,而是在前一个图形点和下一个点之间画对角线...此外,如果你放大到足够的程度,每个样本将有多个像素。 - steamer25
2个回答

2

每个像素可能有不止一个样本。对于映射到单个像素的每组样本,您可以从样本组中的最小值绘制到最大值的 (垂直) 线段。如果缩放到每个像素或更少的样本,则此方法将失效,最好的解决方案是显示sinc插值值。 由于DrawLine无法绘制单个像素,当最小值和最大值相同时存在一些问题。在这种情况下,您可以像下面的代码一样将单个像素图像复制到所需位置:

double samplesPerPixel = (double)L / _width;
double firstSample = 0;
int endSample = firstSample + L - 1;
for (short pixel = 0; pixel < _width; pixel++)
{
    int lastSample = __min(endSample, (int)(firstSample + samplesPerPixel));
    double Y = _data[channel][(int)firstSample];
    double minY = Y;
    double maxY = Y;
    for (int sample = (int)firstSample + 1; sample <= lastSample; sample++)
    {
        Y = _data[channel][sample];
        minY = __min(Y, minY);
        maxY = __max(Y, maxY);
    }
    x = pixel + _offsetx;
    y1 = Value2Pixel(minY);
    y2 = Value2Pixel(maxY);
    if (y1 == y2)
    {
        g->DrawImageUnscaled(bm, x, y1);
    }
    else
    {
        g->DrawLine(pen, x, y1, x, y2);
    }
    firstSample += samplesPerPixel;
}

请注意,Value2Pixel将样本值缩放为像素值(在y方向上)。

0

你可能想要研究一下R语言。虽然我对它的经验不是很丰富,但它主要用于统计分析/可视化场景。如果他们没有一些平滑函数来消除你提到的极端值,我会感到惊讶。

而且你应该没有问题将你的数据导入其中。它不仅可以读取纯文本文件,而且还设计成易于扩展C,因此可能也有某种C#接口。


我怀疑调用外部应用程序来绘制我的位图是否可行。我每秒钟更新位图多次。 - Nifle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接