自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS基于Speech框架的語(yǔ)音識(shí)別波浪動(dòng)圖實(shí)現(xiàn)

移動(dòng)開發(fā)
App開發(fā)中經(jīng)常會(huì)遇到波浪式動(dòng)畫語(yǔ)音識(shí)別轉(zhuǎn)文字的需求,那么實(shí)際是如何實(shí)現(xiàn)這樣的功能的,本文將從技術(shù)框架和視覺實(shí)現(xiàn)層面進(jìn)行Speech框架方案的詳細(xì)介紹。

者 | 伍新爽,家庭運(yùn)營(yíng)中心

Labs 導(dǎo)讀

App開發(fā)中經(jīng)常會(huì)遇到波浪式動(dòng)畫語(yǔ)音識(shí)別轉(zhuǎn)文字的需求,那么實(shí)際是如何實(shí)現(xiàn)這樣的功能的,本文將從技術(shù)框架和視覺實(shí)現(xiàn)層面進(jìn)行Speech框架方案的詳細(xì)介紹。

1Speech框架及使用流程

目前App中的語(yǔ)音識(shí)別功能主要分為本地識(shí)別及網(wǎng)絡(luò)在線識(shí)別兩種情況。網(wǎng)絡(luò)在線識(shí)別依賴于平臺(tái)對(duì)語(yǔ)音的數(shù)據(jù)處理能力,其識(shí)別準(zhǔn)確度較高,優(yōu)點(diǎn)明顯,缺點(diǎn)是識(shí)別的穩(wěn)定性及效率略低;而本地識(shí)別方案識(shí)別的穩(wěn)定性及效率較高,但識(shí)別的準(zhǔn)確度不及網(wǎng)絡(luò)在線識(shí)別方式。本文要介紹的Speech框架屬于語(yǔ)音本地識(shí)別的一種成熟框架,適用于對(duì)識(shí)別精度要求不高,但識(shí)別效率較高的場(chǎng)景。

為了便于功能維護(hù)和調(diào)用方便,工程中建議對(duì)該框架的識(shí)別能力進(jìn)行管理器模塊化封裝,如下可定義一個(gè)Speech框架識(shí)別能力的管理器:

@interface HYSpeechVoiceDetectManager : NSObject
-(void)isHasVoiceRecodingAuthority:(authorityReturnBlock)hasAuthorityBlock;
+(void)isHasSpeechRecognizerAuthority:(authorityReturnBlock)hasAuthorityBlock;
- (void)setupTimer;
-(void)startTransfer;
-(void)endTransfer;

從以上代碼可知封裝函數(shù)包含的是整個(gè)的語(yǔ)音識(shí)別流程:1.判定語(yǔ)音及Speech框架的使用權(quán)限(isHasVoiceRecodingAuthority和isHasSpeechRecognizerAuthority) 2.語(yǔ)音識(shí)別參數(shù)及相關(guān)類初始化(setupTimer) 3.開啟語(yǔ)音識(shí)別并實(shí)時(shí)接受識(shí)別后的文字信息(setupTimer和startTransfer) 4.強(qiáng)制銷毀Speech框架數(shù)據(jù)及重置音頻配置數(shù)據(jù)(endTransfer),下文將按上述四步展開講述。

1.1 判定語(yǔ)音及Speech框架的使用權(quán)限

因?yàn)樽R(shí)別能成功的首要條件就是已經(jīng)獲取到語(yǔ)音和Speech框架的使用權(quán)限,因此在初始化框架功能時(shí)候需要進(jìn)行權(quán)限的獲取操作,Speech框架的使用權(quán)限獲取代碼參考如下:

-(void)isHasSpeechRecognizerAuthority{
if (@available(iOS 10.0, *)) {
SFSpeechRecognizerAuthorizationStatus authorizationStatus = [SFSpeechRecognizer authorizationStatus];
if (authorizationStatus == SFSpeechRecognizerAuthorizationStatusNotDetermined) {
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
}];
}else if(authorizationStatus == SFSpeechRecognizerAuthorizationStatusDenied || authorizationStatus == SFSpeechRecognizerAuthorizationStatusRestricted) {
} else{
}
}else{
}
}

