Добавление платформы AVFoundation Framework
Чтобы использовать класс AVAudioRecorder в SDK, нам нужно добавить в проект инфраструктуру AVFoundation:
Далее мы импортируем заголовки AVFoundation в файл интерфейса контроллера представления и настроим переменную экземпляра AVAudioRecorder:
Разверните ветку проекта 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 раз в секунду. Добавьте переменную экземпляра NSTimer и метод обратного вызова к нему в MicBlowViewController.h.
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
@interface MicBlowViewController : UIViewController {
AVAudioRecorder *recorder;
NSTimer *levelTimer;
}
- (void)levelTimerCallback:(NSTimer *)timer;
@end
Обновите ViewDidLoad файла .m, чтобы включить таймер.
- (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: 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 - полная тишина, а ноль - максимальный ввод.
Не забудьте отпустить таймер в 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");
}
Это пример .
и тема .