Sync sound with NStimer iphone sdk? - objective-c

I am creating an application,in my app i am changing images for countdown.I want to play a Tick sound when one second completes(i mean when image changes).I have a 25 second long sound with repeated tick sound and within time interval of 1 second. sometimes it works fine but sometimes it's not.Now how do i sync audio with my timer.any help appreciated thanks.

record with 25 ticks?) why don't you use record with one tick? if the loudness is not your aim, you can play it using AudioServicesCreateSystemSoundID then call AudioServicesPlaySystemSound every second.

I suggest using AudioServicesCreateSystemSoundID with a sound file that is just one tick, which is about 1/16 of a second long or less, and using this in your init:
clickSound = [[self createSoundWithName:#"click"] intValue];
Here is the code to set up the sound:
- (NSNumber*) createSoundWithName: (NSString*) name {
SystemSoundID soundID = -1;
NSString *path =[[NSBundle mainBundle] pathForResource:name ofType:#"caf"];
if (path != nil) {
NSURL *url = [NSURL fileURLWithPath:path];
if (url != nil) {
OSStatus err = AudioServicesCreateSystemSoundID ((CFURLRef) url, &soundID);
if (err) NSLog (#"AudioServicesCreateSystemSoundID error %d", err);
}
}
return [NSNumber numberWithInt:soundID];
}
And here is where you play the click:
- (void) playClick {
AudioServicesPlaySystemSound (clickSound);
}

Related

AVAudioPlayer makes system sound louder when played at the same time

I've already asked this question before and even set a bounty but it still remains unanswered. Please someone help me out!!
System sound becomes louder when AVAudioPlayer is initiated
I play sound effects such as button clicking sounds etc with SystemSound and background music with AVAudioPlayer. When AVAudioPlayer starts while SystemSound is being played, that particular system sound becomes like 5 times louder all of a sudden. Has anyone else experienced that? What could be the fix?
These are in SoundControl.m and I'm playing gameBG right after transition.
-(void)gameBG {
self.sharedSoundControl = [SoundControl sharedSoundControl];
if (self.sharedSoundControl.musicOff == NO) {
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"bgm" withExtension:#"mp3"] error:nil];
self.audioPlayer.numberOfLoops = -1;
self.audioPlayer.volume = 0.3f;
[self.audioPlayer play];
}}
-(void)transition {
if (self.sharedSoundControl.effectOff == NO) {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"transition" ofType:#"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}}

Objective-C exception handling

I'm trying to figure out how exception handling works in Objective-C. So I'm forcing an exception by performing a selector (boom) which does not exist. When I run it, the application crushes, the exception is not handled properly. Can somebody show me the proper way of handling exceptions in objective-c?
#try{
[self performSelector:#selector(boom)];
}
#catch (NSException *ex) {
NSLog(#"Error");
}
... And can somebody also show me how to handle exception for the code below. I'm using one instance variable for four different sound effects. After playing, I set the variable to nil. For some reason, the code below crushes the app at times, so I will like to handle that exception. Thanks.
- (void) playSound:(NSUInteger) number withDelay:(NSTimeInterval) delay
{
if(sound == nil)
{
NSURL* url;
switch (number)
{
case 1: url = [[NSBundle mainBundle] URLForResource:#"Shuffle" withExtension:#"caf"]; break;
case 3: url = [[NSBundle mainBundle] URLForResource:#"Clap" withExtension:#"caf"]; break;
case 4: url = [[NSBundle mainBundle] URLForResource:#"Glass" withExtension:#"caf"]; break;
case 5: url = [[NSBundle mainBundle] URLForResource:#"Knock" withExtension:#"caf"]; break;
default: break;
}
if (url != nil)
{
sound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[sound setCurrentTime:0];
[sound prepareToPlay];
[sound setVolume:1.0];
[sound performSelector:#selector(play) withObject:nil afterDelay: delay];
}
}
}
Exception Handling will not solve your problem here,
If you call - (void) playSound:(NSUInteger) number withDelay:(NSTimeInterval) delay from button press events. Multiple button presses would lead to this kind of crashes. Because you are using the same AVAudioPlayer variable *sound and that same object is used to play sounds after delays.A call from other button press could be initiating the sound player, while another one tries to play the sound.
If these are short sound clips (less than 30sec), Without using AVAudioPlayer , you better use AudioServicesPlaySystemSound,
You can write a method to delay the start of play, This will let you play multiple sound clips at the same time without any problem.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Shuffle" ofType:#"caf"];
NSURL *url = [NSURL fileURLWithPath:path];
SystemSoundID soundFileObject;
AudioServicesCreateSystemSoundID ((__bridge_retained CFURLRef) url, &soundFileObject);
AudioServicesPlaySystemSound (soundFileObject);

UIWebview does not start loading

I'm developing a native application for a website. The application is basically a wrapper around the website, which implements things like push notifications. When a push notification is clicked, the following code is used to go to the appropriate page:
- (NSString *)handlePush:(NSDictionary *)notification
{
if ([[notification objectForKey:#"aps"] objectForKey:#"badge"]) {
int badgeNum = [[[notification objectForKey:#"aps"] objectForKey:#"badge"] integerValue];
NSLog(#"Badge: %i, got from %#", badgeNum, [[notification objectForKey:#"aps"] objectForKey:#"badge"]);
[UIApplication sharedApplication].applicationIconBadgeNumber = badgeNum;
}
if (!active) {
NSLog(#"Got noti while not active, going to that chat!");
NSString *hash;
if ((hash = [notification objectForKey:#"h"])) {
NSLog(#"Hash: %#", [hash stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]);
return [NSString stringWithFormat:#"#%#", hash];
}
return #"";
}
return nil;
}
Active is changed when the application enters the background and after it resumes, to make sure it does not trigger when a push notification arrives when the user is using the app.
The URL is parsed properly, because if i manually paste the exact same URL in the browser, i do go to the correct page.
I am 100% certain the delegate is set, as the UIWebView: ShouldStartLoadWithRequest method is called:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *url = [[request URL] absoluteString];
NSLog(#"shouldStartLoadWithRequest called with url %#", url);
if ([url hasPrefix:BASE_URL]) {
NSLog(#"Yea, i'll load this one for ya");
// remove any get-params / hash suffix
NSRange r = [url rangeOfString:#"?"];
if (r.location == NSNotFound)
r = [url rangeOfString:#"#"];
if (r.location != NSNotFound)
url = [url substringToIndex:r.location];
if (![url isEqualToString:[defaults valueForKey:#"baseUrl"]]) {
NSLog(#"setting new baseUrl %#", url);
[defaults setValue:url forKey:#"baseUrl"];
[defaults synchronize];
}
NSLog(#"Should go and load it now...");
return YES;
}
}
There's some logic for caching versions of the webpage in there. I stepped through with breakpoints, and it reaches the return YES part, and the logs in there are called. However, in that same delegate, the didStartLoad and didFailLoadWithError are not called, which contain purely NSLogs.
On the initial application start, this does work, and it has worded one time too where i stepped through for a long time using the breakpoint, so it seems it's some timing issue. Hoping not having to use any hacky solutions like timers, i was hoping that anyone around here has experience with a similar problem, or has any other valuable input.

iOS AVAudioPlayer double sound playing issue with Xcode 4.2 and ARC

Ive been beating my head up against the all trying to figure out a weird sound issue in my program. I will post the code below. As a brief description I have a function that gets passed a variable and it takes that and decides which category of sound it should play, within that function I have multiple sounds of reach category so I use an arc4random statement then run that through a switch statement. What keeps happening is that it will play two sounds from the case statement instead of just one, most times if I call it twice with my button push the second time it will play the sound from the first time and a new sound, other times it plays the same same over the top of each other but with a slight delay. I put in a breakpoint in the switch and when it double plays it only goes through the switch once which is really confusing. One thing to note is right before this I do play another sound but it uses a separate AVAudioplayer and path variable so that shouldn't be an issue as it never plays the second sound as the other sound I'm playing. I'm only calling the function once when I press the button so I'm not sure why it does this. I have tried putting the *path and *avaudioplayer variables inside the function but it won't play at all. Searching here it seems as though arc deallocs it before it gets a chance to play it. I ended up trying to put it at the top of my .m file as a global variable then just set the actual path and play the sound within the switch. The sound will play but it plays twice.. Hopefully someone can help me out. I tried putting the avaudioplayer definition as a property as well and it does the same thing. Here is my code snippet. And thanks in advance ...
in the .m file
// Just below my synthesize statements
NSString *path;
AVAudioPlayer *theSound
// My code that I call when the button is pressed
[self playVoice:#"buyVoice"];
// The playVoice function
- (void)playVoice:(NSString*)voiceNum;
if ([voiceNum isEqualToString:#"buyVoice"]) // Bought an Item Time for a voice
{
// play coin sound
[self coinSound];
// play random buy phrase and coin sound
int phraseNumber = 0;
phraseNumber = arc4random() %(3);
switch (phraseNumber)
{
case 0:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy1" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 1:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy2" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 2:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy3" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 3:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy4" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
}
}
set this code before u play the Audio sound
This will reset the player to the beginning:
[theSound setCurrentTime:0.0];
[theSound play];
try this

Stop a sound using the same button that plays it

Pretty simple, I'm using one button that generates a random number and then with a switch/case, it animates an image and plays a sound. My problem is that when you press the button again, the sound that was playing before doesn't stop and the sound overlaps.
Here's the code:
- (IBAction) pushme: (id) sender{
int random = (arc4random()%10);
switch (random) {
case 0: {
[ANIMATION NUMBER 0]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound0.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
}
break;
case 1: {
[ANIMATION NUMBER 1]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound1.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
} break; //Lots more cases after this one
I know that this is not the best way to do it, declaring the same variable over and over.
but is there a way to stop it before it plays another one?
I just dicovered the answer to my own question.
What I did was
Declare SoundSystemID soundID; in the header.
Add this line before the random number gets generated: AudioServicesDisposeSystemSoundID(soundID);
Remember that if you are going to play the sound again, you will need to load the resource again after disposing of it.
Thank you guys, anyway.