如何将 MP3 音频文件读入 numpy 数组 / 将 numpy 数组保存为 MP3?

25

有没有一种类似于scipy.io.wavfile.readscipy.io.wavfile.write的API,可以将MP3音频文件读取/写入到numpy数组中?

sr, x = wavfile.read('test.wav')
wavfile.write('test2.wav', sr, x)

?

注意:pydubAudioSegment对象不直接提供对numpy数组的访问。
PS:我已经阅读了将声音文件导入Python作为NumPy数组(替代audiolab), 尝试了所有答案,包括那些需要使用Popen ffmpeg并从stdout管道中读取内容等。我也阅读了尝试将mp3文件转换为Numpy数组,但ffmpeg卡住了等,并尝试了主要的答案,但没有简单的解决方案。在花费数小时后,我在这里发布它,以“回答自己的问题-分享您的知识,Q&A风格”。我还阅读了如何从pydub AudioSegment创建numpy数组?,但这并不容易涵盖多通道情况等。
2个回答

39

许多帖子建议使用ffmpeg并手动解析其stdout来读取MP3,这是一项繁琐的任务(因为可能有不同数量的声道等许多特殊情况),因此这里提供了一个使用pydub的可行解决方案(您需要先pip install pydub)。

此代码允许读取MP3到numpy数组/将numpy数组写入MP3文件,具有类似于scipy.io.wavfile.read/write的API:

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允许使用浮点数数组(每个项目在[-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)

太好了!对于Linux用户,可以添加输出/参数“tags”以读取/写入元数据,如https://github.com/jiaaro/pydub/issues/44所示。添加`tags=mediainfo(f).get('TAG', {})以读取和export(f, format="mp3", bitrate="320k", tags=tags)`以写入。 - francis
为了使用这个解决方案,可能需要一些额外的依赖项(不能在Windows上仅通过pip安装)。请参阅https://github.com/jiaaro/pydub/issues/348。 - Pro Q

6

您可以使用audio2numpy库。

安装方法如下:

pip install audio2numpy

那么,你的代码将是:

import audio2numpy as a2n
x,sr=a2n.audio_from_file("test.mp3")

写作方面,使用@Basj的答案


1
这些一体化软件包在快速实验时非常方便,但在我看来,使用它们甚至比像@Basj的答案那样简单复制粘贴还要糟糕。(无论如何+1) - Joran
是的...但它能够工作,如果你不关心代码的速度或效率,那么这是最简单的解决方案。 - Adam Jenča

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接