生成的声音没有保存到文件中,因为它应该

Sound generated not being saved to a file, as it should

我在 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

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

我写了一篇little tutorial about the wave module (including how to handle 24-bit data) and an overview about different modules for handling sound files。 您可能还对我关于 creating a simple signal.

的教程感兴趣

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

如果你想听从我的建议,你的代码可能会变成这样(包括 volume 的处理和修复 sinus 参数中缺少的 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.01.0)转换为适当范围内的整数,具体取决于您要使用的数据类型。 我上面提到的第一个 link 包含文件 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)