生成的声音不会保存到文件中

时间:2017-07-11 05:13:45

标签: python audio pyaudio wave

我在pyaudio中按预期生成频率为440hz的声波,但即使我使用相同的样本数组来保存wav文件,它也不会保存相同的声音,我无法找出原因

以下是代码:

import wave
import numpy as np
import pyaudio

p = pyaudio.PyAudio()

volume = 0.5  # range [0.0, 1.0]
fs = 44100  # sampling rate, Hz, must be integer
duration = 2.0  # in seconds, may be float
f = 440.0  # sine frequency, Hz, may be float
channels = 1

# open stream (2)
stream = p.open(format=pyaudio.paFloat32,
                channels=channels,
                rate=fs,
                output=True)


def get_value(i):
    return np.sin(f * np.pi * float(i) / float(fs))


samples = np.array([get_value(a) for a in range(0, fs)]).astype(np.float32)

for i in range(0, int(duration)):
    stream.write(samples, fs)

wf = wave.open("test.wav", 'wb')
wf.setnchannels(channels)
wf.setsampwidth(3)
wf.setframerate(fs)
wf.setnframes(int(fs * duration))
wf.writeframes(samples)
wf.close()

# stop stream (4)
stream.stop_stream()
stream.close()

# close PyAudio (5)
p.terminate()

https://gist.github.com/badjano/c727b20429295e2695afdbc601f2334b

1 个答案:

答案 0 :(得分:2)

我认为主要问题是您使用float32模块不支持的wave数据类型。 您可以使用int16int32,也可以使用24位整数进行手动转换。 由于您使用的是wf.setsampwidth(3),我假设您要使用24位数据?

我已经写了little tutorial about the wave module(包括如何处理24位数据)和overview about different modules for handling sound files。 您可能也对我关于creating a simple signal的教程感兴趣。

由于您已经在使用NumPy,我建议您使用支持NumPy阵列的库,并为您完成所有转换。 我个人的偏好是使用soundfile模块,但我非常偏颇。 对于播放,我还建议使用支持NumPy的库。我的建议是sounddevice模块,但我也非常偏向于此。

如果您想要遵循我的建议,您的代码可能会变成类似的内容(包括处理volume并在窦性参数中修复2的缺失因素):

from __future__ import division
import numpy as np
import sounddevice as sd
import soundfile as sf

volume = 0.5  # range [0.0, 1.0]
fs = 44100  # sampling rate, Hz
duration = 2.0  # in seconds
f = 440.0  # sine frequency, Hz

t = np.arange(int(duration * fs)) / fs
samples = volume * np.sin(2 * np.pi * f * t)

sf.write('myfile.wav', samples, fs, subtype='PCM_24')

sd.play(samples, fs)
sd.wait()

<强>更新

如果你想继续使用PyAudio,那很好。 但是,您必须手动将浮点数组(值从-1.0转换为1.0)到适当范围内的整数,具体取决于您要使用的数据类型。 我上面提到的第一个链接包含文件utility.py,其中有一个函数float2pcm()来执行此操作。

这是该功能的缩写版本:

def float2pcm(sig, dtype='int16'):
    i = np.iinfo(dtype)
    abs_max = 2 ** (i.bits - 1)
    offset = i.min + abs_max
    return (sig * abs_max + offset).clip(i.min, i.max).astype(dtype)