I've implemented AVAudioPlayer into my iPhone app but the audio being played is far too loud. To quieten the sound slightly, I changed the volume to 0.2f to see if it would have any effect. The volume stayed exactly the same. Here's the code I'm using:
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/Blip.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
[audioPlayer setVolume:0.2f];
if (audioPlayer == nil)
NSLog(#"Whoopsies, there was an error with the sound!");
else
[audioPlayer play];
Why won't this turn the volume down?
Can somebody explain how I can?
Thanks!
Replace your code:
[audioPlayer setVolume:0.2f];
with following code:
audioPlayer.volume = 0.2;
Hope this helps you.
As explained in Apples Audio & Video Coding How-To's: You can't set the hardware volume.
How do I access the hardware volume controller?
Global system volume, including your application's volume, is handled
by iPhone OS and is not accessible by applications.
The volume of an AVAudioPlayer instance is a relative volume. You can play two sounds with two AVAudioPlayer instances and set their volume relative to each other.
EDIT:
If you want to control the global volume of your device, you can use MPVolumeView:
MPVolumeView *myVolumeView = [[MPVolumeView alloc] initWithFrame:mpVolumeViewParentView.bounds];
[mpVolumeViewParentView addSubview:myVolumeView];
[myVolumeView release];
Related
I want to play some simple sound effects when people press certain buttons in my app and I've tried several things, but I always get a latency that makes the sound seem out of sync.
I've followed the tutorials here, so I've tried the build in Audio Services, but that had a latency and I've tried the AVAudioPlayer, but that had a latency as well, even though I used "prepareToPlay".
Do I really have to install a big and messy library like Finch to get a simple sound effect with no latency in my simple app?
Hope you can clarify things for me!
UPDATE
Code for Audio Services:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &sound1);
AudioServicesPlaySystemSound(sound1);
Code for AVAudioPlayer in viewDidLoad:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
self.avSound = [[AVAudioPlayer alloc]
initWithContentsOfURL:soundURL error:nil];
[self.avSound prepareToPlay]
Code for AVAudioPlayer in method where I want to play the file:
[self.avSound play];
The way I got this to work (and I think I got the idea from another post on SO) was to create an empty 1 second .wav file and "play" it at initialization. After that, there was no delay when I called the other sound effects.
Something like this in my sound player object
SystemSoundID blID;
SystemSoundID cID;
+(void)doInit
{
if (spinitialized){
AudioServicesPlaySystemSound (blID);
return;
}
NSString *str = [[NSBundle mainBundle] pathForResource:#"ding.wav" ofType:#""];
NSURL *uref = [NSURL fileURLWithPath:str];
OSStatus error = AudioServicesCreateSystemSoundID ((CFURLRef)uref, &cID);
if (error) NSLog(#"SoundPlayer doInit Error is %ld",error);
str = [[NSBundle mainBundle] pathForResource:#"blank.wav" ofType:#""];
uref = [NSURL fileURLWithPath:str];
error = AudioServicesCreateSystemSoundID ((CFURLRef)uref, &blID);
if (error) NSLog(#"SoundPlayer doInit Error is %ld",error);
AudioServicesPlaySystemSound (blID);
spinitialized = YES;
}
Then I could just play the "ding" without any delay using:
AudioServicesPlaySystemSound (cid);
SOLUTION
I ended up doing something similar as Mike above. I ended up playing the sound with the sound volume down in viewDidLoad:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"PlopsX4"
withExtension:#"aif"];
self.plops = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[self.plops setVolume:0.0];
[self.plops play];
And then in the function where I play it I do:
[self.plops setVolume:1.0];
[self.plops play];
One thing I found that seems to help is, upon entry to the screen where the sound MIGHT be played, to play a fraction of a second of a sound. This seems to "prime" the sound mechanism -- allocating internal objects, paging in stuff, etc.
(I observe that this is similar to Mike M's approach.)
I recently implemented sounds into my game. Every time the user touches the screen, an arrow is shot, and a sound is played. I am using the following code to play the sound:
- (void)arrowShoot {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/arrow.mp3", [[NSBundle mainBundle] resourcePath]]];
arrowShootPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
if (arrowShootPlayer != nil) {
[arrowShootPlayer play];
}
}
The reason I was allocating memory to the arrowShootPlayer every time is because the user can tap the screen rapidly, and I want the sounds to overlap. Otherwise, the sound only plays once the previous one has finished playing.
Anyway, I am getting this error:
<com.apple.main-thread> shm_open failed: "AppleAudioQueue.36.5755" (23) flags=0x2 errno=24
Once I get this error, the sounds stop being played. Everything else is fine, just the arrow sounds stop playing.
Is there a better way of playing 'overlapping' sounds like this on the iPhone, or is there a way around this error??
Thanks
if it is the same audio always, use the playing from memory buffer instead of opening the files. Declare some local buffer:
NSData* data;
then in your method:
if(!data) {
data = [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:&err];
}
arrowShootPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
if (arrowShootPlayer) {
[arrowShootPlayer play];
}
I searched everywhere but I couldn't find an answer for my problem.
I play multiple sounds on my app and I let the user to adjust the volume with a button. So if the user wants, he can play with .5 volume. So I have this code:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Orchestra" ofType:#"mp3"];
theOrchestras = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
[theOrchestras play];
and to reduce the volume this:
- (IBAction) volumeReduced {
theOrchestras.volume = 0.5;
}
When the sounds is playing the volume is reduced, no problem. But when the sounds stops, and plays again, the volume always goes back to 1.
To fix this I tried to save the volume as an Integer, but for some reason the value is always 0, I couldn't make it work:
.m
int64_t * volumeSaved;
.h
- (IBAction) volumeReduced {
volumeSaved = .5;
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"Orchestra" ofType:#"mp3"];
theOrchestras = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
theOrchestras.volume = volumeSaved;
[theOrchestras play];
But the audio now always plays with 0 volume, muted.
Is there any way to do this with a button?
Thanks!
You're declaring volumeSaved as a pointer to an integer instead of an integer, but then assigning to it like it's an integer. That's one oddity.
But your real problem is that the volume property in AVAudioPlayer is a float, not a int64_t. So change the type to:
float volumeSaved;
Try storing the volume with NSNumber.
-(IBAction)playSound{ AVAudioPlayer *myExampleSound;
NSString *myExamplePath = [[NSBundle mainBundle] pathForResource:#"myaudiofile" ofType:#"caf"];
myExampleSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:myExamplePath] error:NULL];
myExampleSound.delegate = self;
[myExampleSound play];
}
I want to play a beep sound when a button is clicked. I had used the above code. But it is taking some delay in playing the sound.
Anyone please help.
There are two sources of the delay. The first one is bigger and can be eliminated using the prepareToPlay method of AVAudioPlayer. This means you have to declare myExampleSound as a class variable and initialize it some time before you are going to need it (and of course call the prepareToPlay after initialization):
- (void) viewDidLoadOrSomethingLikeThat
{
NSString *myExamplePath = [[NSBundle mainBundle]
pathForResource:#"myaudiofile" ofType:#"caf"];
myExampleSound =[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:myExamplePath] error:NULL];
myExampleSound.delegate = self;
[myExampleSound prepareToPlay];
}
- (IBAction) playSound {
[myExampleSound play];
}
This should take the lag down to about 20 milliseconds, which is probably fine for your needs. If not, you’ll have to abandon AVAudioPlayer and switch to some other way of playing the sounds (like the Finch sound engine).
See also my own question about lags in AVAudioPlayer.
AudioServicesPlaySystemSound is an option. Tutorial here, sample code here.
Considering the code:
soundFilePath = [[NSBundle mainBundle] pathForResource: #"Sound" ofType: #"wav"];
fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
avPlayerNextLevel = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
avPlayerNextLevel1.volume = volume ;
[soundFilePath release];
[fileURL release];
To play the sound I then do
if([avPlayerNextLevel prepareToPlay]){
[avPlayerNextLevel play];
}
I do this many times within my game. Sometimes on the simulator , the sound stops playing. And when sometimes I detect memory leaks with AvAudioPlayer.
Does everything look alright with my code ?
You'll need to release the instance of AVAudioPlayer that you created. Since the above code sets the delegate to self, just implement the following method and release there:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(#"Audio finished playing.");
[player release];
}
Why are you releaseing a non-owning reference (soundFilePath)?
You don't need to manually prepareToPlay if you're going to invoke play right after.
Quoting the documentation for play:
Discussion
Calling this method implicitly calls the prepareToPlay method if the audio player is not already prepared to play.
Personally, I do this:
NSURL *soundUrl = [NSURL fileURLWithPath:
[[NSBundle mainBundle] pathForResource:track
ofType:nil]];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl
error:nil];
[audioPlayer setDelegate:self];
[audioPlayer play];
Where audioPlayer is an ivar and track is an lvar of type NSString* which I obtained earlier from wherever I configure the next song to play.
I've been working on something similar but I was using a slightly different piece of code. Unfortunately, I got memory leaks, therefore I decided to give a try to the code you posted. Same result: memory leaks again when I invoke [audioPlayer play];
I can't really figure out what's going on. Are you guys aware of any memory leaks when AVAudioPlayer is involved?