在Cocos中通过iPhone MIC检测打击,然后在图像上执行动画

时间:2012-10-20 05:11:17

标签: iphone animation

我正在开发一个与配方相关的应用程序。在这个应用程序中有一个部分,用户可以通过麦克风吹气,并可以通过使用动画过渡CurlDown来改变图像及其上的内容。我是能够使用以下代码检测打击,

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];

    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithFloat: 44100.0],                 AVSampleRateKey,
                              [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
                              [NSNumber numberWithInt: 1],                         AVNumberOfChannelsKey,
                              [NSNumber numberWithInt: AVAudioQualityMax],         AVEncoderAudioQualityKey,
                              nil];

    NSError *error;

    recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];

    if (recorder) {
        [recorder prepareToRecord];
        recorder.meteringEnabled = YES;
        [recorder record];

        levelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target: self selector: @selector(levelTimerCallback:) userInfo:nil repeats:YES];


    }
    else{
//       NSLog([error description]);
    }

    image =[[UIImageView alloc] init];
    image.image =[UIImage imageNamed:@"Recipie.png"];
    image.frame =CGRectMake(50, 100, 150, 200);
    [self.view addSubview:image];

}


- (void)levelTimerCallback:(NSTimer *)timer {

    [recorder updateMeters];
    const double ALPHA = 0.05;
    double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
    lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;  
//  NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);
    if (lowPassResults >0.055 )
    {
        NSLog(@"Mic blow detected");
        [self changeFrame];

    }

}

-(void)changeFrame
{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:image cache:NO];
    [UIView commitAnimations];

}

但我的问题是,当我第一次通过麦克风时,然后将图像动画5到7次,当我第二次吹,然后图像动画9到10次,我想在每次打击检测时单次动画。 请建议我如何使用此代码执行此操作,如果有人可以共享此部分的代码,我会更好。

2 个答案:

答案 0 :(得分:3)

我怀疑问题来自你每秒呼叫levelTimerCallback的事实。因此,当一击进来时,在整个打击过程中,你的回调将使图像发生变化。

解决方法是使用BOOL标志:

@property (nonatomic) BOOL blowDetected;

levelTimerCallback中,您可以跟踪何时检测到击打以及何时结束,并且您只会为新击打更改图像:

- (void)levelTimerCallback:(NSTimer *)timer {

  [recorder updateMeters];
  const double ALPHA = 0.05;
  double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
  lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;  
  if (lowPassResults > 0.055)
  {
    NSLog(@"Blow detected with power: %f", lowPassResults);
    if (!self.blowDetected) {
      self.blowDetected = YES;
      NSLog(@"Mic blow detected");
      [self changeFrame];
    }
  } else {
    NSLog(@"Blow not detected with residual power: %f", lowPassResults);
    self.blowDetected = NO;
  }
}

这可以防止多次图像更改同样的打击......

现在,这可以在击打和下一个等待足够时间之间正常工作,以便麦克风当前检测到的功率降低到0.055阈值以下。这意味着在此之前发生的任何打击都将被忽略。

为了改善这一点,我们可以简单地尝试检测过滤后的值何时增加,而不是简单地过滤信号;所以我建议以下实施:

- (void)levelTimerCallback:(NSTimer *)timer {

  [recorder updateMeters];
  const double ALPHA = 0.05;
  double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
  double currentLowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;  
  if (currentLowPassResults > 0.055)
  {
    NSLog(@"Blow detected with power: %f", lowPassResults);
    if (!self.blowDetected || currentLowPassResult > K * lowPassResults) {
      self.blowDetected = YES;
      NSLog(@"Mic blow detected");
      [self changeFrame];
    }
  } else {
    NSLog(@"Blow not detected with residual power: %f", lowPassResults);
    self.blowDetected = NO;
  }
  lowPassResult = currentLowPassResults;
}

您可以通过一些测试找到K的最佳值。

在后一种实施中:

  1. 首次检测到打击时,我们更改图像并进入“等待打击熄灭”模式(self.blowDetected == YES);

  2. 在“等待打击熄灭”模式下,我们不会更改图像,除非我们发现新的打击,其特点是我们的录制功率远大于当前水平。

答案 1 :(得分:3)

使用返回,因为您获得第一个低通结果> 0.55

我已经解决了这个问题。

-(void)readyToBlow1 {

  NSURL *url = [NSURL fileURLWithPath:@"/dev/null"];

  NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithFloat: 44100.0],                 AVSampleRateKey,
                          [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
                          [NSNumber numberWithInt: 1],                         AVNumberOfChannelsKey,
                          [NSNumber numberWithInt: AVAudioQualityMax],         AVEncoderAudioQualityKey,
                          nil];

NSError *error;

recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];

if (recorder) {
    [recorder prepareToRecord];
    recorder.meteringEnabled = YES;
    [recorder record];
    levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(levelTimerCallback1:) userInfo: nil repeats: YES];
 } 
  else
     NSLog(@"%@",[error description]);

}

 - (void)levelTimerCallback1:(NSTimer *)timer {

    [recorder updateMeters];

const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
//NSLog(@"lowPassResults= %f",lowPassResults);

if (lowPassResults > 0.55)
{

    lowPassResults = 0.0;

    [self invalidateTimers];


    NextPhase *objNextView =[[NextPhase alloc]init];

    [UIView transitionFromView:self.view
                        toView:objNextView.view
                      duration:2.0
                       options:UIViewAnimationOptionTransitionCurlUp
                    completion:^(BOOL finished) {
                    }
     ];

    [self.navigationController pushViewController:objNextView animated:NO];

    **return;**


  }

}