Metronome Using NSTimer

Discussion in 'iOS Programming' started by jim93, Aug 6, 2009.

  1. jim93 macrumors newbie

    Joined:
    Jun 27, 2009
    #1
    Hello

    I decided to try to implement a metronome on my own using NSTimer to learn about NSTimer and playing sounds in the SDK.
    So after looking Apple's thread implementation I did this but it doesnt seem to work. I then tested the play sound function by having a button work on it and noticed that I couldnt get the sound to be interrupted to start the sound from the beginning again which effectively creates a maximum bpm based on the length of my tick and tock. Im not sure how to fix either of these problems but I believe the timer might not be calling the playSound function but Im not sure why.
    Code:
    - (void)playSound {
        AVAudioPlayer *currentPlayer = tickPlayer;
    	
    	NSUInteger timeSignature = kDefaultTimeSignature;	
    	
        if (beatNumber == 1) {
    		currentPlayer = tockPlayer;
        }
    	else if (beatNumber == timeSignature) {
            beatNumber = 0;
        }
        
        [currentPlayer play];
    
        beatNumber++;
    }
    
    
    - (IBAction)startstopSession:(id)sender{
    	if (playStatus){playStatus = FALSE;}
    	if (!playStatus){playStatus = TRUE;}
    	
    	// Number of Milliseconds between beats
    	bpm = kDefaultBPM;
    	beatLength = 60000/bpm;
    	if(playStatus){
    		MasterClock =
    		[NSTimer scheduledTimerWithTimeInterval:(beatLength) target:self 
    									   selector:@selector(playSound) userInfo:nil repeats:YES];
    	}
    	
    	if (!playStatus){
    	[MasterClock invalidate];}
    }
    /*
    I previously initiated the AVAudioPlayer doing*/
    NSBundle *mainBundle = [NSBundle mainBundle];
    	NSError *error;
    
    	NSURL *tickURL = [NSURL fileURLWithPath:[mainBundle pathForResource:@"tick" ofType:@"caf"]];
    
    	tickPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:tickURL error:&error];
    	if (!tickPlayer) {
    	NSLog(@"no tickPlayer: %@", [error localizedDescription]);	
    	}
    	[tickPlayer prepareToPlay];
    
    Any help is appreciated and thanked for in advance.
     
  2. Kingbombs macrumors member

    Joined:
    Jun 24, 2009
    #2
    this line of code probably doesn't work correctly:

    if (playStatus)
    {playStatus = FALSE;}
    if (!playStatus)
    {playStatus = TRUE;}

    you probably want an else if in there so:

    if (playStatus)
    {playStatus = FALSE;}
    else if (!playStatus)
    {playStatus = TRUE;}

    like it is at the moment, it checks if playStatus is true, if it is then set playStatus to false; then check if playStatus is false (which you just set it to) and then set playStatus to be true,
    will always come out true.

    the new code will:
    Check if playStatus is true, if it is then set it to false and won't go into the else if,
    if playStatus is false, it won't enter the first if statement, and will enter the else if and set it to true
    (so can be either false or true)

    EDIT: on a side note you can lay it out like this:

    if (playStatus)
    playStatus = FALSE;
    else if (!playStatus)
    playStatus = TRUE;

    EDIT 2: both problems should get fixed by this i believe
     
  3. plinden macrumors 68040

    plinden

    Joined:
    Apr 8, 2004
    #3
    Or just;
    Code:
    playStatus = !playStatus;
     
  4. jim93 thread starter macrumors newbie

    Joined:
    Jun 27, 2009
    #4
    I didnt notice that I was so busy thinking about how its a NSTimer or AV problem for the last few hours that I never noticed it. Thanks

    Does anyone know how to interrupt the play on an AV player to allow for a higher BPM?
     
  5. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #5
    Using an NSTimer isn't accurate enough for a good quality metronome. For a better metronome, try using an Audio Queue and count a precise number of samples between waveform initiations.
     
  6. jim93 thread starter macrumors newbie

    Joined:
    Jun 27, 2009
    #6
    It was more a proof of concept for myself to see If I could do it and learn in the process, now the only problem im having is with interrupting AVAudioPlayer from play to start another play sequence from the beginning to allow for higher BPM's.
     
  7. jim93 thread starter macrumors newbie

    Joined:
    Jun 27, 2009
    #7
    By waveform initiations you mean samples before starting another play sequence?
     
  8. jim93 thread starter macrumors newbie

    Joined:
    Jun 27, 2009
    #8
    I found out how to do what I wanted in AVAudioPlayer
    Code:
    	[currentPlayer pause];
    	currentPlayer.currentTime = 0;
     

Share This Page