play a sound from an arbitrary position - ios

I'm looking for a way to play an audio file from just any point in the file.
Currently, whenever I play the file, it just starts from the beginning.
Since it is a loop, I could choose to let it loop, and open/close the volume at will, but I think it is kind of a lame solution, not in the least because of battery concerns.
I really did some research on this, but it is either a freak requirement, or I don't know how to phrase my queries.
Thanks in advance for any tip.

That should be a nice easy problem to solve. You don't post any code, so we can't see what you're trying at the moment. What I'd do is this:
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"SoundFile" ofType:#"wav"];
AVAudioPlayer * soundData =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundPath] error:NULL];
[soundData stop];
soundData.currentTime = 22; //This will start playback 22 seconds into the file
[soundData play];
It goes without saying that you need to check the duration of your sound file so that you don't select a time beyond its end!
currentTime is a float (so you can specify millisecond values). You can read more here: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioPlayerClassReference/#//apple_ref/occ/instp/AVAudioPlayer/currentTime

Related

Playing several tracks saved locally in sequence

I need to play n tracks one after another with ability to switch to next/previous song and pause. Songs are located in Documents folder.
I looked in AVQueuePlayer, but it seems that this approach is not working with local files, playing by url works fine. Now i can play one song with AVAudioPlayer like this:
NSURL *url = [NSURL fileURLWithPath:[node path]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[self.player play];
But it seems that playing bunch of tracks one after another this way is not the best practice.
May be there are frameworks that implement this in more convenient way?
Any suggestions?
StreamingKit is probably what your looking for.

How to stream mp3 files (iOS)

I have found many related questions on SO, but or because I am very new, or because it doesn't exactly fit my problem, I can't find a way to succeed.
So, all I would like to do is playing an audio file stored on an exernal server directly on the iOS device (iPhone in my case)
I have tried differents solution on the net, and this is what I get until now.
NSString* resourcePath = #"http://www.chiptape.com/chiptape/sounds/medium/laugh.mp3"; //your url
NSURL *url = [[NSURL alloc]initWithString:resourcePath];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithURL:url error:&error];
audioPlayer.delegate = self;
[url release];
[audioPlayer prepareToPlay];
[audioPlayer play];
The compiler show me this error:
No visible #interface for 'AVAudioPlayer' declares the selector
'initWithURL:error:'
I am not sure at all about my code, and would like your guys to know I have started iOS coding yesterday, so it's not impossible I'm missing something so obvious that tutorials/posts don't mention it.
Also, I have imported the library AVFoundation and imported it on my .h file.
I have also declared this on my .h file
AVAudioPlayer *audioPlayer;
I hope there is an easy way to stream audio file on iOS as provide android/java
Thank you and if you need more details comment and I'll update my post.
Try this:
NSString* resourcePath = #"http://www.chiptape.com/chiptape/sounds/medium/laugh.mp3"; //your url
NSURL *audioURL = [NSURL URLWithString:resourcePath];
AVAudioPlayer *audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL: audioURL error:&error]autorelease];
[audioPlayer play];
I'm working with it recently.
AVAudioPlayer can't work with audio stream. In fact, there isn't an easy way to do that.
You need to learn some Core Audio things, get the raw data of media, play them in audioQueue (audioToolBox framework). Real-time audio processing is not a simple work, it's full of c-level api and so many dirty work, don't rush, have fun :)
Check out the book Learning Core Audio and this open-source audio streamer.
Let me know if you need more help.

SKAction playSoundFileNamed failed at 500 mp3

