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

マイクの音を録音して.wavファイルに保存する ~Delphiソースコード集

マイクの音を録音して.wavファイルに保存する ~Delphiソースコード集

Delphiだけでマイクの音を録音して.wavファイルに保存するするアプリケーションを作成します。 「waveInAddBuffer」でマイクからの音をデータとして取得し、TFileStreamで.wavファイルに保存します。

プロジェクトを作成する

Delphiを起動し、メニューから「ファイル」⇒「新規作成」⇒「Windows VCLアプリケーション -Delphi(W)」 をクリックする。
TCombobox × 2個、TButton × 2個をフォームにドラッグ&ドロップします。

ソースコードの入力

キーボードの「F12」キーを押してソースコードエディタに切り替え、以下のソースコードをコピー&ペーストします。
キーボードの「F12」キーを押してデザインモードに切り替え、
Form1のOnCreateイベントに「FormCreate」を設定し、Form1のOnCloseに「FormClose」を設定します。
Button1のOnClickイベントに「Button1Click」を設定し、Button2のOnClickイベントに「Button2Click」を設定します。

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 宣言 }
    WaveFmt:TWaveFormatEx;
    //サンプリングバッファ
    BufIn:array of TBytes;
    WaveInHandle:HWAVEIN;
    NowBufId:Integer;
    WaveHeader:array of TWaveHdr;
    //Waveバッファ
    WaveBuf:TBytes;

    BufInLen:Integer;
    SaveCount:Integer;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
const
  //サンプリングバッファの数
  BufInNum:Integer=8;


implementation

{$R *.dfm}

//コールバック関数
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'チャンク
    ChunkID := 'RIFF';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));
    Size := 4 + (8 + SizeOf(Form1.WaveFmt)) + (8 + Length(Form1.WaveBuf));
    FileStream.WriteBuffer(Size, SizeOf(Size));

    // 'WAVE'フォーマット
    ChunkID := 'WAVE';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));

    // 'fmt 'チャンク
    ChunkID := 'fmt ';
    FileStream.WriteBuffer(ChunkID, SizeOf(ChunkID));
    Size := SizeOf(Form1.WaveFmt);
    FileStream.WriteBuffer(Size, SizeOf(Size));
    FileStream.WriteBuffer(Form1.WaveFmt, size);

    // 'data'チャンク
    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;


//録音開始
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;
  //1チャンネル(モノラル or ステレオ)
  WaveFmt.nChannels := ComboBox1.ItemIndex + 1;
  //サンプリング周波数 8000 11025 22050 44100 48000
  //対応しているかどうかはハードウェアによる
  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;

  //1サンプル当たりのビット数を指定(符号付き16Bit整数 -32768~32767の範囲)
  WaveFmt.wBitsPerSample := 16;
  //1ブロックのバイト数
  WaveFmt.nBlockAlign := WaveFmt.nChannels * WaveFmt.wBitsPerSample div 8;
  //1秒当たりの平均バイト数
  WaveFmt.nAvgBytesPerSec := WaveFmt.nBlockAlign * WaveFmt.nSamplesPerSec;
  //必ず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
    //バッファサイズの設定
    SetLength(BufIn[i], BufInLen);
    //バッファの設定
    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;


//録音停止
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;
  //録音中なら停止させる
  if Button2.Enabled then Button2Click(Button2);
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  BufInLen := 11025;
  SaveCount := 1;
  ComboBox1.Style:=csDropDownList;
  ComboBox1.Items.Add('モノラル');
  ComboBox1.Items.Add('ステレオ');
  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.

実行

内臓又は外付けマイクをパソコンに接続してください。
実行してButton1をクリックすると録音を開始します。
Button2をクリックすると録音を終了してファイル名「sample***.wav」ファイルに保存されます。
***の箇所は連番の数字が入ります。