我正在使用与食谱相关的应用程序。在此应用程序中,用户可以通过麦克风吹动空气并可以更改图像以及上面的内容通过使用动画过渡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次动画时,我希望在每次打击检测中单次进行动画。请建议我使用此代码如何执行此操作,或者如果有人可以共享本节的代码对我来说会更好。
我怀疑问题来自您每秒调用levelTimerCallback
的事实。因此,当打击进来时,在整个打击期间,您的回调将使图像更改。
解决方法将使用一个布尔标志:
@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 ==是);
在模式中"等待打击熄灭",我们不会更改图像,除非我们检测到新的打击,其特征是我们的记录能力明显大于当前水平。
在获得第一次低通> 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;**
}
}