1

我正在开发一个与食谱相关的应用程序。在这个应用程序中有一个部分,用户可以通过麦克风吹气,并可以通过使用动画转换 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 次,我希望每次检测到这个动画时都会播放一次。请建议我如何使用此代码执行此操作,或者如果有人可以共享本节的代码,对我来说会更好。

4

2 回答 2

3

当你得到第一个低通结果 >0.55 时使用 return

我已经解决了问题看看。

-(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;**


  }

}
于 2013-01-23T14:07:32.907 回答
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. 在“等待打击熄灭”模式下,我们不会更改图像,除非我们检测到新的打击,其特点是我们的记录功率明显大于当前水平。

于 2012-10-20T06:18:23.137 回答