如何从我的wav文件中绘制声音数据?

时间:2012-10-14 04:05:43

标签: java audio drawing wav javasound

首先是家庭作业或......项目。

我无法理解如何在Java中为项目绘制声音数据波的想法。 我必须完全从头开始使用UI进行这项任务,所以基本上都是制作.wav文件编辑器。 我遇到的主要问题是将声音数据输入要绘制的图形中。目前,我正在绘制一个随机生成的值数组。

到目前为止,我有一个运行并验证wav文件的迷你程序,实际上它是一个wav文件。

我正在使用FileInputStream读取它并验证:RIFF字节(0-3),FileLength(4-7),WAVE字节(8-11),然后是格式块格式(从结尾开始) RIFF块;并将索引定位到它的末尾,并给出格式0-3,格式块4-7的长度,然后是波形文件的所有规范的下一个16字节,并将它们存储在适当的命名变量中。

一旦我到达DATA块并且它的长度超过了我的所有声音数据,这就是我不确定如何将每个字节存储为声音数据的字节,甚至将其转换为与之相关的值声音的幅度。我认为验证是相似的,所以它会是相同的,但它似乎不是那样的...要么那么,或者我一直在使一些超级简单的事情复杂化,因为我已经盯着这几天了。 / p>

感谢任何帮助。

3 个答案:

答案 0 :(得分:16)

我不是Java程序员,但我对渲染音频知之甚少,所以希望以下内容可能有所帮助......

鉴于您几乎总是拥有比可用像素更多的样本,理所当然的事情是从样本数据的缓存减少或“摘要”中提取。这通常是音频编辑器(例如Audacity)呈现音频数据的方式。事实上,最常见的策略是计算每个像素的样本数,然后找到每个大小为SamplesPerPixel的块的最大和最小样本,然后在每个最大 - 最小对之间绘制一条垂直线。您可能希望缓存此缩减,或者可能需要针对不同的缩放级别进行一系列此类缩减。 Audacity缓存磁盘上的临时文件(“阻止文件”)。

然而,上面的内容可能过于简单了,因为实际上你需要从一大块固定大小(比如256个样本)计算初始最大 - 最小对,而不是从大小SamplesPerPixel中计算一个。然后,您可以从缓存的减少量中进一步计算“即时”减少量。关键是SamplesPerPixel通常是动态数量 - 因为用户可能随时调整画布大小(希望有意义......)。

另外请记住,在绘制画布时,需要按画布的宽度和高度缩放样本值。执行此操作的最佳方法(至少在垂直方向上)是对样本进行标准化,然后乘以画布高度。 16位音频由[-32768,32767]范围内的样本组成,因此要标准化只需用32768进行浮点除法。然后反转符号(将波形翻转到画布坐标),加1(补偿)对于负值)并乘以 half 画布高度。无论如何,我就是这样做的。

This页面显示了如何使用Java Swing构建基本波形显示。我没有详细研究它,但我认为它只是对数据进行下采样而不是计算max-min对。当然,这不会像max-min方法那样提供精确的减少,但它更容易计算。

如果你想知道如何正确地做事,你应该深入了解Audacity源代码(但要注意 - 它是相当粗糙的C ++)。要获得一般概述,您可以查看Audacity的原作者Dominic Mazzoni撰写的'A Fast Data Structure for Disk-Based Audio Editing'。但是,您需要从CMJ购买。

答案 1 :(得分:2)

对于标准WAV文件,它实际上非常简单。一旦超过标题,您只需将每16位解释为二进制补码整数。我建议使用DataInputStream,因为它就像调用readShort()一样简单。

这些是每个采样点的振幅值。您可能想要做一些平均值或其他事情,因为大多数时候会有比水平像素更多的样本。试图在某种线图上绘制所有样本可能不是最好的方法。

答案 2 :(得分:0)

您需要做的第一件事是阅读原始数据。编写Wav文件解析器并不太难,但您也可以使用javasound API。这里有一些关于使用这个api的很好的提示和示例代码:

http://www.jsresources.org/

如果你想编写自己的解析器,可以从这里开始:

https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

获得原始数据后,您可以将其显示为时间的函数。这称为波形。

但是,当用户“缩小”大量数据时,显示波形非常耗时:一小时的数据需要很长时间才能以这种方式呈现。因此,大多数应用程序预先计算一些数据,以便更快地绘制缩小的数据。 “正确”的方法如下:

  • 循环文件中的样本块(从50到500左右)
    • 阅读样本块
    • 取所有样本的绝对值
    • 取绝对值的最大值
    • 将最大值存储为该块的“缩小”值

当我说“正确”时,我的意思是每个人都这样做,所以它会产生一个看起来像人们期望的视图。如果你做了不同的事情(例如计算日志或平均值而不是寻找峰值),你会得到一些看起来不正确的东西,正如这位研究员所发现的那样:

drawing waveform - converting to DB squashes it

相关问题