基于C#的在线语音识别软件开发
本软件利用了百度语音识别提供的接口,自行开发出的一个在线的语音识别软件。所以,制作之前需要去百度语音识别的网站去注册一个项目,免费的除非你的需求量特别大不然不需要付费。百度语音识别地址
然后就需要自己写代码去解决以下问题
- 获取麦克风输入的语音
- 发送到百度语音识别的接口
- 得到返还的信息识别。
获取麦克风输入的语音
要获取麦克风的输入,需要调用一些WindowsAPI及其他的东西。下面就慢慢梳理 我会分散的梳理,整合需要自己理解着去整合
首先,我们获取麦克风,使用winmm.dll
//调用wavein的dll
[DllImport("winmm.dll")]
//获取有多少可用输入设备
public static extern int waveInGetNumDevs();
[DllImport("winmm.dll")]
//增加一个缓冲区
public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHdr pwh, UInt32 cbwh);
[DllImport("winmm.dll")]
//关闭麦克风
public static extern int waveInClose(IntPtr hwi);
[DllImport("winmm.dll")]
//打开麦克风
public static extern int waveInOpen(out IntPtr phwi, UInt32 uDeviceID, ref WaveFormatEx lpFormat, WaveDelegate dwCallback, UInt32 dwInstance, UInt32 dwFlags);
[DllImport("winmm.dll")]
//标记为可用的缓冲区public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, UInt32 uSize);
[DllImport("winmm.dll")]
//标记为不可用的缓冲区
public static extern int waveInUnprepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, UInt32 uSize);
[DllImport("winmm.dll")]
//把缓冲区内容重置public static extern int waveInReset(IntPtr hwi);
[DllImport("winmm.dll")]
//开始录制
public static extern int waveInStart(IntPtr hwi);
[DllImport("winmm.dll")]
//停止录制
public static extern int waveInStop(IntPtr hwi);
然后 我们要把接收到的波形数据放入到一个缓冲区里面
[StructLayout(LayoutKind.Sequential)]//接受的波形数据放入的缓冲区public struct WaveHdr{public IntPtr lpData;//缓冲区public UInt32 dwBufferLength;//缓冲区长度public UInt32 dwBytesRecorded;//某一刻读取到了多少字节的数据public UInt32 dwUser;//自定义数据public UInt32 dwFlags;public UInt32 dwLoops;//是否循环public IntPtr lpNext;//链表的下一缓冲区public UInt32 reserved;//没实际意义}[StructLayout(LayoutKind.Sequential)]//波形格式public struct WaveFormatEx{ public UInt16 wFormatTag;//波形的类型public UInt16 nChannels;//通道数(1,单声道 2,立体音)public UInt32 nSamplesPerSec;//采样率public UInt32 nAvgBytesPerSec;//字节率public UInt16 nBlockAlign;public UInt16 wBitsPerSample;//每个样多少位public UInt16 cbSize;//长度}
但是在这里我们需要一个delegate的委托事件,其作用是在缓冲区满了或者waveinopen和waveinclose的时候被调用。
public delegate void WaveDelegate(IntPtr hwi, UInt32 uMsg, UInt32 dwInstance, UInt32 dwParam1, UInt32 dwParam2);
上传到百度识别的接口
在全部获取到麦克风语音接收的信息之后,我们需要把识别的波形上传到百度识别的接口上,在这里我们就用HTTP协议来将我们获得的东西上传上去
/// <summary>/// 通过HTTP协议去上传base64数据/// </summary>/// <param name="URL">服务器的url</param>/// <param name="strPostdata">上传的东西</param>/// <param name="strEncoding">采用的编码格式</param>/// <returns></returns>public static string OpenReadWithHttps(string URL, string strPostdata, string strEncoding){Encoding encoding = Encoding.Default;//默认的编码格式为default(GB2312)HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);//向自定义的URL链接发送请求 requestrequest.Method = "post";//请求的方式为postrequest.Accept = "*/*";//告诉服务器能接受*/*(任意)的参数类型request.ContentType = "application/x-www-form-urlencoded";//最常见的post提交数据的方式byte[] buffer = encoding.GetBytes(strPostdata);//用一个byte数组接收发送的数据字节request.ContentLength = buffer.Length;//告诉服务器自己上传的数组长度request.GetRequestStream().Write(buffer, 0, buffer.Length);//写入请求流从第一位开始写入buffer数组,写入长度为buffer.Length的数据流HttpWebResponse response = (HttpWebResponse)request.GetResponse();//从服务器得到的数据为请求获得的数据using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(strEncoding))){//返回从URL获得的内容信息return reader.ReadToEnd();}}
判断是否在录入音频
每个语音都是一个缓冲区,等缓冲区满了,要提供新缓冲区,等缓冲区满了,要提供新缓冲区
static void waveInHandler(IntPtr hwi, UInt32 uMsg, UInt32 dwInstance, UInt32 dwParam1, UInt32 dwParam2){switch (uMsg){case 0x3BE: break;case 0x3C0:unsafe{var waveHdr = (WaveHdr*)dwParam1;}break;case 0x3BF: break;}}
Main函数总结
小的模块说的差不多了,下面就从Main函数说起,中间还会穿插一些小的模块
首先我们设置波纹的格式
static void Main(string[] args){try{var inputFormat = new WaveFormatEx();//波形格式inputFormat.wFormatTag = 1;//波形类型inputFormat.nChannels = 1;inputFormat.nSamplesPerSec = 8000;inputFormat.nAvgBytesPerSec = 16000;inputFormat.nBlockAlign = 2;inputFormat.wBitsPerSample = 16;inputFormat.cbSize = 0;
由于我们是语音识别不是就识别一次,所以我们下面要进入一个死循环
这里我们在等候语音的输入
for (;;){waveInOpen(out inputDevice, UInt32.MaxValue, ref inputFormat, new WaveDelegate(waveInHandler), 0, 0x00030000);int bufferSize = 960000;var buffer1 = new WaveHdr();buffer1.lpData = Marshal.AllocHGlobal(bufferSize);buffer1.dwBufferLength = (UInt32)bufferSize;buffer1.dwLoops = 1;waveInPrepareHeader(inputDevice, ref buffer1, (UInt32)Marshal.SizeOf(typeof(WaveHdr)));waveInAddBuffer(inputDevice, ref buffer1, (UInt32)Marshal.SizeOf(typeof(WaveHdr)));SpeechRecognitionEngine recognizer = null;foreach (var installed in SpeechRecognitionEngine.InstalledRecognizers()){if (installed.Culture.Name.Equals("zh-CN", StringComparison.CurrentCultureIgnoreCase) && installed.Id.Equals("MS-2052-80-DESK")){recognizer = new SpeechRecognitionEngine(installed);break;}}var grammars = new GrammarBuilder();grammars.AppendDictation();recognizer.LoadGrammar(new Grammar(grammars));recognizer.SetInputToDefaultAudioDevice();bool recognizeStarted = false;int speechCount = 0;int silenceCount = 0;Console.WriteLine("正在等候语音输入...");recognizer.RecognizeAsync(RecognizeMode.Multiple);waveInStart(inputDevice);
当说话的时候开始分析语音
for (;;){if (!recognizeStarted){if (recognizer.AudioState == AudioState.Speech)speechCount++;else speechCount = 0;}if (!recognizeStarted && speechCount >= 2){recognizeStarted = true;speechCount = 0;Console.WriteLine("检测到语音输入,正在录制...");}if (recognizeStarted){if (recognizer.AudioState == AudioState.Silence)silenceCount++;else silenceCount = 0;}//checkingMutex.Set();if (recognizeStarted && silenceCount >= 220){//checkingMutex.Reset();silenceCount = 0;unsafe{Console.WriteLine("正在分析语音数据...");waveInReset(inputDevice);waveInStop(inputDevice);recognizer.RecognizeAsyncStop();
在上面的代码中有判断环境噪音的代码
if (recognizer.AudioState == AudioState.Silence)silenceCount++;else silenceCount = 0;
silenceCount 就是统计静音状态持续了多久,到了一定值,就可以发送语音到识别平台了
然后我们就要用到百度给予的接口和key了
var apiKey = "百key";var secretKey = "百度给的密码key";var token = OpenReadWithHttps("百度给你提供的API接口地址http" + $"?grant_type={ "client_credentials" }&client_id={ apiKey }&client_secret={ secretKey }", String.Empty, "utf-8");var tokenPrefix = "\"access_token\":[\"";int i;token = token.Substring(i = token.IndexOf(tokenPrefix) + tokenPrefix.Length + 1, token.IndexOf("\"", i + tokenPrefix.Length) - i);var postData = new StringBuilder();postData.Append("{").Append($"\"format\":\"pcm\",\"rate\":8000,\"channel\":1,\"token\":\"{ token }\",\"cuid\":\"F96625D0-0FBC-491C-B617-9EC0B3A0D5A6\",\"lan\":\"en\",");var base64Data = new byte[buffer1.dwBytesRecorded];Marshal.Copy(buffer1.lpData, base64Data, 0, (int)buffer1.dwBytesRecorded);var base64 = Convert.ToBase64String(base64Data);postData.Append("\"speech\":\"").Append(base64).Append("\",").Append($"\"len\":{ buffer1.dwBytesRecorded }").Append("}");try{Console.Write("\n识别结果: ");Marshal.FreeHGlobal(buffer1.lpData);var result = OpenReadWithHttps("http://vop.baidu.com/server_api", postData.ToString(), "utf-8");var prefix = "\"result\":[\"";result = result.Substring(i = result.IndexOf(prefix) + prefix.Length, result.LastIndexOf("\"]") - i + 1);string[] restt = result.Split('\"');var restlt = restt[0];Console.WriteLine(restlt);//string resultfinally = Recognize(restlt);try{string resultfinally = Recognize(restlt);loading(resultfinally, "word.txt");}catch (Exception ex){Console.WriteLine(ex.Message);//(new SpVoiceClass()).Speak("你说的有些不标准,请重新说");}Console.WriteLine();}catch (Exception ex){Console.WriteLine("无法识别所说的话语。\n");}//checkingMutex.Set();}//checking.Dispose(checkingFinished);break;}Thread.Sleep(1);}//checkingFinished.WaitOne();}}catch (Exception exception){Console.WriteLine(exception);}}}
}
在这里你会发现,我做了一个语音识别和回复,识别目录下的文档里的内容,然后对比,对比到以后将下一句转换为语音。需要用到两个自定义的函数
第一个是判断你说的话是否是在给定的文本里面
public static void loading(string listen, string url){var file = File.OpenRead(url);var sr = new StreamReader(file);List<string> include = new List<string>();while (!sr.EndOfStream){var str = sr.ReadLine();foreach (var chara in str)if (!char.IsLetter(chara))str = str.Replace(chara, ' ');str = str.Trim();include.Add(str);}for (int i = 0; i < include.Count; i++){if (String.Compare(listen.Trim(), include[i].Trim(), StringComparison.CurrentCultureIgnoreCase) == 0){SpeechSynthesizer speaker = new SpeechSynthesizer();speaker.SetOutputToDefaultAudioDevice();speaker.Speak(include[i + 1]);return;}}SpeechSynthesizer speak = new SpeechSynthesizer();speak.SetOutputToDefaultAudioDevice();speak.Speak("口音有问题,请重说。");throw new Exception("口音有问题,请重说。");}
第二个是判断是否跟自定义的语句匹配并说出下一句
public static string Recognize(string getin){var responses = new string[]{"楼主帅吗","当然了","聪明吗","必须的",//你想写和你想输出的语句};getin = getin.ToLower();foreach (var chara in getin)if (!char.IsLetter(chara))getin = getin.Replace(chara, ' ');getin = getin.Trim();int matches;var k = getin.Split();for(var i = 0; i < responses.Length; i++){responses[i] = responses[i].ToLower();foreach (var chara in responses[i])if (!char.IsLetter(chara))responses[i] = responses[i].Replace(chara, ' ');responses[i] = responses[i].Trim();}foreach (var repWord in responses){matches = 0;var j = repWord.Split();foreach (var myword in k){if (j.Contains(myword)){matches++;if (((float)matches / j.Length) >= 0.5F)return repWord;}}}return "你说错了,请重说";}
这里还是有一个小问题,就是你说的语句返识别返还回来会有标点符号,这里我们就把符号全部给抛弃了
我这边做的是英语的语音识别,在发送的json串的时候最后的len用的是en,在语种选择的时候是不区分大小写的,但是好像只支持三种默认中文(zh)。 中文=zh、粤语=ct、英文=en。
总的来说就这些东西,如果有什么疑问和建议或者纠正,可以直接告诉我,期待大神们的指点。
此外。在此特别感谢给我这个程序最大的技术支持的人。我们群里的大佬RURI(也叫Azure)。
基于C#的在线语音识别软件开发相关推荐
- 基于kaldi的在线语音识别
本文是基于kaldi的在线语音识别,使用b/s架构进行在线识别.适用于刚刚接触的小白. 开发环境:jdk-1.8,Ubuntu16.04,Eclipse. 开发过程: 1.准备必须的文件 如果你想要实 ...
- java实现社交平台,基于Java的在线社交软件的设计与实现.doc
摘要:本项目的目标是设计一个基于局域网的网络聊天系统,根据当前网络技术的发展趋势和实际情况,最终达到满足特定群体的需求.软件适用于同一部门工作的同事或同一学校的学生,以满足他们经常需要在学校和同事之间 ...
- 在线教育软件开发的目的是什么?
在线教育在如火如荼地进行,从近几年开始,在线教育也越来越流行,同时在线教育的形式也多种多样,那么在线教育软件开发中需要加入哪些功能才能更好地满足教学的需要呢? 1.在线学习系统 通过在线的互动交流来促 ...
- 基于AUTOSAR规范的电机控制器软件开发
基于AUTOSAR规范的电机控制器软件开发 本系列文章主要介绍如何开发符合AUTOSAR规范的电机控制器软件的详细过程. 全系类分为基础篇和实战篇:基础篇内简要介绍最新的AUTOSAR规范,嵌入式软件 ...
- 基于SSM的在线音乐网站开发与实现
基于SSM的在线音乐网站开发与实现 本人的毕业设计,因为没有系统的学习过HTML和CSS,所以页面想不出什么设计元素,都是基于框架搭建而成的.前台页面为Bootstrap实现,后台页面为LayUI实现 ...
- 在线教育软件开发 教育APP软件开发分析
随着互联网的快速发展,教育机构也纷纷改变了发展模式,教育APP软件的开发大受欢迎,司科认为教育软件的开发不仅能让教学资源共享,更能促进教育行业的发展. 为什么教育类APP软件值得开发 1.使用教育AP ...
- 基于AnyCAD的三维管道设计软件开发
1 简介 管道广泛用于化工.工厂.建筑.市政等方面,关系到国计民生.虽然管道设计软件种类繁多,有的也非常强大(然而也非常昂贵),但也并不能完全满足个性化需要. 如何快速开发一款满足自己需求的三维管道设 ...
- 基于信鸽的在线聊天软件(一)
服务端和客户端的搭建 平台选择 首先想到的是用服务器搭,然而学校封端口,虚拟服务器又麻烦的很,所以考虑到了用云服务.两个选择,腾讯信鸽和百度云推送,本项目基于信鸽. 信鸽开发者中心 http://xg ...
- 基于JavaScript的在线语音识别库Julius
JuliusJS需要的文件有点多(不包括index.html和js.js): html: 只需要引入julius.js <script src="julius.js"> ...
- 基于mysql+php109在线记账软件
随着计算机网络的日益发展和广泛应用,以及数据库技术的应用,人们传统的一些方式发生了巨大的改变,银行的业务从单一的吸收存款,发放贷款,发展为综合财务业务.顺应这种趋势,本次毕业设计主要是分析.设计和实现 ...
最新文章
- 【ACM】连续出现的字符
- Spring Boot + Elasticsearch
- 实际操作_MFC修改控件的Tab顺序
- linux ubuntu pkg-config工具的使用(源代码编译库接口查询工具)
- 传统公司部署OpenStack(t版)简易介绍(四)——placement模块部署
- RabbitMQ消息确认以及return机制
- 2018蓝桥杯A组:方格计数(3种方法)
- Latex——从基础表到进阶表的讲述
- Ubuntu 软件安装(网易云音乐,有道词典,flash插件)
- 英语诗歌选读 | 期末总结
- 美团套餐榜、商家榜数据抓取
- 2021年10月语音合成和语音识别论文月报
- 判断是否是平衡二叉树
- 【附源码】Python计算机毕业设计社团管理系统
- 一个数加100是完全平方数,再加168又是一个完全平方数
- 引用参考文献标准格式
- 【python】BaiDuAI-人脸检测、人脸搜索、人脸注册
- 在html文件中 url是统一资源定位器,HTML URL(统一资源定位器)
- 基于RTP协议的H.264视频传输系统:原理
- LKD-虚拟文件系统