Python 所生成的声音不会像应该的那样保存到文件中

Python 所生成的声音不会像应该的那样保存到文件中,python,audio,pyaudio,wave,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 sec

我以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()

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

我写了一个(包括如何处理24位数据)和一个。 你也可能对我的教程感兴趣

由于您已经在使用NumPy,我建议您使用一个支持NumPy数组的库,该库支持开箱即用,并为您完成所有转换。 我个人倾向于使用这个模块,但我有很大的偏见。 对于播放,我还建议使用支持NumPy的库。这里我的建议是模块,但我在这里也很有偏见

如果您想遵循我的建议,您的代码可能会变成这样(包括处理
volume
并修复窦房结参数中缺少的
2
):


更新:

如果你想继续使用PyAudio,那很好。 但您必须手动将浮点数组(值从
-1.0
1.0
)转换为适当范围内的整数,具体取决于要使用的数据类型。 我上面提到的第一个链接包含一个文件,该文件有一个函数
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)

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

我写了一个(包括如何处理24位数据)和一个。 你也可能对我的教程感兴趣

由于您已经在使用NumPy,我建议您使用一个支持NumPy数组的库,该库支持开箱即用,并为您完成所有转换。 我个人倾向于使用这个模块,但我有很大的偏见。 对于播放,我还建议使用支持NumPy的库。这里我的建议是模块,但我在这里也很有偏见

如果您想遵循我的建议,您的代码可能会变成这样(包括处理
volume
并修复窦房结参数中缺少的
2
):


更新:

如果你想继续使用PyAudio,那很好。 但您必须手动将浮点数组(值从
-1.0
1.0
)转换为适当范围内的整数,具体取决于要使用的数据类型。 我上面提到的第一个链接包含一个文件,该文件有一个函数
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)

我不想使用sounddevice,因为它在windows 10上不工作,我尝试更改为int32,但当我将:aType(np.float32)更改为aType(np.int32)时,我没有听到声音,我设法使它工作,但是现在我听到了声音的咔嗒声,我怀疑咔嗒声来自于这样一个事实:你正在创建一个1秒的信号,然后播放两次?用我修改过的代码一次生成整个两秒钟的信号怎么样?另外,不要忘了
2
的因素,否则你的音调会太低。我在我的mac上测试了你的代码,它更好,不处理整数而不是浮点数也很好。。。太糟糕了,它不能在windows上工作,我想做一些能在3大OSs上工作的东西,
sounddevice
模块通常能在所有3大OSs上工作,包括windows,特别是windows 10。不过,某些系统上似乎存在问题:。我不想使用sounddevice,因为它在windows 10上不工作,我尝试更改为int32,但当我将astype(np.float32)更改为astype(np.int32)时,我没有听到声音,我设法使它工作,但是现在我听到了声音的咔嗒声,我怀疑咔嗒声来自于这样一个事实:你正在创建一个1秒的信号,然后播放两次?用我修改过的代码一次生成整个两秒钟的信号怎么样?另外,不要忘了
2
的因素,否则你的音调会太低。我在我的mac上测试了你的代码,它更好,不处理整数而不是浮点数也很好。。。太糟糕了,它不能在windows上工作,我想做一些能在3大OSs上工作的东西,
sounddevice
模块通常能在所有3大OSs上工作,包括windows,特别是windows 10。不过,某些系统似乎存在问题:。