2016-03-10 1 views
2

Je travaille sur une application qui démarre un certain nombre de boucles simultanément, et qui doit maintenir sa synchronisation.AVAudioEngine: Démarrer un jeu de AVAudioPlayerNodes en même temps

En utilisant les approches précédentes et naïves du problème (sans utiliser AVAudioEngine), j'ai trouvé que le démarrage par programme d'un certain nombre de lecteurs audio dans la séquence donnait assez de retard entre les appels pour rendre les résultats inutiles; les battements étaient audibles. Puis-je obtenir ce type de fonctionnalité avec AVAudioEngine?

Actuellement, je suis en train de câbler AVAudioPlayerNodes à un mélangeur, et je leur ai attaché des tampons et contrôlé les entrées à partir de là. Mais puis-je les faire tous commencer en même temps?

Il semble que les nœuds ne commencent pas produire des sons jusqu'à ce que j'appelle le jeu, et qui ne peut être fait avant que le moteur commence ...

Répondre

1

La bonne façon de le faire serait d'utiliser un mélangeur unité audio. Au minimum, vous auriez un graphique avec un mélangeur et un remoteIO.

Créez un mélangeur avec deux entrées. L'architecture de traction du système audio iOS jouera vos deux tampons audio simultanément.

0

J'atteint l'effet que je recherchais en boucle à travers les instances de AVAudioPlayerNode qui devaient être synchronisés, et pour chacun:

  1. Calling « jouer »
  2. Planification du tampon approprié pour commencer à un peu de temps à l'avenir

le code ressemble à ceci:

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

L'heure spécifiée dans startTime est une heure dans le futur proche (300 ms environ) pour s'assurer que tous les nœuds de joueurs sont prêts à jouer. startTime doit être basé sur l'heure de l'hôte; baser l'heure sur votre échantillon et les choses ne seront plus synchronisées.

Tous ces nœuds ont été attachés à un AVAudioMixerNode comme décrit dans la question. Je ne souhaite pas utiliser un retard de cette manière; Je préférerais que mes nœuds me disent quand ils étaient prêts à partir ... mais ça fonctionne.

2

Pour une explication plus encore en profondeur un coup d'oeil à ma réponse à

AVAudioEngine multiple AVAudioInputNodes do not play in perfect sync


Voici en bref:

Si votre moteur est déjà vous en cours d'exécution obtenu un @property lastRenderTime dans AVAudioNode - superclasse de votre lecteur - Ceci est votre ticket pour une synchronisation 100% échantillon-trame ...

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... 

Par ailleurs - vous pouvez obtenir le même résultat précis d'échantillons cadre 100% avec la classe 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... 

Sans startDelayTime le premier 100-200ms de tous les joueurs auront coupé hors parce que la commande de démarrage prend réellement son temps à la boucle d'exécution, bien que les joueurs ont déjà commencé (bien, été programmée) 100 % en synchronisation à maintenant. Mais avec startDelayTime = 0,25 vous êtes prêt à partir. Et n'oubliez jamais de prepareToPlay vos joueurs à l'avance afin que, au moment du démarrage, aucune mise en mémoire tampon ou configuration supplémentaire doit être fait - juste les commencer les gars ;-)

+0

Merci pour l'aide –