PR
古庄 潤(ふるしょう じゅん)

本業はエンジニア。ICに様々な機械をつなぎ,電流やら電圧を測定する。もちろん,これらの測定器もVBAでコントロールし,取り込んだデータもマクロで処理する。人呼んで,マクロの鬼軍曹!

診断(7)
音で知らせる

「うるうる(泣)」
「先生,どうしたんですか?」
「この時期にしてはわりとでかい黒鯛が釣れたから,タバコ屋のミーちゃんに持っていったんじゃ」
「喜んだでしょう?」
「それが,いらないって」
「まあ」
「理由がわからん」
「その気もないのに,これ以上はマズイと思ったんでしょうねぇ,きっと…」
「え,どういう意味じゃ?」
「あ,えーと,次の方ど~ぞ~」

今月の相談
「実行時間が長い全自動のマクロは,動いているのか,止まっているのかがよくわかりません。以前に実行中のメッセージを表示する手法がありましたが,他にもっとアピールする方法はないでしょうか?」

「具体的症例に対処するのはそう難しくないんじゃが,『何かありませんか?』とアイデアを求められるとな…」
「グリコですか?」
「そうじゃ,お手上げ!って,おい,古いなぁ」
「大きなお世話です。で,どうなんですか?」
「うむ,人の感覚は五感。触覚,聴覚,嗅覚,味覚,そして視覚じゃ。人間が反応するのは,この五つの刺激ということじゃな。この中でPCにあるものは?」
「そんなものあるわけないじゃないですか! PCは機械なんですから」
「そういう意味ではない。PCが刺激できる感覚は何かということだ」
「なるほど,そういう意味なら,まずは視覚。絵や文字でいろいろな刺激,つまり情報を提供できます。ほかには…,匂いは出せないし,PCが人に触ることもできない」
「うむ,匂いについては研究している人もいるがまだ現実的ではないし,触覚については視覚障害者用の点字ディスプレイなどがあるが,これも一般的ではないから,今回は使えない」
「味覚も無理ですから,残るは聴覚。そうか! 音ですね」
「その通り。PCの持つ刺激は,映像と音じゃ」
「そりゃまぁ,ゲームに効果音はつきものですし,動画には当然音がありますが,Excelにそんなことができるんですか?」
「手始めに,メッセージボックス」
「メッセージボックス?」
「そうじゃ,メッセージボックスでちょいと肩慣らしをしよう」

 VBAのメッセージボックスは,表示されると同時に「ポン」と音がします。これがノーマルの音。しかし,下記のように,buttonオプションに異なる組み込み定数を指定すると,違う音が出ます。これらの組み込み定数は,本来,メッセージボックスにアイコンを表示するための定数ですが,同時に音も変わるのです。


Sub OTO_1()
  MsgBox "vbInformationの音", vbInformation
End Sub

Sub OTO_2()
  MsgBox "vbCriticalの音", vbCritical
End Sub

Sub OTO_3()
  MsgBox "vbExclamationの音", vbExclamation
End Sub
リスト1●メッセージボックスのbuttonオプションを変更すると,音も変わる

「なるほど! これは盲点。でも,先生,あまりインパクトがありませんね」
「肩慣らしと言ったじゃろ。次は,いよいよ伝家の宝刀を抜くぞ」
「殿下の包丁?」
「『殿下の包丁』ではない,『伝家の宝刀』じゃ。まぁ,そんなことはどうでもよい。ゲール君は,Win32 APIを知っておるかな?」
「お噂はかねがね」
「人ではない。Windowsの核とも言える関数群のことじゃ」
「『さわるな危険』と注意書きされてるやつですね?」
「高圧線みたいに言うんじゃない。しかし,使い方を間違えると,とんでもないことになることは確かじゃ」
「それを使うんですか?」
「うむ,解説書はプロ向けのものが多く,引数も構造体だったりするから,一般のExcelユーザーには敬遠されがちじゃが,きちんと使えば便利な関数じゃ。とはいえ,ここでAPIの解説はできんから,これをパッケージ化したVBA関数を紹介しよう」
「関数の関数?」
「そう,要するに,音声ファイル(WAVファイル)を引数として渡したら,それを再生する関数を作るということじゃ。もちろん,基になっているAPIの引数も説明するから,アレンジして使うもよし,そのまま便利な関数として使うもよし。使い方は,自由じゃ」

 では,まずはAPIの宣言から。これは,Win32 APIであるsndPlaySound関数をVBAで使えるようにするためのステートメントです。このステートメントは標準モジュールの宣言セクションに記述してください。

