科大讯飞--让你的APP学会说学逗唱

科大讯飞--让你的APP学会说学逗唱


####### 关键字: 讯飞 语音识别 语音合成 配置

在本篇blog中, 您将学到:

  • 使用讯飞语音实现语音识别
  • 使用讯飞语音实现朗读文字
  • 了解他们的内部封装

一.走近讯飞(iFly)

语音技术实现了人机语音交互,使人与机器之间沟通变得像人与人沟通一样简单。语音技术主要包括语音合成和语音识别两项关键技术。让机器说话,用的是语音合成技术;让机器听懂人说话,用的是语音识别技术。此外,语音技术还包括语音编码、音色转换、口语评测、语音消噪和增强等技术,有着广阔应用空间。

  • 早期的语音识别技术让人啼笑皆非, 就连Siri刚出道时, 也是漏洞百出. 但是讯飞通过多年的不懈努力, 最近发展迅速, 这也是技术型项目前期技术积累的必然结果.
  • 百度也推出了自己的语音识别, 但是因为技术积累尚浅, 移植和测试体验尚不如讯飞 – 本条个人观点.

科大讯飞从开始的只做语音识别和语音合成, 到现在的广告+统计+广场+人脸识别+声纹识别+推送, 可以看出它的野心–打造综合性平台, 同时又不放弃专营业务(并且拥有难以记忆的英文缩写和logo).

从使用讯飞的SDK过程中, 还是能感觉到诚意的, 很多设计很人性化, 免费提供了诸多测试和使用接口, 让人好感倍增, 这也是为啥我为其做了这么多广告.

二.搭建环境

登录开发者平台
  • 注册用户并且登录
  • 创建新应用

    选择创建新应用:

    这里可以比较随意填写, 但是注意平台别搞错.


    应用创建好之后, 请记录下讯飞为该APP生成的Appid: 56678310 (每个人都不一样哦)

  • 为新应添加服务

    新创建的应用可以在”我的应用”中查看, 开始的时候, 这个应用没有使用任何SDK, 我们需要向讯飞注册一下我们的app都需要哪些服务.

    点击”开通更多服务”, 选择语言听写和在线语音合成两个SDK, 第一个开发语义是自己添加上的.

  • 下载相应SDK

    进入下载SDK界面, 您可以通过诸多位置进入到这里, 可能与截图不符, 但没有问题.

    这里选择”组合服务SDK下载”, 勾选图中前两个.

    选择平台

    最后选择刚才创建的引用, 之后点击下载.

  • 新建xcode(singleView)工程, 将下载好的文件夹中lib下的iflyMac导入(拖入)工程

  • 添加引用库

三.代码+++++

  • 在storyBoard的viewController中拖入几个控件, 一个UILable用来显示语音翻译后的文字, 两个UIbutton用来触发”带界面的实时翻译”和”不带界面的实时翻译”. 并为他们拖出属性和响应方法.
    如图:

  • appdelegate.m中, 添加如下代码(注册):
    AppDelegate.m 的 didFinishLaunchingWithOptions中:

    1
    2
    3
    4
    5
    6
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 根据appid登录到讯飞的服务器, 过程需要身份验证 , 56678310
        NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@",@"你的appid, 别用我的"];
        [IFlySpeechUtility createUtility:initString];
        return YES;
    }
    
    

下面是写好后的ViewController代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

#import "ViewController.h"
#import <iflyMSC/iflyMSC.h>
// 这个头文件是做什么的呢?
#import "ISRDataHelper.h"
// 还有这个.
#import "IATConfig.h"


@interface ViewController ()<IFlyRecognizerViewDelegate, IFlySpeechRecognizerDelegate>
// 翻译好的Text会展示在这个label上.
@property (weak, nonatomic) IBOutlet UILabel *textView;

/*!
 *  语音识别控件
 *    录音时触摸控件结束录音,开始识别(相当于旧版的停止);触摸其他位置,取消录音,结束会话(取消)
 *  出错时触摸控件,重新开启会话(相当于旧版的再说一次);触摸其他位置,取消录音,结束会话(取消)
 *
 */
@property (nonatomic,strong)IFlyRecognizerView * iflyRecognizerView;

