Слишком высокая задержка при воспроизведении звуковых сэмплов из командной строки с помощью модуля sounddevice
Я хочу написать программу, которая позволит мне воспроизводить сэмплы с клавиатуры компьютера практически без задержек.
Моя программа:
import numpy as np
import sounddevice as sd
import soundfile as sf
import msvcrt
sd.default.latency = 'low'
samplesarray = []
def load_samples(num):
filename='sample'+str(num)+'.wav'
data, fs = sf.read(filename, dtype='float32')
sd.default.samplerate = fs
samplesarray.append(data)
return
numberofsamples=3
for i in range(numberofsamples):
load_samples(i+1)
def play_session():
while 0==0:
key = int(msvcrt.getch())
sd.play(samplesarray[key-1])
return
play_session()
Папка программы содержит несколько коротких сэмплов "one shot" с именами sample1.wav, sample2.wav и т. Д., Например, ударные барабаны или ловушки. В этом примере для простоты загружены только три. Я могу запустить свою текущую программу в терминале и воспроизвести сэмплы, "сопоставленные" с моими клавишами, что я и хочу. Единственная проблема заключается в задержке: хотя она и не велика, она определенно заметна.
Для воспроизведения сэмплов в идеале задержка должна быть практически незаметной (порядка десятков миллисекунд).
Как я мог этого добиться?
1 ответ
Среди прочего, минимально возможная задержка зависит от используемого вами API хоста. Поскольку вы импортируете msvcrt
модуль, я полагаю, вы используете Windows, верно?
Там вы можете выбрать один из нескольких API хостов. Минимальные задержки обычно достигаются с помощью WASAPI, WDM/KS или ASIO.
Если вы используете WASAPI, вы можете попробовать эксклюзивный режим, который, вероятно, позволит снизить задержки, но я не знаю точно.
настройка latency
в 'low'
(как вы сделали) должны сделать трюк, но вы также можете поэкспериментировать с использованием различных значений для blocksize
, Но обратите внимание, что слишком малый размер блока приведет к переполнению буфера, что может привести к слышимым щелчкам.
Наконец, если вы действительно хотите выжать последнюю задержку из вашей настройки, вам, вероятно, следует избавиться от sd.play()
(который открывает новый sd.OutputStream
при каждом вызове) и вместо этого реализуйте свою логику воспроизведения в своей собственной функции обратного вызова.