最近iOS项目中需要用到语音识别技术(也被称为自动语音识别,英语:Automatic Speech Recognition, ASR)。去google搜索了一下,发现语音识别做的不错的有谷歌,微软和科大讯飞。但是微软的语音识别只能在window平台,科大讯飞的语音识别现在主要是中文和英文,而谷歌的语音识别是可以支持多国语言的,考虑到项目以后可能会有多种语言,所以我选择用谷歌的语音识别。
这里有一篇文章,比较详细的对比了三种语音识别:Google,微软,科大讯飞的语音识别引擎对比。
语音识别的流程包括两个步骤:1.语音录入; 2.语音识别.
语音录入
语音录入的方法我使用了两种:
1.参照官方文档例子SpeakHere(使用了OC,C++混编,后来发现有些OC方法,在iOS 7中已经不建议使用了)
2.使用AVAudioRecorder来录音(建议使用第二种方法)。
注意:从查得的资料来看,使用谷歌语音搜索的音频编码暂时可用的有flac,speex,wav三种。网上说flac在iOS上获得比较复杂,speex暂不清楚,wav是可以得到的。获取wav编码格式的设置方式如下:
#pragma mark -
#pragma mark 录音设置
- (NSString *) audioRecordingPath
{
return [NSTemporaryDirectory() stringByAppendingFormat:@"voice.wav"];
}
- (NSDictionary *) audioRecordingSettings{
NSDictionary *result = nil;
/* Let's prepare the audio recorder options in the dictionary.
Later we will use this dictionary to instantiate an audio
recorder of type AVAudioRecorder */
NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];
[settings setValue:[NSNumber numberWithInteger:kAudioFormatLinearPCM]
forKey:AVFormatIDKey];
[settings setValue:[NSNumber numberWithFloat:16000]
forKey:AVSampleRateKey];
[settings setValue:[NSNumber numberWithInteger:1]
forKey:AVNumberOfChannelsKey];
[settings setValue:[NSNumber numberWithInteger:AVAudioQualityLow]
forKey:AVEncoderAudioQualityKey];
result = [NSDictionary dictionaryWithDictionary:settings];
return result;
}
录音完成之后,将音频文件保存,然后进行语音识别。
语音识别
- 基本流程:
一、从音频输入设备获取原始数据。二、对原始数据进行包装、编码。三、将编码后的音频POST至接口地址。四、分析处理接口返回的JSON并得出结果。
- 请求接口
xjerr错误标准
client
客户端类型
lang
待识别语言类型,en-US是英文,中文为zh-CN(其余语言代码参考:http://msdn.microsoft.com/en-us/library/ms533052(v=vs.85).aspx)
maxresults
最大返回识别结果数量,多个结果在hypotheses列表中保存
请求方式:HTTP POST头部信息:Content-Type: audio/x-flac; rate=16000 (注:Content-Type根据所使用的编码格式不同而不同,详见文章底部。rate为音频采样率。)请求数据:编码后的音频数据
- 音频编码格式
FLAC或WAV或SPEEX
iOS语音识别请求实现代码:
- (void)beginRecognition
{
NSURL *url = [NSURL URLWithString:@"http://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en"];
ASIFormDataRequest *request = [[ASIFormDataRequest alloc] initWithURL:url];
[request setRequestMethod:@"POST"];
NSString *filePath_voice = [self audioRecordingPath];
[request appendPostDataFromFile:filePath_voice];
[request addRequestHeader:@"Content-Type" value:@"audio/L16; rate=16000"];
[request setDidFailSelector:@selector(recognitionFailed:)];
[request setDidFinishSelector:@selector(recognitionFinished:)];
request.delegate=self;
[request startAsynchronous];
}
返回结果:
{
"status":0,//返回状态
"id":"",
"hypotheses"://结果列表
[
{
"utterance":"hello", //语音所转换的文字
"confidence":0.8394497 //识别信心度
}
]
}
因为项目中语音是用来做搜索用,基本输入几个词汇就行,不需要大篇幅如短信一般。所以,我希望能在我说完话后,自动停止录音。这样,我们需要自动识别什么时候录入完毕了。
自动识别语音录入完毕
基本流程:
- 录音开始,添加一个定时器,不停地检测话筒是否有接收到声音;
- 一旦检测到有声音,说明开始有说话(期间定时器仍然在检测);
- 再次检测到没有声音,说明录入完毕,然后停止定时器刷新,停止录音。
定时器检测实现方法以及相关注释:
-(void)refresh:(id)sender
{
//发送updateMeters消息来刷新平均和峰值功率
[audioRecorder updateMeters];
//此计数是以对数刻度计量的,-160表示完全安静,0表示最大输入值。
//为方便,我们将其转换为0-1,0代表完全安静,1代表最大音量。
float peakPowerForChannel = pow(10, 0.05*[audioRecorder peakPowerForChannel:0]);
float averagePowerForChannel = pow(10, 0.05*[audioRecorder averagePowerForChannel:0]);
NSLog(@"Average input: %f Peak input: %f", peakPowerForChannel,averagePowerForChannel);
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
averagePassResults = ALPHA * averagePowerForChannel + (1.0 - ALPHA) * averagePassResults;
indicateHigh.alpha = averagePassResults;
if (lowPassResults > 0.55f)
{//此时mic接收到震动
blowDetected = YES;
}
else
{
if (blowDetected)
{
blowDetected = NO;
[self stopRecord];
NSLog(@"录音完成");
}
}
}
噪声/声音是由低频声音组成的。我们将使用low pass filter(低频滤波) 来降低来自麦克的高频声音;当滤波信号的电平等级突然增大时,我们就知道有人向麦克说话了。
blowDetected是一个bool值,因为一开始录音和完成录音都是电频等级较低的时候,所以需要一个开关来区分,否则录音没刚始就结束了。
indicateHigh是个view,时刻改变透明度以告诉用户有人在说话,你也可以用其他方式来指示。
lowPassResults通过低频滤波算法得到,有兴趣的可以研究一下。其中ALPHA这里值为0.05.
好了,到这里语音识别需要的东西基本就完成了。
其实这篇文章只能算是一个汇总吧,把我需要的东西都记在这里,非常感谢网络上那些乐于分享的同学。
参考:
Iphone开发之音频101:
检测用户向麦克吹气:
点击打开链接
自动识别语音录入完毕:
点击打开链接
"Unknown type name 'class'; did you mean 'Class'?"(OC与C++混编发生的问题):
点击打开链接
CADebugPrintf.h file not found:
点击打开链接
Google,微软,科大讯飞的语音识别引擎对比:
点击打开链接