.Net 百度语音Demo(语音识别、语音合成)

百度语音,面向广大开发者永久免费开放语音合成技术。所采用的离在线融合技术,根据当前网络状况,自动判断使用本地引擎或者云端引擎,进行语音合成,再也不用担心流量消耗了!

本Demo将使用官方提供的C#版本RestApi SDK制作一个Winfrom软件,实现以下两个功能。

  • TTS语音合成:可选择语速、音调、音量及发言人
  • ASR语音识别:使用NAudio进行语音录制并识别

Prepare

在正式使用之前,我们需要在百度语音获取API key以及SDK文件。

获取API Key

在百度语音应用管理页面创建新应用。
按照创建引导一步步来即可,注意在选择服务时同时勾选语音识别和语音合成,这样API Key就可以同时用于TTS和ASR了。

下载离线SDK

下载C#版本的RestApi SDK。

Coding

使用Nuget安装Newtonsoft.Json和NAudio、手动引用官方提供的ApiSdk.dll文件。

接下来查看官方Demo中有关语音的SpeechDemo.cs文件

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
using System;
using System.Collections.Generic;
using System.IO;
using Baidu.Aip.Speech;

namespace Baidu.Aip.Demo
{
class SpeechDemo
{
private readonly Asr _asrClient;
private readonly Tts _ttsClient;

public SpeechDemo()
{
_asrClient = new Asr("Api Key", "Secret Key");
_ttsClient = new Tts("Api Key", "Secret Key");
}

// 识别本地文件
public void AsrData()
{
var data = File.ReadAllBytes("语音pcm文件地址");
var result = _asrClient.Recognize(data, "pcm", 16000);
Console.Write(result);
}

// 识别URL中的语音文件
public void AsrUrl()
{
var result = _asrClient.Recoginze(
"http://xxx.com/待识别的pcm文件地址",
"http://xxx.com/识别结果回调地址",
"pcm",
16000);
Console.WriteLine(result);
}

// 合成
public void Tts()
{
// 可选参数
var option = new Dictionary<string, object>()
{
{"spd", 5}, // 语速
{"vol", 7}, // 音量
{"per", 4} // 发音人,4:情感度丫丫童声
};
var result = _ttsClient.Synthesis("众里寻他千百度", option);

if (result.ErrorCode == 0) // 或 result.Success
{
File.WriteAllBytes("合成的语音文件本地存储地址.mp3", result.Data);
}
}
}
}

从代码示例中,我们可以看出语音识别API需要的源语音文件为pcm格式,我们使用NAudio来获取麦克风数据并保存为pcm格式以使用API,同样的也使用NAudio实时预览录制的数据和播放TTS合成的数据。

将官方Demo封装成SpeechHelper

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
using System.Collections.Generic;
using System.IO;
using Baidu.Aip.Speech;

namespace BaiduSpeechDemo
{
static class SpeechHelper
{
private static readonly Asr AsrClient;
private static readonly Tts TtsClient;

static SpeechHelper()
{
AsrClient = new Asr("BWf8AWrvS5h6Y45NAOP3zaGp", "490737eca7a6ff4d20375d1696c7e548");
TtsClient = new Tts("BWf8AWrvS5h6Y45NAOP3zaGp", "490737eca7a6ff4d20375d1696c7e548");
}

// 识别本地文件
public static AsrResult AsrData(string path)
{
var data = File.ReadAllBytes(path);
var result = AsrClient.Recognize(data, "pcm", 8000);
return result.ToObject<AsrResult>();
}

// 识别URL中的语音文件
public static AsrResult AsrUrl(string url, string callback = "")
{
var result = AsrClient.Recoginze(
url,
callback,
"pcm",
16000);
return result.ToObject<AsrResult>();
}

// 合成
public static bool Tts(string input, string path, int spd = 5, int pit = 5, int vol = 6, int per = 4)
{
// 可选参数
var option = new Dictionary<string, object>
{
{"spd", spd}, // 语速,取值0-9,默认为5中语速
{"pit", pit}, // 音调,取值0-9,默认为5中语调
{"vol", vol}, // 音量,取值0-15,默认为5中音量
{"per", per} // 发音人选择, 0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
};
var result = TtsClient.Synthesis(input, option);

if (result.Success) File.WriteAllBytes(path, result.Data);

//Console.WriteLine(result.Serialize());

return result.Success;
}

}
}

NAudio录制麦克风数据为pcm格式并实时预览

NAudio提供了同时进行录制和播放的Demo,其中的SavingWaveProvider可以直接拿来使用,只要传入合适的参数即可将保存文件的格式由示例中的wav改为pcm,下面是修改后的调用代码。
具体则是修改WaveIn的声明:

1
2
3
// 设置记录器
// WaveFormat.CreateCustomFormat 参数依次为 格式\采样率\声道\每秒平均码率\单位采样点的字节数\采样位数
_recorder = new WaveIn { WaveFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, 8000, 1, 16000, 2, 16) };

下面给出修改后的开始录制和结束录制的代码

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
private WaveIn _recorder;
private BufferedWaveProvider _bufferedWaveProvider;
private SavingWaveProvider _savingWaveProvider;
private WaveOut _player;

private void OnStartRecordingClick(object sender, EventArgs e)
{
// 设置记录器
// 参数依次为 格式\采样率\声道\每秒平均码率\单位采样点的字节数\采样位数
_recorder = new WaveIn { WaveFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, 8000, 1, 16000, 2, 16) };
_recorder.DataAvailable += RecorderOnDataAvailable;

// 建立我们的信号链
_bufferedWaveProvider = new BufferedWaveProvider(_recorder.WaveFormat);

_fileName = Path.Combine("temp", Guid.NewGuid() + ".pcm");
_savingWaveProvider = new SavingWaveProvider(_bufferedWaveProvider, _fileName);

//设置播放
_player = new WaveOut();
_player.Init(_savingWaveProvider);

// 开始播放和录制
_player.Play();
_recorder.StartRecording();
}

private void RecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
_bufferedWaveProvider.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
}

private void OnStopRecordingClick(object sender, EventArgs e)
{
// 停止录制
_recorder.StopRecording();
// 停止播放
_player.Stop();
// 最终完成 WAV 文件
_savingWaveProvider.Dispose();

// 请求百度ASR API
var a = SpeechHelper.AsrData(_fileName);
}

TTS完成

窗体界面拖好TTS选项的布局

完成按钮点击事件的逻辑

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
private void btnTts_Click(object sender, EventArgs e)
{
// 临时保存路径
var musicPath = Path.Combine("temp", Guid.NewGuid() + ".mp3");

// 发言人
var per = cbPer.SelectedIndex >= 2 ? cbPer.SelectedIndex + 1 : cbPer.SelectedIndex;

//调用Baidu TTS Api
if (!SpeechHelper.Tts(tbContext.Text, musicPath, (int)nudSpd.Value, (int)nudPit.Value, (int)nudVol.Value, per)) return;

//播放请求得到的结果
IWavePlayer waveOutDevice = new WaveOut();
var audioFileReader = new AudioFileReader(musicPath);
waveOutDevice.Init(audioFileReader);
waveOutDevice.Play();

//播放结束后销毁播放对象
waveOutDevice.PlaybackStopped += delegate
{
waveOutDevice?.Stop();
waveOutDevice?.Dispose();
waveOutDevice = null;
};
}

Complete

最终成品如下:

完整代码托管在GitHub

代码中我自己的Api Key并没有删除,望手下留情,别给我搞封了。