iOS 5 Detect Repeating/Continuous Shake - ios5

I am writing an app that will need to detect a users shake not only once but continuously. The idea is that a sound would play once on a single shake and the sound would loop if the device is continuously shaken.
I have tested it with the both the Shake API and Accelerometer API but neither do exactly what I want. Here is what I've got so far:
- (void)playAudioFile
{
soundFile = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"boing" ofType:#"wav"]];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFile error:nil];
[audioPlayer setDelegate:self];
[audioPlayer play];
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if (acceleration.x > 0.5 || acceleration.y > 0.5 || acceleration.z > 0.5) {
[self playAudioFile];
NSLog(#"Trigger # 0.5x");
}
}

It looks like Apple has a shake gesture. See if this helps:
http://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/MotionEvents/MotionEvents.html

Related

Edit averagePowerForChannel of avaudioplayer in iphone

I am playing the .mp3 file by using AVaudioplayer:-
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Speech"ofType:#"mp3"]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
audioPlayer.delegate = self;
audioPlayer.numberOfLoops=-1;
[audioPlayer prepareToPlay];
[audioPlayer play];
}
audioPlayer.meteringEnabled = YES;
audioPlayer.volume=0;
NSTimer *playerTimer = nil;
if (!playerTimer)
{
playerTimer = [NSTimer scheduledTimerWithTimeInterval:0.001
target:self selector:#selector(monitorAudioPlayer)
userInfo:nil
repeats:YES];
}
[audioPlayer updateMeters];
-(void)monitorAudioPlayer{
[audioPlayer updateMeters];
for (int i=0; i<audioPlayer.numberOfChannels; i++)
{
float power = [ audioPlayer averagePowerForChannel: i ];
float peak = [ audioPlayer peakPowerForChannel: i ];
}
}
And in written i get the float number of power for that audioplayer.
Is there any way to change the power of peak value of this audio player so that the sound get change to some funnysound or something other.
It is possible by using audiosession or some other thing.
I had done this by using DIRAC.
But in that i am not able to get the powervalue.AS it always return the static powervalue.
Thanks in advance.
The average and peak power levels are not writable; they are calculated characteristics of the sample data.
player.volume = x where x is greater than 1.0 will amplify the sound level before it comes out of the speakers. If you set it to a stupidly high number like 20 or 100, it will end up sounding pretty funny!
If you want to do any more funny stuff to the samples, I think you'll have to use a low level API like RemoteIO or AudioQueue.

Buffering label in a stream using MPMoviePlayer

