Я пытаюсь создать приложение секвенсора на iOS. На сайте Apple Developer есть образец, который заставляет аудиоустройство воспроизводить повторяющуюся шкалу, здесь:
https://developer.apple.com/documentation/audiotoolbox/incorporating_audio_effects_and_instruments
В примере кода есть файл " SimplePlayEngine.swift ", с классом" InstrumentPlayer ", который обрабатывает отправку MIDI-событий на выбранный аудиоустройство. Он порождает поток с al oop, который перебирает масштаб. Он отправляет сообщение MIDI Note On, вызывая AUScheduleMIDIEventBlock аудиоустройства, на короткое время спит нить, отправляет ноту Off и повторяет.
Вот сокращенная версия:
DispatchQueue.global(qos: .default).async {
...
while self.isPlaying {
// cbytes is set to MIDI Note On message
...
self.audioUnit.scheduleMIDIEventBlock!(AUEventSampleTimeImmediate, 0, 3, cbytes)
usleep(useconds_t(0.2 * 1e6))
...
// cbytes is now MIDI Note Off message
self.noteBlock(AUEventSampleTimeImmediate, 0, 3, cbytes)
...
}
...
}
Это достаточно хорошо работает для демонстрации, но не требует строгой синхронизации, так как события будут планироваться всякий раз, когда поток просыпается.
Как я могу изменить его, чтобы воспроизводить шкалу в определенном темпе с образцом -точный тайминг?
Я предполагаю, что мне нужен способ заставить аудиоустройство синтезатора вызывать обратный вызов в моем коде перед каждым рендерингом с количеством кадров, которые должны быть визуализированы. Затем я могу запланировать MIDI-событие на каждое количество «х» кадров. Вы можете добавить смещение, вплоть до размера буфера, к первому параметру scheduleMIDIEventBlock
, чтобы я мог использовать его для планирования события точно в нужном кадре в данном цикле рендеринга.
I попытался использовать audioUnit.token(byAddingRenderObserver: AURenderObserver)
, но ответный звонок, который я ему дал, никогда не вызывался, хотя приложение издавало звук. Этот метод звучит так, как будто это Swift-версия AudioUnitAddRenderNotify, и из того, что я здесь прочитал, звучит как то, что мне нужно сделать - { ссылка }. Почему это не будет называться? Можно ли даже сделать этот «точный образец» с помощью Swift или мне нужно использовать C для этого?
Я на правильном пути? Спасибо за вашу помощь!