百度语音,面向广大开发者永久免费开放语音合成技术。所采用的离在线融合技术,根据当前网络状况,自动判断使用本地引擎或者云端引擎,进行语音合成,再也不用担心流量消耗了!
本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文件
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
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的声明:
// 设置记录器
// WaveFormat.CreateCustomFormat 参数依次为 格式\采样率\声道\每秒平均码率\单位采样点的字节数\采样位数
_recorder = new WaveIn { WaveFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Pcm, 8000, 1, 16000, 2, 16) };
下面给出修改后的开始录制和结束录制的代码
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选项的布局
完成按钮点击事件的逻辑
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并没有删除,望手下留情,别给我搞封了。