【问题标题】:Sound generated not being saved to a file, as it should生成的声音没有被保存到文件中,因为它应该
【发布时间】:2017-12-15 00:07:37
【问题描述】:

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

【问题讨论】:

    标签: python audio pyaudio wave


    【解决方案1】:

    我认为主要问题是您使用了 float32 模块不支持的 float32 数据类型。 您可以使用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 并修复 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)转换为适当范围内的整数,具体取决于您要使用的数据类型。 我上面提到的第一个链接包含文件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)
    

    【讨论】:

    • 我不想使用 sounddevice 因为它在 Windows 10 上不起作用,我尝试更改为 int32 但是当我更改时: astype(np.float32) 到 astype(np.int32) 我得到了没有声音
    • 我设法让它工作,但现在我听到了音频gist.github.com/badjano/c727b20429295e2695afdbc601f2334b的咔嗒声
    • 我怀疑咔哒声是因为您正在创建一个一秒钟的信号并播放两次?使用我修改后的代码一次生成整个两秒信号怎么样?另外,不要忘记2的因素,否则你的音色会太低八度。
    • 我在我的 Mac 上测试了你的代码,它好多了,而且不处理 insted 的浮点数也很好......太糟糕了,它在 Windows 上不起作用,我想做一些适用于 3 个主要操作系统
    • sounddevice 模块确实一般适用于所有 3 个主要操作系统,包括 Windows,特别是包括 Windows 10。但在某些系统上似乎存在问题: github.com/spatialaudio/python-sounddevice/issues/7.
    猜你喜欢
    • 2021-10-29
    • 1970-01-01
    • 2014-10-24
    • 1970-01-01
    • 2019-04-04
    • 1970-01-01
    • 2012-01-21
    • 2014-01-07
    • 1970-01-01
    相关资源
    最近更新 更多