连续声音采集最好版本(c#),把书读薄了
为了识别一个短元音,比如,啊(a),钨(u),诸如此类,抄来了别人的声音采集程序,visual c++和c#两个版本,在采集短元音的过程中,发现,c#版本不如c++版本好,一直未找到原因,耿耿于怀(人生的烦恼诞生于此,放不下!)。
当能进行mfcc语音识别这些短元音后,很想用自己的方式去存储一段自己的录音,而非.wav格式,语音识别不能总是停留在短元音识别是吧?
近期尝试了c++版本录音,是ok的,具体是这样,每次采集1920字节声音,满了,再添加1920字节buffer备用继续录音,已满的1920字节buffer写入磁盘,命名为.mch文件,然后重复以上过程,把已满的1920字节buffer源源不断的追加写入到这个.mch文件中。
可惜,c#尝试,始终不成功,再次想起前面的芥蒂,两重放不下,你现在是靠c#吃饭的,底层怎么可以不牢靠呢?
有一种精神叫做“要把书读薄了!”,七月初,机器视觉很多算法都在整理,就是在继承这种精神,只有这样,你的机器视觉才能稳定,准确,高效。
近期,抄了不下四个版本一步一步来精简这个c#版本的连续声音采集程序,终于等到了该来的,放下了该放下的。
抄别人的东西,就应该有所自己的收获,否则,掌控不了,而心生烦恼!
以下是c#版本精简后连续声音采集最好程序,c++版本不再累述。代码如下,你可以去翻看我前面博客有关于此,做个对比。
虽然你还能看到网络程序的影子,但他在你手中,已经脱胎换骨。(删掉了不必要的线程thread以及线程事件掌控AutoResetEvent,这是一种误导,他并不是一种好的方式,除非你更热衷于c#编程技术,这种方式对付短元音采集,虽然绰绰有余,但在连续采集上,反复debug,你会发现缺陷,只要你保证了录音buffer的添加不中断,微软已经保证了录音的连续性,不需要再来一个线程去掌控)
第一,创建一个form,声明变量
public const short device = (-1);
public WaveFormat format = new WaveFormat();
private WaveInRecorder m_WIR;
第二,在formload函数中初始化
m_WIR = new WaveInRecorder(device, format, 1920, 1, new BufferDoneEventHandler(DataArrived));//委托函数
好,结束了!
不懂向下看:(保证最精简,无关全删掉)
第一解释,WaveFormat
public enum WaveFormats
{
Pcm = 1,
Float = 3
}
[StructLayout(LayoutKind.Sequential)]
public class WaveFormat
{
public short wFormatTag;
public short nChannels;
public int nSamplesPerSec;
public int nAvgBytesPerSec;
public short nBlockAlign;
public short wBitsPerSample;
public short cbSize;
public WaveFormat()
{
wFormatTag = (short)WaveFormats.Pcm;
nChannels = 1;
nSamplesPerSec = 8000;
nAvgBytesPerSec = 8000;
nBlockAlign = 1;
wBitsPerSample = 8;
cbSize = 0;
}
}
第二解释,internal class WaveInRecorder
{
private IntPtr m_WaveIn;
private WaveInBuffer m_Buffers = null;
private WaveInBuffer m_CurrentBuffer = null;
private BufferDoneEventHandler m_DoneProc;
public WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc); //委托函数
int buffersize = 0;
public void wimdatacomplete(IntPtr data, int size)
{
m_DoneProc(data, size);//dataarrived
}
public WaveInRecorder(int device, WaveFormat format, int bufferSize, int bufferCount, BufferDoneEventHandler doneProc)
{
this.buffersize = bufferSize;
m_DoneProc = doneProc;//dataarrived传进来
WaveInHelper.Try(WaveNative.waveInOpen(out m_WaveIn, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION)); //录音第一步waveInOpen
if (bufferCount > 0)
{
m_Buffers = new WaveInBuffer(m_WaveIn, bufferSize);//录音第二步waveInPrepareHeader
WaveInBuffer Prev = m_Buffers;
//因为只有一个1920字节buffer,其他不相关删除了
Prev.NextBuffer = m_Buffers;
}
for (int i = 0; i < bufferCount; i++)
{
m_CurrentBuffer = m_CurrentBuffer == null ? m_Buffers : m_CurrentBuffer.NextBuffer;
bool temp= m_CurrentBuffer.Record();//waveinaddbuffer,录音第三步
m_CurrentBuffer.m_DoneProc = wimdatacomplete;
}
WaveInHelper.Try(WaveNative.waveInStart(m_WaveIn));//开始录音,录音第四步
}
}
第三解释,internal class WaveInBuffer
{
private IntPtr m_WaveIn;
private WaveNative.WaveHdr m_Header;
private byte[] m_HeaderData;
private GCHandle m_HeaderDataHandle;
public WaveInBuffer NextBuffer;
public BufferDoneEventdowith m_DoneProc;
public int Size
{
get { return m_Header.dwBufferLength; }
}
public IntPtr Data
{
get { return m_Header.lpData; }
}
public WaveInBuffer(IntPtr waveInHandle, int size)
{
m_WaveIn = waveInHandle;
m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
m_HeaderData = new byte[size];
m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
m_Header.dwBufferLength = size;
WaveInHelper.Try(WaveNative.waveInPrepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
}
public bool Record()
{//录音第六步,添加一个1920字节buffer,若添加不上,录音失败
bool m_Recording = false;
lock (this)
{
m_Recording = WaveNative.waveInAddBuffer(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)) == WaveNative.MMSYSERR_NOERROR;
}
return m_Recording;
}
private void OnCompleted(IntPtr Data, int size)
{
m_DoneProc(Data, size); //录音第七步 ,录满1920字节buffer 取出来存盘
}
internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
{//录音第五步 , MM_WIM_DATA到了,说明录音满了一个1920字节buffer
if (uMsg == WaveNative.MM_WIM_DATA)
{
try
{
GCHandle h = (GCHandle)wavhdr.dwUser;
WaveInBuffer buf = (WaveInBuffer)h.Target;
bool ret = buf.Record();
buf.OnCompleted(buf.Data, buf.Size);
}
catch
{
}
}
}
}
第四解释,相关其他:
internal class WaveInHelper
{
public static void Try(int err)
{
if (err != WaveNative.MMSYSERR_NOERROR)
{
// throw new Exception(err.ToString());
Thread.Sleep(250);
}
}
}
internal class WaveNative
{
public const int MM_WIM_DATA = 0x3C0;
public const int CALLBACK_FUNCTION = 0x00030000; // dwCallback is a FARPROC
public delegate void WaveDelegate(IntPtr hdrvr, int uMsg, int dwUser, ref WaveHdr wavhdr, int dwParam2);
[StructLayout(LayoutKind.Sequential)]
public struct WaveHdr
{
public IntPtr lpData; // pointer to locked data buffer
public int dwBufferLength; // length of data buffer
public int dwBytesRecorded; // used for input only
public IntPtr dwUser; // for client's use
public int dwFlags; // assorted flags (see defines)
public int dwLoops; // loop control counter
public IntPtr lpNext; // PWaveHdr, reserved for driver
public int reserved; // reserved for driver
}
//尝试简单录音20200724
[DllImport("winmm.dll")]
public static extern int waveInOpen(out IntPtr phwi, int uDeviceID, WaveFormat lpFormat, WaveDelegate dwCallback, int dwInstance, int dwFlags);
[DllImport("winmm.dll")]
public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WaveHdr lpWaveInHdr, int uSize);
[DllImport("winmm.dll")]
public static extern int waveInStart(IntPtr hwi);
[DllImport("winmm.dll")]
public static extern int waveInAddBuffer(IntPtr hwi, ref WaveHdr pwh, int cbwh);
}
另外就是两个委托函数的使用,把录音数据传到form层面,form下的委托函数是:
public void DataArrived(IntPtr data, int size)
{ //每写满一个1920字节buffer,都会给到这里来
bt2 = new byte[1920];
Marshal.Copy(data, bt2, 0, bt2.Length);
//取出即可,显示也好,存盘也好
}
所以要在form类之外,项目namespace空间之内声明:
// callbacks
public delegate void BufferDoneEventHandler(IntPtr data, int size);//dataarrived ,在WaveInRecorder中
public delegate void BufferDoneEventdowith(IntPtr data, int size);//testsucess,在waveinbuffer中
正如你所看到的,DataArrived函数的地址给了WaveInRecorder.m_DoneProc
而WaveInRecorder.m_DoneProc又给了 waveinbuffer.m_DoneProc (通过 wimdatacomplete函数);
所以WaveInProc中的录音数据(每一个录满的1920字节)都是通过 waveinbuffer.m_DoneProc给出的。
如果不这样,你还有什么好方法?
WaveInProc也是一个委托函数(回调函数),只不过函数格式微软已经定义好(waveinopen函数要求),这是源头活水。
在WaveInProc调用了waveinbuffer.m_DoneProc,故有机会取水泡茶,哈哈!
连续声音采集最好版本(c#),把书读薄了相关推荐
- 基于RTMP实现Linux|麒麟操作系统下屏幕|系统声音采集推送
背景 Windows操作系统自问世以来,以其简单易用的图形化界面操作受到大众追捧,为计算机的普及.科技的发展做出了不可磨灭的功绩,也慢慢的成为人们最依赖的操作系统.在中国,90%以上的办公环境都是Wi ...
- Android手机直播(三)声音采集
一.文章说明 开始写文章了,才知道写文章真心耗费心力,希望自己尽量做到快速更新,也希望这些文章真心能帮助到开发者们. 这篇文章主要讲述Android声音采集相关的知识,首先介绍声音的基础知识,然后介绍 ...
- 多看Android版本WIFI传书的实现
多看Android版本WIFI传书的实现 参照<多看>的WIFI传书功能 * 手机端的HttpServer采用开源项目AndroidAsync实现的. * 网页端采用jQuery实现,文件 ...
- 爱剪辑导出视频显示服务器繁忙,声音采集与视频剪辑(第二届广东省普通高中信息技术优质课评选活动二等奖).doc...
声音采集与视频剪辑(第二届广东省普通高中信息技术优质课评选活动二等奖) 声音采集与视频剪辑(第二届广东省普通高中信息技术优质课评选活动二等奖) 教学分析与教学设计思路 ? 一.教学对象分析与教学设计 ...
- 麦克风采样率设置导致视频会议中声音采集异常问题分享
目录 1.问题描述 2.麦克风音频采集频率引发的声音采集异常 3.修改麦克风采集频率的详细说明 4.最后 这几年,大家已经习惯于使用视频会议软件(比如免费的腾讯会议软件)进行线上沟通与交流,通过摄像头 ...
- WCF把书读薄(4)——事务编程与可靠会话
WCF把书读薄(3)--数据契约.消息契约与错误契约 真不愧是老A的书,例子多,而且也讲了不少原理方面的内容,不过越读越觉得压力山大--这次来稍微整理整理事务和可靠会话的内容. 十八.事务编程 WCF ...
- 从混合云到云原生 KubeSphere 3.0先把书读厚,再把书读薄
KubeSphere把云原生的书"读厚",客户才能把云原生的书"读薄". 出品 | 常言道 作者 | 丁常彦 从2018年7月青云QingCloud正式发布Ku ...
- 传感器测试--声音采集与FFT 分析
三天不学习,就不知道如何用声卡了. 1 MATLAB-- Audio record for specified time 做了一个简单的demo,仅采集1次的声音,并做FFT 分析 记得存为.m文件, ...
- 编译Linux版本飞鸽传书的不完全解决办法
前几天想起在局域网常用的飞鸽传书,想知道在Ubuntu有没有办法运行或者有类似的软件可用,首先想到了Wine,马上Wine一个Windows最新版本的IPMSG,一试就成功了,完美模拟运行. 在 ...
最新文章
- solaris11学习必用工具及ISO
- c语言多线程mysql_多线程读写mysql数据库
- 脑电情绪识别:脑功能连接网络与局部激活信息结合
- 虚拟机上使用ghost xp
- pdo mysql连接类_PHP PDO-MYSQL:如何在不同类之间使用数据库连接
- 通过Cookie存取用户游览记录的代码示例
- 通过Socket configuration controls 获取网络设备地址
- Windows7 简体中文旗舰版下载 (MSDN官方发布正式版原版镜像)
- IMX6ULL开发板,系统移植——第一步Uboot移植
- layer的iframe用法整理
- 计算机ps相框怎么做,教你用PS给相片加上很漂亮的相框
- 新唐单片机选型手册_Nuvoton新唐8位8051单片机选型指南
- c#的chart标题_C#之Chart篇
- 事件绑定-addEventListener()和attachEvent()的区别及用法
- 抖音快手短视频功能解读
- 用户协议栈之协议设计
- 可信数字版权保护解决方案Sky Engine—重塑原创价值,构建数字版权新生态
- php 接口token生成验证
- 实验一OpenGL图形编程入门
- 法线贴图呈蓝紫色的原因
热门文章
- Archicad二次开发——MessageBox、USstring转字符、打开保存文件的对话框获取选择的地址、获取文件信息
- 软件开发项目管理检查清单:天气晴雨表
- ActiveStorage. 英文书Learnrails5.2的案例,看如何放到云上。
- java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path
- 如何实现扫描条码自动打印标签?
- tplink软件升级有用吗_tp-link无线路由器软件如何升级【教程图解】
- 计算机组成原理学习-实验四 模型机实验(简易版)(详细、人话)
- Unity连接KBE云服务器:登录网关(baseapp)异常
- github下载的matlab代码,如何从GitHub存储库下载代码
- 用Matlab和SPM批量处理被试的经验总结