4

我正在开发一个同时启动多个循环的应用程序,并且应该保持它们的同步。

使用以前的幼稚方法解决问题(不使用 AVAudioEngine),我发现以编程方式依次启动多个音频播放器会在调用之间产生足够的延迟,从而使结果无用;节拍听上去不同步。

我可以使用 AVAudioEngine 实现这种功能吗?

目前我正在将 AVAudioPlayerNodes 连接到混音器,并且我已经将缓冲区附加到它们并从那里控制输入。但是我可以让它们同时启动吗?

似乎在我调用播放之前节点不会开始产生声音,并且在引擎启动之前无法完成......

4

3 回答 3

4

如需更深入的解释,请查看我的答案

AVAudioEngine 多个 AVAudioInputNode 不能完美同步播放


简而言之:

如果您的引擎已经在运行,那么您在 AVAudioNode 中有一个@property lastRenderTime - 您的播放器的超类 - 这是您获得 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...

顺便说一句-您可以使用 AVAudioPlayer 类实现相同的 100% 样本帧准确结果...

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-200 毫秒将被剪掉,因为尽管播放器现在已经开始(好吧,被安排)100% 同步,但 start 命令实际上需要时间进入运行循环。但是如果startDelayTime = 0.25,你就可以开始了。并且永远不要忘记提前准备好你的球员,这样在开始时就不需要额外的缓冲或设置 - 只是让他们开始;-)

于 2016-06-02T22:21:44.467 回答
1

正确的方法是使用混音器音频单元。至少你会有一个带有混音器和 remoteIO 的图表。

创建一个有两个输入的混音器。iOS 音频系统的 pull 架构会同时播放你的两个音频缓冲区。

于 2016-03-11T03:29:58.803 回答
0

我通过循环遍历需要同步的 AVAudioPlayerNode 实例来实现我想要的效果,并且对于每个实例:

  1. 叫“玩”
  2. 安排适当的缓冲区在未来某个时间开始

代码看起来像这样:

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

startTime 中指定的时间是在不久的将来(300 毫秒左右)的时间,以确保所有玩家节点都准备好​​播放。startTime 必须基于主机时间;将时间基于您的样本,事情将不同步。

如问题中所述,所有这些节点都附加到 AVAudioMixerNode 。

我不热衷于以这种方式使用延迟。我希望我的节点告诉我他们什么时候准备好……但这有效。

于 2016-03-11T10:01:48.703 回答