使用GO从头开始播放音频:立体声平移

2020-07-27 02:40:24

在上一篇文章中,我们已经编写了代码来更改波形文件的振幅。

现在我们来看一下如何通过可选的平移将单声道波形文件转换为立体声波形文件,并探索如何在内部使用波形文件格式来表示这一点。

WAVE文件内的原始音频数据由多个帧组成。目前,我们称它们为“样品”,尽管严格地说这并不完全正确。事实上,当我们假设一个单声道音频文件时,rawdio数据中的单个浮点仅对应于单个样本。

当您有多个通道时,单个“采样”可以由多个帧组成。因为每个频道需要在任何给定的时间点播放特定的“帧”。

在WAVE文件格式中,通道是交错的。例如,立体声文件如下所示:

这里,每个示例由两个帧组成。使得帧1和2组成样本1,帧3和4组成样本2,依此类推。

程序知道如何解释原始音频数据,因为音频文件中的FMT块指定了原始音频数据中存在的声道数。一个WAVE文件中的最大通道数实际上高达65,536个,这对于音频数据来说实际上是没有意义的。

不过,为了方便起见,我们主要处理单声道和立体声文件。它们不仅是最常用的,而且还允许我们在不需要更昂贵的设置的情况下测试我们的代码。

那么什么是平底锅呢?当您平移音频信号时,实质上是使音频信号在左侧或右侧变得“更响亮”。通常,在DAW中,这将由介于-1到1之间的“AutomationTrack”表示。

对于输入文件,我们将限制为单声道文件,而对于输出文件,我们将始终生成立体声文件。PAN变量应介于-1(左)和1(右)之间。在我们可以开始应用PAN之前,我们需要从输入WAVE文件中读取原始音频数据。请记住,要读取wave文件,我们将使用前面创建的GoAudio库:

这个程序的设置相当简单,我们将使用内置的标志包来解析来自CLI的输入。

Var(INPUT=标志。字符串(";I";,";";,";,";输入文件";)输出=标志。字符串(";o";,";";,";输出文件";)PAN=flag。浮动64(";p";,0.0,";平移范围在-1(左)到1(右)";)。

一旦我们设置了标志,我们就可以解析它们并读取输入文件。

Func main(){标志。Parse()infile:=*input outfile:=*output panfac:=*PAN WAVE,ERR:=WAV。ReadWaveFile(Infile)if err!=nil{死机(";无法解析波形文件";)}...}。

到目前一切尚好。我们已经解析了输入,因此我们知道要为PAN使用哪个值,我们还读取了原始音频数据。但是我们如何才能从(-1)到(1)范围内的值变成左侧或右侧的实际响度变化呢?我们可以想象,一个简单的函数将如下所示:

类型panposition struct{LEFT,RIGHT FLOAT64}函数计算Position(Position Float64)panposition{position*=0.5 return panposition{LEFT:Position-0.5,Right:Position+0.5,}}

这里我们使用一个结构,它可以表示左声道和右声道在0到1的范围内的振幅。这样我们就可以观察到以下值:

换句话说,如果位置为零,耳机左右两侧的声音完全平衡。在极端情况下,声音要么是左侧的,要么是右侧的。

就像在前一篇文章中一样,我们实际上需要基于在culatePosition函数中找到的位置数据来更改帧。我们可以创建一个函数,根据前一个函数中返回的全景位置修改框架。

Func applyPan(FRAMES[]WAV.。帧,p全景)[]WAV。帧{OUT:=[]WAV。帧{}for_,s:=范围帧{out=追加(out,wav.。FRAME(FLOAT64(S)*P.LEFT))OUT=APPEND(OUT,WAV)。FRAME(FLOAT64(S)*P.right)}返回}。

请注意,对于每个帧,我们实际上是如何将两个帧附加到结果切片上的!这就是我们如何交错左声道和右声道。

..。位置:=culatePosition(Panfac)scaledFrames:=applyPan.。帧,计算位置(Panfac))波。NumChannels=2//样本现在是立体声的,所以如果err:=wav,我们需要双声道。WriteFrames(scaledFrames,Wav.。WaveFmt,outfile);错误!=无{死机(错误)}。

这里的关键一步是,在编写我们设置的Ran Wave.NumChannels=2样本之前,WAVE文件将被解释为单声道声音文件,并且我们的平移效果将会丢失。

为了测试这一点,我发现不用做很多事情就可以很容易地使用输入文件。我主要使用这个简单的单声道文件。

当我们运行go run main.go-i mon.wav-o right-side.wav-p1时,我们得到:

我们正在使用的平移功能实际上存在一个缺陷。然而,这还不明显,因为我们只能为整个音频源设置平移。要了解为什么这个平移功能不完美,我们需要首先引入断点作为创建自动化跟踪的一种方式,因此接下来几篇文章的重点将是断点。:-)。

如果你喜欢这篇文章,并想知道我什么时候写了新帖子,最好的更新方式就是在Twitter上关注我。-)