现在有些朋友和我正在制作一个程序,用Python中的方波生成音乐(我们还处于开发阶段) . 沿途的一个障碍是我们认为PyAudio一次只能播放一个声音,如果你试图互相播放声音,例如为了制作一个和弦,声音会相互覆盖 . 我们当前的策略是使用线程来绕过它,它几乎可以工作,但是线程启动的时间非常短暂 . 以下是我们生成C大调和弦的代码片段:
import numpy as np
import pyaudio
import math
from scipy import signal
import multiprocessing
from time import time
def noteTest(frequency):
l = np.linspace(0, 2, 384000, endpoint=False)
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16, channels=1, rate=192000, output=True)
wave_data = signal.square(2 * math.pi * frequency * l)
stream.write(wave_data)
def playNotes():
if __name__ == "__main__":
multiprocessing.Process(target = noteTest, args = [523.25113060119]).start()
print(time())
multiprocessing.Process(target = noteTest, args = [659.25511382575]).start()
print(time())
multiprocessing.Process(target = noteTest, args = [783.99087196355]).start()
print(time())
playNotes()
当我查看程序的输出时,这是它给出的时间:
1510810518.870557
1510810518.8715587
1510810518.8730626
如你所见,线程相隔千分之一秒 . 这令人惊讶地显而易见,即使只有一个和弦,但我们担心如果我们试图制作一首真正的歌曲,这将成为一个更大的问题,因为曲目将分开并彼此消失 . 请注意,我们使用DO测试的所有计算机都有多个物理核心 . 有没有办法让线程更好地同步,或者我们最好找到替代解决方案?
1 回答
一个选项是在播放声音之前在每个线程中有一个延迟 . 如果您对启动线程所涉及的偏移有一个合理的了解,则可以将该值作为延迟传递 .
例如,假设启动线程之间有1ms的延迟:
0ms:启动线程1,延迟1ms
0ms:线程1在新核心上启动,等待
1ms:启动线程2,没有延迟
1ms:线程1在延迟后开始播放
1ms:线程2在新核心上启动,没有延迟,并开始播放
另一种选择是让每个线程启动,但在开始播放之前等待主进程循环到所有线程的信号 .