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回画像をアニメーション化し、2回目に吹き飛ばしてから画像を9〜10回アニメーション化する場合、このアニメーションをすべての打撃検出で1回実行することです。このコードを使用してこれを行う方法を教えてください。そうしないと、誰かがこのセクションのコードを共有できるとよいでしょう。

4

2 に答える 2

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 に答える
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 に答える