Tap pressure strength detection using CPBPressureTouchGestureRecognizer
Asked Answered
I

2

3

it's working great with one UIButton:

 – (void) viewDidLoad {
[super viewDidLoad];

CPBPressureTouchGestureRecognizer* recognizer = [[CPBPressureTouchGestureRecognizer alloc] initWithTarget:self action:@selector(A_button:)];
[A_button addGestureRecognizer: recognizer];
[recognizer release];
}


- (void) A_button: (CPBPressureTouchGestureRecognizer*) recognizer {
[pan_A setGain:recognizer.pressure];
[pan_A] play;
}

i tried to use more but only the second one is working:

- (void) viewDidLoad {
[super viewDidLoad];
CPBPressureTouchGestureRecognizer* recognizer1 = [[CPBPressureTouchGestureRecognizer alloc] initWithTarget:self action:@selector(A_button:)];
[A_button addGestureRecognizer: recognizer1];

CPBPressureTouchGestureRecognizer* recognizer2 = [[CPBPressureTouchGestureRecognizer alloc] initWithTarget:self action:@selector(B_button:)];
[B_button addGestureRecognizer: recognizer1];
[recognizer1 release];
[recognizer2 release];
}

- (void) A_button: (CPBPressureTouchGestureRecognizer*) recognizer1 {
[pan_A setGain:recognizer1.pressure];
[pan_A] play;
}

- (void) B_button: (CPBPressureTouchGestureRecognizer*) recognizer1 {
[pan_B setGain:recognizer2.pressure];
[pan_B] play;
}

how can i get both to work?

Ita answered 10/11, 2011 at 12:34 Comment(1)
What technology is involved? i.e. programming language, framework, platform?Yoga
L
5

The CPBPressureTouchGestureRecognizer only supported a single instance of itself do to the delegate model of the UIAccelerometer. Here is a better version that supports multiple instances.

//  CPBPressureTouchGestureRecognizer.h
//  PressureSensitiveButton

#import <UIKit/UIKit.h>

#define CPBPressureNone         0.0f
#define CPBPressureLight        0.3f
#define CPBPressureMedium       0.4f
#define CPBPressureHard         0.6f
#define CPBPressureInfinite     2.0f

@interface CPBPressureTouchGestureRecognizer : UIGestureRecognizer {
    @public
    float pressure;
    float minimumPressureRequired;
    float maximumPressureRequired;

    @private
    float pressureValues[50];
    uint currentPressureValueIndex;
    uint setNextPressureValue;
}

@property (readonly, assign) float pressure;
@property (readwrite, assign) float minimumPressureRequired;
@property (readwrite, assign) float maximumPressureRequired;

@end

//  CPBPressureTouchGestureRecognizer.m

#import <UIKit/UIGestureRecognizerSubclass.h>
#import "CPBPressureTouchGestureRecognizer.h"
#import "CPBAcceleromterDelegate.h"

#define kUpdateFrequency            60.0f
#define KNumberOfPressureSamples    3

@interface CPBPressureTouchGestureRecognizer (private)
    - (void)setup;
@end

@implementation CPBPressureTouchGestureRecognizer
@synthesize pressure, minimumPressureRequired, maximumPressureRequired;

- (id)initWithTarget:(id)target action:(SEL)action {
    self = [super initWithTarget:target action:action];
    if (self != nil) {
       [self setup];
    }
    return self;
}

- (id)init {
    self = [super init];
    if (self != nil) {
        [self setup];
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (void)setup {
    minimumPressureRequired = CPBPressureNone;
    maximumPressureRequired = CPBPressureInfinite;
    pressure = CPBPressureNone;

    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:0.001f / kUpdateFrequency];
    [[UIAccelerometer sharedAccelerometer] setDelegate:[CPBAcceleromterDelegate sharedCPBAcceleromterDelegate]];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accelerateNotification:) name:CPB_ACCELERATION_EVENT object:nil];
}

