Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Excel 2013)
Windows Media Playeに関して
投稿日時: 20/03/19 13:59:19
投稿者: 黄金山

お世話になります。
以下のように、ユーザーフォームに Media Playerコントールを埋め込み音楽を楽しんでいます。
しかし、このモジュールでは、再生終了後もフオームは開かれたままです。
 
やりたい事
  音楽が終了したら、フォームを閉じて、次のステップへ進みたい。
そのために、終了したかどうか(イべントの取得?)を確認したい。
注記)再生時、途中をスキップして再生したりするので、再生時間とその曲の所要時間とは、
必ずしも一致しません。
 
ネット上を、色々探してみましたが、答えにはたどり着けませんでした。
宜しくお願いします。
 
Private Sub UserForm_Activate()
    Dim Mypath As String, Sound As String
    Mypath = Worksheets("DB").Range("D3").Value
    Sound = Cells(ActiveCell.Row, 2).Value2
    If Sound = "" Then
        Unload uf1
        Exit Sub
    End If
    Me.wmp.URL = Mypath & Sound
End Sub

回答
投稿日時: 20/03/20 18:29:26
投稿者: mattuwan44

そのユーザーフォームは、どういうきっかけで、開くのですか?
 
勝手に閉じる仕様が使いやすいとは思えないのですが、
勝手に閉じたら次はないのですか?

投稿日時: 20/03/21 14:04:55
投稿者: 黄金山

WinArrowさん
お世話になります。返事が遅なリもし分けありません。
再生が終了しても、WinArrowさんの情報により、イベントは発生しないことは、分りました。
ありがとうございました。
 
mattuwan44さん
このモジュールは、セルの選択をトリガーとして、作動するように仕込んでいます。
希望としては、再生が終了、もしくは再生経過時間が所要時間に達したら、フォームを閉じ、ある条件のセルにアクティブセルを移動して、そのセルの情報で次のステップに進みたい。
 
イベントが発生しないのであれば、ループ内で所要時間と現在の経過時間の比較をすれば、
終了か否かの判定ができるのではないかと思い下記のモジュールを追加しました。
しかし、ステップ実行では機能するようですが、実際に実行させるとフリーズしてしまいます。
原因はよくわかりませんが、音楽再生とループは並行処理はできない? のではないかと思いました。
 
Me.wmp.URL = Mypath & Sound の次に以下のモジュールを追加しました。
 
     nw1 = Me.wmp.currentMedia.Duration - 0.5 '再生所要時間(0.5秒前に止める)
     Do
        nw2 = Me.wmp.Controls.currentPosition '再生経過時間(スライダーの位置)
        If nw2 >= nw1 Then '再生所要時間の0.5秒前
            Unload uf1
            Exit Sub
        End If
     Loop
End Sub

回答
投稿日時: 20/03/21 17:13:55
投稿者: MMYS

     Do
          '〜何らかの処理〜
          DoEvents
          Sleep 100
     Loop

 
DoEvents を記述する
 
処理をVBAで占有されOS側がWMPを操作出来ません。
一時的に制御を渡さないといけません。
 
 
なお、今回のように、単に終了を待つだけという場合、
WindowsAPIのSleep でCPUの開放してCPU使用率を抑えてください。
http://officetanaka.net/excel/vba/tips/tips116.htm
 

回答
投稿日時: 20/03/21 20:02:12
投稿者: mattuwan44

引用:
mattuwan44さん
このモジュールは、セルの選択をトリガーとして、作動するように仕込んでいます。
希望としては、再生が終了、もしくは再生経過時間が所要時間に達したら、フォームを閉じ、ある条件のセルにアクティブセルを移動して、そのセルの情報で次のステップに進みたい。

 
次のステップとは?
 
次の曲に行きたいのでは?????
閉じる必要がどこにあります?
 
Private Sub UserForm_Initialize()
    Dim c As Range
    Dim m As IWMPMedia
    Dim i As Long

    For Each c In ThisWorkbook.Worksheets(3).Range("C1:C3")
        Set m = Me.WindowsMediaPlayer1.mediaCollection.Add(c.Value)
        Me.WindowsMediaPlayer1.currentPlaylist.insertItem i, m
        i = i + 1
    Next
End Sub

 
シート上のC1:C3に音楽ファイルのフルパスを記入して、
それを元にプレイリストを作ってます。
 
こちらは、2010でテストしました。
 
ちなみに海外の掲示板を参考にしました。
日本語で、詳しい解説がないので、苦労しますね。
たったこれだけのコードを書くのに1時間半かかった><
英語読めないけど、コードは何となく読めた^^;
変数の宣言とかしてないんですねぇ。。。。結構いい加減なのかなぁ・・・・
 
ちなみに、
「曲が終わった」は、
PlayStateChangeイベントでわかりそうですね。
 
Private Sub WindowsMediaPlayer1_PlayStateChange(ByVal NewState As Long)
    Debug.Print NewState
End Sub
 
こんなことをしてみると、
NewStateに8が渡ってくると終りっぽい。(勘違いしてたらごめんなさい)
連続してイベントが発生してるので、
何番がどの状態かいまいちつかめないけど、
オブジェクトブラウザで何かそれっぽい定数が見つからないだろうか?
この辺で出かけるので、終了です。
ヒントは出したので、あとは自分で開拓するしかないかもです。
 
あぁ、、、
あと、イベント探すなら、
プロシージャボックスで探したらいいと思いますよ。
英語解らないけど、
Stateってなんかそれっぽいと思って、挿入してブレークポイント置いてみたら、
一応イメージ通りな反応しました。
(再生ボタン押したときとか曲終わったときに、3回発生したのは想定外でしたが。。。)

