Excel/Calc VBA: サウンドデータの再生
2021/11/20
サウンドを使いたいときがある
  • VBAで何かしらの操作環境を提供しているとサウンド/効果音を使いたくなる時があります。例えば処理を待っている間や、ある操作を実施したという印象付けを目的とする効果音等です。

  • しかし、Excel自身には音楽データを扱う機能が無いので、OSの機能...WindowsのAPI(Application Programming Interface)を使用します。言い換えると、今回のVBAはWindows上でのみ動作します。

API:mciSendString使用宣言
  • 音楽データの処理にはAPIとしてmciSendStringを使用します。APIを使用する場合、VBA記述モジュール内で対象API使用を宣言します。宣言の書き方は下記になりますが、ExcelとCalcで異なります(*1)。まずはExcelでの記述です。
    Option Explicit
    Option Base 1
    
    '======================================================================
    '使用Windowsのbit数で有効ステートメント変わる
    'API使用宣言: mciSendString (Excel)
    #If Win64 Then
      Private Declare PtrSafe Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _
       (ByVal lpstrCommand As String, _
        ByVal lpstrReturnString As String, _
        ByVal uReturnLength As Long, _
        ByVal hwndCallback As Long) _
      As Long
    #Else
      Private Declare Function mciSendString Lib "winmm" Alias "mciSendStringA" _
        (ByVal lpstrCommand As String, _
         ByVal lpstrReturnString As String, _
         ByVal uReturnLength As Long, _
         ByVal hwndCallback As Long) _
      As Long
    #End If

  • 次はCalcでの記述です。使用Windowsのbit数に関わらず下記となります。
    Option Explicit
    Option Base 1
    Option VBASupport 1
    
    '======================================================================
    'API使用宣言: mciSendString (Calc)
    Private Declare Function mciSendString Lib "winmm" Alias "mciSendStringA" _
      (ByVal lpstrCommand As String, _
       ByVal lpstrReturnString As String, _
       ByVal uReturnLength As Long, _
       ByVal hwndCallback As Long) _
    As Long

  • これでmciSendStringが使用可能になりました。それでは実際に音楽データを操作してみましょう。

音楽データの再生と停止
  • 音楽データの操作は非常にシンプル(*2)です。下記のように使います。strSoundFileには、音楽データファイルのフルパス名が入っていると思って下さい。音楽ファイル名にplay等のコマンドを文字列で追加して第1引数に与えます。
    '============================================================
    'strSoundFileには、音楽データファイルのフルパス名が入ります
    '============================================================
    '再生
      Call mciSendString("play " & strSoundFile, "", 0, 0)
    'リピート再生
      Call mciSendString("play " & strSoundFile & " repeat", "", 0, 0)
    '停止
      Call mciSendString("stop " & strSoundFile, "", 0, 0)
    '一時停止
      Call mciSendString("pause " & strSoundFile, "", 0, 0)
    '一時停止解除
      Call mciSendString("resume " & strSoundFile, "", 0, 0)

  • 再生できる音楽データはwavとmp3です。ファイルサイズからmp3を使う機会が多そうです。ちなみに第2,第3引数は戻り値を受け取る変数と、そのサイズを書きます。単に再生/停止といった操作だと使用しません。

ファイルパスに空白がある時: きちんとopenそしてclose
  • しかしですね...、サウンドファイルの置かれた場所やファイル名に「空白」が含まれる場合、先に示した方法では操作ができません。対応方法ですが下記の「全て」が必要です。
    • ファイルパス名をダブルクォーテーション(")で囲む
    • 再生前にopenする
    • 停止後はcloseする

  • 例えばサウンドファイルのフルパスが下記のように「空白」を持つ場合です(2021 と 1120 の間)。    C:\sounds\dir2021 1120\bgm_sound.mp3

  • この文字列をダブルクォーテーションで囲みます。そして、再生(play)前に必ずopenします。下記のコードを見るとopenしなくてもplayできそうに見えますが、やってみるとplayできません。わかりにくい...。
    Dim strSoundFile As String
    strSoundFile = "C:\sounds\dir2021 1120\bgm_sound.mp3"
    
    '再生前にopenする。その際ダブルクォーテーションで囲む
    'ダブルクォーテーションが4つなのは、エスケープの「"」と本物の「"」を文字列として「"」で囲んでいるから
      Call mciSendString("open " & """" & strSoundFile & """", "", 0, 0)
    
    'ファイルの置き場所表現にはaliasも使えるが、わかりやすさのために直書き
    'open後再生(play)する
      Call mciSendString("play " & """" & strSoundFile & """", "", 0, 0)

  • そして次は停止ですが、停止後に必ずcloseします。closeしないと再度open/playができません。これもわかりにくい...。
    Dim strSoundFile As String
    strSoundFile = "C:\sounds\dir2021 1120\bgm_sound.mp3"
    
    'stopする。
      Call mciSendString("stop " & """" & strSoundFile & """", "", 0, 0)
    
    'stop後closeする
      Call mciSendString("close " & """" & strSoundFile & """", "", 0, 0)

ファイルパスに空白がある時: いつstop & close ... もう、いいかな
  • サウンドを扱うAPIのmciSendStringですが非同期実行です。したがって短い曲を再生する場合でも、その曲の再生時間分を待ってからstop & closeする必要があります。

  • サウンドの再生時間はstatusコマンドで取得できますが、その待ち時間の間ExcelをずっとWaitさせるわけにもいかず、Application.OnTimeを使ったりするわけですが、ここまで来ると労力と効果のバランスがかなり悪く(*3)なります。

  • もうテンポラリ領域にサウンドファイルをコピーして、パス名の制約を取り払う方がシンプルだと思い始めています。Bookオープン時とファイル決定時にテンポラリファイル名決めつつコピーするのです。

  • う〜ん。またテンポラリファイルを使うという結論になってしまいました。前回もそうだったので2回連続です。まだ私はVBA初心者なんだな...。まぁ、これからも頑張って覚えていきます。良い手が見つかったら追記しようと思います。

  • あと、mciSendStringを使用したVBAサンプルはこちら(sample_2021_0110.zip)になります。
Notes
  • Calcが受け付ける宣言記述は32bitタイプのようです。
  • 音楽データファイルのパスに「空白が無ければ」という前提条件付きです。
  • 何でこんなことしてるんだっけ...と目的を忘れそうになる。
Copyright(C) 2021 Altmo
本HPについて