天天看點

iOS中 語音識别功能/語音轉文字教程詳解

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

前言:最近研究了一下語音識别,從百度語音識别到訊飛語音識别;首先說一下個人針對兩者的看法,訊飛毫無疑問比較專業,識别率也很高真對語音識别是比較精準的,但是很多開發者和我一樣期望離線識别,而訊飛離線是收費的;請求次數來講,兩者都可以申請高配額,真對使用者較多的幾乎都一樣。基于免費并且支援離線我選擇了百度離線語音識别。比較簡單,ui設計多一點,下面寫一下教程:

1.首先:需要的庫

iOS中 語音識别功能/語音轉文字教程詳解

2.我是自定義的ui是以以功能實作為主(頭檔案)

iOS中 語音識别功能/語音轉文字教程詳解

// 頭檔案  

#import "bdvrcustomrecognitonviewcontroller.h"  

#import "bdvrclientuimanager.h"  

#import "wbvoicerecordhud.h"  

#import "bdvrviewcontroller.h"  

#import "myviewcontroller.h"  

#import "bdvrsconfig.h"  

3.需要知道的功能:能用到的如下:

iOS中 語音識别功能/語音轉文字教程詳解

//-------------------類方法------------------------  

// 建立語音識别客戶對像,該對像是個單例  

+ (bdvoicerecognitionclient *)sharedinstance;  

// 釋放語音識别用戶端對像  

+ (void)releaseinstance;  

//-------------------識别方法-----------------------  

// 判斷是否可以錄音  

- (bool)iscanrecorder;  

// 開始語音識别,需要實作mvoicerecognitionclientdelegate代理方法,并傳入實作對像監聽事件  

// 傳回值參考 tvoicerecognitionstartworkresult  

- (int)startvoicerecognition:(id<mvoicerecognitionclientdelegate>)adelegate;  

// 說完了,使用者主動完成錄音時調用  

- (void)speakfinish;  

// 結束本次語音識别  

- (void)stopvoicerecognition;  

/** 

 * @brief 擷取目前識别的采樣率 

 * 

 * @return 采樣率(16000/8000) 

 */  

- (int)getcurrentsamplerate;  

 * @brief 得到目前識别模式(deprecated) 

 * @return 目前識别模式 

- (int)getcurrentvoicerecognitionmode __attribute__((deprecated));  

 * @brief 設定目前識别模式(deprecated),請使用-(void)setproperty:(tbdvoicerecognitionproperty)property; 

 * @param 識别模式 

 * @return 是否設定成功 

- (void)setcurrentvoicerecognitionmode:(int)amode __attribute__((deprecated));  

// 設定識别類型  

- (void)setproperty:(tbdvoicerecognitionproperty)property __attribute__((deprecated));  

// 擷取目前識别類型  

- (int)getrecognitionproperty __attribute__((deprecated));  

// 設定識别類型清單, 除evoicerecognitionpropertyinput和evoicerecognitionpropertysong外  

// 可以識别類型複合  

- (void)setpropertylist: (nsarray*)prop_list;  

// cityid僅對evoicerecognitionpropertymap識别類型有效  

- (void)setcityid: (nsinteger)cityid;  

// 擷取目前識别類型清單  

- (nsarray*)getrecognitionpropertylist;  

//-------------------提示音-----------------------  

// 播放提示音,預設為播放,錄音開始,錄音結束提示音  

// bdvoicerecognitionclientresources/tone  

// record_start.caf   錄音開始聲音檔案  

// record_end.caf     錄音結束聲音檔案  

// 聲音資源需要加到項目工程裡,使用者可替換資源檔案,檔案名不可以變,建音提示音不宜過長,0。5秒左右。  

// atone 取值參考 tvoicerecognitionplaytones,如沒有找到檔案,則傳回NO  

- (bool)setplaytone:(int)atone isplay:(bool)aisplay;  

4.錄音按鈕相關動畫(我自定義的,大家可以借鑒)

iOS中 語音識别功能/語音轉文字教程詳解

// 錄音按鈕相關  

@property (nonatomic, weak, readonly) uibutton *holddownbutton;// 說話按鈕  

 *  是否取消錄音 

@property (nonatomic, assign, readwrite) bool iscancelled;  

 *  是否正在錄音 

