Аудио с низкой задержкой с Python
Когда используешь pygame
при воспроизведении звука наблюдается большая задержка (>100 мс):
import pygame
pygame.init()
pygame.mixer.init()
sounda = pygame.mixer.Sound("test.wav")
def callback()
sounda.play()
# callback is called by another function, but I could measure a high latency (> 100ms)
Является pygame
причина задержки? В целом, возможно ли воспроизведение звука с низкой задержкой на Python?
Пример применения: воспроизвести некоторые файлы.wav, когда MIDI-сообщения поступают с MIDI-клавиатуры. (Я хочу закодировать очень простой музыкальный сэмплер). Конечно, задержка будет сильно зависеть от аудиоинтерфейса (ASIO или нет ASIO и т. Д.), Но теперь я хочу проанализировать, возможна ли низкая дополнительная задержка с Python, и если да, то какие модули предпочтительнее для этой цели.
1 ответ
Является ли Pygame причиной задержки?
Возможно нет.
Pygame - это просто оболочка вокруг SDL. В некоторых областях - как эта - это очень тонкая обертка.
Но SDL - или, скорее, SDL_mixer
- легко может быть проблемой.
Таким образом, вам, вероятно, нужно немного узнать о SDL, чтобы использовать pygame
для аудио, выходящего за рамки обычного игрового стиля. Аудио с SDL - хороший обзор, хотя кажется немного устаревшим.
Первое, что нужно учитывать, это то, какой аудио драйвер вы используете. Например, во многих системах linux ALSA не может воспроизводить звук с низкой задержкой, а это означает, что все, что вы пишете, в конечном итоге говорит с ALSA, не может этого сделать. И если ваша система настроена на использование esd
или какой-нибудь другой звуковой демон, если это возможно, и отступайте, если это необходимо, вы явно не хотите этого здесь. Итак, если что-то подобное является вашей проблемой, вам придется настроить SDL_mixer
использовать другой драйвер.
Предполагая, что драйвер может справиться с этим, определенно возможно сделать звук с низкой задержкой pygame.mixer
/SDL_mixer
, Но это может не работать из коробки.
Первое, что вы хотите сделать, это выбрать меньший размер буфера, чем по умолчанию.
Также обратите внимание, что SDL_mixer
автоматически перекодирует ваши звуки за вашей спиной, если они не имеют ту же частоту дискретизации / и т.д. поскольку цель, которая не только добавляет небольшую задержку для работы процессора, это также означает, что реальный размер буфера не имеет ничего общего с тем, который, как вы думаете, вы используете…
Альтернатива этому - обойти pygame.mixer
/SDL_mixer
, сделайте микширование самостоятельно и идите прямо к pygame.sound
/SDL_sound
, Это будет иметь те же проблемы с драйверами, но все, что вызвано SDL_mixer
(как перекодирование) уходит.
Если вы не можете заставить Pygame/SDL делать то, что вам нужно (например, потому что все драйверы, которые он поддерживает в вашей системе, все отстой), вам придется использовать другую библиотеку. PythonInMusic в вики имеет сотни ссылок, и вы также можете искать PyPI. Однако вы можете начать с другой стороны - найти аудио-библиотеку C, которую вы хотите использовать, а затем найти для нее привязки Python. Например, pyAudio - это относительно тонкая оболочка для PortAudio, поэтому он выглядит так, как если бы требования Portaudio по переносимости, конфигурируемости и производительности соответствовали вашим потребностям, а его API соответствовал вашему дизайну, но в противном случае это плохо.
Другое место может пойти не так в вашем коде.
Это, очевидно, не проблема в вашем случае, потому что все, что вы делаете, это дает pygame.mixer
готовый звук. Но если вы решите, что вам нужно, скажем, предварительно преобразовать звуки и буферы подачи в pygame.sound
Вы можете столкнуться с проблемой, что Python медленен в цикле и медленен в арифметике.
Под "медленным" я подразумеваю порядка микросекунд. Зацикливание буфера один раз в 20 мс не является проблемой. Цикл один раз на образец может быть. Если вы выполняете какую-либо обработку, вам следует подумать об использовании NumPy или выделенной звуковой библиотеки для выполнения работы, а не на чистом Python.