编码基本混响算法–第1部分:音频编程简介

混响音乐中一种非常强大的效果,可以增强音频效果,并广泛用于音乐制作中。 我确定您在浴室里表现出色,并且注意到您在浴室内而不是房子其他任何房间的声音特别棒。 好吧,这归功于混响。 混响的想法很简单。

混响的特征是在发出声音后三十毫秒内发生声音的随机,混合重复。

当我没有音频编程方面的经验并且对数字音频的工作原理有非常基本的了解时,我便开始研究此问题。 在解决问题的过程中,我搜寻了互联网以了解如何实现这一目标。 我的动机是通过参考在每个步骤中使用的资源来对我的学习进行说明,以便它成为开始使用音频编程的任何人的综合参考文章。


问题陈述:

给定音频文件,将混响应用于音频。

假设:

  1. 音频文件将是WAV文件(8位和16位PCM编码)
  2. 可以控制的混响参数为:延迟,衰减因子,干/湿混合百分比

使用的编程语言:Java

可以从我的Github访问完整的代码:https://github.com/Rishikeshdaoo/Reverberator


基本上是简化问题。

将混响限制为仅WAV文件的原因与音频文件的编码方式有关。 我们知道的各种音频格式,例如: mp3,wav,ogg和flac ,基本上是数字存储音频的不同方式。

数字化地,音频以“ 样本 ”的形式存储。

声音是一种连续时间功能,数字设备仅在离散事件上起作用。 因此,我们需要某种方式将声音表示为离散时间函数。

可以将样本可视化为以周期性间隔从连续可变的模拟波形中提取的值。 采样将模拟波形转换为离散的一系列采样(数字),表示精确时间的波形值。 采样将波形从模拟域转换为数字域,更适合计算机处理。

WAV(特别是8位和16位PCM)文件遵循称为脉冲编码调制的编码 您可以在这里和这里详细了解它。

本质上,从编程的角度来看,这意味着文件中的每个样本都将采用固定大小(称为“ 帧” )。 例如:在8位PCM编码的文件中,每8位将组成一个样本。

因为我们可以直接将WAV文件读入Byte数组,所以这使我们的工作变得容易 所有样本框在阵列内依次排列

对于其他格式(例如mp3),编码要复杂得多,并且要从音频文件中检索样本就需要进行大量编码。


从读取WAV文件到播放经过混响处理的文件的完整程序可以分为以下几个步骤作为里程碑:

步骤3步骤4是程序中最重要的步骤。


步骤1步骤2非常简单。 WAV文件被读入Input流。 将此数据复制到Byte数组中。 在此处浏览代码以实现Java。


在此步骤中,需要实现两个主要目标,才能将存储在字节数组中的音频数据转换为样本数组。

我为此(此处)提供的大量资源。 我将在解释中使用该资源中的段落。 在代码中,此转换是通过调用SampleDataRetrieval类中的unpack方法进行的。

  1. 串联字节数组:

字节数组包含拆分的样本帧,并且全部排成一行。 实际上,这非常简单明了,除了所谓的endianness ,这是每个数据包中字节的顺序。

字节序:

这是一张图。 该数据包保留十进制值9999:

它们具有相同的二进制值。 但是,字节顺序相反。

  • big-endian中 ,更高有效字节的索引更大。 即MSB将处于最高索引。
  • little-endian中 ,较高有效字节的索引较小。 即MSB将在索引“ 0”处

WAV文件以小字节序字节顺序存储,而AIFF文件以大字节序字节顺序存储。 可以从AudioFormat.isBigEndian (A Java class that provides audio format specifications)获得字节AudioFormat.isBigEndian (A Java class that provides audio format specifications)

2. 解码有符号和无符号值:

对于PCM签名系统:

计算机通过称为二进制补码的系统来表示带符号的数字 这有助于代表两个不同类型的负数和正数,而无需任何特殊逻辑。 现在,当我们尝试从中检索实际数值时,我们需要扩展两者的补码。

要获得整数的二进制补码负号,请用二进制形式写出数字。 然后,您将数字取反,并在结果中加一位。 这基本上将MSB的负值设置为“ 1”,将正值设置为“ 0”。

这意味着,如果最高有效位(MSB)设置为1,则将其上方的所有位都填充为1。算术右移( >> )将在设置符号位时自动为我们填充。

对于PCM无符号系统:

无符号系统只是数字偏移量表示


在第3步之后,我们有一个float数组,其中包含每个样本的实际幅度值。 现在,它将作为混响的输入信号。

步骤4是混响的设计和编程实现。 这涉及很多详细的讨论,我在这里的另一篇文章中进行了介绍。 另外,请参考混响实现的源代码。

在第4步结束时,我们将有一个“ 混响”音频的浮动数组。 现在我们需要返回并将其写入WAV文件,以便我们可以播放并收听它。


我们已经处理了过程中的困难部分。 我们只需要将样本包装回其原始音频规格,我们就可以收听混响!

正如您凭直觉所猜到的,将float数组打包为一个字节数组的过程是相反的步骤3。

  1. 对于未签名的PCM,请将其转换回原始表示形式。 这是通过添加我们之前减去的偏移量满量程 )来完成的。 PCM签名将不需要任何更改,因为符号扩展数不会在进一步的计算中引起任何问题。
  2. 根据Little Endian规范,将上述值转换​​为字节—用0xffL屏蔽数字,以从数字中提取8位并存储在字节数组元素中。 对于16位表示,将MSB移8位,然后应用掩码。

3.音频的播放使用JavaSound API。

它使用API​​组件的混合控制台的隐喻。 “混音器”是声音设备的概念。 “行”是音频i / o混合控制台中的条之一。 我在此实现中使用了“剪辑” ,该剪辑在播放之前将完整的音频存储在内存中。 您可以在此处阅读有关JavaSound API的详细信息。 请参考代码注释,以详细了解此实现。


我希望这篇文章至少对您有所帮助。 请让我知道说明中是否有任何错误或我可以做出的改进。 另外,如果您有任何我可以写的主题或想要一起工作的项目,请给我写信。

里士