Reputation: 3064
I am trying to build a simple metronome app and I am wondering if there is any sample code or open source projects out there to learn from. I think apple used to have it but not any more. I figure it should not be that hard but I am curious to see how to load the audio, how to set timer and loop the audio accordingly. Any help much appreciated.
Upvotes: 1
Views: 7587
Reputation: 5887
Apple's Metronome App is still available in the iOS 4.2 library.
In Xcode simply go to Window
-> Organizer
.
Then go to the Documentation
pane and search for Metronome
.
The Metronome project will appear under the Sample Code section.
You can make sure you have the iOS 4.2 library by going to Preferences -> Downloads -> Documentation and ensuring that the iOS 4.2 library is in you list.
So...as of Summer 2015, Apple's redesign of their website seems to have broken these links. I have found the docket link in .xar
format http://devimages.apple.com/docsets/20101122/com.apple.adc.documentation.AppleiOS4_2.iOSLibrary.Xcode4.xar which you can download and then extract with the xar -xf <docsetfilename>
command line tool or else something like the unarchiver app.
Upvotes: 3
Reputation: 681
Just for the purpose of Google here's my findings on this. I've tried both the Apple example approach (using a background thread) and the NSTimer approach, and the winner by far is the use of threading. There just isn't a way to get an NSTimer to fire accurately enough whilst running on the main (UI) thread. I suppose you could get a time running in the background but Apple's example really does work very well.
Upvotes: 0
Reputation: 21
I tried the NSTimer, but it's not a good solution if you are looking for a Pro Metronome. You need a core engine that push the time to be at the place it need to be. NSTimer let you just to loop in time spaces that couldn't have the precision you need.
Look now, iOS 5 let you use Music Sequencer that is a good solution for Musical Apps. And It have a core engine to control the time.
Upvotes: 2
Reputation: 1614
This is a metronome project that I've made previously, It's fairly simple but It should help, If you use it just reference me, Jordan Brown 15y Mango Apps. It took a while to do but never made an app out of it.
//.h
NSTimer *timer;
int count;
float bpm;
float speed;
UILabel *numberLabel;
IBOutlet UISwitch *vibrate;
IBOutlet UISegmentedControl *timing;
}
- (IBAction)up;
- (IBAction)down;
- (IBAction)stop:(id)sender;
@property (nonatomic, retain)IBOutlet UILabel *numberLabel;
@property (nonatomic, retain)IBOutlet UILabel *bpmLabel;
@property (nonatomic, retain)IBOutlet UISegmentedControl *timing;
//.m
#define SECONDS 60
#import <AudioToolbox/AudioToolbox.h>
@implementation metronome
@synthesize numberLabel; // labels
@synthesize bpmLabel;
@synthesize timing;
-(IBAction)stop:(id)sender{
[timer invalidate];
[self performSelector:@selector(playTockSound)];
numberLabel.text = [NSString stringWithFormat:@"%i",count];
bpm = bpm;
if (bpm > 300) {
bpm = 300;
}
int new = bpm;
bpmLabel.text = [NSString stringWithFormat:@"%i",new];
speed = INFINITY;
NSLog(@"%f",speed);
timer = [NSTimer scheduledTimerWithTimeInterval:speed target:self selector:@selector(updateNumber) userInfo:nil repeats:YES];
}
-(IBAction)up{
[timer invalidate];
count = 1;
[self performSelector:@selector(playTockSound)];
numberLabel.text = [NSString stringWithFormat:@"%i",count];
bpm = bpm+10;
if (bpm > 300) {
bpm = 300;
}
int new = bpm;
bpmLabel.text = [NSString stringWithFormat:@"%i",new];
speed = SECONDS/bpm;
NSLog(@"%f",speed);
timer = [NSTimer scheduledTimerWithTimeInterval:speed target:self selector:@selector(updateNumber) userInfo:nil repeats:YES];
}
-(IBAction)down{
[timer invalidate];
count = 1;
[self performSelector:@selector(playTockSound)];
numberLabel.text = [NSString stringWithFormat:@"%i",count];
bpm = bpm-10;
if (bpm < 10) {
bpm = 10;
}
int new = bpm;
bpmLabel.text = [NSString stringWithFormat:@"%i",new];
speed = SECONDS/bpm;
NSLog(@"%f",speed);
timer = [NSTimer scheduledTimerWithTimeInterval:SECONDS/bpm target:self selector:@selector(updateNumber) userInfo:nil repeats:YES];
}
-(void)updateNumber{
count += 1;
//if 4/4 timing is selected then the count wont go past 4
if (timing.selectedSegmentIndex == 2) {
if (count >= 5) {
count = 1;
}
}
//if 3/4 timing is selected then the count wont go past 3
if (timing.selectedSegmentIndex == 1) {
if (count >= 4) {
count = 1;
}
}
//if 2/4 timing is selected then the count wont go past 2
if (timing.selectedSegmentIndex == 0) {
if (count >= 3) {
count = 1;
}
}
//In each timing case it plays the sound on one and depending
//on the limitiations on the cont value the amount of each tick
if (count == 1) {
[self performSelector:@selector(playTockSound)];
}else {
[self performSelector:@selector(playTickSound)];
}
numberLabel.text = [NSString stringWithFormat:@"%i",count];
}
-(void)playTickSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"tick"
ofType:@"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path]
, &soundID);
AudioServicesPlaySystemSound (soundID);
}
-(void)playTockSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"tock"
ofType:@"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path]
, &soundID);
AudioServicesPlaySystemSound (soundID);
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidLoad
{
bpm = 60.00;
speed = SECONDS/bpm;
timer = [NSTimer scheduledTimerWithTimeInterval:speed target:self selector:@selector(updateNumber) userInfo:nil repeats:YES];
int new = bpm;
bpmLabel.text = [NSString stringWithFormat:@"%i",new];
[super viewDidLoad];
}
Upvotes: 0