以上代碼中獲取到SFSpeechRecognizerAuthorizationStatus后就能獲知Sepeech框架權(quán)限信息。語(yǔ)音的使用權(quán)限獲取操作,相關(guān)代碼參考如下:

-(void)isHasVoiceRecodingAuthority:(authorityReturnBlock)hasAuthorityBlock{
if ([[[UIDevice currentDevice]systemVersion]floatValue] >= 7.0) {
AVAuthorizationStatus videoAuthStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
if (videoAuthStatus == AVAuthorizationStatusNotDetermined) {
} else if(videoAuthStatus == AVAuthorizationStatusRestricted || videoAuthStatus == AVAuthorizationStatusDenied) {
} else{
}
}
}

通過如上代碼中的videoAuthStatus可以獲知語(yǔ)音權(quán)限信息,實(shí)際使用時(shí)候首先應(yīng)該獲取語(yǔ)音的權(quán)限然后在此基礎(chǔ)上再獲取Sepeech框架權(quán)限信息,只有用戶在擁有兩個(gè)權(quán)限的前提下才能進(jìn)入到下一個(gè)“語(yǔ)音識(shí)別參數(shù)及相關(guān)類初始化”環(huán)節(jié)。

1.2 語(yǔ)音識(shí)別參數(shù)及相關(guān)類初始化

Sepeech框架初始化前需要建立一個(gè)音頻流的輸入通道,AVAudioEngine為這個(gè)輸入通道不可或缺的節(jié)點(diǎn),通過AVAudioEngine可以生成和處理音頻信號(hào),執(zhí)行音頻信號(hào)的輸入操作,AVAudioInputNode 為音頻流的拼接通道,該通道可以實(shí)時(shí)拼接一段一段的語(yǔ)音,以此完成動(dòng)態(tài)化的音頻流數(shù)據(jù)。AVAudioEngine和AVAudioInputNode 配合使用完成音頻流數(shù)據(jù)獲取的準(zhǔn)備工作,AVAudioEngine執(zhí)行方法- (void)prepare后初始化工作才能生效,相關(guān)代碼如下所示:

AVAudioEngine *bufferEngine = [[AVAudioEngine alloc]init];
AVAudioInputNode *buffeInputNode = [bufferEngine inputNode];
SFSpeechAudioBufferRecognitionRequest *bufferRequest = [[SFSpeechAudioBufferRecognitionRequest alloc]init];
AVAudioFormat *format =[buffeInputNode outputFormatForBus:0];
[buffeInputNode installTapOnBus:0 bufferSize:1024 format:format block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[bufferRequest appendAudioPCMBuffer:buffer];
}];
[bufferEngine prepare];

如上代碼中通過buffeInputNode回調(diào)接口可以獲取到SFSpeechAudioBufferRecognitionRequest完整實(shí)時(shí)音頻數(shù)據(jù)流信息。

Sepeech框架使用時(shí)需要一個(gè)關(guān)鍵類-錄音器(AVAudioRecorder),該類用來設(shè)定語(yǔ)音采集的格式,音頻通道,比特率,數(shù)據(jù)緩存路徑等重要信息并完成語(yǔ)音的采集等功能,只有調(diào)用AVAudioRecorder的- (BOOL)record方法,語(yǔ)音識(shí)別功能才能正常開始,參考如下代碼:

[self endTransfer];
NSDictionary *recordSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithFloat: 14400.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleIMA4], AVFormatIDKey,
[NSNumber numberWithInt: 2], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSString *monitorPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"monitor.caf"];
NSURL *monitorURL = [NSURL fileURLWithPath:monitorPath];
AVAudioRecorder *monitor = [[AVAudioRecorder alloc] initWithURL:_monitorURL settings:recordSettings error:NULL];
monitor.meteringEnabled = YES;
[monitor record];

