メトロノームを作ってみる

iPhoneアプリ メトロノーム

テンポを刻む道具を自作して、楽器の練習に励むのも一興です。ということで、メトロノームのiPhoneアプリを作ってみます。


動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。




ポイント
振り子のおもりを指で上下に動かせるようにして、そこでテンポを変更できるようにしました。カチッカチッという振り子は、棒の一番下にCALayerのanchorを設定して、Rotationのアニメーションをテンポに合わせてNSTimerで動かしています。


サンプルコード


#import "ViewController.h"

#import <QuartzCore/QuartzCore.h>


@interface ViewController () {

    UIView *pendulum;

    BOOL isPlaying;

    BOOL even;

    float tempo;

}

@end


@implementation ViewController


- (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor brownColor];

    

    tempo = 100;

    isPlaying = NO;

    

    [self createMetronome];

    

    [self createPendulum];

    

    [self createStartBtn];

}


- (void)createMetronome

{

    float topW = 50;

    float bottomW = topW * 5;

    float topH = 50;

    float bottomH = topH * 8;


    // frame

    {

        UIBezierPath *path = [UIBezierPath bezierPath];

        [path moveToPoint:CGPointMake(160 - topW/2.0, topH)];

        [path addLineToPoint:CGPointMake(160 + topW/2.0, topH)];

        [path addLineToPoint:CGPointMake(160 + bottomW/2.0, bottomH)];

        [path addLineToPoint:CGPointMake(160 - bottomW/2.0, bottomH)];

        [path closePath];

        CAShapeLayer *sl = [[CAShapeLayer alloc] init];

        sl.fillColor = [UIColor blackColor].CGColor;

        sl.strokeColor = [UIColor orangeColor].CGColor;

        sl.lineWidth = 5;

        sl.path = path.CGPath;

        [self.view.layer addSublayer:sl];

    }

    

    // orange trapezoid

    // use even odd

    {

        UIBezierPath *path = [UIBezierPath bezierPath];

        [path moveToPoint:CGPointMake(160 - topW/2.0 * 4.1, topH * 6.5)];

        [path addLineToPoint:CGPointMake(160 + topW/2.0 * 4.1, topH * 6.5)];

        [path addLineToPoint:CGPointMake(160 + bottomW/2.0, bottomH)];

        [path addLineToPoint:CGPointMake(160 - bottomW/2.0, bottomH)];

        [path closePath];

        

        CAShapeLayer *sl = [[CAShapeLayer alloc] init];

        sl.fillColor = [UIColor orangeColor].CGColor;

        sl.path = path.CGPath;

        [self.view.layer addSublayer:sl];

    }

    

    // memory

    CALayer *scale = [CALayer layer];

    scale.frame = CGRectMake(160 - topW * 0.3, topH + 40, topW * 0.6, 230);

    scale.backgroundColor = [UIColor whiteColor].CGColor;

    [self.view.layer addSublayer:scale];

}


- (void)createPendulum

{

    pendulum = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 220)];

    pendulum.backgroundColor = [UIColor clearColor];

    pendulum.layer.anchorPoint = CGPointMake(0.5, 1.0);

    pendulum.layer.position = CGPointMake(160, 320);

    [self.view addSubview:pendulum];

    

    CALayer *line = [CALayer layer];

    line.frame = CGRectMake(15, 0, 10, 220);

    line.backgroundColor = [UIColor lightGrayColor].CGColor;

    [pendulum.layer addSublayer:line];

    

    UILabel *weight = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];

    weight.backgroundColor = [UIColor orangeColor];

    weight.layer.cornerRadius = 10;

    weight.layer.borderColor = [UIColor yellowColor].CGColor;

    weight.layer.borderWidth = 4;

    weight.center = CGPointMake(20, 100);

    weight.text = @"100";

    weight.textAlignment = NSTextAlignmentCenter;

    weight.font = [UIFont boldSystemFontOfSize:15];

    weight.textColor = [UIColor whiteColor];

    [pendulum addSubview:weight];

    

    weight.userInteractionEnabled = YES;

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(slide:)];

    [weight addGestureRecognizer:pan];

}


- (void)slide:(UIPanGestureRecognizer*)gr

{

    CGPoint p = [gr locationInView:pendulum];

    

    if (p.y < 200 && p.y > 10) {

        gr.view.center = CGPointMake(gr.view.center.x, p.y);

        [(UILabel*)gr.view setText:[NSString stringWithFormat:@"%d", (int)p.y]];

        tempo = p.y;

    }

}


- (void)createStartBtn

{

    UILabel *btn = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];

    btn.center = CGPointMake(160, 480);

    btn.text = @"PUSH";

    btn.textAlignment = NSTextAlignmentCenter;

    btn.layer.cornerRadius = 40;

    btn.layer.cornerRadius = 40;

    [self.view addSubview:btn];

    

    btn.userInteractionEnabled= YES;

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(push)];

    [btn addGestureRecognizer:tap];

}


- (void)push

{

    isPlaying = !isPlaying;

    if (isPlaying) {

        [self swing:nil];

        [NSTimer scheduledTimerWithTimeInterval:60.0/tempo target:self selector:@selector(swing:) userInfo:nil repeats:YES];

    }

}


- (void)swing:(NSTimer*)sender

{

    if (isPlaying) {

        float duration = 60.0 / tempo;

        [UIView animateWithDuration:duration animations:^{

            if (even) {

                pendulum.transform = CGAffineTransformMakeRotation(+ M_PI/4.0);

            } else {

                pendulum.transform = CGAffineTransformMakeRotation(- M_PI/4.0);

            }

        }];

        even = !even;

    } else {

        [sender invalidate];

        [UIView animateWithDuration:1.0 animations:^{

            pendulum.transform = CGAffineTransformIdentity;

        }];

    }

}


- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


@end