在python中演奏和弦

时间:2016-10-29 11:09:41

标签: python audio python-multithreading music-notation

我想做一个像吉他一样弹奏和弦的平台。 例如 - 要播放E和弦,它会播放[0,2,2,1,0,0](从Low-E字符串到High-E字符串)。

我试图通过同时播放所有不同的字符串(通过使用线程)在python上弹奏和弦。

问题是每次我开始播放下一个字符串时,似乎最后一个字符串停止播放,而新的字符串会替换它。所以我在弹奏和弦后听到的是最高弦(最后一个)。

我是否正确使用线程?或者它是当前功能的问题?或者也许是winsound.Beep()函数可以处理这类事情?

这是我的代码:

from winsound import Beep
import threading
import time


def play(freq, dur):
    Beep(round(freq), round(dur))


def get_freq(string, fret):
    a3_freq = 220
    half_tone = 2 ** (1 / 12)

    higher_from_a3_by = 5 * (string - 2) + fret
    if string > 4:
        higher_from_a3_by += 1
    return a3_freq * half_tone ** higher_from_a3_by


def strum(string, fret, time):
    freq = get_freq(string, fret)
    t = threading.Thread(target=play, args=(freq, time))
    t.start()
    return t


def chord(frets, dur):
    threads = []
    for i in range(6):
        if frets[i] != -1:
            threads.append(strum(i + 1, frets[i], dur))
    for t in threads:
        t.join()


chord((-1, 0, 2, 2, 2, 0), 1000) # plays the A chord for one second, for example.

从我解决的问题来看,playwt()和get_freq()函数都没有任何问题。

那么问题是什么,我该如何解决呢?

编辑:

我在C#中尝试过它,但它也没有用。这是在C#中启动线程的正确方法吗?

foreach (Thread t in threads)
    t.Start();
foreach (Thread t in threads)
    t.Join();

3 个答案:

答案 0 :(得分:1)

Gevent会让这更容易。虽然技术上仍然是单线程,但是上下文切换速度非常快,因此它可以同时显示。您甚至可以使用GIPC进行多线程双向多进程通信。

但是我觉得你的问题要简单得多。你的问题是windsound模块。嘟嘟声不是异步的。这是你的限制。你需要使用

winsound.SND_ASYNC

这将允许您同时发送多个事件进行播放。

答案 1 :(得分:0)

Python不支持线程的真正并行执行。使用python进行多线程处理将产生一个新进程。但是,一旦运行,您将无法访问该进程来管理它,因此如果您生成了一个要执行的新进程,则时间可能会关闭。

但是,您可以为每个基础音符创建一系列库,并使用像gevent这样的协程库来管理这些音符的时序和执行,以便组合成一个和弦。

答案 2 :(得分:0)

我真的建议不要使用线程,解决你的复音问题是没有必要和非常复杂的。另一种解决方案可以是访问当前正在播放的字符串的样本,并简单地将任何新播放的字符串与其相加。但是,当您使用winsound时,这可能是不可能的。因此,我建议使用python a quick search shows this

查看其他一些播放和/或生成声音的方法