API实时录音软件winmm.dll

易语言 2020-06-13 15:26:29

后来研究了winmm.dll的API函数,查了很多资料,终于写好一个API录音的源码。也算是解决了易语言录音控件不能长时间录制的问题,说白了就是录音数据实时写入本地,所以也就不会出现内存分配失败的情况拉。

.子程序 开始录音, 整数型, , 0=成功 1=无录音设备 2=获取设备信息失败 3=打开设备失败 -1=未知错误
.参数 声道数, 整数型, , 单声道=1, 立体声=2;
.参数 比特率, 整数型, , 比特率; 8 16
.参数 取样率, 整数型, , 取样率; 11025,22050,44100
.参数 保存路径, 文本型, , 录音文件写入路径 C:\1.WAV
.参数 参_设备名称, 文本型, 参考 可空, 返回当前录音设备的名称
.参数 参_运行提示, 文本型, 参考 可空, 如果返回值 不等于0 ,那么这个参数将会返回 相关错误文本
.局部变量 错误编号, 整数型, , , 获取返回数据编号
.局部变量 错误文本, 文本型, , , 根据返回编号取出的文本信息
.局部变量 设备结构, 设备结构, , , 波形输入设备性能结构

录音文件号 = 0
数据长度 = 0
设备句柄 = 0
.如果 (waveInGetNumDevs () ≠ 0) ' 获取音频输入设备的数量
' ////获取声音输入设备性能信息 ,其实这步可以省略
错误编号 = waveInGetDevCapsA (-1, 设备结构, 46)
.如果真 (错误编号 ≠ 0)
参_运行提示 = 编号描述 (错误编号)
调试输出 (编号描述 (错误编号))
返回 (2)
.如果真结束
参_设备名称 = 到文本 (设备结构.制造商名称)
' 调试输出 (“设备名称:” + 参_设备名称)
' ////打开声音输入设备
录音结构.格式 = #WAVE_FORMAT_PCM ' 记录着此声音的格式代号; 默认 WAVE_FORMAT_PCM;
录音结构.声道数 = 声道数
录音结构.采样率 = 取样率
录音结构.比特率 = 比特率
录音结构.传输速率 = 声道数 × 取样率 × 比特率 ÷ 8 ' 指定数据传输的传输速率(每秒的字节数)
录音结构.块对齐 = 声道数 × 比特率 ÷ 8 ' 指定块对齐(每个样本的字节数), 块对齐是数据的最小单位
错误编号 = waveInOpen (设备句柄, -1, 录音结构, &回调函数, 0, #CALLBACK_FUNCTION) ' 第二个参数为设备ID,默认 -1 为系统自动选择
.如果真 (错误编号 ≠ 0)
参_运行提示 = 编号描述 (错误编号)
调试输出 (编号描述 (错误编号))
返回 (3)
.如果真结束
' 调试输出 (“设备句柄:” + 到文本 (设备句柄))
' ////为音频输入设备准备一个缓冲区
缓存大小 = 1024 × 64
闲置缓存1 = 取空白字节集 (缓存大小)
闲置缓存2 = 取空白字节集 (缓存大小)
缓存地址1 = lstrcpyn (闲置缓存1 [1], 闲置缓存1 [1], 0) ' 取内存变量地址
缓存地址2 = lstrcpyn (闲置缓存2 [1], 闲置缓存2 [1], 0) ' 取内存变量地址
缓存结构.缓冲区地址 = 缓存地址1 ' 指向波形格式的缓冲区的指针,先用 缓存1
缓存结构.缓冲区大小 = 缓存大小 ' 缓冲区的大小
缓存结构.循环次数 = 1 ' 标识播放循环次数
waveInPrepareHeader (设备句柄, 缓存结构, 32) ' 为音频输入设备准备一个缓冲区
waveInAddBuffer (设备句柄, 缓存结构, 32) ' 将准备好的缓冲区发送给设备,若缓冲区填满,则不起作用。(参数同上)
当前缓存 = 1 ' 设置下当前使用缓存的编号
' ////创建本地录音文件(实时写入用)
删除文件 (保存路径)
写到文件 (保存路径, { })
录音文件号 = 打开文件 (保存路径, 5, )

' Windows的录音流程大致如下:
' 1 先查看本地机器是否拥有声音输入设备。
' 2 获取声音输入设备的信息
' 一般上面的两部不是很必要,毕竟现在的电脑基本都拥有集成声卡。不过从稳定性和通用性看,还是很必要的。
' 3 打开设备,获取设备句柄,传入对应的事件句柄。
' 4 准备一个异步线程专门用于录音完成后的处理工作,并等待事件。
' 5 通过设备句柄为其准备缓冲区
' 6 将准备好的缓冲区通过句柄添加到设备中
' 接下来属于系统的工作,正常情况下,在缓冲区被填满后,将会触发事件,来通知异步线程进行处理。获取声音信息后,要再次添加缓冲区,才能继续录音。
' 有时在缓冲区的建立上,一般会采取栈分配或者堆分配的方式。栈分配内存的析构处理通过退栈完成,用户不用手动处理。但是堆分配的时候就会遇到麻烦,具体如下:
' 在准备缓冲区的时候会调用waveInPrepareHeader函数,这个函数调用后,为其分配的内存就无法通过delete或者free来释放了,因为在该函数调用后这块内存区域被锁定了。此时必须调用waveInUnprepareHeader函数才能解锁定,然后才能释放。
' 但是在调用waveInPrepareHeader函数后,再接着调用了waveInAddBuffer函数,在该缓冲区未被填满的时候,尝试使用waveInUnprepareHeader函数解锁定,就会返回失败码33。这里的解决方案就是在决定释放空间前,首先调用一个函数:waveInReset。这个函数调用后,就可以将内存从waveInAddBuffer函数的限定中释放,然后再常规使用waveInUnprepareHeader释放,最后调用delete或者free释放内存空间。