iOS 8 の新しい AVAudioEngine 機能を使用して単純なドラム マシンを構築していますが、ループ メカニズムを構築する方法を考えるのに苦労しています。
これを行う唯一の方法は、回転バッファをAVAudioPlayerNodes
用意し、将来的にバッファの再生を常にスケジュールするある種のジョブを用意することです。これは正しいです?
ノード (およびそのバッファー) を 1 回だけスケジュールする必要があると便利です。次に、再生ヘッドがシーケンスの最後に到達するたびに、ノードはすべて最初から再生されreset
ます。play
空のサンプル バッファを作成し、シーケンサの最後にスケジュールし、その にアタッチして、後者を試しましたcompletionHandler
が、うまくいかないようです。
self.audioEngine = [[AVAudioEngine alloc] init];
self.instrumentNodes = [[NSMutableArray alloc] initWithCapacity:12];
AVAudioMixerNode *mixer = self.audioEngine.mainMixerNode;
NSError *error;
if (![self.audioEngine startAndReturnError:&error]) {
NSLog(@"Error starting engine: %@", error);
} else {
NSLog(@"Started engine");
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Bleep_C3" withExtension:@"caf"];
AVAudioFile *file = [[AVAudioFile alloc] initForReading:url error:nil];
AVAudioPCMBuffer *buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:file.processingFormat frameCapacity:(AVAudioFrameCount)file.length];
[file readIntoBuffer:buffer error:nil];
double sampleRate = buffer.format.sampleRate;
AVAudioPCMBuffer *blankBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:buffer.format frameCapacity:0];
AVAudioPlayerNode *loopingNode = [[AVAudioPlayerNode alloc] init];
[self.audioEngine attachNode:loopingNode];
[self.audioEngine connect:loopingNode to:mixer format:[mixer outputFormatForBus:0]];
__block void (^schedule_loops)() = ^{
for (NSUInteger i = 0; i < 16; i++) {
double sampleTime = sampleRate * (0.2 * i);
double loopTime = sampleRate * (0.2 * 16);
AVAudioPlayerNode *playerNode = [[AVAudioPlayerNode alloc] init];
[self.audioEngine attachNode:playerNode];
[self.audioEngine connect:playerNode to:mixer format:[mixer outputFormatForBus:0]];
[playerNode scheduleBuffer:buffer atTime:[AVAudioTime timeWithSampleTime:sampleTime atRate:sampleRate] options:AVAudioPlayerNodeBufferInterrupts completionHandler:^{
[playerNode stop];
[playerNode reset];
[self.audioEngine disconnectNodeOutput:playerNode];
}];
[playerNode play];
if (i == 15) {
[loopingNode scheduleBuffer:blankBuffer atTime:[AVAudioTime timeWithSampleTime:loopTime atRate:sampleRate] options:AVAudioPlayerNodeBufferInterrupts completionHandler:^{
NSLog(@"Looping");
[loopingNode stop];
schedule_loops();
}];
[loopingNode play];
}
}
};
schedule_loops();
}