【问题标题】:Android microphone issue安卓麦克风问题
【发布时间】:2010-08-01 23:03:08
【问题描述】:

是否可以(实时)检测到是否有人对着麦克风吹气? 谢谢

【问题讨论】:

    标签: android audio microphone


    【解决方案1】:

    是的,

    您可以使用 AudioRecord 类并分析返回的波形。

    编辑:刚刚做了一些研究 - 对此有一个警告。事实证明,Android 不能很好地实时处理音频。您会看到 100 毫秒的延迟。如果这对您的项目来说没问题(可能听起来不错),但只是需要注意的事情。

    【讨论】:

      【解决方案2】:

      添加 AVFoundation 框架

      为了使用 SDK 的 AVAudioRecorder 类,我们需要将 AVFoundation 框架添加到项目中:

      接下来,我们将在视图控制器的接口文件中导入 AVFoundation 头文件并设置一个 AVAudioRecorder 实例变量:

      在项目的 Groups & Files 面板中展开 MicBlow 项目分支 展开类文件夹 通过选择它来编辑 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");
      }
      

      这个example

      还有thema

      【讨论】:

      • 请注意 link-only answers 是不鼓励的,所以答案应该是寻找解决方案的终点(相对于另一个参考中途停留,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的概要,并保留链接作为参考。
      猜你喜欢
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多