Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】音声ファイルを再生する方法

Delphiでゲームや趣味のアプリケーションを作成する場合はもちろん、
現場などで業務用のアプリケーションを作成する場合にも欠かせない技術の1つが、
「音声」を鳴らす方法だと思います。

古くからビープ音を鳴らす方法は存在しましたが、
コンポーネントを使ってwavなどの音声を読み込んで再生することも可能です。
今回はその手順を紹介します。

 


VCLでの実装方法

指定した音声や動画を再生するには

VCLでは、TMediaPlayerコンポーネントを使って音声や動画を再生することができます。

かなり古いバージョンから(筆者が知る限りV5~)存在するコンポーネントですが、
ほぼその頃のアーキテクチャのまま11 Alexandriaまで推移しています。
内部的には古いMCIコマンドのAPIを用いており、現在でも対応しているファイル形式は限られています。

詳細は割愛しますが、主に以下のファイル形式が対応しています。
音声・動画とも、エンコード方式によっては対応していない場合もあります。
警告音などの短い音声であれば、非圧縮のWAVEサウンド(*.wav)が適任でしょう。

音声:wav・wma・mp3(一部除く)
動画:mpg・avi・wmv(一部除く)

音声再生時には、TMediaPlayerコンポーネントを画面に配置(または内部生成)して、
それぞれ以下のように記述します。

なお、画面に配置したTMediaPlayerの各ボタンで再生や停止の操作が可能ですが
今回はロジックでの音声自動再生を想定しています。
(ロジックであれば、TMediaPlayerのVisibleをFalseに設定しても再生できます。)

  // wavまたはmp3のフルパスを指定して開く
  MediaPlayer1.Close;    // 閉じる(初期化)
  MediaPlayer1.FileName := '音声ファイルのフルパス.wav';
  MediaPlayer1.Open;     // ファイルを開く(エンコード等に問題がある場合ここでエラー)

  // (以下は音声ファイルがOpenされている必要あり)
  // 開いた音声を再生
  MediaPlayer1.Previous; // 頭出し
  MediaPlayer1.Play;     // 再生開始

  // 停止したい場合
  MediaPlayer1.Stop;     // 再生終了

 
再生完了時に繰り返させたい場合はTMediaPlayerのOnNotifyイベントを使用し、
その中で以下のように記述します。

// 再生完了時繰り返し
procedure TForm1.MediaPlayer1Notify(Sender: TObject);
begin
  // 再生位置が最終位置まで来たら頭出しして再び再生
  if (MediaPlayer1.Position >= MediaPlayer1.Length) then
  begin
    MediaPlayer1.Previous;
    MediaPlayer1.Play;
  end;
end;

 

ビープ音を鳴らすだけでよい場合は

なお、冒頭で紹介したビープ音(デフォルトの警告音)を鳴らすだけで良い場合は
以下のようにBeepまたはMessageBeepメソッドを使用します。

  // 通常のビープ音を鳴らす(Windows 一般の警告音)
  Beep;

  // エラーの警告音を鳴らす(Windows システムエラー)
  // (他の効果音と使い分けたい場合は、ここの引数を変更する)
  MessageBeep(MB_ICONERROR);

 


FireMonkeyでの実装方法

