现在我和一些朋友正在制作一个程序,用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测试的所有计算机都有多个物理核心。有没有办法让线程更好地同步,或者我们最好找到替代解决方案?
答案 0 :(得分:1)
选项是在播放声音之前在每个线程中有延迟。如果您对启动线程所涉及的偏移有一个合理的了解,则可以将该值作为延迟传递。
例如,假设启动线程之间有1ms的延迟:
另一种选择是让每个线程开始,但是在开始播放之前等待主进程循环到所有线程的信号。