投稿日時: 20/03/21 20:13:45
投稿者: 黄金山

MMYSさん
 
ありがとうございました。
希望通りの結果が得られました。
実は並行処理がダメならと思って、sleepも使って見ましたが、DoEvents との組み合わせを忘れていました。
おかげで、解決しました。感謝・感謝です。
 
確認ですが、[時間の計算]→[100ミリ秒のsleepの間、音楽を再生]を繰り返す・・・ただし人間の耳には、連続して再生しているように聞こえるという、認識でよろしいのですよね?
 
     Do
         nw2 = Me.wmp.Controls.currentPosition '再生経過時間(スライダーの位置)
        If nw2 >= nw1 Then '再生所要時間の0.5秒前
            DoEvents
            Sleep 100
            Unload uf1
            Exit Sub
         End If
      Loop

回答
投稿日時: 20/03/22 00:02:15
投稿者: MMYS

ご提示のコードだと
・WindowsMediaPlayer のグラフィック描写がされない。
・スライダーは動かせない。
といった現象。や
曲が終わるまで、WindowsMediaPlayerがフリーズしているように見える
となるはず。
もちろん、正しく記述すれば上記現象は発生しません。
 
 

mattuwan44 さんの引用:
ちなみに、
「曲が終わった」は、
PlayStateChangeイベントでわかりそうですね。

これは曲が変わったとき。みたいです。
1曲だけの時は終了時に発生しませんでした。(私の環境では)
 
 
ところで、テキストファイルに
曲ファイル名を記述して
拡張子.m3u で保存。
プレイリストファイル作れば十分な気もしますか。
 

回答
投稿日時: 20/03/22 11:30:57
投稿者: MMYS

CPUは1秒の実行回数が決まっています。その処理能力を
・OSの処理
・起動中のアプリの処理リ
・起動中のExcelの処理
などで使います。
もし、処理時間が余ったら、余裕が出来ます
高速なCPUは処理能力に、余裕があります。
非力なCPUは余裕がなく、遅いマシンになります。
 
さて、CPUは与えられたコードを最速で実行します。
CPUはとにかく実行に専念します。
 

  Dim t As Single
  Dim cnt As Long
  t = Timer + 10
  Do
    If Timer > t Then
      Exit Do
    End If
    cnt = cnt + 1
  Loop
  Debug.Print cnt

上記コードは10秒間。待つプログラムです。待つだけです。
で、私の環境では変数cntは「94,187,948」でした。
つまり、1秒間に
If Timer > t Then  を 約9千万回実行しています。
待つ。というだけなのにCPUに約9千万回の仕事をさせてます。
待つだけで、約9千万回のチェックは無駄です。
 
  Dim t As Single
  Dim cnt As Long
  t = Timer + 10
  Do
    If Timer > t Then
      Exit Do
    End If
    cnt = cnt + 1
    Sleep 100
  Loop
  Debug.Print cnt

上記で1秒に10回のチェックです。
CPU処理能力の1%以下です。残り99%のCPU処理能力はExcel以外に使ってもらいます。
 
 
DoEventsは全く別の目的です。DoEventsのヘルプには
>オペレーティング システムに制御を渡します。
と書かれています。
 
WindowsMediaPlayerコントロールの描写やスライダーの処理はOSが行っています。
しかし、UserFormに組み込んだWindowsMediaPlayerはExcelの配下にあります。
WindowsMediaPlayerコントロールの描写はOSが行いますが、
VBAコードを実行中はCPUをVBAが使っているため
WindowsMediaPlayerコントロールの描写は行われません。

なのでVBAが終了するまでOSがWindowsMediaPlayerを処理出来ません。
 
そこで、出てくるのがDoEventsです。VBA実行中にDoEventsでOSに制御を渡して
OSにWindowsMediaPlayerを処理してもらいます。
つまり、ループ中に何回もDoEventsを呼び出します。
 
 
なお、音楽再生自体はバックグラウンドで行われるのでDoEventsは不要です。
 

投稿日時: 20/03/22 13:24:01
投稿者: 黄金山

WinArrowさん、MMYSさん、mattuwan44 さん
 
DoEventsの仕組みなど、丁寧に教えていただき、ありがとうございました。
 
最初に、目的を詳しく説明すれば、良かったのですが、フォルダにある2000曲を超えるmp3から、
1.音楽を再生し、内容を確認したうえで別フォルダに保存。
2.ジャンルやアーティスト別のフォルダに層別する。
3.TAG情報を取得して、編集し直す。
などなど、色々とファイルの整理に、VBAで処理しています。
単に音楽を聴く場合は、Windows Media Player や、Music Center for PCを利用し、
Workmanなどで楽しんでいます。
 
最終的には、再生時間等の計算ではなく、mattuwan44 さんに提示していただいた、
  ”PlayStateChangeイベント” で処理する事にしました。
どうも皆様、いろいろと教えていただき、ありがとうございました。
これでクローズさせていただきます。
 
Private Sub wmp_PlayStateChange(ByVal NewState As Long)
    If NewState = 8 Then ’停止=1、一時停止=2、再生中=3
        Worksheets("DB").Range("b1") = "STOP"Doevents
    End If
End Sub
 
Private Sub UserForm_Activate()
    ・
    ・
    ・
    Do
        DoEvents
        Sleep 100
        If Worksheets("DB").Range("b1") = "STOP" Then
            Unload uf1
            Range(adr).Offset(1).Select
            Exit Sub
        End If
    Loop
End Sub