FireMonkeyでもTMediaPlayerというコンポーネントが存在します。
(VCLのTMediaPlayerと同名ですが全く別物で、互換性はありません。

VCLと比較するとアーキテクチャが新しく、
再生できるファイル形式も多くなっているのが特長です。

ここでは、それぞれのターゲット プラットフォームで
「2009.wav」という名前の音声ファイルを再生させる手順を紹介します。

 

Windows

Windowsで音声を再生する場合は、以下の手順で記述します。

  • VCLのTMediaPlayerと同様に、
    FileNameプロパティに再生するファイルのフルパスを指定します。
    VCLとは違って、FileNameを指定すると自動でオープンされます。
    (見つからない場合やフォーマット不正時はこのタイミングでエラー)
  • VCLに無かった機能として、必要に応じてVolumeプロパティで音量を設定できます。
    設定値は0~1の範囲の小数値で、0が消音、1が最大音量になります。
  • 頭出しはCurrentTimeプロパティを0に設定します。
    再生はVCLと同じPlayメソッドです。
    停止(一時停止)もVCLと同じStopメソッドです。
  if (MediaPlayer1.FileName = '') then
  begin
    // ファイルを読み込む(今回は「2009.wav」がEXEと同階層にある想定)
    MediaPlayer1.FileName  := ExtractFilePath(ParamStr(0)) + '2009.wav';
  end;
  MediaPlayer1.Volume      := 0.9; // 音量を0~1の範囲(小数可)で指定
  MediaPlayer1.CurrentTime := 0;   // 頭出し
  MediaPlayer1.Play;               // 再生開始

 
終了時に繰り返し再生を行いたい場合、VCLのような完了時のイベントが存在しないため、
Timer等で再生終了を検知して巻き戻し・再生する必要があります。
現在位置や全体の長さのプロパティ名もVCLとは異なります。

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  // 現在位置≧全体の長さ になった場合は巻き戻して再度再生
  if (MediaPlayer1.CurrentTime >= MediaPlayer1.Duration) then
  begin
    MediaPlayer1.CurrentTime := 0;   // 頭出し
    MediaPlayer1.Play;               // 再生開始
  end;
end;

 


Android・iOS

AndroidやiOSで音声を鳴らす場合は、アプリに埋め込んで配置する必要があります。
なおここで解説する埋め込みの手順は、音声だけでなく動画や画像でも同様となります。

AndroidやiOSではFileNameプロパティに設定して読み込ませるファイルのフルパスが
内部値となっており固定値を設定できないため、以下の手順が必要となります。
(読み込んだ後の再生の手順は、上記のWindowsと同様です。)
 

IDE(統合開発環境)のメニューから[プロジェクト|配置]を選択すると、
このような「配置 XXXX」という画面が表示されます。(XXXX部分はアプリ名)

この配置画面で、対象のプラットフォームを選択したあと、
左上の [+](追加)ボタンを押してファイルを追加します。

ファイルを追加すると、上図のように行が追加されます。
追加された行に、それぞれ以下のように設定します。

  • ローカル パス、ローカル名:
    今追加したファイルの開発環境側のパスとファイル名です。
    コンパイル~配置時のファイルコピー元となるため、
    開発端末側で移動や削除を行うと配置できなくなりますのでご注意ください。
  • 構成、プラットフォーム:
    配置先の構成やプラットフォームです。
    複数ある場合はそれぞれ行が作成されますので、それぞれ設定が必要です。
  • リモート パス:
    この設定値を初期値から変更する必要があります。
    【】内の値を先頭の「.」も含めて正確に設定して下さい。
    • Androidの場合:【.\assets\internal\】
    • iOSの場合:【.\StartUp\Documents\】
  • リモート名:
    ファイルを追加した際にはローカル名と同名が設定されています。
    動作時に別名のファイルとして扱いたい場合は変更します。
    (ローカル側でパスが異なる同名のファイルを複数追加した場合など)
     

上記の設定でアプリと一緒に配置した音声(または画像等)ファイルは、
端末内部のファイラーアプリでは参照できない場所に格納されます。

ここでSystem.IOUtilsユニット(uses節に無ければ追加)にある
TPathクラスを使って、Android・iOSそれぞれのパスを指定させることが可能です。
GetDocumentsPathメソッドでリモートパスを探し、
Combineメソッドでそのパスとファイル名(リモート名)を結合します。

例えば
TPath.Combine(TPath.GetDocumentsPath, ‘2009.wav’);
といった記述が可能です。

以下のサンプルロジックは、
iOS・Android・Windowsそれぞれで同じソースのイベントを利用する想定で
コンパイラ指令を使ってファイル指定方法を呼び分けるサンプルとなります。

{*****************************************************************************
 目的: 検証用 音を鳴らす
*****************************************************************************}
procedure TForm1.Button2Click(Sender: TObject);
const
  c2009 = '2009.wav';
var
  fPath: string; // フォルダを保管
begin
{$IFDEF IOS}
  // iOS向け処理
  fPath := System.IOUtils.TPath.GetDocumentsPath;
  MediaPlayer1.FileName    := System.IOUtils.TPath.Combine(fPath, c2009);

{$ELSE}
{$IFDEF Android}
  // Android向け処理(今回はiOSと同じ)
  fPath := System.IOUtils.TPath.GetDocumentsPath;
  MediaPlayer1.FileName    := System.IOUtils.TPath.Combine(fPath, c2009);

{$ELSE}
  // Windows向け処理(FileName指定だけでよい)
  if (MediaPlayer1.FileName = '') then
  begin
    MediaPlayer1.FileName  := ExtractFilePath(ParamStr(0)) + c2009;
  end;
{$ENDIF}
{$ENDIF}

  // ファイルを読み込んだ後は共通
  MediaPlayer1.Volume      := 0.9; // 音量を0~1の範囲(小数)で指定
  MediaPlayer1.CurrentTime := 0;   // 頭出し
  MediaPlayer1.Play;               // 再生開始
end;

 


<参考リンク> (Embarcadero Docwiki)