Planification d'un file audio pour la lecture à l'avenir avec AVAudioTime

J'essaie de comprendre comment corriger correctement un audiofile dans un proche avenir. Mon objective réel est de jouer plusieurs pistes synchronisées.

Donc, comment configurer correctement 'aTime' de sorte qu'il commence dans environ par exemple 0,3 secondes à partir de maintenant. Je pense que j'ai peut-être aussi besoin du hostTime, mais je ne sais pas comment l'utiliser correctement

func createStartTime() -> AVAudioTime? { var time:AVAudioTime? if let lastPlayer = self.trackPlayerDictionary[lastPlayerKey] { if let sampleRate = lastPlayer.file?.processingFormat.sampleRate { var sampleTime = AVAudioFramePosition(shortStartDelay * sampleRate ) time = AVAudioTime(sampleTime: sampleTime, atRate: sampleRate) } } return time } 

Voici la fonction que j'utilise pour démarrer la lecture:

 func playAtTime(aTime:AVAudioTime?){ self.startingFrame = AVAudioFramePosition(self.currentTime * self.file!.processingFormat.sampleRate) let frameCount = AVAudioFrameCount(self.file!.length - self.startingFrame!) self.player.scheduleSegment(self.file!, startingFrame: self.startingFrame!, frameCount: frameCount, atTime: aTime, completionHandler:{ () -> Void in NSLog("done playing")//actually done scheduling }) self.player.play() } 

Je l'ai compris!

Pour le paramètre hostTime que j'ai rempli mach_absolute_time (), il s'agit de l'heure 'now' de l'ordinateur / de l'iPad. le AVAudioTime (hostTime: sampleTime: atRate) ajoute le sampleTime au hostTime et donne dans un proche avenir un time qui peut être utilisé pour planifier plusieurs segments audio au même time de début

 func createStartTime() -> AVAudioTime? { var time:AVAudioTime? if let lastPlayer = self.trackPlayerDictionary[lastPlayerKey] { if let sampleRate = lastPlayer.file?.processingFormat.sampleRate { var sampleTime = AVAudioFramePosition(shortStartDelay * sampleRate ) time = AVAudioTime(hostTime: mach_absolute_time(), sampleTime: sampleTime, atRate: sampleRate) } } return time } 

Eh bien, c'est ObjC – mais vous aurez compris …

Pas besoin de mach_absolute_time () – si votre moteur tourne, vous avez déjà un @property lastRenderTime dans AVAudioNode – la superclass de votre lecteur …

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

En passant – vous pouvez get le même résultat précis de 100% échantillon-frame avec la class AVAudioPlayer …

 NSTimeInterval startDelayTime = 0.0; // seconds - in case you wanna delay the start NSTimeInterval now = playerA.deviceCurrentTime; NSTimeInterval startTime = now + startDelayTime; [playerA playAtTime: startTime]; [playerB playAtTime: startTime]; [playerC playAtTime: startTime]; [playerD playAtTime: startTime]; [player... 

En l'absence de startDelayTime, les 100-200 premiers de tous les joueurs seront coupés, car la command de démarrage prend son time à la boucle d'exécution bien que les joueurs aient déjà commencé (bien, programmé) 100% en synchronisation à ce jour . Mais avec un startDelayTime = 0.25, vous êtes prêt à partir. Et n'oubliez jamais de préparer vos joueurs à l'avance afin que, au moment du démarrage, aucune mise en memory tampon ou configuration supplémentaire ne soit nécessaire – juste en commençant les gars 😉


Pour une explication encore plus approfondie jetez un oeil à ma réponse

AVAudioEngine plusieurs AVAudioInputNodes ne sont pas synchronisés parfaitement