играть аккорд в питоне

Я хочу сделать платформу для игры аккордами, как это делает гитара. Например, чтобы сыграть аккорд E, он играет [0, 2, 2, 1, 0, 0] (от струны Low-E к струне High-E).

Я пытаюсь играть аккорды на питоне, одновременно воспроизводя все разные струны (используя потоки).

Проблема в том, что каждый раз, когда я начинаю играть на следующих струнах, кажется, что последняя струна перестает играть, и что ее заменяет новая. Так что все, что я слышу после игры аккорда, это самая высокая струна (последняя).

Я использую темы неправильно? Или это проблема с текущими функциями? Или, может быть, это функция 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.

Из того, что я проверил, функции play() и get_freq() не вызывают никаких проблем.

Так в чем проблема, и как я могу это исправить?

Редактировать:

Я пробовал это на С#, но это тоже не сработало. Это правильный способ запуска потоков в С#?

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

person Tom    schedule 29.10.2016    source источник
comment
Python не поддерживает истинное параллельное выполнение потоков в пределах одного экземпляра интерпретатора. Это связано с тем, что базовый код интерпретатора Python частично написан на C, и есть некоторые проблемы с обеспечением потокобезопасности кода. Чтобы добиться этого, вам нужно будет запустить другой интерпретатор Python и запустить там поток. Затем ваша ОС обрабатывает параллельное выполнение потоков. Я думаю, однако, что начинать ноты в одно и то же время может быть немного сложно. Удачи!   -  person Ukimiku    schedule 29.10.2016
comment
Спасибо за быстрый ответ, буду пробовать! Как вы думаете, я мог бы сделать то же самое в C#, и это сработало бы? Что проблема только в питоне?   -  person Tom    schedule 29.10.2016
comment
Я не знаю, как обстоят дела в C#. Я полагаю, это зависит от того, закодировано ли программное обеспечение для воспроизведения заметок потокобезопасным способом. Вам нужно будет проверить документацию. С Уважением   -  person Ukimiku    schedule 29.10.2016
comment
Один из вариантов — поместить аккорд в файл MOD/XM/IT и сыграть его с помощью BASS. Я вижу, что есть модуль Python для BASS, но сам не пробовал. (И вопиющий плагин для OpenMPT как хороший способ сделать такие файлы!)   -  person cxw    schedule 29.10.2016
comment
Использование потоков таким образом не годится ни для одного языка, потому что базовая система потоков в большинстве ОС не гарантирует ничего о том, когда она будет выполнена. Еще одной проблемой может быть модуль звукового сигнала, который, я не знаю, может поддерживать воспроизведение только одной ноты за раз. Вы должны сделать простую реализацию синтезатора, которая обрабатывает, скажем, до N частот с некоторой заданной продолжительностью, а затем иметь функцию для создания сэмплов на основе этой информации.   -  person J. P. Petersen    schedule 29.10.2016
comment
Привет, Дж. П. Петерсен, я не очень понял ваше предложение, не могли бы вы объяснить его мне? cxw спасибо за ваше предложение, но оно кажется мне слишком сложным для создания нового файла мода для каждого кода, который я играю, и это может даже занять некоторое время расчета, и я хочу, чтобы аккорды работали плавно и без задержек.   -  person Tom    schedule 30.10.2016
comment
Ukimiku Я пытался делать это параллельно с разными файлами python (я сделал 1 файл на гитарную струну, всего 6 файлов), но похоже не работает...   -  person Tom    schedule 31.10.2016
comment
Функция Beep() звучит как неправильный инструмент для игры аккордами. Рассматривали ли вы вместо этого использование PyAudio?   -  person blubberdiblub    schedule 29.04.2017


Ответы (3)


Gevent сделал бы это намного проще. Хотя технически переключение контекста все еще является однопоточным, оно настолько быстрое, что может показаться одновременным. Вы даже можете использовать GIPC для многопоточной двунаправленной многопроцессорной связи.

Однако я думаю, что ваша проблема намного проще. Ваша проблема связана с модулем Windsound. Звуковой сигнал не асинхронный. Так что это ваше ограничение. Вам нужно использовать

winsound.SND_ASYNC

Это позволит вам отправить несколько событий для одновременного воспроизведения.

person eatmeimadanish    schedule 11.04.2018
comment
Итак, как вы используете winsound.SND_ASYNC? Какие аргументы нужны? - person fasterthanlight; 25.06.2020
comment
winsound.PlaySound("*", winsound.SND_ASYNC) docs.python.org/2/library/winsound.html - person eatmeimadanish; 25.06.2020

Python не поддерживает истинное параллельное выполнение потоков. Многопоточность с Python создаст новый процесс. Однако вы не сможете получить доступ к процессу, чтобы управлять им после его запуска, поэтому время может быть отключено, если вы создали новый процесс для выполнения.

Однако вы можете создать серию библиотек для каждой базовой заметки и использовать библиотеку сопрограмм, например gevent, для управления временем. и исполнение этих нот объединить в аккорд.

person castaway2000    schedule 05.04.2018

Я бы действительно предложил не использовать для этого потоки, это не обязательно и очень запутанно для решения вашей проблемы с полифонией. Альтернативным решением может быть доступ к сэмплам воспроизводимой в данный момент строки и простое суммирование с ней любых вновь воспроизводимых строк. ОДНАКО, учитывая, что вы используете winsound, это, вероятно, невозможно. Поэтому я бы предложил посмотреть на какой-то другой способ воспроизведения и/или генерации звука с помощью python поиск показывает это

person Rampartisan    schedule 05.04.2018