Слишком высокая задержка при воспроизведении звуковых сэмплов из командной строки с помощью модуля 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 при каждом вызове) и вместо этого реализуйте свою логику воспроизведения в своей собственной функции обратного вызова.

Другие вопросы по тегам