在不同的音频库中传递 numpy 音频数组

问题描述 投票:0回答:1

我正在开发一个项目,其中涉及大量文本转语音的音频处理任务,但我遇到了一个小障碍。我将处理可能数百个 TTS 音频片段,因此我想尽可能减少文件 IO。 我需要使用 Coqui TTS 合成语音,使用 AudioTSM 对其进行时间拉伸,然后使用 PyDub 进行附加处理和拼接。

我正在使用 Coqui TTS 生成如下文本:

from TTS.api import TTS
tts = TTS()
audio = tts.tts("Hello StackOverflow! Please help me!")

这将返回一个 Float32 值列表,需要将其转换为与 AudioTSM 的 ArrayReader

一起使用

像这样:

audio_array = np.array(tts_audio)

# Reshape the array to (channels, samples)
samples = len(audio_array)
channels = 1
sample_rate = 22050
audio_array = audio_array.reshape(channels, samples)

from audiotsm.io.array import ArrayReader, ArrayWriter

reader = ArrayReader(audio_array)
tsm = wsola(reader.channels, speed=2) # increase the speed by 2x
rate_adjusted = ArrayWriter(channels=channels)
tsm.run(reader, rate_adjusted)

到目前为止,一切都很顺利。问题出在 Pydub

如果我使用 AudioTSM 的

WavWriter
来代替,则音频会正确地进行时间拉伸,就像我先完成
tts_to_file
然后
WavReader()

一样

问题来自于 PyDub

如果我直接传入

ArrayWriter
rate_adjusted.data.tobytes()
的结果,像这样,我们会得到严重失真的音频

from pydub import AudioSegment

# Convert the processed audio data to a PyDub AudioSegment
processed_audio_segment = AudioSegment(
    rate_adjusted.data.tobytes(),
    frame_rate=samplerate,
    sample_width=2,
    channels=channels
)
# Perform additional audio processing

processed_audio_segment.export('tts_output.wav', format='wav')

我找不到支持这一点的文档,但是查看

AudioSegment
__init__
的源代码,我怀疑它与 Coqui 输出有关
float32
AudioSegment 想要缩放
int16

转换数组实际上似乎会产生一些有用的结果

# Scale the floats to whole numbers and convert
converted_audio = (rate_adjusted.data * 2**15).astype(np.int16).tobytes()

这会生成一个不失真但质量明显下降的音频文件,导出时实际上比 AudioTSM

WavWriter
未经任何处理导出的文件小约 25KB。我猜这是因为 Int16 使用较少的数据。我尝试像这样转换为 Int32:

converted_audio = (rate_adjusted.data * 2**31).astype(np.int32).tobytes()

但这实际上听起来并没有更好,而且占用了更多的空间。我在这里缺少什么?

如果我只是用

WavWriter
导出到 wav 并用
AudioSegment.from_wav()
读入,则不会出现失真,导出是相同的,而且我不必转换,但同样,文件 IO 既昂贵又痛苦。

除了将内容转换为 wav 之外,是否有任何方法可以在这些数组格式之间正确进行转换,而不会导致失真、质量损失或理智?我也可以尝试其他库,但我的项目已经大量使用 PyDub,尽管它被证明是一个巨大的眼中钉。我的目标只是在内存中执行所有音频操作,并在库之间提供尽可能多的互操作性。

python numpy audio audio-processing pydub
1个回答
0
投票

我怀疑您可能会遇到失真,因为原始

float32
音频阵列和要转换为的
int16
格式之间的数值范围存在差异。在浮点 wav 文件中,值通常在 -1.0 和 1.0 之间缩放。但是,为了避免音频削波,录音(尤其是语音录音)通常会使用较窄的范围,例如 -0.1 到 0.1 之间。

值得注意的是,

float32
最多可以容纳
2^31
不同的值,因此仅利用该范围的一部分并不是一个重要问题。另一方面,在处理
int16
时,如果您仅使用可用范围的十分之一,则实际上将可用存储空间减少了大约
6%
。范围的减小可能会导致音频质量明显下降。

我怀疑这种范围减小可能是您观察到的质量损失的原因。为了解决这个问题,我建议在将其转换为

int16
之前重新调整音频阵列以跨越 -1 到 1 的整个范围。这种调整应该会提高数据分辨率。所以类似:


data = data / np.max(np.abs(data))

除以数据中的最大绝对值可确保整个范围得到充分利用,从而减轻转换过程中潜在的质量损失。

© www.soinside.com 2019 - 2024. All rights reserved.