Reputation: 9051
I'm playing looped sound with AVAudioPlayer by setting the numberOfLoops property to -1. And I want to control the loop rate programmatically, so I'm loading my audio data like this:
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"Click" ofType:@"aif"];
NSMutableData *soundData = [NSMutableData dataWithContentsOfFile:soundFilePath];
And then changing its length before initializing the audio player:
int loopDuration = .5; // seconds
int desiredDataLength = loopDuration * 2 * 44100; // this assumes 16-bit mono data
[soundData setLength:desiredDataLength];
NSLog(@"data: %@", soundData); // this shows the data after our length change
AVAudioPlayer soundPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:NULL];
soundPlayer.numberOfLoops = -1;
[soundPlayer play];
This works perfectly if I set a loopDuration that's smaller than the duration of the original file -- the extra data is truncated and the loop plays at the desired speed. But if I set a loopDuration that's longer than the original file, the loop plays too quickly -- each iteration only lasts as long as the duration of the original file.
I can confirm from the NSLog line that soundData is getting padded to the correct length. I thought maybe AVAudioPlayer was ignoring the trailing 0's in the data and restarting the loop when it saw all those 0's, so instead of simply setting the data length, I tried padding it with some values:
NSData *filler = [@"1234" dataUsingEncoding:NSASCIIStringEncoding];
while (desiredDataLength > [soundData length]) {
[soundData appendData:filler];
}
But the loop still restarts at the point where the original file data stops. As a sanity check, I tried doubling the sound data...
[soundData appendData:soundData];
...and then setting numberOfLoops to 4 and playing the data. I expected to hear the sound 8 times, but I only heard it play 4 times! But if I log soundData, I can see that its length has been doubled.
It seems like there's some kind of intelligence built into the looping mechanism that makes the loop restart when it thinks it should, instead of when it gets to the end of the data. Does anyone have insight into what's really happening, and how I can work around it to get my desired result?
UPDATE: I found that if I open my original sound files in an audio editor and add silence to the ends, to make them long enough for my slowest loop speed, AVAudioPlayer handles them as I want it to. But when I view the NSLog output, I see that this data also ends in all 0's. Why does AVAudioPlayer respect the silence I added in an audio editor, but not the silence I added by padding the data programmatically?
Upvotes: 2
Views: 1057
Reputation: 3939
The sound data is not just data. It's an AIF file which also contains a header which defines the length of the contents. AVAudioPlayer clearly is looking at the header, not at the length of your buffer.
Upvotes: 0