#pragma -
#pragma UIAccelerometerDelegate methods

- (void)accelerateNotification:(NSNotification *)notification {

    UIAcceleration *acceleration = [[CPBAcceleromterDelegate sharedCPBAcceleromterDelegate] acceleration];

    int sz = (sizeof pressureValues) / (sizeof pressureValues[0]);

    // set current pressure value
    pressureValues[currentPressureValueIndex%sz] = acceleration.z;

    if (setNextPressureValue > 0) {

        // calculate average pressure
        float total = 0.0f;
        for (int loop=0; loop<sz; loop++) total += pressureValues[loop]; 
        float average = total / sz;

        // start with most recent past pressure sample
        if (setNextPressureValue == KNumberOfPressureSamples) {
            float mostRecent = pressureValues[(currentPressureValueIndex-1)%sz];
            pressure = fabsf(average - mostRecent);
        }

        // caluculate pressure as difference between average and current acceleration
        float diff = fabsf(average - acceleration.z);
        if (pressure < diff) pressure = diff;
        setNextPressureValue--;

        if (setNextPressureValue == 0) {
            if (pressure >= minimumPressureRequired && pressure <= maximumPressureRequired)
                self.state = UIGestureRecognizerStateRecognized;
            else
                self.state = UIGestureRecognizerStateFailed;
        }
    }

    currentPressureValueIndex++;
}

#pragma -
#pragma UIGestureRecognizer subclass methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    setNextPressureValue = KNumberOfPressureSamples;
    self.state = UIGestureRecognizerStatePossible;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    self.state = UIGestureRecognizerStateFailed;
}

- (void)reset {
    pressure = CPBPressureNone;
    setNextPressureValue = 0;
    currentPressureValueIndex = 0;
}

@end


//
//  CPBAcceleromterDelegate.h
//  iPan
//
//  Created by Anthony Picciano on 1/25/12.
//  Copyright (c) 2012 Crispin Porter + Bogusky. All rights reserved.
//

#import <Foundation/Foundation.h>
#define CPB_ACCELERATION_EVENT @"accellerationEvent"

@interface CPBAcceleromterDelegate : NSObject <UIAccelerometerDelegate>

@property (nonatomic, retain) UIAcceleration *acceleration;

+ (CPBAcceleromterDelegate *)sharedCPBAcceleromterDelegate;

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration;

@end


//
//  CPBAcceleromterDelegate.m
//  iPan
//
//  Created by Anthony Picciano on 1/25/12.
//  Copyright (c) 2012 Crispin Porter + Bogusky. All rights reserved.
//

#import "CPBAcceleromterDelegate.h"
#include "SynthesizeSingleton.h"

@implementation CPBAcceleromterDelegate
@synthesize acceleration;

SYNTHESIZE_SINGLETON_FOR_CLASS(CPBAcceleromterDelegate)

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)newAcceleration
{
    self.acceleration = newAcceleration;
    [[NSNotificationCenter defaultCenter] postNotificationName:CPB_ACCELERATION_EVENT object:self];
}

@end


//
//  SynthesizeSingleton.h
//  CocoaWithLove
//
//  Created by Matt Gallagher on 20/10/08.
//  Copyright 2009 Matt Gallagher. All rights reserved.
//  http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
//
//  Permission is given to use this source code file without charge in any
//  project, commercial or otherwise, entirely at your risk, with the condition
//  that any redistribution (in part or whole) of source code must retain
//  this copyright and permission notice. Attribution in compiled projects is
//  appreciated but not required.
//

#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}
Lovellalovelock answered 25/1, 2012 at 17:31 Comment(2)
Is there updated version of this code available (using CoreMotion)?Catha
No. This code is more than four years old and there should be better ways to do this now.Lovellalovelock
S
1

See this line: [B_button addGestureRecognizer: recognizer1];?

You add recognizer1 not recognizer2, so the recognizer2 is not used;

Spectroscope answered 4/9, 2012 at 1:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.