pyaudio 中的破解声音正弦音调
cracking sound sine tone in pyaudio
我正在使用 python 和 pyaudio 使用回调方法流式传输纯正弦音,以便稍后通过用户输入调制声音。一切都很好,除了当我 运行 代码时,我得到 1-2 秒的与警告消息相关的破裂的嗡嗡声
ALSA 库 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()
干杯
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,无需您进行手动转换。
接受的答案仍然没有提供完美的音频质量。从我听到的(没有测量)来看,正弦中有时会出现 and/or 相位跳变。基于 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()
这应该可以播放正弦波直到你的硬件死机或下一次断电...但我只测试了半小时;-)
我正在使用 python 和 pyaudio 使用回调方法流式传输纯正弦音,以便稍后通过用户输入调制声音。一切都很好,除了当我 运行 代码时,我得到 1-2 秒的与警告消息相关的破裂的嗡嗡声 ALSA 库 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()
干杯
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,无需您进行手动转换。
接受的答案仍然没有提供完美的音频质量。从我听到的(没有测量)来看,正弦中有时会出现 and/or 相位跳变。基于 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()
这应该可以播放正弦波直到你的硬件死机或下一次断电...但我只测试了半小时;-)