Необъяснимое отставание в классе для сэмплирования звука с 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)

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