AKMetronome обратный отсчет, как опубликовать sh в главном потоке из фонового потока для запуска рекордера? - PullRequest
0 голосов
/ 03 мая 2020

Я изучал, как реализовать обратный отсчет Метронома с помощью библиотеки AudioKit, но столкнулся с проблемой, связанной с потоками и моей реализацией.

Моя реализация использует AudioKit AKMetronome, метод для обработки metronome.start и обработчик metronome.callback для запуска recording после завершения заданного количества тактов.

init () {
  metronome.callback = handler
}

func record () {
    self.metronome.start()
}

Обработчик вычисляет позицию метронома во времени и, если желаемое количество тактов завершается ( обратный отсчет), рекордер запускается.

К сожалению, выполнение .record из AKNodeRecorder в .callback handler из AKMetronome вызывает предупреждение:

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

По этой причине вызов начала записи в обработчике metronome.callback передается в основной поток через GCD API:

            DispatchQueue.main.sync {
                do {
                    try self.recorder.record()
                } catch {
                    print("[ERROR] Oops! Failed to record...")
                }
            }

Я использовал метод блокировки .sync, чтобы разрешить вычисление немедленно, насколько это возможно, поскольку синхронизация имеет решающее значение в аудиоприложениях (в идеале вызов должен выполняться в режиме реального времени); Понимаю ли я, что GCP API main thread обеспечивает наивысший приоритет, но я не уверен, что это лучший вариант для чувствительных ко времени приложений?

Хотел бы получить отзывы или указания, если это возможно, от другие пользователи, спасибо!

Ответы [ 2 ]

1 голос
/ 03 мая 2020

ОК, так что настоящий вопрос не имеет ничего общего с метрономами или обратным отсчетом? Что вы действительно хотите знать, так это то, что использование sync из фонового потока приведет меня к основному потоку быстрее?

Если так: в основном нет. Это не то, для чего sync или что это значит. Разница async / sync абсолютно не влияет на скорость. Если вы попадете в основной поток, используя async, вы включите его, как только он освободится, поэтому вы ничего не получите, сказав sync.

Более того, если вы уже поступили в ответный вызов в фоновом потоке async, любой возможный ущерб уже нанесен; ваше время теперь неточное, и вы ничего не можете с этим поделать, если у вас не окажется машина времени в вашем кармане.

0 голосов
/ 04 мая 2020

Следуя совету @matt относительно вызовов внутри обратных вызовов, я применил подход, основанный на .scheduledTimer из Timer.

func record () {
    metronome.restart()
    Timer.scheduledTimer(withTimeInterval: self.barLength, repeats: false) { _ in
        self.startRecording()
        print("Timer fired!")
    }
}

record - это handler, который инициирует AKMetronome, для которого было выбрано .restart, так что каждый раз запрашиваемый начинается с самого начала.

Свойство .barLength содержит значение для вычисленной длины the desired countdown. Вызванный метод .startRecording - это обработчик, который отвечает за вызов AKRecorder .record.

Будущий читатель, помните, что Timer не должен быть точным в соответствии с ( Точность NSTimer ), но, к сожалению, это лучший подход, который я тестировал, и я нашел до сих пор.

...