@property (nonatomic, assign, readwrite) bool isrecording;  

 *  當錄音按鈕被按下所觸發的事件,這時候是開始錄音 

- (void)holddownbuttontouchdown;  

 *  當手指在錄音按鈕範圍之外離開螢幕所觸發的事件,這時候是取消錄音 

- (void)holddownbuttontouchupoutside;  

 *  當手指在錄音按鈕範圍之内離開螢幕所觸發的事件,這時候是完成錄音 

- (void)holddownbuttontouchupinside;  

 *  當手指滑動到錄音按鈕的範圍之外所觸發的事件 

- (void)holddowndragoutside;  

5.初始化系統ui

iOS中 語音識别功能/語音轉文字教程詳解

#pragma mark - layout subviews ui  

 *  根據正常顯示和高亮狀态建立一個按鈕對象 

 *  @param image   正常顯示圖 

 *  @param hlimage 高亮顯示圖 

 *  @return 傳回按鈕對象 

- (uibutton *)createbuttonwithimage:(uiimage *)image hlimage:(uiimage *)hlimage ;  

- (void)holddowndraginside;  

- (void)createinitview; // 建立初始化界面,播放提示音時會用到  

- (void)createrecordview;  // 建立錄音界面  

- (void)createrecognitionview; // 建立識别界面  

- (void)createerrorviewwitherrortype:(int)astatus; // 在識别view中顯示詳細錯誤資訊  

- (void)createrunlogwithstatus:(int)astatus; // 在狀态view中顯示詳細狀态資訊  

- (void)finishrecord:(id)sender; // 使用者點選完成動作  

- (void)cancel:(id)sender; // 使用者點選取消動作  

- (void)startvoicelevelmetertimer;  

- (void)freevoicelevelmetertimertimer;  

6.最重要的部分

iOS中 語音識别功能/語音轉文字教程詳解

// 錄音完成  

 [[bdvoicerecognitionclient sharedinstance] speakfinish];  

iOS中 語音識别功能/語音轉文字教程詳解

// 取消錄音  

[[bdvoicerecognitionclient sharedinstance] stopvoicerecognition];  

7.兩個代理方法

iOS中 語音識别功能/語音轉文字教程詳解

- (void)voicerecognitionclientworkstatus:(int)astatus obj:(id)aobj  

