トップへ(mam-mam.net/)

Record Microphone Audio in Delphi and Save as a WAV File

Japanese

Record Microphone Audio in Delphi and Save as a WAV File

This article shows how to create a Delphi application that records microphone audio and saves it as a .wav file.
Audio is captured from the microphone using "waveInAddBuffer", and the recorded data is written to a .wav file using TFileStream.

Create a New Project

Start Delphi, then choose "File" => "New" => "Windows VCL Application – Delphi (W)" from the menu.
Drag and drop two TComboBox components and two TButton components onto the form.

Enter the Source Code

Press the "F12" key to switch to the code editor, then copy and paste the following source code.
Press "F12" again to return to the design view,
set "FormCreate" for Form1’s OnCreate event and "FormClose" for the OnClose event.
Set "Button1Click" for the OnClick event of Button1, and “Button2Click” for the OnClick event of Button2.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, MMSystem, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    ComboBox1: TComboBox;
    ComboBox2: TComboBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    WaveFmt:TWaveFormatEx;
    //Sampling buffers
    BufIn:array of TBytes;
    WaveInHandle:HWAVEIN;
    NowBufId:Integer;
    WaveHeader:array of TWaveHdr;
    //Wave data buffer
    WaveBuf:TBytes;

    BufInLen:Integer;
    SaveCount:Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
const
  //Number of sampling buffers
  BufInNum:Integer=8;


implementation

{$R *.dfm}

//Callback function
procedure WaveInCallBackFunc(hW:HWAVEOUT;uMsg:Cardinal;
  dwInstance,dwParam1,dwParam2:UINT_PTR);stdcall;
var OldBufId, n:Integer;
begin
  if uMsg=MM_WIM_DATA then
  begin
    OldBufId := Form1.NowBufId;
    inc(Form1.NowBufId);
    Form1.NowBufId := Form1.NowBufId mod BufInNum;
    waveInAddBuffer(
      Form1.WaveInHandle,
      @Form1.WaveHeader[Form1.NowBufId],
      SizeOf(TWaveHdr)
    );
    n := Length(Form1.WaveBuf);
    SetLength(Form1.WaveBuf, n + Form1.BufInLen);
    Move(Form1.BufIn[OldBufId][0], Form1.WaveBuf[n], Form1.BufInLen);
  end;
end;

procedure SaveWaveFile(filename:string);
var ChunkID:array[0..3] of AnsiChar;
    FileStream:TFileStream;
    Size:Cardinal;
begin
  FileStream := TFileStream.Create(Filename, fmCreate);
  try
    // 'RIFF' chunk
    ChunkID := 'RIFF';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));
    Size := 4 + (8 + SizeOf(Form1.WaveFmt)) + (8 + Length(Form1.WaveBuf));
    FileStream.WriteBuffer(Size, SizeOf(Size));

    // 'WAVE' format
    ChunkID := 'WAVE';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));

    // 'fmt ' chunk
    ChunkID := 'fmt ';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));
    Size := SizeOf(Form1.WaveFmt);
    FileStream.WriteBuffer(Size, SizeOf(Size));
    FileStream.WriteBuffer(Form1.WaveFmt, size);

    // 'data' chunk
    ChunkID := 'data';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));
    Size := Length(Form1.WaveBuf);
    FileStream.WriteBuffer(Size, SizeOf(Size));
    FileStream.WriteBuffer(Form1.WaveBuf[0], Size);
  finally
    FileStream.Free;
  end;
end;


