Wave 文件(11): 使用 waveIn...函数录制 wav 文件
使用窗口接受音频设备发出的消息:
使用回调函数处理音频设备发出的消息:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); protected procedure WndProc(var m: TMessage); override; end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; var whIn1,whIn2, whOut: TWaveHdr; hWaveIn,hWaveOut: HWAVE; fmt: TWaveFormatEx; buf1,buf2,SaveBuf: TBytes; procedure TForm1.FormCreate(Sender: TObject); begin Button1.Caption := '开始录音'; Button2.Caption := '停止录音'; Button3.Caption := '播放录音'; end; //开始录音 procedure TForm1.Button1Click(Sender: TObject); begin {指定要录制的格式} fmt.wFormatTag := WAVE_FORMAT_PCM; fmt.nChannels := 2; fmt.nSamplesPerSec := 22050; fmt.nAvgBytesPerSec := 88200; fmt.nBlockAlign := 4; fmt.wBitsPerSample := 16; fmt.cbSize := 0; SaveBuf := nil; {清除已录制的内容} if waveInOpen(@hWaveIn, WAVE_MAPPER, @fmt, Handle, 0, CALLBACK_WINDOW) = 0 then begin SetLength(buf1, 1024*8); SetLength(buf2, 1024*8); whIn1.lpData := PAnsiChar(buf1); whIn1.dwBufferLength := Length(buf1); whIn1.dwBytesRecorded := 0; whIn1.dwUser := 0; whIn1.dwFlags := 0; whIn1.dwLoops := 0; whIn1.lpNext := nil; whIn1.reserved := 0; whIn2.lpData := PAnsiChar(buf2); whIn2.dwBufferLength := Length(buf2); whIn2.dwBytesRecorded := 0; whIn2.dwUser := 0; whIn2.dwFlags := 0; whIn2.dwLoops := 0; whIn2.lpNext := nil; whIn2.reserved := 0; waveInPrepareHeader(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInPrepareHeader(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInAddBuffer(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInAddBuffer(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInStart(hWaveIn); end; end; //停止录音 procedure TForm1.Button2Click(Sender: TObject); begin waveInStop(hWaveIn); waveInUnprepareHeader(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInUnprepareHeader(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInClose(hWaveIn); end; //播放录音 procedure TForm1.Button3Click(Sender: TObject); begin whOut.lpData := PAnsiChar(SaveBuf); whOut.dwBufferLength := Length(SaveBuf); whOut.dwBytesRecorded := 0; whOut.dwUser := 0; whOut.dwFlags := 0; whOut.dwLoops := 1; whOut.lpNext := nil; whOut.reserved := 0; waveOutOpen(@hWaveOut, WAVE_MAPPER, @fmt, Handle, 0, CALLBACK_WINDOW); waveOutPrepareHeader(hWaveOut, @whOut, SizeOf(TWaveHdr)); waveOutWrite(hWaveOut, @whOut, SizeOf(TWaveHdr)); end; procedure TForm1.WndProc(var m: TMessage); var ordLen: Integer; begin inherited; case m.Msg of {处理录音消息} MM_WIM_OPEN: ; {此消息只携带了设备句柄} MM_WIM_CLOSE: ; {此消息只携带了设备句柄} MM_WIM_DATA: begin {此消息携带了设备句柄和 WaveHdr 指针(LParam)} {保存录制的数据} ordLen := Length(SaveBuf); SetLength(SaveBuf, ordLen + PWaveHdr(m.LParam).dwBytesRecorded); CopyMemory(Ptr(DWORD(SaveBuf)+ordLen), PWaveHdr(m.LParam).lpData, PWaveHdr(m.LParam).dwBytesRecorded); {继续录制} waveInAddBuffer(hWaveIn, PWaveHdr(m.LParam), SizeOf(TWaveHdr)); end; {处理播放消息} MM_WOM_OPEN: ; {此消息只携带了设备句柄} MM_WOM_CLOSE: ; {此消息只携带了设备句柄} MM_WOM_DONE: begin {此消息携带了设备句柄和 WaveHdr 指针(LParam)} waveOutUnprepareHeader(hWaveOut, PWaveHdr(m.LParam), SizeOf(TWaveHdr)); waveOutClose(hWaveOut); end; end; end; end.
使用回调函数处理音频设备发出的消息:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} uses MMSystem; var whIn1,whIn2, whOut: TWaveHdr; hWaveIn,hWaveOut: HWAVE; fmt: TWaveFormatEx; buf1,buf2,SaveBuf: TBytes; //回调函数; 容易出错的是: 系统回调函数中不能使用本地变量 procedure WaveProc(hWave: HWAVE; uMsg, dwInstance, dwParam1, dwParam2: DWORD); stdcall; var ordLen: Integer; begin case uMsg of {处理录音消息} MM_WIM_OPEN: ; {此消息只携带了设备句柄} MM_WIM_CLOSE: ; {此消息只携带了设备句柄} MM_WIM_DATA: begin {此消息携带了设备句柄和 WaveHdr 指针(dwParam1)} {保存录制的数据} ordLen := Length(SaveBuf); SetLength(SaveBuf, ordLen + PWaveHdr(dwParam1).dwBytesRecorded); CopyMemory(Ptr(DWORD(SaveBuf)+ordLen), PWaveHdr(dwParam1).lpData, PWaveHdr(dwParam1).dwBytesRecorded); {继续录制} waveInAddBuffer(hWave, PWaveHdr(dwParam1), SizeOf(TWaveHdr)); end; {处理播放消息} MM_WOM_OPEN: ; {此消息只携带了设备句柄} MM_WOM_CLOSE: ; {此消息只携带了设备句柄} MM_WOM_DONE: begin {此消息携带了设备句柄和 WaveHdr 指针(dwParam1)} waveOutUnprepareHeader(hWave, PWaveHdr(dwParam1), SizeOf(TWaveHdr)); waveOutClose(hWave); end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin Button1.Caption := '开始录音'; Button2.Caption := '停止录音'; Button3.Caption := '播放录音'; end; //开始录音 procedure TForm1.Button1Click(Sender: TObject); begin {指定要录制的格式} fmt.wFormatTag := WAVE_FORMAT_PCM; fmt.nChannels := 2; fmt.nSamplesPerSec := 22050; fmt.nAvgBytesPerSec := 88200; fmt.nBlockAlign := 4; fmt.wBitsPerSample := 16; fmt.cbSize := 0; SaveBuf := nil; {清除已录制的内容} if waveInOpen(@hWaveIn, WAVE_MAPPER, @fmt, DWORD(@WaveProc), 0, CALLBACK_FUNCTION) = 0 then begin SetLength(buf1, 1024*8); SetLength(buf2, 1024*8); whIn1.lpData := PAnsiChar(buf1); whIn1.dwBufferLength := Length(buf1); whIn1.dwBytesRecorded := 0; whIn1.dwUser := 0; whIn1.dwFlags := 0; whIn1.dwLoops := 0; whIn1.lpNext := nil; whIn1.reserved := 0; whIn2.lpData := PAnsiChar(buf2); whIn2.dwBufferLength := Length(buf2); whIn2.dwBytesRecorded := 0; whIn2.dwUser := 0; whIn2.dwFlags := 0; whIn2.dwLoops := 0; whIn2.lpNext := nil; whIn2.reserved := 0; waveInPrepareHeader(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInPrepareHeader(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInAddBuffer(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInAddBuffer(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInStart(hWaveIn); end; end; //停止录音 procedure TForm1.Button2Click(Sender: TObject); begin waveInStop(hWaveIn); waveInUnprepareHeader(hWaveIn, @whIn1, SizeOf(TWaveHdr)); waveInUnprepareHeader(hWaveIn, @whIn2, SizeOf(TWaveHdr)); waveInClose(hWaveIn); end; //播放录音 procedure TForm1.Button3Click(Sender: TObject); begin whOut.lpData := PAnsiChar(SaveBuf); whOut.dwBufferLength := Length(SaveBuf); whOut.dwBytesRecorded := 0; whOut.dwUser := 0; whOut.dwFlags := 0; whOut.dwLoops := 1; whOut.lpNext := nil; whOut.reserved := 0; waveOutOpen(@hWaveOut, WAVE_MAPPER, @fmt, DWORD(@WaveProc), 0, CALLBACK_FUNCTION); waveOutPrepareHeader(hWaveOut, @whOut, SizeOf(TWaveHdr)); waveOutWrite(hWaveOut, @whOut, SizeOf(TWaveHdr)); end; end.
欢迎沟通及共同进步
QQ:1441299
Email:1441299@qq.com
越折腾越快乐!
分类:
vb
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端