如上代碼中語(yǔ)音識(shí)別初始化過程中的第一行代碼應(yīng)該首先執(zhí)行endTransfer,該接口主要功能是初始化音頻參數(shù)為默認(rèn)狀態(tài):強(qiáng)制銷毀音頻流輸入通道,清除語(yǔ)音錄音器,清除音頻識(shí)別任務(wù)。其中初始化音頻參數(shù)屬于較為重要的一個(gè)步驟,其目的是為了防止工程中其它功能模塊對(duì)音頻輸入?yún)?shù)等信息修改引起的語(yǔ)音識(shí)別異常,下文將會(huì)進(jìn)行相關(guān)細(xì)節(jié)講述。

1.3 開啟語(yǔ)音識(shí)別并實(shí)時(shí)接受識(shí)別后的文字信息

識(shí)別轉(zhuǎn)化函數(shù)-(void)startTransfer會(huì)一直輸出語(yǔ)音識(shí)別轉(zhuǎn)換的文字信息,該能力主要依賴于SFSpeechRecognizer類,我們可以從回調(diào)接口返回的實(shí)時(shí)參數(shù)SFSpeechRecognitionResult  _Nullable result中獲取到識(shí)別轉(zhuǎn)化后的文字信息,需要注意的是只有回調(diào)無(wú)錯(cuò)時(shí)輸出的文字信息才是有效的,參考代碼如下所示:

SFSpeechAudioBufferRecognitionRequest *bufferRequest = [[SFSpeechAudioBufferRecognitionRequest alloc]init];
SFSpeechRecognizer *bufferRec = [[SFSpeechRecognizer alloc]initWithLocale:[NSLocale localeWithLocaleIdentifier:@"zh_CN"]];
[bufferRec recognitionTaskWithRequest:bufferRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
if (error == nil) {
NSString *voiceTextCache = result.bestTranscription.formattedString;
}else{
}
}];

如上代碼中的bufferRec為Sepeech框架中的語(yǔ)音識(shí)別器,通過該類即可完成對(duì)音頻數(shù)據(jù)進(jìn)行本地化文字信息轉(zhuǎn)化,其中voiceTextCache即為語(yǔ)音實(shí)時(shí)轉(zhuǎn)化后的信息。

1.4 強(qiáng)制銷毀Speech框架數(shù)據(jù)及重置音頻配置數(shù)據(jù)

當(dāng)識(shí)別結(jié)束的時(shí)候,需調(diào)用-(void)endTransfer方法完成強(qiáng)制關(guān)閉音頻流通道,刪除語(yǔ)音緩沖文件,停止語(yǔ)音監(jiān)聽器等工作,其中還需要對(duì)音頻模式及參數(shù)進(jìn)行默認(rèn)重置處理,相關(guān)代碼參考如下:

-(void)endTransfer{
[bufferEngine stop];
[buffeInputNode removeTapOnBus:0];
bufferRequest = nil;
bufferTask = nil;
[monitor stop];
[monitor deleteRecording];
NSError *error = nil;
[[AVAudioSession sharedInstance] setActive:NO error:&error];
if (error != nil) {
return;
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
if (error != nil) {
return;
}
[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:&error];
if (error != nil) {
return;
}
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error != nil) {
return;
}
}

2語(yǔ)音識(shí)別波浪效果實(shí)現(xiàn)原理

2.1語(yǔ)音識(shí)別動(dòng)畫效果

ios語(yǔ)音識(shí)別需求經(jīng)常會(huì)要求實(shí)時(shí)展示語(yǔ)音識(shí)別的動(dòng)畫過程,常見的動(dòng)畫效果是根據(jù)語(yǔ)音識(shí)別音量大小實(shí)時(shí)展示不同幅度的平移波浪效果,最終效果如下圖所示:

圖片

如上最終效果圖中一共有32個(gè)波浪圓點(diǎn),其中前6個(gè)和后6個(gè)屬于固定靜止的圓點(diǎn),只有中間20個(gè)圓點(diǎn)屬于隨音量大小類似波浪上下浮動(dòng)的長(zhǎng)柱圖。

2.2 語(yǔ)音識(shí)別動(dòng)畫實(shí)現(xiàn)原理

