Необъяснимое отставание в классе для сэмплирования звука с PyAudio
Используя классы, которые я написал ниже, я сталкиваюсь с, по-видимому, невозможными временными проблемами. когда AudioStream.sample()
вызывается в цикле, первый образец занимает около 12-14 мс. Каждый последующий вызов занимает около 280 мс. Я не могу понять, почему. Более того, я рассчитал каждый отдельный шаг в потоке, и в совокупности они составляют в целом ~12-14 мс. Оставшиеся 265мс я не могу объяснить. Я запустил это на двух компьютерах - MacBook и совершенно новом iMac (3,2 ГГц, 16 ГБ ОЗУ), с почти одинаковыми результатами синхронизации (я просто использую time.time()
Кстати).
Я пробовал:
- снижение частоты дискретизации
- разные размеры куска
- используя настройки платформы для потоковой передачи
- используя только вход
- используя один канал
Ни один из них не имеет более чем незначительного (то есть микросекунды, в лучшем случае, миллисекунды или две) воздействия. Я просто в тупик.
import pyaudio
import wave
from array import array
class AudioSample(object):
def __init__(self, raw_sample):
super(AudioSample, self).__init__()
self.array = array('h', raw_sample) # ~7.8^-6s
self.peak = max(self.array) # ~4.3^-5s
self.trough = min(self.array) # ~4.2^-5s
self.mean = sum(self.array) / len(self.array) # ~1.6^-5s
class AudioStream(object):
p = None
stream = None
def __init__(self):
super(AudioStream, self).__init__()
self.p = pyaudio.PyAudio()
def sample(self): # ~0.28s after the first time
try:
chunk = self.stream.read(1024) # ~0.01s
return AudioSample(chunk, 100) # ~0.001s
except IOError: # in case of buffer overflow
self.init_stream() # ~0.004s
return self.sample()
def init_stream(self):
try:
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
except (AttributeError, IOError) as e:
pass # on first pass, no stream exists; on subsequent passes, extant stream should be stopped & overwritten
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=pyaudio.paInt16, channels=2, rate=44100, input=True, output=True, frames_per_buffer=1024)
1 ответ
Глупая проблема, в конце концов; "задержка" была вызвана тихой обработкой IOError путем повторного вызова sample()
Способ; оказывается, что это исключение (выброшенное из-за переполнения буфера) возрастало в десятки раз, в зависимости от другой активности во время цикла.
Управление размером порции и частотой дискретизации было одной из стратегий (но это требует контекстно-зависимого тестирования). Мое решение, в конце концов, другое; если потеря контекста из буфера не является проблемой для контекста, второй аргумент PyAudio stream.read()
Метод - это логическое значение, которое отключает выдачу исключений для переполнения буфера, поэтому получим следующее решение:
chunk = self.stream.read(1024, False)