问题 如何用Python编写24位WAV文件?


我想使用Python 2.7从-1到1之间的浮点值数组生成一个24位WAV格式的音频文件。我无法使用 scipy.io.wavfile.write 因为它只支持16位或32位。 Python自己的文档  模块没有指定它采用的数据格式。

那么在Python中可以做到这一点吗?


11109
2018-05-27 06:09


起源



答案:


另一种选择是 wavio (也在PyPI上: https://pypi.python.org/pypi/wavio),我创建的一个小模块,解决了尚未支持24位WAV文件的scipy问题。文件 wavio.py 包含该功能 write,将numpy数组写入WAV文件。要编写24位文件,请使用参数 sampwidth=3。唯一的依赖 wavio 笨拙 wavio 使用标准库 wave 处理WAV文件格式。

例如,

In [21]: import numpy as np

In [22]: import wavio

In [23]: rate = 22050             # samples per second

In [24]: T = 3                    # sample duration (seconds)

In [25]: f = 440.0                # sound frequency (Hz)

In [26]: t = np.linspace(0, T, T*rate, endpoint=False)

In [27]: sig = np.sin(2 * np.pi * f * t)

In [28]: wavio.write("sine24.wav", sig, rate, sampwidth=3)

3
2018-02-04 04:17





我已经 提交了这个问题的答案 2年前,我推荐的地方 scikits.audiolab

与此同时,情况发生了变化,现在有一个可用的库,更容易使用,也更容易安装,它甚至附带了自己的副本。 libsndfile 适用于Windows和OSX的库(在Linux上,无论如何都很容易安装): PySoundFile

如果安装了CFFI和NumPy,只需运行即可安装PySoundFile

pip install soundfile --user

编写24位WAV文件很简单:

import soundfile as sf
sf.write('my_24bit_file.wav', my_audio_data, 44100, 'PCM_24')

在这个例子中, my_audio_data 必须是一个NumPy数组 dtype  'float64''float32''int32' 要么 'int16'

顺便说一下,我做了一个 概述页面 我试图比较许多可用的Python库来读/写声音文件。


3
2017-09-02 08:32





试试吧 wave 模块:

In [1]: import wave

In [2]: w = wave.open('foo.wav', 'w') # open for writing

In [3]: w.setsampwidth(3) # 3 bytes/sample

Python只能打包2和4个大小的整数。所以你可以在int32上使用带有dtype的numpy数组,并使用列表推导来获得每个整数的3/4字节:

In [14]: d = np.array([1,2,3,4], dtype=np.int32)

In [15]: d
Out[15]: array([1, 2, 3, 4], dtype=int32)

In [16]: [d.data[i:i+3] for i in range(0,len(d)*d.dtype.itemsize, d.dtype.itemsize)]
Out[16]: ['\x01\x00\x00', '\x02\x00\x00', '\x03\x00\x00', '\x04\x00\x00']

2
2018-05-27 06:23



我应该给什么? writeframes 功能? - detly
@detly:如果你从一个numpy数组开始 int32 类型,你可以只需要你需要的字节,见上文。 - Roland Smith
问题是如何编写帧,但没有写帧的例子。 - Greg


答案:


另一种选择是 wavio (也在PyPI上: https://pypi.python.org/pypi/wavio),我创建的一个小模块,解决了尚未支持24位WAV文件的scipy问题。文件 wavio.py 包含该功能 write,将numpy数组写入WAV文件。要编写24位文件,请使用参数 sampwidth=3。唯一的依赖 wavio 笨拙 wavio 使用标准库 wave 处理WAV文件格式。

例如,

In [21]: import numpy as np

In [22]: import wavio

In [23]: rate = 22050             # samples per second

In [24]: T = 3                    # sample duration (seconds)

In [25]: f = 440.0                # sound frequency (Hz)

In [26]: t = np.linspace(0, T, T*rate, endpoint=False)

In [27]: sig = np.sin(2 * np.pi * f * t)

In [28]: wavio.write("sine24.wav", sig, rate, sampwidth=3)

3
2018-02-04 04:17





我已经 提交了这个问题的答案 2年前,我推荐的地方 scikits.audiolab

与此同时,情况发生了变化,现在有一个可用的库,更容易使用,也更容易安装,它甚至附带了自己的副本。 libsndfile 适用于Windows和OSX的库(在Linux上,无论如何都很容易安装): PySoundFile

如果安装了CFFI和NumPy,只需运行即可安装PySoundFile

pip install soundfile --user

编写24位WAV文件很简单:

import soundfile as sf
sf.write('my_24bit_file.wav', my_audio_data, 44100, 'PCM_24')

在这个例子中, my_audio_data 必须是一个NumPy数组 dtype  'float64''float32''int32' 要么 'int16'

顺便说一下,我做了一个 概述页面 我试图比较许多可用的Python库来读/写声音文件。


3
2017-09-02 08:32





试试吧 wave 模块:

In [1]: import wave

In [2]: w = wave.open('foo.wav', 'w') # open for writing

In [3]: w.setsampwidth(3) # 3 bytes/sample

Python只能打包2和4个大小的整数。所以你可以在int32上使用带有dtype的numpy数组,并使用列表推导来获得每个整数的3/4字节:

In [14]: d = np.array([1,2,3,4], dtype=np.int32)

In [15]: d
Out[15]: array([1, 2, 3, 4], dtype=int32)

In [16]: [d.data[i:i+3] for i in range(0,len(d)*d.dtype.itemsize, d.dtype.itemsize)]
Out[16]: ['\x01\x00\x00', '\x02\x00\x00', '\x03\x00\x00', '\x04\x00\x00']

2
2018-05-27 06:23



我应该给什么? writeframes 功能? - detly
@detly:如果你从一个numpy数组开始 int32 类型,你可以只需要你需要的字节,见上文。 - Roland Smith
问题是如何编写帧,但没有写帧的例子。 - Greg


使用 wave 模块, Wave_write.writeframes 函数期望WAV数据以小端格式打包成3字节字符串。以下代码可以解决问题:

import wave
from contextlib import closing
import struct

def wavwrite_24(fname, fs, data):
    data_as_bytes = (struct.pack('<i', int(samp*(2**23-1))) for samp in data)
    with closing(wave.open(fname, 'wb')) as wavwriter:
        wavwriter.setnchannels(1)
        wavwriter.setsampwidth(3)
        wavwriter.setframerate(fs)
        for data_bytes in data_as_bytes:
            wavwriter.writeframes(data_bytes[0:3])

2
2018-05-27 06:34



我认为你的缩放应该是 (2**23-1) 或者你的样品会在翻转时签字 samp == 1.0 - papahabla
嗯,很棘手。这是固定点的固有问题 - -1可以表示,但+1不能。缩放 2**23-1表示-1映射到 -2**23+1,这是错误的...但可能不如翻转标志错误。 (剪辑为 2**23-1 会更好,但我认为它可能会添加很多代码。) - detly
根据我的经验,仅仅进行扩展是相当标准的做法。从技术上讲,每个价值也都是浮动的。该 ideal 转换为整数也包括舍入。 - papahabla
@paphabla这些值没有被覆盖,而是被截断,所以 int(1.2) 是1但是 int(-1.2) 是-1 不 -2(如 int(floor(-1.2)) 会回来) - Joe


你应该试试 scikits.audiolab

import numpy as np
from scikits.audiolab import Sndfile, Format

sig = np.array([0, 1, 0, -1, 0], dtype=np.float32)
f = Sndfile('test_pcm24.wav', 'w', Format('wav', 'pcm24'), 1, 44100)
f.write_frames(sig)
f.close()  # use contextlib.closing in real code

并再次阅读:

f = Sndfile('test_pcm24.wav')
sig = f.read_frames(f.nframes, dtype=np.float32)
f.close()  # use contextlib.closing in real code

scikits.audiolab 使用 libsndfile,因此除了WAV文件,您还可以使用FLAC,OGG和更多文件格式。


2
2017-07-03 08:43



+1我怎么会错过这个? - detly
请注意,目前(audiolab版本0.11.0)存在一个错误 read_frames() 指定其他类型时 float64: github.com/cournape/audiolab/issues/3 - Matthias
我刚刚发现尝试在Windows上安装它是多么的糟糕。改变答案 wavio。 - detly
@detly我创造了 另一个答案 提示 PySoundFile。你觉得怎么样? - Matthias
我会试一试!对不起,我没有去 您,我只有两天的挫折和依赖地狱。 - detly


这是更新版本 scipy.io.wavfile 这增加了:

  • 24位.wav文件支持读/写,
  • 访问提示标记,
  • 提示标记标签,
  • 一些其他元数据,如音高(如果已定义)等。

wavfile.py(增强版)


0
2017-12-11 19:17