我正在开发一个与配方相关的应用程序。在这个应用程序中有一个部分,用户可以通过麦克风吹气,并可以通过使用动画过渡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次,我想在每次打击检测时单次动画。 请建议我如何使用此代码执行此操作,如果有人可以共享此部分的代码,我会更好。
答案 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的最佳值。
在后一种实施中:
首次检测到打击时,我们更改图像并进入“等待打击熄灭”模式(self.blowDetected == YES);
在“等待打击熄灭”模式下,我们不会更改图像,除非我们发现新的打击,其特点是我们的录制功率远大于当前水平。
答案 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;**
}
}