2016-03-10 3 views
2

Я работаю над приложением, которое запускает несколько циклов одновременно и должно поддерживать их синхронизацию.AVAudioEngine: Запуск набора AVAudioPlayerNodes сразу

Используя предыдущие наивные подходы к проблеме (не используя AVAudioEngine), я обнаружил, что программный запуск нескольких аудиоплееров в последовательности дал достаточно задержки между вызовами, чтобы сделать результаты бесполезными; биты были слышно не синхронизированы.

Могу ли я достичь такой функциональности с помощью AVAudioEngine?

В настоящее время я подключаю AVAudioPlayerNodes к микшеру, и я подключил к ним буферы и контролировал ввод оттуда. Но могу ли я начать их одновременно?

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

ответ

1

Правильный способ сделать это будет использовать смеситель аудио. Минимально у вас будет график с микшером и remoteIO.

Создать смеситель с двумя входами. Архитектура вытягивания аудиосистемы iOS будет воспроизводить ваши два аудио буфера одновременно.

0

я достиг эффект я искал с помощью цикла через AVAudioPlayerNode экземпляры, которые необходимы, чтобы быть в синхронизации, и для каждого из них:

  1. Вызова «играть»
  2. Планирования соответствующего буфера, чтобы начать в некоторое время в будущем

код выглядит примерно так:

for (AVAudioPlayerNode *playerNode in playerNodes) { 
     [playerNode play]; 
     [playerNode scheduleBuffer:loopBufferForThisPlayer atTime:startTime options:AVAudioPlayerNodeBufferLoops completionHandler:nil]; 
    } 

Время, указанное в startTime, - это время в ближайшем будущем (300 мс или около того), чтобы все игровые узлы были готовы к воспроизведению. startTime должен основываться на времени хоста; основывайте время на вашем образце, и все будет не синхронизироваться.

Все эти узлы были присоединены к AVAudioMixerNode, как описано в вопросе.

Я не заинтересован в использовании задержки таким образом; Я бы предпочел, чтобы мои узлы сказали мне, когда они будут готовы пойти ... но это работает.

2

Для объяснения еще более углубленного взглянуть на мой ответ в

AVAudioEngine multiple AVAudioInputNodes do not play in perfect sync


Вот короче:

Если ваш двигатель уже работает у вас есть @property lastRenderTime в AVAudioNode - суперкласс вашего игрока - это ваш билет на 100% выборочную рамку с точной синхронизацией ...

AVAudioFormat *outputFormat = [playerA outputFormatForBus:0]; 

const float kStartDelayTime = 0.0; // seconds - in case you wanna delay the start 

AVAudioFramePosition startSampleTime = playerA.lastRenderTime.sampleTime; 

AVAudioTime *startTime = [AVAudioTime timeWithSampleTime:(startSampleTime + (kStartDelayTime * outputFormat.sampleRate)) atRate:outputFormat.sampleRate]; 

[playerA playAtTime: startTime]; 
[playerB playAtTime: startTime]; 
[playerC playAtTime: startTime]; 
[playerD playAtTime: startTime]; 

[player... 

Кстати - вы можете достичь того же 100% выборки кадров точный результат с классом AVAudioPlayer ...

NSTimeInterval startDelayTime = 0.0; // seconds - in case you wanna delay the start 
NSTimeInterval now = playerA.deviceCurrentTime; 

NSTimeIntervall startTime = now + startDelayTime; 

[playerA playAtTime: startTime]; 
[playerB playAtTime: startTime]; 
[playerC playAtTime: startTime]; 
[playerD playAtTime: startTime]; 

[player... 

При отсутствии startDelayTime первый 100-200ms всех игроков получит обрезаны, потому что команда начала фактически берет свое время цикла выполнения, хотя игроки уже начали (ну, было запланировано) 100 % в синхронизации на сейчас. Но с startDelayTime = 0.25 Вы хорошо пойдете. И никогда не забывайте prepareToPlay ваших игроков заранее, чтобы во время начала не было никакой дополнительной буферизации или настройки - только начинать их ребята ;-)

+0

Спасибо за помощь –

Смежные вопросы