当前位置: 首页 > 科技观察

基于语音框架的IOS语音识别

时间:2023-03-14 19:45:23 科技观察

作者|家庭运营中心实验室指导吴鑫双App开发经常会遇到需要对文字进行波浪动画语音识别,那么如何真正实现这样的功能,本文将从技术框架和可视化实现的角度详细介绍Speech框架方案.1语音框架及使用流程目前App中的语音识别功能主要分为两种情况:本地识别和在线识别。网络在线识别依赖于平台处理语音数据的能力。其识别准确率高,优势明显。缺点是识别的稳定性和效率稍低;虽然本地识别方案的稳定性和效率都比较高,但识别准确率不如在线识别方法。本文要介绍的Speech框架是一个成熟的本地语音识别框架,适用于对识别精度要求不高但识别效率高的场景。为了方便功能的维护和调用,项目中建议将框架的识别能力封装成manager模块。语音框架识别能力的管理器可以定义如下:@interfaceHYSpeechVoiceDetectManager:NSObject-(void)isHasVoiceRecodingAuthority:(authorityReturnBlock)hasAuthorityBlock;+(void)isHasSpeechRecognizerAuthority:(authorityReturnBlock)hasAuthorityBlock;-(void)setupTimer;-(void)startTransfer;-(void)endTransfer;从上面的代码我们可以看出封装函数包含了整个语音识别过程:1.判断语音和Speechframe使用权限(isHasVoiceRecodingAuthority和isHasSpeechRecognizerAuthority)2.语音识别参数及相关类初始化(setupTimer)3.开启语音识别并实时接收识别到的文本信息(setupTimer和startTransfer)4.强行销毁语音帧数据并重置设置音频配置数据(endTransfer),下面分别对以上四个步骤进行说明。1.1确定语音语音框架使用权限因为识别成功的首要条件是已经获得语音语音框架的使用权限,所以在初始化框架功能的时候需要获取权限。获取Speech框架使用权限的代码如下:-(void)isHasSpeechRecognizerAuthority{if(@available(iOS10.0,*)){SFSpeechRecognizerAuthorizationStatusauthorizationStatus=[SFSpeechRecognizerauthorizationStatus];如果(authorizationStatus==SFSpeechRecognizerAuthorizationStatusNotDetermined){[SFSpeechRecognizer请求授权:^(SFSpeechRecognizerAuthorizationStatus状态){}];}elseif(authorizationStatus==SFSpeechRecognizerAuthorizationStatusDenied||authorizationStatus==SFSpeechRecognizerAuthorizationStatusRestricted){}else{}}else{}}上面代码中获取SFSpeechRecognizerAuthorizationStatus后,就可以得到Sepeech框架的权限信息。语音使用权限获取操作,相关代码参考如下:-(void)isHasVoiceRecodingAuthority:(authorityReturnBlock)hasAuthorityBlock{if([[[UIDevicecurrentDevice]systemVersion]floatValue]>=7.0){AVAuthorizationStatusvideoAuthStatus=[AVCaptureDeviceauthorizationMediaStatusForMediaType:if(videoAuthStatus==AVAuthorizationStatusNotDetermined){}elseif(videoAuthStatus==AVAuthorizationStatusRestricted||videoAuthStatus==AVAuthorizationStatusDenied){}else{}}}通过上述代码中的videoAuthStatus,可以获取语音权限信息。在实际使用中,应该先获取语音权限信息Permissions,然后在此基础上获取Sepeech框架权限信息,只有用户在拥有两个权限的前提下,才能进入下一步“语音识别参数及相关类初始化”环节。1.2语音识别参数及相关类初始化在Sepeech框架初始化之前,需要建立一个音频流输入通道。AVAudioEngine是这个输入通道不可或缺的节点。AVAudioEngine可以产生和处理音频信号,并进行音频信号输入操作。AVAudioInputNode是音频流的拼接通道,可以实时拼接一段语音,完成动态音频流数据。AVAudioEngine和AVAudioInputNode配合使用,完成音频流数据获取的准备工作。AVAudioEngine执行方法-(void)prepare只有在初始化后才能生效。相关代码如下:AVAudioEngine*bufferEngine=[[AVAudioEnginealloc]init];AVAudioInputNode*bufferInputNode=[bufferEngineinputNode];SFSpeechAudioBufferRecognitionRequest*bufferRequest=[[SFSpeechAudioBufferRecognitionRequestalloc]init];AVAudioFormat*format=[buffeInputNodeoutputFormatForBus:0];[buffeInputNodeinstallTapOnBus:0bufferSize:1024format:formatblock:^(AVAudioPCMBuffer*_Nonnullbuffer,AVAudioTime*_Nonnullwhen){[bufferRequestappendAudioPCMBuffer:buffer];}];[缓冲引擎准备];上述代码中,可以通过bufferInputNode回调接口获取SFSpeechAudioBufferRecognitionRequest完整的实时音频数据流信息。使用Sepeech框架时,需要一个关键类——录音机(AVAudioRecorder),用于设置语音采集的格式、音频通道、比特率、数据缓存路径等重要信息,完成语音采集等功能。只有调用AVAudioRecorder-(BOOL)录音方法,语音识别功能才能正常启动,参考如下代码:[selfendTransfer];NSDictionary*recordSettings=[[NSDictionaryalloc]initWithObjectsAndKeys:[NSNumbernumberWithFloat:14400.0],AVSampleRateKey,[NSNumbernumberWithInt:kAudioFormatAppleIMA4],AVFormatIDKey,[NSNumbernumberWithInt:2],AVNumberOfChannelsKey,[NSNumbernumberWithInt:AVAudioQualityKey,niludio],AVEncode;NSString*monitorPath=[NSTemporaryDirectory()stringByAppendingPathComponent:@"monitor.cafathorNSPathorfile]:URL=WathorURL*monitURL];AVAudioRecorder*monitor=[[AVAudioRecorderalloc]initWithURL:_monitorURLsettings:recordSettingserror:NULL];monitor.meteringEnabled=YES;[监控记录];上述代码中语音识别初始化过程的第一行代码应该先执行endTransfer。该接口的主要作用是将音频参数初始化为默认状态:强行销毁音频流输入通道、清空录音机、清除音频识别任务,其中,初始化音频参数是比较重要的一步。其目的是防止项目中其他功能模块修改音频输入参数等信息导致语音识别异常。相关细节将在下文描述。1.3开启语音识别,实时接收识别出的文字信息。识别转换函数-(void)startTransfer会一直输出语音识别转换后的文本信息。此功能主要取决于SFSpeechRecognizer类。我们可以通过回调接口返回实时参数SFSpeechRecognitionResult_Nullableresult需要注意的是,只有回调无错时,输出的文本信息才有效。参考代码如下:SFSpeechRecognitionResult*_Nullable结果,NSError*_Nullableerror){if(error==nil){NSString*voiceTextCache=result.bestTranscription.formattedString;}别的{}}];上面代码中的bufferRec就是Sepeech框架中的语音识别器。通过该类可以完成音频数据的本地化文本信息转换,voiceTextCache是??语音信息的实时转换。1.4强行销毁Speech帧数据,重置音频配置数据。识别结束时,需要调用-(void)endTransfer方法强行关闭音频流通道,删除语音缓冲文件,停止语音监听等,还需要修改音频模式和参数为默认重置。相关代码如下:-(void)endTransfer{[bufferEnginestop];[bufferInputNoderemoveTapOnBus:0];缓冲区请求=零;缓冲区任务=零;[监控停止];[监听删除录音];NSError*错误=无;[[AVAudioSessionsharedInstance]setActive:NOer??ror:&error];如果(错误!=无){返回;}[[AVAudioSessionsharedInstance]setCategory:AVAudioSessionCategoryPlaybackerror:nil];如果(错误!=无){返回;}[[AVAudioSessionsharedInstance]setMode:AVAudioSessionModeDefaulterror:&error];如果(错误!=无){返回;}[[AVAudioSessionsharedInstance]setActive:YESerror:&error];if(error!=nil){return;}}2语音识别波浪效果实现原理2.1语音识别动画效果ios语音识别需求往往需要实时显示语音识别的动画过程。效果如下图所示:上图最终效果图共有32个波浪点,其中前6个和后6个属于固定静态点,只有中间20个点属于声音2.2语音识别动画的实现原理上图中的动效实际有两种实现方式:1.ios系统传统的CoreAnimation框架;2.动态更新点框。如果使用传统的CoreAnimation框架,需要为每个点做一个浮空效果动画,从实现过程和系统开销上来说是得不偿失的。但是,如果使用简单的动态更新点框的方法,则会事半功倍。本文的内容也将以动态更新点阵的方式进行讲述。对于上图的动画效果,很容易联想到数学中的正弦函数图,所以可以将波浪图的水平方向定义为正弦X轴(其实ios的坐标也是基于在这个概念上),垂直方向是正弦Y轴(高度是体积到坐标的映射值)。首先局部初始化32个浮点对应32个X轴映射坐标x,设置坐标间隙的等价值。传输实时语音音量volume数据时,正弦函数y=F*sin(pi*x-pi*t)可以计算出映射幅度y,其中语音音量定义最大音量数据,强与正弦函数幅值数据F相关,相关实现示意图如下:如何获取实时语音音量volume数据?其实上一篇中的monitor(AVAudioRecorder)提供了一个语音音量数据的封装接口——(float)peakPowerForChannel:(NSUInteger)channelNumber,channelNumber是音频输入/输出的通道号,这个函数返回的数据是分贝值。取值范围为-160~0,声音峰值越大越接近0。获取实时语音音量数据后,进行相应的量化处理,得到振幅的映射值y。相关代码可参考如下:AVAudioRecorder*monitor[monitorupdateMeters];floatpower=[monitorpeakPowerForChannel:0];2.3动态更新点的帧代码层次的实现先生成32个点视图,加入当前层同时,相关代码如下:self.sinXViews=[NSMutableArraynew];for(NSUIntegeri=0;i5&&i