我具有各种频率的音频音调,用于不同的时间长度。我试图将这些输入切成块(无论输入频率如何,大小均相同),并在输出中清楚地再现这些块。当我使用阻止方法时,例如stream.write(),我得到一个干净的输出,但没有太多处理能力可以处理其他任务。因此,我已使用callback()函数将代码转换为非阻塞方法,如下所示。
这篇文章之后,我尝试过对代码进行模式化:https://stackoverflow.com/a/22354593/12076263但这根本不起作用。
# Generate a 250 Hz tone in chunks amounting to 100 chunks per second,
# using a non-blocking method.
#
# How does one fit a 250 Hz wave into 100 Hz packets?
# Slice up a sine wave into segments of two-and-a-half waves apiece:
#
# | | | |
# _ _ _| _ _ | _ _ _| _ _ |
# / \ / \ / \ / \ / \ / \ / \ / \ / \ / \
# \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
# | | | |
# <----X1----> | <----X2----> | <----X1----> | <----X2----> |
#
# Play back each segment in alternating fashion.
# This simulates continuous audio where zero crossings do not necessarily
# occur at the edge of a chunk.
import numpy as np
import pyaudio
import time
# based on examples from https://people.csail.mit.edu/hubert/pyaudio/docs/
def callback(in_data, frame_count, time_info, status):
waveData = Y.tobytes()
return (waveData, pyaudio.paContinue)
Y = np.zeros((441), dtype = np.int16) # initialize audio array Y
p = pyaudio.PyAudio()
stream = p.open(format = 8, # 8 is code for int16 format
channels = 1,
rate = 44100,
frames_per_buffer = 441,
stream_callback = callback, # !! COMMENT OUT to enable blocking
output = True)
stream.start_stream()
X1 = np.linspace(0, 5 * np.pi, num = 441, endpoint = False)
Y1 = (5000 * np.sin(X1)).astype(np.int16) # Generate two-and-a-half waves
X2 = np.linspace(5 * np.pi, 10 * np.pi, num = 441, endpoint = False)
Y2 = (5000 * np.sin(X2)).astype(np.int16) # The "other" two-and-a-half waves
# Play the two wave segments one after the other
# Result should be a clean 250 Hz tone
while True:
Y = Y1 # First set of waves
time.sleep(0.0015) # This 1.5 millisecond delay
# simulates other stuff happening
# within the While loop.
#stream.write(Y.tobytes()) # !! UNCOMMENT to use blocking method
Y = Y2 # Second set of waves
time.sleep(0.0015) # More miscellaneous delays
#stream.write(Y.tobytes()) # !! UNCOMMENT to use blocking method
[预期无失真(随着数字音频的发展)正弦波,并产生了严重失真的声音,就像一个巨大的电影怪兽的吼声。通常没有错误消息,但是如果增加time.sleep值,则可能发生欠载。如果完全删除了time.sleep语句,问题就消失了,但是将使用该语句的完整应用程序每个块至少要有1.5毫秒的处理负载。
要部分回答我自己的问题,关键是使用队列在主循环和回调函数之间传输数据。现在声音没有失真。但是,阻塞似乎对While循环中运行的每个语句的执行时间有重大影响。当然,整个循环的速度会变慢,但是它会以正确的刷新率循环。我希望看到语句inwith循环以正常速度运行,但是它们每个都以正常速度的1/5运行。
# Generate a 250 Hz tone in chunks amounting to 100 chunks per second,
# using a non-blocking method.
#
# How does one fit a 250 Hz wave into 100 Hz packets?
# Slice up a sine wave into segments of two-and-a-half waves apiece:
#
# | | | |
# _ _ _| _ _ | _ _ _| _ _ |
# / \ / \ / \ / \ / \ / \ / \ / \ / \ / \
# \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
# | | | |
# <----X1----> | <----X2----> | <----X1----> | <----X2----> |
#
# Play back each segment in alternating fashion.
# This simulates continuous audio where zero crossings do not necessarily
# occur at the edge of a chunk.
import numpy as np
import pyaudio
import time
import queue
# based on examples from https://people.csail.mit.edu/hubert/pyaudio/docs/
def callback(in_data, frame_count, time_info, status):
Y = qu.get()
waveData = Y.tobytes()
return (waveData, pyaudio.paContinue)
qu = queue.Queue(maxsize = 1) # 1 complete buffer (of length 441)
Y = np.zeros((441), dtype = np.int16) # initialize audio array Y
p = pyaudio.PyAudio()
stream = p.open(format = 8, # 8 is code for int16 format
channels = 1,
rate = 44100,
frames_per_buffer = 441,
stream_callback = callback,
output = True)
stream.start_stream()
X1 = np.linspace(0, 5 * np.pi, num = 441, endpoint = False)
Y1 = (5000 * np.sin(X1)).astype(np.int16) # Generate two-and-a-half waves
X2 = np.linspace(5 * np.pi, 10 * np.pi, num = 441, endpoint = False)
Y2 = (5000 * np.sin(X2)).astype(np.int16) # The "other" two-and-a-half waves
# Play the two wave segments one after the other
# Result should be a clean 250 Hz tone
while True:
qu.put(Y1) # First set of waves
time.sleep(0.0015) # This 1.5 millisecond delay
# simulates other stuff happening
# within the While loop.
qu.put(Y2) # Second set of waves
time.sleep(0.0015) # More miscellaneous delays
我的问题的另一部分是如何加快执行速度,因为while循环内发生了很多处理。但是,某些事情正在使时间紧迫的代码减慢大约5倍。代码的“ while”部分已被下面的代码替换。如果将qu.put语句注释掉,则t2减去t1快5倍,这很奇怪,因为qu.put在时间关键代码测量间隔之外。
import time
from multiprocessing import Process
def whileLoop():
while True:
qu.put(Y1)
t1 = time.time()
# time-critical processing code goes here
# must run in < 10ms to prevent audio underrun
t2 = time.time()
qu.put(Y2)
t3 = time.time()
# more time-critical processing code goes here
# must run in < 10ms to prevent audio underrun
t4 = time.time()
if __name__ == '__main__':
pr = Process(target = whileLoop)
pr.start()
pr.join()