Question

I'm in the course of developing a metronome for iPad. I'm using CGAffineTransformRotate for the metronomeArm animation, NSTimer(I'm not interested in great precision) for sound and a UIPanGestureRecognizer for dragging the metronomeWeight on the metronomeArm.enter image description here

My problem is that I don't know how to update the bpm by dragging the weight using the pan. For now I have this : metronomeWeight.center.y is 240 and the default bpm for this position is 80.The weight goes from top 140 to a maximum of 450. I have implemented this method but it is not correct :

-(void)updateBPM
    {
        CGFloat weightYPosition = metronomeWeight.center.y;
        NSUInteger newBPM = (weightYPosition/3);
        self.bpm = newBPM;
    }

and the selector for the pan is this :

-(void)handlePan:(UIPanGestureRecognizer*)gesture
{

    CGPoint translation = [gesture translationInView:metronomeArm];
    CGPoint location = [gesture locationInView:metronomeArm];

    NSLog(@"miscarea pe oy are valoare de: %f", location.y);

    CGPoint newCenter = CGPointMake(metronomeArm.frame.size.width/2, gesture.view.center.y + translation.y );

    if (newCenter.y >= 140 && newCenter.y <= 450) 
{
        gesture.view.center = newCenter;
        [gesture setTranslation:CGPointZero inView:metronomeArm];
        [self updateBPMFromWeightLocation];
        tempoLabel.text = [NSString stringWithFormat:@"%d", self.bpm];
        NSLog(@"metronomeWeight position : %f ",metronomeWeight.center.y);
    }
}

The sound and animation update but not as desired, meaning that the lower limit bpm should be 225 and the upper one should be 1. In my case they are 150 and 46 respectively.

My calculations are not good, so it will be fantastic if you can help me solve this problem... I have looked at apple's metronome project for days and can't understand how they do this...

Thanks

The new updateBPM method thanks to @zimmryan suggestion

-(void)updateBPMFromWeightLocation
{
    CGFloat weightYPosition = metronomeWeight.center.y;
    float lengthInM = ((weightYPosition - 140) * 0.00041333);
    float time = 2 * M_PI * sqrt(lengthInM / 9.8);
    NSUInteger newBPM = floor(60.0 / time);
    self.bpm = newBPM;
}
Was it helpful?

Solution

From my understanding of physics and calculus, the equation for the period of a pendulum is T=2pi sqrt(l/g) where T is time in seconds, l is length in meters, and g is gravity.

You are picking a base point of 290 (pixels) and a BPM of 120. A BPM of 120 converts to a period of .5 seconds. So T = .5. Solving the equation you get .062 for l, or 6.2cm.

But your length is not in cm it is in pixels s now you have to convert it. Since your range is from 140 to 350, your zero point is 350. So first you take 350 - 390 to get an offset of 60. Now create your equation of 60pixels * k = .062 so your k = .001033

Your final function should read

-(void)updateBPM
{
    CGFloat weightYPosition = metronomeWeight.center.y;
    float lengthInM = ((350 - weightYPosition) * .001033);
    float time = 2 * M_PI * sqrt(lengthInM / 9.8);
    NSUInteger newBPM = floor(60 / time);
    self.bpm = newBPM;
}

or

-(void)updateBPM
{
    self.bpm = floor(60 / (2 * M_PI * sqrt(((350 - metronomeWeight.center.y) * .001033) / 9.8)));
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top