Declare Function sndPlaySound Lib "WINMM.DLL" Alias "sndPlaySoundA" _
  (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long
リスト2●API(sndPlaySound関数)の宣言

 次に,定数です。これらの定数は,sndPlaySound関数の第2引数に使用します。sndPlaySound関数の第2引数は,直接数値(長整数型)を指定しても構いませんが,その意味がわかりやすいように,内容が想像できる名前の定数を宣言して引数に指定する手法が一般的です。その意味は表1にまとめました。これも,標準モジュールの宣言セクションに記述してください。


Public Const SND_SYNC = &H0
Public Const SND_ASYNC = &H1
Public Const SND_NODEFAULT = &H2
Public Const SND_LOOP = &H8
Public Const SND_NOSTOP = &H10
リスト3●定数の宣言

表1●sndPlaySound関数の第2引数に指定する定数の意味
定数名 意味
SND_SYNC &H0 再生が終了するまで制御を返さない(デフォルト)
SND_ASYNC &H1 再生した直後に制御を返す(鳴らしながら次の処理ができる)
SND_NODEFAULT &H2 再生できないときに警告音を鳴らさない
SND_MEMORY &H4 メモリー上のデータを再生する
SND_LOOP &H8 次のsndPlaySound呼び出しまでループ演奏する
SND_NOSTOP &H10 他のsndPlaySoundが鳴っている場合はそれを止めない

 そして,リスト3がsndPlaySound関数をパッケージ化した関数mySOUNDです。


Function mySOUND(SoundName As String)
  Dim wFlags As Long

  wFlags = SND_ASYNC Or SND_NODEFAULT        '<-------(1)
  mySOUND = sndPlaySound(SoundName, wFlags)  '<-------(2)
End Function
リスト3●WAVファイルを再生するmySOUND関数

 (1)では,sndPlaySound関数の第2引数に渡す値を計算しています。それぞれの定数は16進数の数値で定義されていて,2進数にすると,どれか一つのビットだけが1になっています。したがって,定数同士をOr演算子で計算すると,それぞれのオプションに対応したビットが1になります。

 例えば,「SND_ASYNC Or SND_NODEFAULT」は「0001 Or 0010」となるので,計算結果は「0011」となります(16進数では「&H3」,10進数では「3」)。この引数を受け取るsndPlaySound関数はビットで理解します。LSB(最下位ビット)とその次のビットが立っている(1になっている)ので,「再生した直後に制御を返す & 再生できないときに警告音を鳴らさない」の二つのオプションをイネーブル(有効化)して,WAVファイルを再生します。

 (2)でsndPlaySound関数を呼び出します。第1引数に,呼び出し時に受け取ったSoundName,第2引数に(1)のステートメントで計算した結果を格納した変数wFlagsを渡します。sndPlaySound関数は,実行した結果を返すので,その結果を変数mySOUNDに代入します。では,早速使ってみましょう(リスト4)。


Sub Syori_2()
  Dim myRESULT As Long

  myRESULT = mySOUND("E:\WINDOWS\Media\test.wav")  '<-------(1)
End Sub
リスト4●mySOUND関数の使用例

 (1)では,再生するファイル名を第1引数にしてmySOUND関数を呼び出し,その実行結果を変数myRESULTに代入します。このプロシジャを実行すると「test.wav」が再生されます。