我使用python和pyaudio使用回调方法传输纯正弦音,以便稍后通过用户输入调制声音。一切都很好,除了当我运行代码时,我得到1-2秒的与警告信息相关的破解 - 嗡嗡声 ALSA lib pcm.c:7339:(snd_pcm_recover)发生了欠载 之后,正弦音正确流式传输。有关如何删除初始弹出声音的任何提示? 这是将声音传播一秒钟的代码
import pyaudio
import time
import numpy as np
CHANNELS = 1
RATE = 44100
freq = 600
CHUNK = 1024
lastchunk = 0
def sine(current_time):
global freq,lastchunk
length = CHUNK
factor = float(freq)*2*np.pi/RATE
this_chunk = np.arange(length)+lastchunk
lastchunk = this_chunk[-1]
return np.sin(this_chunk*factor)
def get_chunk():
data = sine(time.time())
return data * 0.1
def callback(in_data, frame_count, time_info, status):
chunk = get_chunk() * 0.25
data = chunk.astype(np.float32).tostring()
return (data, pyaudio.paContinue)
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
channels=CHANNELS,
rate=RATE,
output=True,
stream_callback=callback)
stream.start_stream()
time.sleep(1)
stream.stop_stream()
stream.close()
干杯
答案 0 :(得分:2)
PortAudio(PyAudio背后的库)允许您指定块大小,在PyAudio示例中通常称为CHUNK
。如果你没有指定一个,默认值为0
,在PortAudio术语中表示将自动选择块大小,甚至会从回调更改为回调!
要检查这一点,请尝试在回调中打印frame_count
(块大小的另一个名称)。我怀疑PortAudio在开始时选择一个太小的块大小,当它导致欠载时,它会增加块大小。我是对的吗?
要避免这种情况,您应该从头开始指定固定的块大小,使用:
stream = p.open(..., frames_per_buffer=CHUNK, ...)
...其中frames_per_buffer
是块大小的另一个名称。
这也更有意义,因为到目前为止您在代码中使用length = CHUNK
而不知道实际的块大小!
如果仍然导致欠载,您可以尝试进一步将块大小增加到2048
。
最后,让我冒昧地为我自己的PortAudio包装器sounddevice模块制作一个无耻的插件。它基本上与PyAudio相同,但它更容易安装,恕我直言有更好的API,它直接支持NumPy,无需你进行手动转换。
答案 1 :(得分:0)
接受的答案仍然没有提供完美的音质。从我所听到的(没有测量)来看,正弦曲线中有时会出现辍学和/或相位跳跃。基于PyAudio示例中的代码以及可以找到的内容here我找到了这个解决方案:
"""PyAudio Example: Play a wave file (callback version)."""
import pyaudio
import time
import math
from itertools import count
import numpy as np
RATE = 96000
# More efficient calculation but period = int(framer... causes high granularity for higher frequencies (15kHz becoming 16kHz for instance)
# def sine_wave(frequency=1000, framerate=RATE, amplitude=0.5):
# period = int(framerate / frequency)
# amplitude = max(min(amplitude, 1), 0)
# lookup_table = [float(amplitude) * math.sin(2.0 * math.pi * float(frequency) *
# (float(i % period) / float(framerate))) for i in xrange(period)]
# return (lookup_table[i % period] for i in count(0))
def sine_wave(frequency=440.0, framerate=RATE, amplitude=0.5):
amplitude = max(min(amplitude, 1), 0)
return (float(amplitude) * math.sin(2.0*math.pi*float(frequency)*(float(i)/float(framerate))) for i in count(0))
sine = [sine_wave(150), sine_wave(1500), sine_wave(15000)]
# instantiate PyAudio (1)
p = pyaudio.PyAudio()
# define callback (2)
def callback(in_data, frame_count, time_info, status):
wave = sine[0]
data = [wave.next()]
for i in range(frame_count - 1):
data.append(wave.next())
ret_array =np.array(data).astype(np.float32).tostring()
return (ret_array, pyaudio.paContinue)
# open stream using callback (3)
stream = p.open(format=pyaudio.paFloat32,
channels=1,
rate=RATE,
frames_per_buffer=1024,
output=True,
stream_callback=callback)
# start the stream (4)
stream.start_stream()
# Insert your own solution to end the sound
time.sleep(3)
# stop stream (6)
stream.stop_stream()
stream.close()
# close PyAudio (7)
p.terminate()
这应该可以正常播放,直到你的硬件死机或下次断电......但我只测试了半小时; - )