是否可以(实时)检测是否有人对着麦克风吹气?谢谢
2 回答
是的,
您可以使用 AudioRecord 类并分析返回的波形。
编辑:刚刚做了一些研究——对此有一个警告。事实证明,Android 不能很好地实时处理音频。您会看到 100 毫秒的延迟。如果这对您的项目没问题(可能听起来不错),但只是需要注意的事情。
添加 AVFoundation 框架
为了使用 SDK 的 AVAudioRecorder 类,我们需要将 AVFoundation 框架添加到项目中:
接下来,我们将在视图控制器的接口文件中导入 AVFoundation 头文件并设置一个 AVAudioRecorder 实例变量:
在项目的 Groups & Files 面板中展开 MicBlow 项目分支 展开 Classes 文件夹 通过选择它来编辑 MicBlowViewController.h 更新文件:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface MicBlowViewController : UIViewController {
AVAudioRecorder *recorder;
}
从麦克风 中获取输入 取消注释样板 ViewDidLoad 方法 如下更新它。
- (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];
} else
NSLog([error description]);
}
对音频电平进行采样 我们将使用一个计时器每秒检查大约 30 次音频电平。在 MicBlowViewController.h 中添加一个 NSTimer 实例变量及其回调方法。
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface MicBlowViewController : UIViewController {
AVAudioRecorder *recorder;
NSTimer *levelTimer;
}
- (void)levelTimerCallback:(NSTimer *)timer;
@end
更新 .m 文件的 ViewDidLoad 以启用计时器。- (void)viewDidLoad { [超级 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: 0.03 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES];
} else
NSLog([error description]);
}
现在,我们将直接采样音频输入电平/不进行过滤。将 levelTimerCallback: 的实现添加到 .m 文件中:
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
NSLog(@"Average input: %f Peak input: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0]);
}
发送 updateMeters 消息会刷新平均功率计和峰值功率计。仪表使用对数刻度,-160 表示完全安静,0 表示最大输入。
不要忘记在 dealloc 中释放计时器。更改为粗体:
- (void)dealloc {
[levelTimer release];
[recorder release];
[super dealloc];
}
聆听吹响的声音 如概述中所述,我们将使用低通滤波器来减少高频声音对电平的贡献。该算法创建了一组包含过去样本输入的运行结果;我们需要一个实例变量来保存结果。更新 .h 文件。
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface MicBlowViewController : UIViewController {
AVAudioRecorder *recorder;
NSTimer *levelTimer;
double lowPassResults;
}
通过将 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;
NSLog(@"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);
}
对于我的应用程序的需要,0.95 有效。我们将用一个简单的条件替换日志行:
- (void)listenForBlow:(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.95)
NSLog(@"Mic blow detected");
}
这个例子。
和主题。