{  

    switch (astatus)  

    {  

        case evoicerecognitionclientworkstatusflushdata: // 連續上屏中間結果  

        {  

            nsstring *text = [aobj objectatindex:0];  

            if ([text length] > 0)  

            {  

//                [clientsampleviewcontroller logouttocontinusmanualresut:text];  

                uilabel *clientworkstatusflushlabel = [[uilabel alloc]initwithframe:cgrectmake(kscreenwidth/2 - 100,64,200,60)];  

                clientworkstatusflushlabel.text = text;  

                clientworkstatusflushlabel.textalignment = nstextalignmentcenter;  

                clientworkstatusflushlabel.font = [uifont systemfontofsize:18.0f];  

                clientworkstatusflushlabel.numberoflines = 0;  

                clientworkstatusflushlabel.backgroundcolor = [uicolor whitecolor];  

                [self.view addsubview:clientworkstatusflushlabel];  

            }  

            break;  

        }  

        case evoicerecognitionclientworkstatusfinish: // 識别正常完成并獲得結果  

            [self createrunlogwithstatus:astatus];  

            if ([[bdvoicerecognitionclient sharedinstance] getrecognitionproperty] != evoicerecognitionpropertyinput)  

                //  搜尋模式下的結果為數組,示例為  

                // ["公園", "公元"]  

                nsmutablearray *audioresultdata = (nsmutablearray *)aobj;  

                nsmutablestring *tmpstring = [[nsmutablestring alloc] initwithstring:@""];  

                for (int i=0; i < [audioresultdata count]; i++)  

                {  

                    [tmpstring appendformat:@"%@\r\n",[audioresultdata objectatindex:i]];  

                }  

                clientsampleviewcontroller.resultview.text = nil;  

                [clientsampleviewcontroller logouttomanualresut:tmpstring];  

            else  

                nsstring *tmpstring = [[bdvrsconfig sharedinstance] composeinputmoderesult:aobj];  

                [clientsampleviewcontroller logouttocontinusmanualresut:tmpstring];  

            if (self.view.superview)  

                [self.view removefromsuperview];  

        case evoicerecognitionclientworkstatusreceivedata:  

            // 此狀态隻有在輸入模式下使用  

            // 輸入模式下的結果為帶置信度的結果,示例如下:  

            //  [  

            //      [  

            //         {  

            //             "百度" = "0.6055192947387695";  

            //         },  

            //             "擺渡" = "0.3625582158565521";  

            //      ]  

            //             "一下" = "0.7665404081344604";  

            //         }  

            //      ],  

            //   ]  

//暫時關掉 -- 否則影響跳轉結果  

//            nsstring *tmpstring = [[bdvrsconfig sharedinstance] composeinputmoderesult:aobj];  

//            [clientsampleviewcontroller logouttocontinusmanualresut:tmpstring];  

        case evoicerecognitionclientworkstatusend: // 使用者說話完成,等待伺服器傳回識别結果  

            if ([bdvrsconfig sharedinstance].voicelevelmeter)  

                [self freevoicelevelmetertimertimer];  

            [self createrecognitionview];  

        case evoicerecognitionclientworkstatuscancel:  

        {              

            if ([bdvrsconfig sharedinstance].voicelevelmeter)   

            [self createrunlogwithstatus:astatus];    

            if (self.view.superview)   

        case evoicerecognitionclientworkstatusstartworking: // 識别庫開始識别工作,使用者可以說話  

            if ([bdvrsconfig sharedinstance].playstartmusicswitch) // 如果播放了提示音,此時再給使用者提示可以說話  

                [self createrecordview];  

            if ([bdvrsconfig sharedinstance].voicelevelmeter)  // 開啟語音音量監聽  

                [self startvoicelevelmetertimer];  

            [self createrunlogwithstatus:astatus];   

        case evoicerecognitionclientworkstatusnone:  

        case evoicerecognitionclientworkplaystarttone:  

        case evoicerecognitionclientworkplaystarttonefinish:  

        case evoicerecognitionclientworkstatusstart:  

        case evoicerecognitionclientworkplayendtonefinish:  

        case evoicerecognitionclientworkplayendtone:  

        case evoicerecognitionclientworkstatusnewrecorddata:  

        default:  

    }  

}  

iOS中 語音識别功能/語音轉文字教程詳解

- (void)voicerecognitionclientnetworkstatus:(int) astatus  

    switch (astatus)   

        case evoicerecognitionclientnetworkstatusstart:  

        {     

            [[uiapplication sharedapplication] setnetworkactivityindicatorvisible:yes];  

            break;     

        case evoicerecognitionclientnetworkstatusend:  

            [[uiapplication sharedapplication] setnetworkactivityindicatorvisible:no];  

        }            

8.錄音按鈕的一些操作

iOS中 語音識别功能/語音轉文字教程詳解

#pragma mark ------ 關于按鈕操作的一些事情-------  

- (void)holddownbuttontouchdown {  

    // 開始動畫  

    _displaylink = [cadisplaylink displaylinkwithtarget:self selector:@selector(delayanimation)];  

    _displaylink.frameinterval = 40;  

    [_displaylink addtorunloop:[nsrunloop currentrunloop] formode:nsdefaultrunloopmode];  

    self.iscancelled = no;  

    self.isrecording = no;  

 // 開始語音識别功能,之前必須實作mvoicerecognitionclientdelegate協定中的voicerecognitionclientworkstatus:obj方法  

    int startstatus = -1;  

    startstatus = [[bdvoicerecognitionclient sharedinstance] startvoicerecognition:self];  

    if (startstatus != evoicerecognitionstartworking) // 建立失敗則報告錯誤  

        nsstring *statusstring = [nsstring stringwithformat:@"%d",startstatus];  

        [self performselector:@selector(firststarterror:) withobject:statusstring afterdelay:0.3];  // 延遲0.3秒,以便能在出錯時正常删除view  

        return;  

    // "按住說話-松開搜尋"提示  

    [voiceimagestr removefromsuperview];  

    voiceimagestr = [[uiimageview alloc]initwithframe:cgrectmake(kscreenwidth/2 - 40, kscreenheight - 153, 80, 33)];  

    voiceimagestr.backgroundcolor = [uicolor colorwithpatternimage:[uiimage imagenamed:@"searchvoice"]];  

    [self.view addsubview:voiceimagestr];  

- (void)holddownbuttontouchupoutside {  

    // 結束動畫  

    [self.view.layer removeallanimations];  

    [_displaylink invalidate];  

    _displaylink = nil;  

    // 取消錄音  

    [[bdvoicerecognitionclient sharedinstance] stopvoicerecognition];  

    if (self.view.superview)  

        [self.view removefromsuperview];  

- (void)holddownbuttontouchupinside {  

    [[bdvoicerecognitionclient sharedinstance] speakfinish];  

- (void)holddowndragoutside {  

    //如果已經開始錄音了, 才需要做拖曳出去的動作, 否則隻要切換 iscancelled, 不讓錄音開始.  

    if (self.isrecording) {  

//        if ([self.delegate respondstoselector:@selector(diddragoutsideaction)]) {  

//            [self.delegate diddragoutsideaction];  

//        }  

    } else {  

        self.iscancelled = yes;  

- (uibutton *)createbuttonwithimage:(uiimage *)image hlimage:(uiimage *)hlimage {  

    uibutton *button = [[uibutton alloc] initwithframe:cgrectmake(kscreenwidth/2 -36, kscreenheight - 120, 72, 72)];  

    if (image)  

        [button setbackgroundimage:image forstate:uicontrolstatenormal];  

    if (hlimage)  

        [button setbackgroundimage:hlimage forstate:uicontrolstatehighlighted];  

    return button;  

#pragma mark ----------- 動畫部分 -----------  

- (void)startanimation  

    calayer *layer = [[calayer alloc] init];  

    layer.cornerradius = [uiscreen mainscreen].bounds.size.width/2;  

    layer.frame = cgrectmake(0, 0, layer.cornerradius * 2, layer.cornerradius * 2);  

    layer.position = cgpointmake([uiscreen mainscreen].bounds.size.width/2,[uiscreen mainscreen].bounds.size.height - 84);  

    //    self.view.layer.position;  

    uicolor *color = [uicolor colorwithred:arc4random()%10*0.1 green:arc4random()%10*0.1 blue:arc4random()%10*0.1 alpha:1];  

    layer.backgroundcolor = color.cgcolor;  

    [self.view.layer addsublayer:layer];  

    camediatimingfunction *defaultcurve = [camediatimingfunction functionwithname:kcamediatimingfunctiondefault];  

    _animationgroup = [caanimationgroup animation];  

    _animationgroup.delegate = self;  

    _animationgroup.duration = 2;  

    _animationgroup.removedoncompletion = yes;  

    _animationgroup.timingfunction = defaultcurve;  

    cabasicanimation *scaleanimation = [cabasicanimation animationwithkeypath:@"transform.scale.xy"];  

    scaleanimation.fromvalue = @0.0;  

    scaleanimation.tovalue = @1.0;  

    scaleanimation.duration = 2;  

    cakeyframeanimation *opencityanimation = [cakeyframeanimation animationwithkeypath:@"opacity"];  

    opencityanimation.duration = 2;  

    opencityanimation.values = @[@0.8,@0.4,@0];  

    opencityanimation.keytimes = @[@0,@0.5,@1];  

    opencityanimation.removedoncompletion = yes;  

    nsarray *animations = @[scaleanimation,opencityanimation];  

    _animationgroup.animations = animations;  

    [layer addanimation:_animationgroup forkey:nil];  

    [self performselector:@selector(removelayer:) withobject:layer afterdelay:1.5];  

- (void)removelayer:(calayer *)layer  

    [layer removefromsuperlayer];  

- (void)delayanimation  

    [self startanimation];  

完成以上操作,就大功告成了!

溫馨提示:

1.由于是語音識别,需要用到麥克風相關權限,模拟器會爆12個錯誤,使用真機可以解決;

2.涉及到授權檔案相關并不複雜,工程bundle identifier隻需要設定百度的離線授權一緻即可,如下圖:

iOS中 語音識别功能/語音轉文字教程詳解
iOS中 語音識别功能/語音轉文字教程詳解

最終效果如下:

iOS中 語音識别功能/語音轉文字教程詳解
iOS中 語音識别功能/語音轉文字教程詳解
iOS中 語音識别功能/語音轉文字教程詳解
iOS中 語音識别功能/語音轉文字教程詳解

有不懂或不明白的地方可以微網誌聯系我: