Play and stop a sound sample on iOS (Novocaine)
I'm trying to make a simple Drumpad app. The app needs to be super fast and play the sound with as little latency as possible. The premise is store audio samples in an array and each one is played when you hit a pad.
The catch is that some pads are chords (and not drums) so they need to stop right away On Touch Up.
Here are the approaches I have tried:
System Sound - Very simple to implement, super responsive, no way to stop sounds without destroying them, sounds cant be more than 30 seconds.
AV Framework - Way to slow.
The Amazing Audio Engine - Seems nice, but not sure what the advantage is over CoreAudio as setup was rather complicated I wasn't able to get a sound to play. Also not sure about latency.
Novocaine - I settled on this for now, it seems very fast, and I can play sounds, but I've seen no way to stop them once they start. I don't know how I can stop a single sound without stopping the whole audioManager?
- (void) playSoundN:(int)padNum
{
__weak ViewController * wself = self;
NSURL *inputFileURL = [[NSBundle mainBundle] URLForResource:@"Drum - Kick" withExtension:@"wav"];
self.fileReader = [[AudioFileReader alloc]
initWithAudioFileURL:inputFileURL
samplingRate:self.audioManager.samplingRate
numChannels:self.audioManager.numOutputChannels];
[self.fileReader play];
self.fileReader.currentTime = 0.0;
[self.audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)
{
[wself.fileReader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels];
NSLog(@"Time: %f", wself.fileReader.currentTime);
}];
[self.audioManager play];
}
Seems like a simple task, starting and stoping a sound with super low latency.
Should I use one of the above approaches or just bite the bullet and dive into Core Audio Units.
Anyone have any ideas?
I just made an app that has similar functionality to what you are trying to accomplish. My recommendation:
prepareToPlay
method of the class to preload the sound and reduce lag. You can read more about the classes in the AVFoundation
documentation: https://developer.apple.com/library/ios/DOCUMENTATION/AVFoundation/Reference/AVFoundationFramework/_index.html
Surprisedly, alexbw accepted the patch quickly. If you updated to newest code, you may simply use following lines in output block:
[weakSelf.reader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels];
if (!weakSelf.reader.playing) {
weakSelf.audioManager.outputBlock = nil;
dispatch_async(dispatch_get_main_queue(), ^{
// UI stuff
});
}
Novocaine cannot tell EOF of the file, the last buffer is used repeat. Considering the author think AudioFileReader is just a piece of sugar and not likely to fix it, here is a dirty solution.
__block float lastTimeLeft = 0.0f;
[self.audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
float timeLeft = weakSelf.reader.duration - [weakSelf.reader getCurrentTime];
if ( timeLeft > 0.01 && timeLeft != lastTimeLeft ) {
lastTimeLeft = timeLeft;
[weakSelf.reader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels];
} else {
[weakSelf.reader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels]; //forget this line will cause a buzz at the end.
[weakSelf.reader pause];
weakSelf.audioManager.outputBlock = nil;
}
}];
A better solution would be to patch the AudioFileReader.
链接地址: http://www.djcxy.com/p/67938.html