有没有办法使用与 scipy.io.wavfile.read 和 scipy.io.wavfile.write 类似的 API 将 MP3 音频文件读取到 numpy
数组中或从中写入 MP3 音频文件:
sr, x = wavfile.read('test.wav')
wavfile.write('test2.wav', sr, x)
<强>?强>
注意:pydub
的 AudioSegment
对象无法直接访问 numpy 数组。
PS:我已经阅读了 Importing sound files into Python as NumPy arrays (alternatives to audiolab) ,尝试了所有答案,包括那些需要 Popen
ffmpeg 并从 stdout 管道读取内容的答案等。我还阅读了 Trying to convert an mp3 file to a Numpy Array, and ffmpeg just hangs 等。 ,并尝试了主要答案,但没有简单的解决方案。在花了几个小时研究这个问题之后,我将其发布在这里,标题是“回答你自己的问题 - 以问答方式分享你的知识”。我也读过 How to create a numpy array from a pydub AudioSegment?,但这并不能轻易涵盖多 channel 情况等。
最佳答案
按照许多有关读取 MP3 的文章中的建议,调用 ffmpeg 并手动解析其 stdout
是一项繁琐的任务(许多极端情况,因为可能有不同数量的 channel ,等等.),所以这是一个使用 pydub 的可行解决方案(您需要首先 pip install pydub
)。
此代码允许使用与 scipy.io.wavfile.read/write
类似的 API 将 MP3 读取到 numpy 数组/将 numpy 数组写入 MP3 文件:
import pydub
import numpy as np
def read(f, normalized=False):
"""MP3 to numpy array"""
a = pydub.AudioSegment.from_mp3(f)
y = np.array(a.get_array_of_samples())
if a.channels == 2:
y = y.reshape((-1, 2))
if normalized:
return a.frame_rate, np.float32(y) / 2**15
else:
return a.frame_rate, y
def write(f, sr, x, normalized=False):
"""numpy array to MP3"""
channels = 2 if (x.ndim == 2 and x.shape[1] == 2) else 1
if normalized: # normalized array - each item should be a float in [-1, 1)
y = np.int16(x * 2 ** 15)
else:
y = np.int16(x)
song = pydub.AudioSegment(y.tobytes(), frame_rate=sr, sample_width=2, channels=channels)
song.export(f, format="mp3", bitrate="320k")
注释:
- 目前仅适用于 16 位文件(即使 24 位 WAV 文件很常见,但我很少见过 24 位 MP3 文件......这存在吗?)
normalized=True
允许使用 float 组([-1,1) 中的每个项目)
使用示例:
sr, x = read('test.mp3')
print(x)
#[[-225 707]
# [-234 782]
# [-205 755]
# ...,
# [ 303 89]
# [ 337 69]
# [ 274 89]]
write('out2.mp3', sr, x)
关于python - 如何将 MP3 音频文件读入 numpy 数组/将 numpy 数组保存到 MP3?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53633177/