//Start recording
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
begin
  ComboBox1.Enabled:=False;
  ComboBox2.Enabled:=False;
  Button1.Enabled:=False;
  Button2.Enabled:=True;
  SetLength(WaveBuf, 0);

  ZeroMemory(@WaveFmt,SizeOf(TWaveFormatEx));
  WaveFmt.wFormatTag:=WAVE_FORMAT_PCM;
  //Number of channels (mono or stereo)
  WaveFmt.nChannels := ComboBox1.ItemIndex + 1;
  //Sampling rate: 11025 / 22050 / 44100 / 48000
  //Supported values depend on the hardware
  if ComboBox2.ItemIndex=0 then
    WaveFmt.nSamplesPerSec := 11025
  else if ComboBox2.ItemIndex=1 then
    WaveFmt.nSamplesPerSec := 22050
  else if ComboBox2.ItemIndex=2 then
    WaveFmt.nSamplesPerSec := 44100
  else
    WaveFmt.nSamplesPerSec := 48000;

  //Bits per sample (signed 16‑bit integer: −32768 to 32767)
  WaveFmt.wBitsPerSample := 16;
  //Bytes per block
  WaveFmt.nBlockAlign := WaveFmt.nChannels * WaveFmt.wBitsPerSample div 8;
  //Average bytes per second
  WaveFmt.nAvgBytesPerSec := WaveFmt.nBlockAlign * WaveFmt.nSamplesPerSec;
  //Must be 0
  WaveFmt.cbSize := 0;

  waveInOpen(
    @WaveInHandle, WAVE_MAPPER, @WaveFmt, DWORD_PTR(@WaveInCallBackFunc),
    0, CALLBACK_FUNCTION+WAVE_ALLOWSYNC
  );

  BufInLen := WaveFmt.nSamplesPerSec * WaveFmt.nChannels;

  SetLength(WaveHeader, BufInNum);
  SetLength(BufIn, BufInNum);
  for i := 0 to BufInNum-1 do
  begin
    //Set buffer size
    SetLength(BufIn[i], BufInLen);
    //Configure buffer
    WaveHeader[i].lpData := PAnsiChar(BufIn[i]);
    WaveHeader[i].dwBufferLength := BufInLen;
    WaveHeader[i].dwBytesRecorded := 0;
    WaveHeader[i].dwUser := i;
    WaveHeader[i].dwFlags := 0;
    WaveHeader[i].dwLoops := 0;
    WaveHeader[i].lpNext := nil;
    WaveHeader[i].reserved := 0;
    waveInPrepareHeader(WaveInHandle, @WaveHeader[i], SizeOf(TWaveHdr));
  end;
  NowBufId := 0;
  waveInAddBuffer(WaveInHandle, @WaveHeader[NowBufId], SizeOf(TWaveHdr));
  waveInStart(WaveInHandle);
end;


//Stop recording
procedure TForm1.Button2Click(Sender: TObject);
var i:Integer;
begin
  ComboBox1.Enabled := True;
  ComboBox2.Enabled := True;
  Button1.Enabled := True;
  Button2.Enabled := False;

  waveInStop(WaveInHandle);
  for i := 0 to BufInNum-1 do
    waveInUnprepareHeader(WaveInHandle, @WaveHeader[i], SizeOf(TWaveHdr));
  waveInClose(WaveInHandle);

  SaveWaveFile('sample'+SaveCount.ToString+'.wav');

  Inc(SaveCount);
end;


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
  //Stop recording if still active
  if Button2.Enabled then Button2Click(Button2);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  BufInLen := 11025;
  SaveCount := 1;
  ComboBox1.Style:=csDropDownList;
  ComboBox1.Items.Add('Mono');
  ComboBox1.Items.Add('Stereo');
  ComboBox1.ItemIndex := 0;
  ComboBox2.Style:=csDropDownList;
  ComboBox2.Items.Add('11025');
  ComboBox2.Items.Add('22050');
  ComboBox2.Items.Add('44100');
  ComboBox2.Items.Add('48000');
  ComboBox2.ItemIndex := 0;
  Button2.Enabled := False;
end;

end.

Running the Application

Connect a built‑in or external microphone to your PC.
Run the application and click Button1 to start recording.
Click Button2 to stop recording. The audio will be saved as a file named “sample***.wav”.
The *** part will be replaced with an incrementing number.