I created this method to easily play sounds in an XCode iPhone application.
void playSound(NSString* myString) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
NSString *string = myString;
CFURLRef soundFileURLRef;
soundFileURLRef = CFBundleCopyResourceURL(mainBundle, (__bridge CFStringRef) string, CFSTR ("wav"), NULL);
UInt32 soundID;
AudioServicesCreateSystemSoundID(soundFileURLRef, &soundID);
AudioServicesPlaySystemSound(soundID);
}
The problem with this is, I don't know how to later stop the sound or to make the sound play on a loop forever until it is stopped. How would I go about doing this? Could I possibly make the method return the sound, and then put that in a variable to later be modified?
I'm afraid i dont know how to stop it, but try this for looping:
soundFile = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"AudioName" ofType:#"wav"]];
sound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFile error:nil];
sound.numberOfLoops = -1; //infinite
[sound play];
From documentation: "The interface does not provide level, positioning, looping, or timing control, and does not support simultaneous playback...".
http://developer.apple.com/library/ios/#documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference
So for sound playback it is better use AVFoundation classes.
System Sound Services usually is used to play short sounds/alerts/etc and pausing/stopping probably should be avoided. If this is really needed you could try AudioServicesDisposeSystemSoundID(systemSoundID) to stop the sound.
As for looping you could create recursive function to loop the sound using AudioServicesPlaySystemSoundWithCompletion.
Example (swift 3):
func playSystemSound(systemSoundID: SystemSoundID, count: Int){
AudioServicesPlaySystemSoundWithCompletion(systemSoundID) {
if count > 0 {
self.playSystemSound(systemSoundID: systemSoundID, count: count - 1)
}
}
}
So in your example you would just replace AudioServicesPlaySystemSound(soundID); with playSystemSound(systemSoundID: soundID, count: numOfPlays)
In case if you want to decide to play a sound based on a bool variable,
private func playSound() {
if isStarted {
AudioServicesPlaySystemSoundWithCompletion(kSystemSoundID_Vibrate, {
if self.isStarted {
self.playSound()
}
})
}
}
Related
I have an object moving around the screen and once it reaches the edges it it changes direction and plays a sound this all works fine except that when it plays the sound I freezes for about half a second is there any way of making this run smoothly with the sound and object movement?
-(void)viewDidLoader
{
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"ballbounce" ofType:#"mp3"];
ballbounce = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path1] error: NULL];
[ballbounce prepareToPlay];
}
-(void) ballcollition
{
[self ballplaysound]
enemy.center = CGPointMake(enemy.center.x+pos.x,enemy.center.y+pos.y);
if (enemy.center.x > 328 || enemy.center.x < 0)
{
pos.x = -pos.x;
}
}
-(void)ballplaysound
{
if (enemy.center.x > 328 || enemy.center.x < 0 ||enemy.center.y < 0||enemy.center.y < 300)
[ballbounce play];
}
use the System Sound for sound that plays smoothly.
Original NON-ARC answer:
#import <AudioToolbox/AudioToolbox.h>
- (IBAction)soundButton:(id)sender {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"alert" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
[soundPath release];
}
Updated for ARC, and turned into a utility function:
- (void)soundPlay:(NSString*)waveName {
// wavName = #"alert" without any file extension (not alert.wav)
NSString *soundPath = [[NSBundle mainBundle] pathForResource:waveName ofType: #"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
}
Use AudioServicesPlaySystemSound(): https://developer.apple.com/library/ios/#documentation/AudioToolbox/Reference/SystemSoundServicesReference/Reference/reference.html
You can gain sound "smoothness" with AVPlayer by simply converting your mp3 to caf format as explained here.
1) Create AVAudioPLayer and cache it in your apps initialization code and never call it again
also call prepare as well.
2) so the method you included should only have to call play;
3) If you still get a skip use
[ballbounce performSelectorOnMainThread:#selector(play) withObject:nil];
Since you didnt include all the code and you are clearly doing drawing - putting the play method
on the queue could let the drawing code finish without interruption.
Doing this correctly might fix you. Using AudioSystemSound is much lower overhead but you should follow the same principles of preparing any often used sounds in your app initialization and not spawning them at the exact time you need them to avoid performance issues.
In my project i have a function that play music
-(void)playPlin {
AudioSessionSetActive(true);
// Set up audio session, to prevent iPhone from deep sleeping, while playing sounds
UInt32 category = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory,
sizeof (category),
&category
);
//UInt32 category = kAudioSessionCategory_MediaPlayback;
OSStatus result = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(category), &category);
if (result){
NSLog(#"ERROR SETTING AUDIO CATEGORY!\n");
}
result = AudioSessionSetActive(true);
if (result) {
NSLog(#"ERROR SETTING AUDIO SESSION ACTIVE!\n");
}
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"chimes" ofType:#"wav"];
NSData *sampleData = [[NSData alloc] initWithContentsOfFile:soundFilePath];
NSError *audioError = nil;
AVAudioPlayer *alarmAudioPlayer = [[AVAudioPlayer alloc] initWithData:sampleData error:&audioError];
[sampleData release];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
if(audioError != nil) {
NSLog(#"An audio error occurred: \"%#\"", audioError);
}
else {
[alarmAudioPlayer play];
} }
The file play ok but i have three issue:
1.how can I make that the audio file starts not from the beginning but from the number of second that i pass? for example, if i step value 300 audio file should start from the second 300 of it
2.How can i set volume of audio file?
3.How can i set loop property of it?
thank in advance
This is all pretty clearly laid out in the documentation.
1) Use the playAtTime: method call instead of play. Pass the time in seconds.
2) Set the volume property on the AVAudioPlayer. Note that this is the gain of the player, and will be modulated with the current system volume.
3) Set the numberOfLoops property. Assign a huge value like NSIntegerMax to keep looping indefinitely.
I'm having trouble using AudioServicesPlaySystemSound. Things work great when output goes through the speakers. However, when a user plugs in headphones, there is no output. Is there an easy way to set up some kind of listener so that audio is automatically routed through the headphones when they are plugged in, and otherwise through the speaker?
I'm using the following method to play short, simple AIF sound samples:
-(void)playAif:(NSString *)filename {
SystemSoundID soundID;
NSString *path = [[NSBundle mainBundle]
pathForResource:filename ofType:#"aif"];
if (path) { // test for path, to guard against crashes
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path],&soundID);
AudioServicesPlaySystemSound (soundID);
}
}
I know I must be missing something, some bit of setup that would do this. Any ideas?
Thanks #Till for pointing me to the relevant portion of the docs. For others with this issue, the solution is to explicitly set the session category, in my case to ambient sound. This code snipped from apple's docs:
UInt32 sessionCategory = kAudioSessionCategory_AmbientSound; // 1
AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory, // 2
sizeof (sessionCategory), // 3
&sessionCategory // 4
);
So, my method for playing audio now looks like this:
-(void)playAif:(NSString *)filename {
// NSLog(#"play: %#", filename);
SystemSoundID soundID;
NSString *path = [[NSBundle mainBundle]
pathForResource:filename ofType:#"aif"];
if (path) { // test for path, to guard against crashes
UInt32 sessionCategory = kAudioSessionCategory_AmbientSound; // 1
AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory, // 2
sizeof (sessionCategory), // 3
&sessionCategory // 4
);
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path],&soundID);
AudioServicesPlaySystemSound (soundID);
}
}
This solves my problem handily! The only worry I have is that setting it explicitly every single time I play a sound might be excessive. Anyone know a better and safer way to set it and forget it? Otherwise, this works delightfully.
I have an app I am working on and It uses some of the hardware sensors to provide data on screen, there is a Label that updates with the number. I want a sound to play whenever the number is above 100 or something. For example, say it was reading numbers then all of the sudden it finds a good spot (or whatever), then I would like a sound to play or a light to light up. I am an absolute beginner and it would be nice if the answer would be easy for a absolute beginner to understand.
I am using the system AudioToolbox.framework for playing sounds in my simple game. I added this static function to common MyGame class:
+ (SystemSoundID) createSoundID: (NSString*)name
{
NSString *path = [NSString stringWithFormat: #"%#/%#",
[[NSBundle mainBundle] resourcePath], name];
NSURL* filePath = [NSURL fileURLWithPath: path isDirectory: NO];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);
return soundID;
}
I added the "Morse.aiff" file to project Resources and initialized it in (any) class initialization with the following:
self.mySound = [MyGame createSoundID: #"Morse.aiff"];
And then I played sound with this call:
AudioServicesPlaySystemSound(mySound);
Also, don't forget to import AudioServices.h file.
This audio toolbox can play also different sound formats.
h
#import <AVFoundation/AVFoundation.h>
#interface CMAVSound : NSObject {
AVAudioPlayer *audioPlayer;
}
- (id)initWithPath:(NSString*)fileNameWithExctension;
- (void)play;
#end
m
#import "CMAVSound.h"
#implementation CMAVSound
-(void)dealloc {
[audioPlayer release];
}
- (id)initWithPath:(NSString*)fileNameWithExctension {
if ((self = [super init])) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], fileNameWithExctension]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (audioPlayer == nil) {
NSLog(#"%#", [error description]);
}
}
return self;
}
- (void)play {
[audioPlayer play];
}
#end
Check out the documentation for the AVAudioPlayer class. It allows you to play sounds clips. If you have troubles implementing that, show us some code.
If the sounds gonna up to 5 seconds and no stereo output is needed I would recommend you to do that with system sounds. It is easy and better solution then any other.
Apple sample code is provided under name SysSound
EDIT1
Or maybe tutorial could help you more
http://howtomakeiphoneapps.com/2009/08/how-to-play-a-short-sound-in-iphone-code/
Take a look at following links;
http://blog.guvenergokce.com/avaudioplayer-on-iphone-simulator/57/
http://mobileorchard.com/easy-audio-playback-with-avaudioplayer/
Here you can find list of AudioServicesPlaySystemSound
http://iphonedevwiki.net/index.php/AudioServices
Here is the code:
-(void)stop
{
NSLog(#"Disposing Sounds");
AudioServicesDisposeSystemSoundID (soundID);
//AudioServicesRemoveSystemSoundCompletion (soundID);
}
static void completionCallback (SystemSoundID mySSID, void* myself) {
NSLog(#"completion Callback");
}
- (void) playall: (id) sender {
[self stop];
AudioServicesAddSystemSoundCompletion (soundID,NULL,NULL,
completionCallback,
(void*) self);
OSStatus err = kAudioServicesNoError;
NSString *aiffPath = [[NSBundle mainBundle] pathForResource:#"slide1" ofType:#"m4a"];
NSURL *aiffURL = [NSURL fileURLWithPath:aiffPath];
err = AudioServicesCreateSystemSoundID((CFURLRef) aiffURL, &soundID);
AudioServicesPlaySystemSound (soundID);
NSLog(#"Done Playing");
}
Output:
Disposing Sounds
Done Playing
In actual no sound gets play at all and completion call back isn't called as well. Any idea what could be wrong here?
I want to stop any previous sound before playing current.
AFAIK, the only supported files are .caf, .aif, or .wav:
To play your own sounds, add the sound
file to your application bundle; the
sound file must adhere to the
following requirements:
Must be .caf, .aif, or .wav files.
The audio data in the file must be in PCM or IMA/ADPCM (IMA4) format.
The file's audio duration must be less than 30 seconds.
Audio & Video Coding How-To's
What does err contain? From that you should be able to infer the problem.
You can use AudioToolBox framework for this:
CFBundleRef mainbundle = CFBundleGetMainBundle();
CFURLRef soundFileURLRef = CFBundleCopyResourceURL(mainbundle, CFSTR("tap"), CFSTR("aif"), NULL);
AudioServicesCreateSystemSoundID(soundFileURLRef, &soundFileObject);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(1100);