Im making a radio streaming application, my app is working perfectly. I have two buttons in my screen one for playing and the other for pausing, also I have a label that indicates the state of my player. I have no problem making this label show the state "Playing" or "Paused" my problem is that when I press the play button there is a time where the buffer is gathering information and I can't figure out a way to show a "Buffering..." label before the player start to stream the audio.
This is the code Im using for streaming the radio station.
NSString *url = [NSString stringWithFormat:#"http://66.7.218:8816"];
player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
player.movieSourceType = MPMovieSourceTypeStreaming;
player.view.hidden = YES;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[player prepareToPlay];
[player play];
Im usin a function I created called changeStatus and this function is called each second to identify the status of the player.
-(void)changeStatus
{
if (player.loadState == MPMovieLoadStateUnknown) {
status.text = #"Buffering...";
}
if(player.playbackState == MPMoviePlaybackStatePlaying)
{
status.text = #"Playing.";
}
if(player.playbackState == MPMoviePlaybackStatePaused)
{
status.text = #"Paused";
}
}
I really need to solve this problem and Ive tried all I can to solve it. Hope you can help me! Thanks in advance.
I achieved to solve the problem. The part that was missing is the if clause which gives the signal to start playing only when the player is prepared to play. Without that the player starts to play before the buffer is completely loaded so it plays no audio. And that was the reason my Playing label showed immediately instead of the buffering one.
NSString *url = [NSString stringWithFormat:#"http://66.7.218:8816"];
player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
player.movieSourceType = MPMovieSourceTypeStreaming;
player.view.hidden = YES;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[player prepareToPlay];
if(player.isPreparedToPlay)
{
[player play];
}
Adittionally, the MPMoviePlaybackStateInterrupted refers to the buffering process while doing an stream. So if you want to make something happens in the buffering process refer to this method.
-(void)changeStatus
{
if(player.playbackState == MPMoviePlaybackStatePlaying)
{
status.text = #"Playing.";
}
if(player.playbackState == MPMoviePlaybackStateInterrupted)
{
status.text = #"Buffering...";
}
}
Thanks a lot to the user That Guy who helped me solving this.
Actually there's a notification called
MPMediaPlaybackIsPreparedToPlayDidChangeNotification
The observer will get notified after it is ready to play. It is more or less the same effect but with different mechanism.

Touchesbegan always fire when using touchesmoved?

I'm new to iPhone programing.
I'm trying to do a simple window with a cat doing two sounds. When you click at the cat icon it should do "miaau", and when wou drag over window (stroke) it should make "mrrrr".
It works, but always when I try to make cat mrrrrr function TouchesBegan fires and cat also do "miaaau".
What to do to make the interface recognize I want only stroke cat, not to touch it for doing the first option, "miaau"?
I suggest to add a NSTimer to touchesBegan method with small time interval (say 0.1 sec):
BOOL tap_event = NO; //ivar declared in header
-(void) touchesBegan:... {
tap_event = YES;
[NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: #selector(checkTap:) userInfo: nil repeats: NO];
}
-(void) checkTap:(NSTimer*) t {
if( tap_event ) //miauu here
tap_event = NO;
}
-(void) touchesMoved:... {
tap_event = NO;
//mrrrr here
}
Or as an option check docs for UIGestureRecognizers
This may help you
When does a touchesBegan become a touchesMoved?
touchesBegin & touchesMove Xcode Obj C Question
Max' solution is correct. It will definitely work. I am having an alternative, see this approach.
Make your player object in an .h file then allocate it in viewDidLoad and release in dealloc.
-(void) touchesBegan:... {
//Play the miauu sound.
}
-(void) touchesMoved:... {
[self.yourPlayer stop];
//Play mrrrr.
}
Edit
.h file,
AVAudioPlayer *avPlayer1;
AVAudioPlayer *avPlayer2;
.m file
-(void) touchesBegan:... {
NSString *path = [[NSBundle mainBundle] pathForResource:#"cat" ofType:#"wav"];
avPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[avPlayer1 play];
}
-(void) touchesMoved:... {
[avPlayer1 stop];
NSString *path = [[NSBundle mainBundle] pathForResource:#"cat" ofType:#"wav"];
avPlayer2 = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[avPlayer2 play];
}
-(void)dealloc
{
[avPlayer1 release];
[avPlayer2 release];
[super dealloc];
}

didSelectRowAtIndexPath - access tapCount or similar

I'd like to control an instance of AVAudioPlayer from a UITableView item in a didSelectRowAtIndexPath instance.
First touch of the row item triggers 'play' of the AVAudioPlayer. Second touch of the row item triggers 'stop' of the AVAudioPlayer.
I can make the 'play' work but can't get the 'stop' to work. Also, subsequent touches of the row item starts another thread of the audio in the background.
What's the best way to ensure 1 tap starts the audio and a 2nd tap stops it?
Code samples - this method preps audio file and AVAudioPlayer for use:
- (void)makeReadyAudio {
NSString *path = [[NSBundle mainBundle] pathForResource:#"Murderers" ofType:#"mp3"];
NSURL *url = [NSURL fileURLWithPath:path];
NSError *error;
musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[musicPlayer prepareToPlay];
}
This block will start & stop the AVAudioPlayer within a case statement in the didSelectRowAtIndexPath section:
case 7: {
//touch to start audio sound playing, touch again to stop playing
[self makeReadyAudio];
if ([musicPlayer isPlaying]) {
[musicPlayer stop];
NSLog(#"musicPlayer tested to be playing, so stop it.");
} else {
[musicPlayer play];
NSLog(#"musicPlayer tested to be *not* playing, so play it.");
}
break;
}
How about:
- (void) didSelectRowAtIndexPath:
{
if (player.isPlaying) {
[player stop];
} else {
[player start];
}
}
In other words, keep the player around and see what it is doing.
The problem is that you call makeReadyAudio every single time the row is tapped. You need to check if you have already done that. For example by doing something like:
if (musicPlayer == nil) {
[self makeReadyAudio];
}

off a sound effect with NSUserDefaults

i try to off a sound effect on my app
play method is ' [myMusic play];
-(void)viewDidLoad {
BOOL soundIsOff = [defaults boolForKey:#"sound_off"];
//the problem is here
//xcode compiler doesn't copile this code
[myMusic play] = soundIsOff;
}
sound code :
'
///sound effect
NSString * musicSonati = [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"wav"];
myMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:musicSonati] error:NULL];
myMusic.delegate = self;
myMusic.numberOfLoops = 0;
Shake API Code :
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.subtype == UIEventSubtypeMotionShake)
//Play sound :
[myMusic play] ;
}
}
Looks like you are trying to assign a value to a method call. That is why you are getting the compiler error:
[myMusic play] = soundIsOff //This does not work.
You probably want something like this:
if(!soundIsOff) {
[myMusic play];
}
The question is unclear however, so this is a guess at this point.
I am confused by the question, but if what you want is to stop the sound, then you just need:
[myMusic stop];
Like the others, I can only guess at what you want to do here. Perhaps you are trying to do this:
soundIsOff ? [music stop] : [music play];