文档章节

操作 Wave 文件(11): 使用 waveIn...函数录制 wav 文件

涂孟超
 涂孟超
发布于 2014/09/26 15:30
字数 993
阅读 36
收藏 0

使用窗口接受音频设备发出的消息:

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.

 
 
 
 
 

 

 

  

本文转载自:http://www.cnblogs.com/del/archive/2009/11/11/1601006.html

涂孟超
粉丝 12
博文 2011
码字总数 14107
作品 0
深圳
程序员
私信 提问
pcm 转化为wav 文件

pcm是纯粹的音频数据文件,缺少对录制音频时的参数的描述,主要参数包括 通道数量 采样率,每秒采样多少次 每个采样的占用多少字节 wav是加上头和pcm 数据,构成一个可以播放的格式 wav头:参...

李勇2
2016/08/25
178
0
进阶音效控制与管理(转载)

摘要 以 XNA 为基础的游戏程序可以利用 SoundEffect 类别的功能执行简单的音效播放,或是利用 SoundEffectInstance 类别进行进阶的音效播放控制,包括播放、暂停、恢复、结束、是否要播放 3D...

junwong
2012/02/17
506
0
【wav音频解析】之wavread函数的C++实现

本文由三部分组成,第一部分背景介绍 —— 音频类型及本文动机,第二部分类比matlab下wavread()函数的作用,第三部分则给出该函数的C++实现。 一 背景介绍 1.1 本文动机 1)所有wav音频处理的...

刘小米
2014/09/29
12.8K
8
使用Festivox创建Festival英语语音库

所用版本:EST 2.1, Festival 2.1, Festvox2.4(该版本兼容Festival2.1,官方发布的Festvox2.1版本可能存在兼容问题) The process is fairly long, recording and labelling take a few hour......

Cherrot
2011/08/16
555
0
Windows上的音频采集技术(转)

转自:http://shanewfx.github.io/blog/2013/08/14/caprure-audio-on-windows/前一段时间接到一个任务,需要采集到声卡的输出信号,以便与麦克风的输入信号进行混音。 之前一直没有研究过音频...

元谷
2013/12/05
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

IT兄弟连 HTML5教程 HTML5表单 小结及习题

小结 HTML表单提交的方法有get方法和post方法,get方法的作用是从指定的资源请求数据,post方法的作用是向指定的资源提交要被处理的数据。HTML表单一直都是Web的核心技术之一,有了它我们才能...

老码农的一亩三分地
23分钟前
13
0
向maven工程中导入自己封装好的jar包方法

1.打开cmd窗口 输入并执行:mvn install:install-file -DgroupId=com.test   -DartifactId=ptest -Dversion=0.1  -Dfile=E:\test\test-0.1.0.jar    -Dpackaging=jar注:Dgr......

gantaos
25分钟前
3
0
【jQuery基础学习】09 jQuery与前端(这章很水)

本文转载于:专业的前端网站➨【jQuery基础学习】09 jQuery与前端(这章很水) 这章主要是将如何将jQuery应用到网站中,或者说其实就是一些前端知识,对于我这种后端程序来说其实还是蛮有用的...

前端老手
37分钟前
11
0
深度科技与金山云完成兼容互认证 共同促进我国软件生态发展

近日,深度科技与金山云完成兼容互认证工作,经双方共同严格测试,深度操作系统ARM服务器版软件V15与金山云分布式数据库软件DragonBase V1.0相互兼容、稳定运行,可以为企业级应用提供全面保...

后浪涛涛
38分钟前
7
0
Less导入选项

Less 提供了CSS @import CSS规则的几个扩展,以提供更多的灵活性来处理外部文件。 语法: @import (keyword) "filename"; 以下是导入指令的相关详情: reference,使用较少的文件但不输出。 ...

凌兮洛
54分钟前
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部