對(duì)于上節(jié)圖中的動(dòng)態(tài)效果實(shí)際實(shí)現(xiàn)方式存在兩種:一、ios系統(tǒng)傳統(tǒng)CoreAnimation框架, 二、動(dòng)態(tài)更新圓點(diǎn)frame。如果采用傳統(tǒng)CoreAnimation框架那么對(duì)于每一個(gè)圓點(diǎn)都要做一個(gè)浮動(dòng)效果的動(dòng)畫,在實(shí)現(xiàn)流程和系統(tǒng)開銷兩方面顯得得不償失,而如果采用簡(jiǎn)單的動(dòng)態(tài)更新圓點(diǎn)frame的方式則事半功倍,本文內(nèi)容也將基于動(dòng)態(tài)更新圓點(diǎn)frame的方式進(jìn)行講述。

對(duì)于上圖中的動(dòng)畫效果很容易就會(huì)聯(lián)想到數(shù)學(xué)中的正弦函數(shù)圖,因此可以把波浪圖的橫向定義為正弦X軸(實(shí)際上ios的坐標(biāo)也是基于此概念),縱向即為正弦Y軸(高度為音量對(duì)坐標(biāo)的映射值)。首先對(duì)于32個(gè)浮動(dòng)圓點(diǎn)本地初始化對(duì)應(yīng)出32個(gè)X軸映射坐標(biāo)x,坐標(biāo)間隙等值設(shè)定,當(dāng)實(shí)時(shí)語(yǔ)音音量voluem數(shù)據(jù)傳輸過來后通過正弦函數(shù)y=F*sin(pi*x-pi*t)可以算出映射的振幅y,其中語(yǔ)音音量限定了最大的音量數(shù)據(jù),該數(shù)據(jù)和正弦函數(shù)振幅數(shù)據(jù)F強(qiáng)相關(guān),相關(guān)實(shí)現(xiàn)原理圖參考如下:

圖片

那么實(shí)時(shí)語(yǔ)音音量voluem數(shù)據(jù)是如何獲取的?實(shí)際上前文中的監(jiān)聽器(AVAudioRecorder)就提供了語(yǔ)音音量數(shù)據(jù)的封裝接口- (float)peakPowerForChannel:(NSUInteger)channelNumber,channelNumber為音頻輸入/輸出的通道號(hào),該函數(shù)返回的數(shù)據(jù)即為分貝數(shù)值,取值的范圍是 -160~0 ,聲音峰值越大,越接近0。當(dāng)獲取到實(shí)時(shí)語(yǔ)音音量voluem數(shù)據(jù)后進(jìn)行相應(yīng)的量化處理就能得到振幅y的映射值。相關(guān)代碼可參考如下:

AVAudioRecorder *monitor
[monitor updateMeters];
float power = [monitor peakPowerForChannel:0];

2.3 動(dòng)態(tài)更新圓點(diǎn)的frame代碼層面的實(shí)現(xiàn)

首先生成32個(gè)的圓點(diǎn)view,同時(shí)添加到當(dāng)前圖層,相關(guān)代碼如下所示:

self.sinXViews = [NSMutableArray new];
for (NSUInteger i = 0; i < sinaXNum+12; i++) {
UIView *sinView = [[UIView alloc]initWithFrame:CGRectMake(offsetX, offsetY, 3, 3)];
sinView.layer.cornerRadius = 1.5f;
sinView.layer.masksToBounds = YES;
[self.sinXViews addObject:sinView];
[self addSubview:sinView];
}

其中代碼中的sinXViews是緩存32個(gè)圓點(diǎn)view的數(shù)組,該數(shù)組是為了方便重置圓點(diǎn)的frame而設(shè)定,offsetX為圓點(diǎn)在圖層中的具體坐標(biāo),需要根據(jù)需求進(jìn)行詳細(xì)計(jì)算獲得。

將32個(gè)圓點(diǎn)添加到對(duì)應(yīng)圖層后核心需要解決的問題就是如何獲取圓點(diǎn)振幅了,因?yàn)樾枨髮?shí)現(xiàn)的最終效不僅是圓點(diǎn)正弦波浪效果,還需要同時(shí)對(duì)整個(gè)波浪進(jìn)行右邊平移,因此正弦函數(shù)y=F*sin(pi*x-pi*t)輸入數(shù)據(jù)應(yīng)該包含圓點(diǎn)坐標(biāo)x和格式化的時(shí)間戳數(shù)據(jù)t,具體實(shí)現(xiàn)代碼參考如下:

