AVAudioPlayer Stops Before End of File - ios

I have a function that is almost working. A different audio file is played depending on what page you're on. The problem is, some of the audio files end abruptly. For example, while the audio file plays to the end on "case 1", on "case 2" it stops about 90% in.
- (void)playAudio
{
NSURL *audioURL;
[voiceAudio release];
switch (pageNumber)
{
case 1:
audioURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:#"file1" ofType:#"aac"]];
voiceAudio = [[AVAudioPlayer alloc]
initWithContentsOfURL:audioURL error:nil];
[audioURL release];
voiceAudio.delegate = self;
[voiceAudio play];
break;
case 2:
audioURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:#"file2" ofType:#"aac"]];
voiceAudio = [[AVAudioPlayer alloc]
initWithContentsOfURL:audioURL error:nil];
[audioURL release];
voiceAudio.delegate = self;
[voiceAudio play];
break;
// And so on...
}
}
The AACs are a few minutes long. Maybe there's a better way to go about this? AVAudioPlayer can be a bit funky. Thanks!

Edit: AVAudioPlayer is a bit unpredictable with the 64kb mono AACs I made in Adobe Soundbooth, but seems to run fine after remuxing the files to M4A. I used MP4Box to convert them using the syntax: "mp4box -add source.aac:mpeg4 -sbr -ipod target.m4a" (credit)
Reencoding to a higher bitrate (128kb) seemed to fix some, but not all, of the files as well. I didn't thoroughly test this before I discovered remuxing.

Related

AudioKit AKTimePitch does not work for the recoded file example.m4a

I am building up a APP on iOS by AudioKit(version 4.5.3), and I find out the AKTimePitch class does not work for me, here is my code(objective-c xcode 10):
(IBAction)startButton:(id)sender {
NSURL *url = [[NSBundle mainBundle] URLForResource:#"burncalory" withExtension:#"m4a"];
AKAudioFile *file = [[AKAudioFile alloc] initForReading:url error:nil];
AKAudioPlayer *player = [[AKAudioPlayer alloc] initWithFile:file looping:NO lazyBuffering:YES error:nil completionHandler:^{
NSLog(#"Finished!");
}];
AKTimePitch *akTimePitch = [[AKTimePitch alloc] init:player rate:2.0 pitch:1600 overlap:8];
AudioKit.output = akTimePitch;
[akTimePitch start];
[AudioKit startAndReturnError:nil];
[player playFrom:0.0];
}
I check out the playground(4.5.3), and the sample of "Time Stretching and Pitch Shifting" works well.
Is there something wrong in my code to use AKTimePitch or something wrong with my audio file example.m4a? By the way, this audio file can be loaded and play well by AKAudioPlayer.
After some testing I found that the parameter in the init method does not work, but after I add akTimePitch.pitch=1600 before [player playFrom:0.0], then the AKTimePitch effects works!! I don't know why the AKTimePitch *akTimePitch = [[AKTimePitch alloc] init:player rate:2.0 pitch:1600 overlap:8]; just does not work...

Xcode pre-load many audio files into one AVAudioPLayer?

I managed to load an audio file onto a player and play it via the following method:
- (void) play:(NSString*)loop{
NSString* resourcePath = [[NSBundle mainBundle] pathForResource:loop
ofType:#"mp3"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath]];
player.delegate = self;
[player play];
player.numberOfLoops = 1;
player.currentTime = 0;
player.volume = 1.0;
}
}
(I removed a couple of lines in this post but the method itself works great)
The problem here is, that the sound only gets loaded when the method play() is being called which results in a little delay in between the button click that calls the method and the player actually playing it.
I have about 200 sounds in my app and one way would be to load each sound in its own AVAudioPLayer in the viewDidLoad, but I doubt that this is considered good code.
On Android, I am using the SoundPool for this concern and it works great but I don't think there is an equivalent for this on iOS.
I now managed to do it via AudioServicesPlaySystemSound()
I use a method that loads all the sounds in a giant array
- (void)prepSounds{
NSString *soundPath =
[[NSBundle mainBundle] pathForResource:#"bl3"
ofType:#"mp3"];
NSURL *soundPathURL = [NSURL fileURLWithPath:soundPath];
AudioServicesCreateSystemSoundID(
(__bridge CFURLRef)soundPathURL, &soundID[0]);
AudioServicesPlaySystemSound(soundID[0]);
}
where soundID[] is an array of SystemSoundID declared in the header.
Now, I can just easily fire the sound via AudioServicesPlaySystemSound(soundID[0]) where 0 relates to the first sound I loaded. The latency is close to 0 (I would guess 5ms)
However, this only works for sounds no longer than about 30 seconds.
If you need any assistance with that, just comment here, I'm glad to help.

How do I loop music in Sprite Kit?

I have an 8 second mp3 file and I'm trying to loop it as main menu music. I do this by using SKAction repeatActionForever, however every time it starts over there is a small pause between the loops. This is very annoying since it doesn't sound like it is one long song this way. How can I fix this?
EDIT:
It also doesn't work with AVAudioPlayer :(
Use AVAudioPlayer and set the numberOfLoops property to -1 in order to loop the sound indefinitely.
For example:
NSError *error;
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"SomeSound.wav" withExtension:nil];
myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
myPlayer.numberOfLoops = -1;
myPlayer.volume = 0.4;
myPlayer.delegate = self;
[myPlayer prepareToPlay];
[myPlayer play];

Playing a sound in background

I have read some threads about this topic, and currently have this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *soundFilePath = [NSString stringWithFormat:#"%#/testsoundsr.aiff",
[[NSBundle mainBundle] resourcePath]];
NSURL *soundFileURL = [NSURL fileURLWithPath: soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL
error:nil];
player.numberOfLoops = -1; //Infinite
[player play];
}
The sound is not played though, and I can only imagine that the problem is with the NSString definition which is used to reference the file
The file I'm trying to play is named 'testsoundsr.aiff' and I have dragged that into the project. Also I have added several frameworks to the project, including AudioToolBox.framework
---UPDATE---
I have now tried using an .mp3 file instead, but still getting no sound through.
Try player.delegate = self before [player play]

Play audio after a Time Interval IOS7

Hi in my application, audio is playing when user press the button but now I have two audio buttons like audio1 and audio2, now I want to play second audio after a time interval once the audio1 is completed by clicking the same button.
- (IBAction)btn1:(id)sender {
NSString *audioPath = [[NSBundle mainBundle] pathForResource:#"audio" ofType:#"mp3" ];
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
}
The above code I have used for play one audio now I want to play second audio once the first audio completed please tell me how to make it.
Thanks.
Try this:
You have to add a bool variable with the name 'firstAudioPlayed' on start the variable should be NO or FALSE.
- (IBAction)btn1:(id)sender {
if (![self.audioPlayer isPlaying]) {
NSString *audioPath;
if (self.firstAudioPlayed) {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio2" ofType:#"mp3" ];
} else {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio1" ofType:#"mp3" ];
}
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
self.firstAudioPlayed = !self.firstAudioPlayed;
}
}
I'm not sure if it's working like this, else just ask with a comment...
Explication of the code:
First you check if the player is already playing a song, if he isn't, you check if the first audio already has played (self.firstAudioPlayed) with this you can give the correct path to load the audio file. Now you play this audio file.
(Sorry for my grammar and my english, corrections are welcome)
You probably should use player's delegate. Set audioPlayer.delegate=self; and implement audioPlayerDidFinishPlaying:successfully: method to see when a player finished playing.
Then you can do whatever you want in there, for example start the second audio.

Resources