继续上面的内容。
5. 如何在自己的应用中添加离线语音识别功能
看了OpenEarsSampleApp这个示例项目后,其实基本上已经大概了解了如何在应用中添加离线语音识别功能,不过这里还是要大概总结下一些基本的步骤(具体的操作完全可以参照OpenEarsSampleApp这个官方示例项目来看):
(1) 创建自己的项目,下载OpenEars框架,然后把解压缩文件中的Frameworks文件夹拖到项目中,确保选中”Create groups for any added folders”,而不是”Create folder references for any added folders”.
(2) 可选:为减少应用大小,可以切换到build setting,将Deployment Postprocessing 设置为Yes
(3) 添加 AudioToolbox 和 AVFoundation 这两个框架。(4) 使用语言模型生成器
在自己要用到语音识别的类(比如示例中的ViewController.m)中添加下面的代码:
#import
在需要初始化语言模型生成器的地方添加以下代码:
LanguageModelGenerator *languageModelGenerator = [[LanguageModelGenerator alloc] init];
在OpenEarsSampleApp这个官方示例中,是在viewDidLoad方法中添加的这行代码。
在使用离线语音识别的时候,开发者需要定义自己想要在应用中识别的词汇。对于离线语音识别的iPhone应用来说,词汇在3到300个单词间为宜。
在你想要创建自己语言模型的方法中,(比如示例项目的viewDidLoad方法),添加以下方法调用(使用你想要识别的真实词汇和短语替代其中的”WORD”和”A PHRASE”.
NSArray *words = [NSArray arrayWithObjects:@"WORD", @"STATEMENT", @"OTHER WORD", @"A PHRASE", nil];
NSString *name = @"NameIWantForMyLanguageModelFiles";
NSError *err = [lmGenerator generateLanguageModelFromArray:words withFilesNamed:name];
NSDictionary *languageGeneratorResults = nil;
NSString *lmPath = nil;
NSString *dicPath = nil;
if([err code] == noErr) {
languageGeneratorResults = [err userInfo];
lmPath = [languageGeneratorResults objectForKey:@"LMPath"];
dicPath = [languageGeneratorResults objectForKey:@"DictionaryPath"];
} else {
NSLog(@"Error: %@",[err localizedDescription]);
}
如果你使用默认的英语语言模型生成,那么需要将单词和短语全部大写(但根据我的实际测试,不需要这么做)。如果你需要提前创建一个固定的语言模型,而不是在应用中动态创建,那么可以使用Simulator提交自己的语言模型,然后使用Simulator documents folder script来获取语言模型和词典文件,然后手动添加到应用中。
(5) 使用PocketsphinxController
在使用PocketsphinxController的时候,需要准备好一个语言模型和一个语音词典文件。这两个文件将决定PocketsphinxController可以识别的词汇。当然,在上一步中已经说明了语言模型和语音词典的创建方式。
在项目中需要用到语音识别的类的.h文件顶部(比如示例中的ViewController.h)添加以下代码:
#import
然后在类声明部分添加以下代码:
PocketsphinxController *pocketsphinxController;
然后在.m文件中添加以下方法:
- (PocketsphinxController *)pocketsphinxController {
if (pocketsphinxController == nil) {
pocketsphinxController = [[PocketsphinxController alloc] init];
}
return pocketsphinxController;
}
当然,如同示例项目中的代码一样,你还可以在这里设置它的一些属性。
然后在需要实现语音识别的方法(比如示例项目的viewDidLoad方法)中添加以下代码:
[self.pocketsphinxController startListeningWithLanguageModelAtPath:lmPath dictionaryAtPath:dicPath languageModelIsJSGF:NO];
当然,在OpenEarsSampleApp这个示例项目中,把这行代码放在startListening这个方法中,然后在viewDidLoad方法中调用startListening方法,本质上是一样的。
(6) 使用OpenEarsEventsObserver
接下来将以下代码添加到需要实现语音识别类的.h文件中:
#import
在类声明部分添加对该代理的继承说明,比如在示例项目中如以下代码所示:
@interface ViewController : UIViewController
然后添加以下实例变量:
OpenEarsEventsObserver *openEarsEventsObserver;
还需要添加一个属性:
@property (nonatomic, strong) OpenEarsEventsObserver *openEarsEventsObserver;
在.m实现文件中添加以下方法:
// Lazily allocated OpenEarsEventsObserver.
- (OpenEarsEventsObserver *)openEarsEventsObserver {
if (openEarsEventsObserver == nil) {
openEarsEventsObserver = [[OpenEarsEventsObserver alloc] init];
}
return openEarsEventsObserver;
}
接下来,在你想要使用第一个OpenEars功能之前(比如在第一个self.fliteController say:withVocie: 消息或是在第一个self.pocketsphinxController startListeningWithLanguageModelAtPath:dictionaryAtPath:languageModelIsJSGF: message前)添加以下代码:
[self.openEarsEventsObserver setDelegate:self];
在官方示例代码中,是在viewDidLoad方法的第二行代码添加的。
然后要添加以下代码方法的实现代码:
- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID {
NSLog(@"The received hypothesis is %@ with a score of %@ and an ID of %@", hypothesis, recognitionScore, utteranceID);
}
- (void) pocketsphinxDidStartCalibration {
NSLog(@"Pocketsphinx calibration has started.");
}
- (void) pocketsphinxDidCompleteCalibration {
NSLog(@"Pocketsphinx calibration is complete.");
}
- (void) pocketsphinxDidStartListening {
NSLog(@"Pocketsphinx is now listening.");
}
- (void) pocketsphinxDidDetectSpeech {
NSLog(@"Pocketsphinx has detected speech.");
}
- (void) pocketsphinxDidDetectFinishedSpeech {
NSLog(@"Pocketsphinx has detected a period of silence, concluding an utterance.");
}
- (void) pocketsphinxDidStopListening {
NSLog(@"Pocketsphinx has stopped listening.");
}
- (void) pocketsphinxDidSuspendRecognition {
NSLog(@"Pocketsphinx has suspended recognition.");
}
- (void) pocketsphinxDidResumeRecognition {
NSLog(@"Pocketsphinx has resumed recognition.");
}
- (void) pocketsphinxDidChangeLanguageModelToFile:(NSString *)newLanguageModelPathAsString andDictionary:(NSString *)newDictionaryPathAsString {
NSLog(@"Pocketsphinx is now using the following language model: \n%@ and the following dictionary: %@",newLanguageModelPathAsString,newDictionaryPathAsString);
}
- (void) pocketSphinxContinuousSetupDidFail { // This can let you know that something went wrong with the recognition loop startup. Turn on OPENEARSLOGGING to learn why.
NSLog(@"Setting up the continuous recognition loop has failed for some reason, please turn on OpenEarsLogging to learn more.");
}
以上这些代理方法并不都是必须实现的,根据项目的实际需要来决定,其具体作用在官方示例项目中已经非常清楚,这里就不废话了。
(7) 使用FliteController(语音合成)
为了使用FliteController,首先需要在项目中添加至少一种Flite语音。当然,在将OpenEars框架添加到应用中时,就已经添加了一种名为Slt的默认语音。你还可以通过这里获得其它8种免费的语音: https://bitbucket.org/Politepix/openearsextras
首先在要实现语音合成的类的.h文件(示例中的ViewController.h)顶部添加以下代码:
#import
#import
然后在类声明中添加以下实例变量:
FliteController *fliteController;
Slt *slt;
接下来添加两个属性声明:
@synthesize fliteController;
@synthesize slt;
然后在.m文件中添加以下方法:
// Lazily allocated slt voice.
- (Slt *)slt {
if (slt == nil) {
slt = [[Slt alloc] init];
}
return slt;
}
// Lazily allocated FliteController.
- (FliteController *)fliteController {
if (fliteController == nil) {
fliteController = [[FliteController alloc] init];
}
return fliteController;
}
以上代码很简单,只不过是初始化方法而已。
接下来在想要调用语音合成的方法中添加以下代码:
[self.fliteController say:[NSString stringWithFormat:@"You said %@",hypothesis] withVoice:self.slt];
在示例中是分别在- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis recognitionScore:(NSString *)recognitionScore utteranceID:(NSString *)utteranceID和pocketsphinxDidCompleteCalibration这两个方法中调用的。
基本上,使用以上的步骤,就可以在项目中轻松添加基本的英语语音识别和语音合成功能了。付费插件介绍:
1. 离线语音识别,忽略不在词汇表中的单词
2. 离线语音识别(实时)
3. 将OpenEars离线语音识别的音频保存为wav文件
4. 更好的语音
参考:http://www.politepix.com/openears/