-(double)fSinValueWithOriginX:(CGFloat)originX timeS:(NSTimeInterval)timeStamp voluem:(CGFloat)voluem{
CGFloat sinF ;
double sinX ;
double fSin = sinF *(4/(pow(sinX,4)+4))*sin(3.14*sinX-3.14*timeStamp);
return fabs(fSin);
}

其中代碼中的sinF是根據(jù)視覺映射出的圓點(diǎn)y軸振幅,sinX是根據(jù)入?yún)riginX及圓點(diǎn)x軸坐標(biāo)間隔值計(jì)算得出,timeStamp為音量實(shí)時(shí)采集時(shí)間戳格式化數(shù)據(jù)。

經(jīng)過以上步驟實(shí)現(xiàn)就只剩更新圓點(diǎn)frame這一步了,這一步相對(duì)簡(jiǎn)單,代碼實(shí)現(xiàn)參考如下:

for (NSUInteger i = 0; i < self.sinXViews.count; i++) {
if (i > 5 && i < self.sinaXNum+6) {
UIView *sinView = (UIView *)self.sinXViews[i];
CGRect frame = sinView.frame;
double _viewHeight = [self fSinValueWithOriginX:frame.origin.x timeS:timeStamp voluem:Voluem];
double viewHeight ;
frame.size.height = viewHeight;
if (viewHeight == 0) {
return;
}
frame.origin.y = (self.frame.size.height-viewHeight)/2;
[sinView setFrame:frame];
}
}

從以上代碼可知遍歷self.sinXViews獲取到當(dāng)前圓點(diǎn)view后先取出frame數(shù)據(jù),然后通過計(jì)算得到當(dāng)前時(shí)刻圓點(diǎn)的振幅viewHeight,最后用viewHeight去更新當(dāng)前時(shí)刻圓點(diǎn)的frame,此時(shí)即完成了某個(gè)時(shí)刻20個(gè)圓點(diǎn)的正弦振動(dòng)動(dòng)態(tài)效果圖。

以上為本人工程中的技術(shù)實(shí)現(xiàn)經(jīng)驗(yàn),現(xiàn)做一個(gè)簡(jiǎn)單的總結(jié)歸納,如有錯(cuò)誤之處請(qǐng)不吝賜教,謝謝閱讀!

參考資料

[1] Speech框架資料:https://developer.apple.com/documentation/speech

[2] ios錄音功能資料:https://developer.apple.com/documentation/avfaudio

責(zé)任編輯:未麗燕 來源: 移動(dòng)Labs
相關(guān)推薦

2023-07-16 18:46:30

2011-05-31 16:38:47

Android 實(shí)現(xiàn)語(yǔ)音

2020-09-21 07:00:00

語(yǔ)音識(shí)別AI人工智能

2021-12-08 14:06:19

Python語(yǔ)音識(shí)別開發(fā)

2021-04-27 15:47:12

人工智能語(yǔ)音識(shí)別Transformer

2012-07-25 13:23:32

ibmdw

2012-07-10 13:29:30

Java

2015-12-07 14:39:18

微軟Windows 95語(yǔ)音識(shí)別

2011-01-18 11:52:25

Linux語(yǔ)音識(shí)別

2020-09-23 09:24:01

堆棧開發(fā)實(shí)現(xiàn)

2018-01-31 13:09:35

Pythonface_recogn人臉識(shí)別

2017-10-27 16:19:23

語(yǔ)音識(shí)別CNN

2021-11-17 10:37:39

語(yǔ)音識(shí)別技術(shù)人工智能

2013-06-13 16:06:57

iOSWWDCin the Car

2016-02-17 10:39:18

語(yǔ)音識(shí)別語(yǔ)音合成語(yǔ)音交互

2009-06-03 15:38:37

Struts框架RBAC

2023-06-05 09:28:32

CSS漸變

2019-06-24 09:30:00

開源技術(shù) 趨勢(shì)

2018-06-28 12:55:10

華為云

2024-01-11 15:54:55

eTS語(yǔ)言TypeScript應(yīng)用開發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)