In my application I need to use a lot of short different mp3s (about 500 items one by one)
So I use SKAction playSoundFileNamed
After ~200 sounds it crashed with 'Failed to load resource - Resource s234.mp3 can not be loaded'. Memory rises to 70mb.
How to avoid this?
What I tried:
recreate sound in every iteration
SKAction *mySound=[SKAction playSoundFileNamed:aa waitForCompletion:YES];
create the one variable in the beggining of .m
SKAction *mySound;
and reuse it in iterations
mySound=[SKAction playSoundFileNamed:aa waitForCompletion:YES];
2.
load all sounds to array once at start
for (int j=0;j<500;j++){
NSString *aa=[NSString stringWithFormat:#"s%d.mp3", j];
[item.sounds addObject:[SKAction playSoundFileNamed:aa waitForCompletion:YES]];
}
...but never changed - it crashes and can't load mp3.
How to clean this memory leaks?
EDITED
I also tried to turn off ARC and manually dealloc it every time. Nothing changed.
This little ditty right here will allow you to use a regular old SKAction but customize the playback in code.
https://github.com/pepelkod/iOS-Examples/tree/master/PlaySoundWithVolume
+(SKAction*)playSoundFileNamed:(NSString*)fileName atVolume:(CGFloat)volume waitForCompletion:(BOOL)wait{
// setup audio
NSString* nameOnly = [fileName stringByDeletingPathExtension];
NSString* extension = [fileName pathExtension];
NSURL *soundPath = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:nameOnly ofType:extension]];
AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:soundPath error:NULL];
[player setVolume:volume];
[player prepareToPlay];
SKAction* playAction = [SKAction runBlock:^{
[player play];
}];
if(wait == YES){
SKAction* waitAction = [SKAction waitForDuration:player.duration];
SKAction* groupActions = [SKAction group:#[playAction, waitAction]];
return groupActions;
}
return playAction;
}
You may be better off with a "proper" sound engine. You could use AVAudioPlayer or even better, ObjectAL (already included in Kobold Kit). That way you have more control over preloading and caching the sound files, and treating streaming audio (MP3) differently from short-lived sound effects (usually CAF or WAV).
For very short sound files, say shorter than 5 seconds, MP3 isn't ideal. You should try CAF/WAV instead.
And do consider how much your sound files use in memory. Say each mp3 file is buffered into a 250 KB buffer, times 500, then that uses over 120 MB of memory. Do not look at the size of the mp3 file because it's a compressed format, and will likely be buffered uncompressed.
I think you're running out of file descriptors. What i've found is that every time playSoundFileNamed is run the sound file is opened and never closed... so the file descriptor is not released.
My testing in instruments leads me to believe there's about 250 available file descriptors. And my research tells me that not only file access uses them up but other things too. So I think your ~200 sound files sounds just about right to crash. Whenever a sound file is the next file that Xcode is trying to access I get nothing from the debugger, but when the next file is a png (I have way more art then sounds) it gives,
error = 24 (Too many open files)
I found the error while play testing and switching back to my menu scene from the game play scene every time I lost. So normally it didn't matter but running the init method for the game play scene over and over was piling up these open sound files.
I've searched and searched for a way to close these files but have come up with nothing. I'm thinking of implementing a singleton to run my sound and moving all of the playSoundFileNamed calls into it so they only ever get called once. I think this is a bug from Apple. These files should be closing with ARC. Has anyone found anything similar?

Playing short selfmade sound with immediate start in iOS

I have a self-generated DTMF sound (with a wav header) generated by program that I want to be able to play quickly, in fact as soon as the user touches a button. This DTMF sound must play/loop infinitely, until I stop it. Some other sounds must be able to be played at the same time.
I'm very new to Audio programming, and I tested many ways of doing that and I'm lost now.
How can I achieve that ?
Needs :
very quick playback start (including the first time)
many sounds at the same time (short sounds +- 2-6 seconds)
infinite DTMF sound without gaps
having control over the different sounds that are playing / being able to stop just one played sound
AVAudioPlayer if you can live with some latency, OpenAL (for example Finch) if you really need to have the latency as low as possible.
I use already exist .wav file. and I can easily play it.
For run following code. include AudioToolbox framework.
write into .h file #import <AudioToolbox/AudioToolbox.h>
Write into .m file
-(IBAction)startSound{
//Get the filename of the sound file:
NSString *path = [NSString stringWithFormat:#"%#%#", [[NSBundle mainBundle] resourcePath], #"/sound1.wav"];
//declare a system sound
SystemSoundID soundID;
//Get a URL for the sound file
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
//Use audio sevices to create the sound
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
//Use audio services to play the sound
[self sound];
timer =[ [NSTimer scheduledTimerWithTimeInterval:2.1 target:self selector:#selector(sound) userInfo:nil repeats:YES]retain];
}

iOS AVAudioPlayer multiple instances, multiple sounds at once

I am working on an interactive children's book for the iPad that has a "read to me" option.
For each page (that has an index), theres an audio clip that produces the "read to me" feature. The feature works well, except for the fact that when I turn the page, the previous pages audio still plays, even when the new audio starts, here's my example:
- (void) didTurnToPageAtIndex:(NSUInteger)index
{
if ([delegate respondsToSelector:#selector(leavesView:didTurnToPageAtIndex:)])
[delegate leavesView:self didTurnToPageAtIndex:index];
if([[NSUserDefaults standardUserDefaults] boolForKey:#"kReadToMe"] == YES)
{
NSString* filename = [voices objectAtIndex:index];
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:#"m4v"];
NSLog(#"File: %#, Index: %i",path,index);
//Create new audio for next page
AVAudioPlayer * newAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil];
rtmAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
//[newAudio release];
[rtmAudio play];
}
}
Say for instance, I turn to page 3 before the audio for page 2 stops playing, both clips play over eachother, which will annoy the sh*t out of kids, I know it does me.
I've tried placing [rtmAudio stop] before I allocate the new file, but that doesnt seem to work. I need a way to kill the prevous audio clip before starting the new clip.
I would suggest that you have one instance of the audio player in your whole application. Then you can check if it playing, if so stop it and then move on.
you are creating a new player in this method before stopping the old.... I believe
As AlexChaffee mentioned the Apple docs, "Play multiple sounds simultaneously, one sound per audio player, with precise synchronization". It seems preferable to use multipe instances across the app with NSNotificationCenter's notifications.

Resources