/*!
 *  语音识别类
 *   此类现在设计为单例,你在使用中只需要创建此对象,不能调用release/dealloc函数去释放此对象。所有关于语音识别的操作都在此类中。
 */
@property (nonatomic, strong)IFlySpeechRecognizer * iFlySpeechRecognizer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 语音识别视图空间及配置.
    [self initRecognizerView];
    
    // 语音识别类的初始化及配置.
    [self initSpeechRecognizer];
}

// !!!:语音识别视图空间及配置--方法.
-(void)initRecognizerView{
    _iflyRecognizerView = [[IFlyRecognizerView alloc] initWithCenter:self.view.center];
    _iflyRecognizerView.delegate = self;
    [_iflyRecognizerView setParameter: @"iat" forKey: [IFlySpeechConstant IFLY_DOMAIN]];
    //asr_audio_path保存录音文件名,如不再需要,设置value为nil表示取消,默认目录是documents
    [_iflyRecognizerView setParameter:@"asrview.pcm " forKey:[IFlySpeechConstant ASR_AUDIO_PATH]];
}
// !!!:语音识别类的初始化及配置--方法.
-(void)initSpeechRecognizer{
    //单例模式,无UI的实例
    if (_iFlySpeechRecognizer == nil) {
        _iFlySpeechRecognizer = [IFlySpeechRecognizer sharedInstance];
        
        [_iFlySpeechRecognizer setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
        
        //设置听写模式
        [_iFlySpeechRecognizer setParameter:@"iat" forKey:[IFlySpeechConstant IFLY_DOMAIN]];
    }
    _iFlySpeechRecognizer.delegate = self;
    
    if (_iFlySpeechRecognizer != nil) {
        IATConfig *instance = [IATConfig sharedInstance];
        
        //设置最长录音时间
        [_iFlySpeechRecognizer setParameter:instance.speechTimeout forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
        //设置后端点
        [_iFlySpeechRecognizer setParameter:instance.vadEos forKey:[IFlySpeechConstant VAD_EOS]];
        //设置前端点
        [_iFlySpeechRecognizer setParameter:instance.vadBos forKey:[IFlySpeechConstant VAD_BOS]];
        //网络等待时间
        [_iFlySpeechRecognizer setParameter:@"20000" forKey:[IFlySpeechConstant NET_TIMEOUT]];
        
        //设置采样率,推荐使用16K
        [_iFlySpeechRecognizer setParameter:instance.sampleRate forKey:[IFlySpeechConstant SAMPLE_RATE]];
        
        if ([instance.language isEqualToString:[IATConfig chinese]]) {
            //设置语言
            [_iFlySpeechRecognizer setParameter:instance.language forKey:[IFlySpeechConstant LANGUAGE]];
            //设置方言
            [_iFlySpeechRecognizer setParameter:instance.accent forKey:[IFlySpeechConstant ACCENT]];
        }else if ([instance.language isEqualToString:[IATConfig english]]) {
            [_iFlySpeechRecognizer setParameter:instance.language forKey:[IFlySpeechConstant LANGUAGE]];
        }
        //设置是否返回标点符号
        [_iFlySpeechRecognizer setParameter:instance.dot forKey:[IFlySpeechConstant ASR_PTT]];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// !!!: push界面的识别,点击事件
- (IBAction)voiceToText:(id)sender {
    [self.iflyRecognizerView start];
}

// !!!: 触发语音识别类的点击事件
- (IBAction)voiceToTextWithoutUI:(id)sender {
    self.textView.text = @"";
    // 这个需要手动停止翻译.
    [_iFlySpeechRecognizer cancel];
    
    //设置音频来源为麦克风
    [_iFlySpeechRecognizer setParameter:IFLY_AUDIO_SOURCE_MIC forKey:@"audio_source"];
    
    //设置听写结果格式为json
    [_iFlySpeechRecognizer setParameter:@"json" forKey:[IFlySpeechConstant RESULT_TYPE]];
    
    //保存录音文件,保存在sdk工作路径中,如未设置工作路径,则默认保存在library/cache下
    [_iFlySpeechRecognizer setParameter:@"asr.pcm" forKey:[IFlySpeechConstant ASR_AUDIO_PATH]];
    
    [_iFlySpeechRecognizer setDelegate:self];
    
    [_iFlySpeechRecognizer startListening];
}

// !!!:实现代理方法
// !!!:注意有没有s, 语音识别的结果回调(带界面的那个)
-(void)onResult:(NSArray *)resultArray isLast:(BOOL)isLast
{
    NSMutableString *result = [[NSMutableString alloc] init];
    NSDictionary *dic = [resultArray objectAtIndex:0];
    for (NSString *key in dic) {
        [result appendFormat:@"%@",key];
    }
    
    // 注意: 语音识别回调返回结果是一个json格式字符串, 解析起来比较麻烦, 但是我们只需要其中的字符串部分, 这个过程讯飞也觉得麻烦, 就推出了一个工具类, 能将这个josn解析最终字符串返回. 这也是前面导入ISRDataHelper.h的作用.
    NSString * resu = [ISRDataHelper stringFromJson:result];
    self.textView.text = [NSString stringWithFormat:@"%@%@",self.textView.text,resu];
}
// !!!:解析失败代理方法
-(void)onError:(IFlySpeechError *)error
{
    NSLog(@"解析失败了");
}

// !!!:语音识别类的回调方法(不带界面的那个)
- (void) onResults:(NSArray *) results isLast:(BOOL)isLast{
    NSMutableString *result = [[NSMutableString alloc] init];
    NSDictionary *dic = [results objectAtIndex:0];
    for (NSString *key in dic) {
        [result appendFormat:@"%@",key];
    }
    NSString * resu = [ISRDataHelper stringFromJson:result];
    self.textView.text = [NSString stringWithFormat:@"%@%@", self.textView.text, resu];
}

@end

在上面的代码中, 使用了两个类:

1
2

#import "ISRDataHelper.h"
#import "IATConfig.h"

他们的功能已经在注释中说明, 那么这两个类的源文件怎办呢… 让我想想…
算了, 最后我把这个工程传到git上吧. 你们从哪里扒下来就好了.

四.语音合成

其实iOS自带语音合成, 我们不必使用讯飞也可以达到这样的效果, 下面的代码能让你的APP读出这些文字.
Appdelegate.m中, 添加一个延展, 并且 didFinishLaunchingWithOptions 中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@interface AppDelegate ()
@property(nonatomic,strong)AVSpeechSynthesizer * speechSynthesizer; // 合成器
@property(nonatomic,strong)AVSpeechUtterance * speechUtterance; // 合成器所说的内容
@end

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    self.speechSynthesizer = [[AVSpeechSynthesizer alloc] init];
    
    self.speechUtterance = [[AVSpeechUtterance alloc] initWithString:@"啪啪啪"];
    
    [self.speechSynthesizer  speakUtterance:self.speechUtterance];
    
    return YES;
}

运行之后, app能读出”啪啪啪”. 女性发音效果更好.


  • 使用讯飞实现啪啪啪的功能
    我们直接在上面的工程里添加吧.
    首先在sb中的viewcontroller里, 再拖一个textfiled, 我们让讯飞朗读textfiled中的内容.

viewController.m, 这个将三个功能写到了同一个controller中.比较臃肿, 你们自己捋顺一下, 封装成类, 供以后使用.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

#import "ViewController.h"
#import <iflyMSC/iflyMSC.h>
#import "ISRDataHelper.h"
#import "IATConfig.h"

#import "PcmPlayerDelegate.h"
#import "PcmPlayer.h"
#import "TTSConfig.h"

typedef NS_OPTIONS(NSInteger, SynthesizeType) {
    NomalType           = 5,//普通合成
    UriType             = 6, //uri合成
};

@interface ViewController ()<IFlyRecognizerViewDelegate, IFlySpeechRecognizerDelegate, IFlySpeechRecognizerDelegate>
// 翻译好的Text会展示在这个label上.
@property (weak, nonatomic) IBOutlet UILabel *textView;
// 朗读这里的内容.
@property (weak, nonatomic) IBOutlet UITextField *VoiceText;

/*!
 *  语音识别控件
 *    录音时触摸控件结束录音,开始识别(相当于旧版的停止);触摸其他位置,取消录音,结束会话(取消)
 *  出错时触摸控件,重新开启会话(相当于旧版的再说一次);触摸其他位置,取消录音,结束会话(取消)
 *
 */
@property (nonatomic,strong)IFlyRecognizerView * iflyRecognizerView;

/*!
 *  语音识别类
 *   此类现在设计为单例,你在使用中只需要创建此对象,不能调用release/dealloc函数去释放此对象。所有关于语音识别的操作都在此类中。
 */
@property (nonatomic, strong)IFlySpeechRecognizer * iFlySpeechRecognizer;


@property (nonatomic, strong) IFlySpeechSynthesizer * iFlySpeechSynthesizer;//语音合成对象
@property (nonatomic, strong) PcmPlayer *audioPlayer;//用于播放音频的
@property (nonatomic, assign) SynthesizeType synType;//是何种合成方式
@property (nonatomic, assign) BOOL hasError;//将解析过程中是否出现错误
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 语音识别视图空间及配置.
    [self initRecognizerView];
    
    // 语音识别类的初始化及配置.
    [self initSpeechRecognizer];
 
    // 初始化语音合成
    [self initMakeVoice];
}
// !!!:语音识别视图空间及配置--方法.
-(void)initRecognizerView{
    _iflyRecognizerView = [[IFlyRecognizerView alloc] initWithCenter:self.view.center];
    _iflyRecognizerView.delegate = self;
    [_iflyRecognizerView setParameter: @"iat" forKey: [IFlySpeechConstant IFLY_DOMAIN]];
    //asr_audio_path保存录音文件名,如不再需要,设置value为nil表示取消,默认目录是documents
    [_iflyRecognizerView setParameter:@"asrview.pcm " forKey:[IFlySpeechConstant ASR_AUDIO_PATH]];
}
// !!!:语音识别类的初始化及配置--方法.
-(void)initSpeechRecognizer{
    //单例模式,无UI的实例
    if (_iFlySpeechRecognizer == nil) {
        _iFlySpeechRecognizer = [IFlySpeechRecognizer sharedInstance];
        
        [_iFlySpeechRecognizer setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
        
        //设置听写模式
        [_iFlySpeechRecognizer setParameter:@"iat" forKey:[IFlySpeechConstant IFLY_DOMAIN]];
    }
    _iFlySpeechRecognizer.delegate = self;
    
    if (_iFlySpeechRecognizer != nil) {
        IATConfig *instance = [IATConfig sharedInstance];
        
        //设置最长录音时间
        [_iFlySpeechRecognizer setParameter:instance.speechTimeout forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
        //设置后端点
        [_iFlySpeechRecognizer setParameter:instance.vadEos forKey:[IFlySpeechConstant VAD_EOS]];
        //设置前端点
        [_iFlySpeechRecognizer setParameter:instance.vadBos forKey:[IFlySpeechConstant VAD_BOS]];
        //网络等待时间
        [_iFlySpeechRecognizer setParameter:@"20000" forKey:[IFlySpeechConstant NET_TIMEOUT]];
        
        //设置采样率,推荐使用16K
        [_iFlySpeechRecognizer setParameter:instance.sampleRate forKey:[IFlySpeechConstant SAMPLE_RATE]];
        
        if ([instance.language isEqualToString:[IATConfig chinese]]) {
            //设置语言
            [_iFlySpeechRecognizer setParameter:instance.language forKey:[IFlySpeechConstant LANGUAGE]];
            //设置方言
            [_iFlySpeechRecognizer setParameter:instance.accent forKey:[IFlySpeechConstant ACCENT]];
        }else if ([instance.language isEqualToString:[IATConfig english]]) {
            [_iFlySpeechRecognizer setParameter:instance.language forKey:[IFlySpeechConstant LANGUAGE]];
        }
        //设置是否返回标点符号
        [_iFlySpeechRecognizer setParameter:instance.dot forKey:[IFlySpeechConstant ASR_PTT]];
    }
}

// !!!:语音合成的初始化
-(void)initMakeVoice{
    TTSConfig *instance = [TTSConfig sharedInstance];
    if (instance == nil) {
        return;
    }
    
    //合成服务单例
    if (_iFlySpeechSynthesizer == nil) {
        _iFlySpeechSynthesizer = [IFlySpeechSynthesizer sharedInstance];
    }
    
    _iFlySpeechSynthesizer.delegate = self;
    
    //设置语速1-100
    [_iFlySpeechSynthesizer setParameter:instance.speed forKey:[IFlySpeechConstant SPEED]];
    
    //设置音量1-100
    [_iFlySpeechSynthesizer setParameter:instance.volume forKey:[IFlySpeechConstant VOLUME]];
    
    //设置音调1-100
    [_iFlySpeechSynthesizer setParameter:instance.pitch forKey:[IFlySpeechConstant PITCH]];
    
    //设置采样率
    [_iFlySpeechSynthesizer setParameter:instance.sampleRate forKey:[IFlySpeechConstant SAMPLE_RATE]];
    
    //设置发音人
    [_iFlySpeechSynthesizer setParameter:instance.vcnName forKey:[IFlySpeechConstant VOICE_NAME]];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// !!!: push界面的识别,点击事件
- (IBAction)voiceToText:(id)sender {
    [self.iflyRecognizerView start];
}
// !!!: 触发语音识别类的点击事件
- (IBAction)voiceToTextWithoutUI:(id)sender {
    self.textView.text = @"";
    [_iFlySpeechRecognizer cancel];
    
    //设置音频来源为麦克风
    [_iFlySpeechRecognizer setParameter:IFLY_AUDIO_SOURCE_MIC forKey:@"audio_source"];
    
    //设置听写结果格式为json
    [_iFlySpeechRecognizer setParameter:@"json" forKey:[IFlySpeechConstant RESULT_TYPE]];
    
    //保存录音文件,保存在sdk工作路径中,如未设置工作路径,则默认保存在library/cache下
    [_iFlySpeechRecognizer setParameter:@"asr.pcm" forKey:[IFlySpeechConstant ASR_AUDIO_PATH]];
    
    [_iFlySpeechRecognizer setDelegate:self];
    
    [_iFlySpeechRecognizer startListening];
}
- (IBAction)speechAction:(id)sender {
    if ([self.VoiceText.text isEqualToString:@""]) {
        return;
    }
    
    if (_audioPlayer != nil && _audioPlayer.isPlaying == YES) {
        [_audioPlayer stop];
    }
    
    _synType = NomalType;
    
    self.hasError = NO;
    [NSThread sleepForTimeInterval:0.05];
    _iFlySpeechSynthesizer.delegate = self;
    [_iFlySpeechSynthesizer startSpeaking:self.VoiceText.text];
}

// !!!:实现代理方法
// !!!:注意有没有s, 语音识别的结果回调
-(void)onResult:(NSArray *)resultArray isLast:(BOOL)isLast
{
    NSMutableString *result = [[NSMutableString alloc] init];
    NSDictionary *dic = [resultArray objectAtIndex:0];
    for (NSString *key in dic) {
        [result appendFormat:@"%@",key];
    }
    
    // 注意: 语音识别回调返回结果是一个json格式字符串, 解析起来比较麻烦, 但是我们只需要其中的字符串部分, 这个过程讯飞也觉得麻烦, 就推出了一个工具类, 能将这个josn解析最终字符串返回. 这也是前面导入ISRDataHelper.h的作用.
    NSString * resu = [ISRDataHelper stringFromJson:result];
    self.textView.text = [NSString stringWithFormat:@"%@%@",self.textView.text,resu];
}
// !!!:解析失败代理方法
-(void)onError:(IFlySpeechError *)error
{
    NSLog(@"解析失败了");
}

// !!!:语音识别类的回调方法
//语音合成回调函数
- (void) onResults:(NSArray *) results isLast:(BOOL)isLast{
    NSMutableString *result = [[NSMutableString alloc] init];
    NSDictionary *dic = [results objectAtIndex:0];
    for (NSString *key in dic) {
        [result appendFormat:@"%@",key];
    }
    NSString * resu = [ISRDataHelper stringFromJson:result];
    self.textView.text = [NSString stringWithFormat:@"%@%@", self.textView.text, resu];
}
@end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章