Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jim93

macrumors newbie
Original poster
Jun 27, 2009
16
0
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.
 
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
 
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?
 
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.
 
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.
 
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.
By waveform initiations you mean samples before starting another play sequence?
 
I found out how to do what I wanted in AVAudioPlayer
Code:
	[currentPlayer pause];
	currentPlayer.currentTime = 0;
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.