録音もできます
ここでは、TDDSDCaptureの使い方をご説明します。
マイクなどの音声入力機器からの音声の波形を、リアルタイムで画面に表示するプログラムを、ここでは作成しましょう。音声に合わせてラインが「みよみよ〜」と踊るのは、案外見てて気持ちのいいものです(^^;)
まずはいつもどおり、Delphi IDEから、「ファイル−アプリケーションの新規作成」を選び、空のプロジェクトを作成しましょう。
そうしたら、DDSDコンポーネントと、ApplicationEventsコンポーネントを貼り付けましょう。ここでは、DDSDコンポーネントの名前は、DDSD1として、ApplicationEventsコンポーネントはApplicationEvents1として貼り付けましたので、以下、それにしたがって解説を続けます。
さらに、フォームのサイズを600x300にし、DDDDコンポーネントの設定も、それに合わせてInitialScreenWidth = 600, InitialScreenHeight = 300 という事にします。
以上を行うと、こんな感じになるでしょう。

次に、一度に表示するサンプル(波形を構成するデータ)の数を決めておきますか。 ここでは、画面の横幅と同じ、600サンプルという事にしましょう。
とりあえずは、このサンプル数を定数として宣言しましょう。
場所は関数や手続きの外側なら何処でもいいのですが、とりあえず、Formの宣言の終わった下、var文のさらに真下に書き入れました。
var Form1: TForm1; const NUM_SAMPLE = 600; //600サンプルを一度に表示
録音に使う、TDDSDCaptureオブジェクトと、波形を描画するためのTBitmapオブジェクトを用意し、使えるようにしときます。
フォームのCanvasに直接グラフを描くと、チラついて見づらいグラフになるので、TBitmapに一旦描きこんで、グラフが全部出来たらフォームに転送するようにするわけです。
type
TForm1 = class(TForm)
DDSD1: TDDSD;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private 宣言 }
public
{ Public 宣言 }
Capture:TDDSDCapture;
OffBMP:TBitmap;
end;
まずは、こんな感じで、TDDSDCaptureオブジェクト変数を、フォームの定義に書き加えましょう。
そうしたら、今度はTForm.OnCreateイベントで初期化します。
procedure TForm1.FormCreate(Sender: TObject);
begin
Capture:=TDDSDCapture.Create(DDSD1);
OffBMP:=TBitmap.Create;
OffBMP.Width:=ClientWidth;
OffBMP.Height:=ClientHeight;
//サポートしてる録音フォーマットなのか、チェックしてから
if Capture.IsSupportedFormat(44100, 16, False) then begin
//16ビット・44.1KHz・モノラルで録音、バッファは一度に表示するぶんだけ
Capture.SetupCaptureBuffer(44100,16,False, NUM_SAMPLE * 2);
end else if Capture.IsSupportedFormat(22050, 16, False) then begin
//16ビット・22.05KHz・モノラルで妥協
Capture.SetupCaptureBuffer(22050,16,False, NUM_SAMPLE * 2);
end else begin
//悪態をついて終わる
MessageDlg('録音環境がヘボいです',mtWarning, [mbOK], 0);
Capture.Free;
Application.Terminate;
end;
end;
環境によって特定のサンプリングレートでの録音をサポートしていないことがあるので、一応チェックしておきましょう。そのための関数が、IsSupportedFormatメソッドです。このメソッドの返り値がTrueならば、そのフォーマットはサポートされているので、SetupCaptureBufferメソッドを呼んで、録音した結果を溜めておくバッファを確保させます。
今回は、意地でもビットレートは16です(^^;) 44.1KHzで録音できないなら、22.05KHzで妥協するという事にしています。
それから、終了時には録音を中止して、録音用オブジェクトを解放することにしましょう。
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Capture.Stop; Capture.Free; end;
では、録音を開始しましょう。
procedure TForm1.FormCreate(Sender: TObject);
begin
Capture:=TDDSDCapture.Create(DDSD1);
//サポートしてる録音フォーマットなのか、チェックしてから
if Capture.IsSupportedFormat(44100, 16, False) then begin
//16ビット・44.1KHz・モノラルで録音、バッファは一度に表示するぶんだけ
Capture.SetupCaptureBuffer(44100,16,False, NUM_SAMPLE * 2);
Capture.StartLoop;
end else if Capture.IsSupportedFormat(22050, 16, False) then begin
//16ビット・22.05KHz・モノラルで妥協
Capture.SetupCaptureBuffer(22050,16,False, NUM_SAMPLE * 2);
Capture.StartLoop;
end else begin
//悪態をついて終わる
MessageDlg('録音環境がヘボいです',mtWarning, [mbOK], 0);
Capture.Free;
OffBMP.Free;
Application.Terminate;
end;
end;
StartLoopメソッドで、録音を開始します。録音はバックグラウンドで常時行われる事になります。
今回は取り扱いませんが、一定の時間だけ録音して、録音する間だけ処理を止めたい、という場合には、Startメソッドを使います。
とりあえず、これでF9キーを押せば、録音している事にはなるのですが、ホントに録音しているのか、全く分かりませんね(^^;) まだ波形の表示ルーチンを作ってないからです。
波形はいつでも表示されていて、音声入力に合わせてどんどん書き換わって欲しいので、Application.OnIdleイベントを利用します。
そういうわけで、ApplicationEvents1.OnIdleイベントを書き換えます。
波形を表示させるような手続きという事にしましょう。
procedure TForm1.ApplicationEvents1Idle(Sender: TObject;
var Done: Boolean);
var
i:Integer;
Buf:Array[0..NUM_SAMPLE-1] of SmallInt;
Points:Array[0..NUM_SAMPLE-1] of TPoint;
begin
//波形の表示
with OffBmp.Canvas do begin
//キャンバスを塗りつぶす
Brush.Color:=clBlack;
Pen.Color:=clLime;
FillRect(Rect(0,0, 600,300));
Capture.BlockCopy(Capture.Position, @Buf[0], NUM_SAMPLE * 2); //Buf配列にコピー(1/10秒分)
//グラフを描く…150とかは、グラフを描く位置を調節するための値です。
For i:=0 to NUM_SAMPLE-1 do begin
Points[i]:= Point(i, 150 - (Buf[i] div 256));
end;
Polyline(Points);
end;
Canvas.CopyRect(ClientRect, OffBmp.Canvas, ClientRect);
//おかわり!
done:=False;
end;
グラフの描き方そのものはDelphiのTCanvasの説明を見ていただくとして、ここで重要なのは、水色の一行。 BlockCopyメソッドで、Buf配列変数に波形データを転送している部分だけです。
BlockCopyで波形データを頂いたら、後はその値を元にグラフを描くだけ、FFTすればスペクトラムアナライザとかができます。

で、DirectSoundCaptureを使用した、オシロスコープ(!?) が出来ました!
結構、面白い…でしょ?
これを利用して、音声入力をサポートするゲームやなんかが出来てしまうわけなんですね。言うのは簡単ですが、本格的にやるとなるとなかなか険しい道のりとなりそうです(^^;)