C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

WaveStreamのクラス化がうまくいかない

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■91060 / inTopicNo.1)  WaveStreamのクラス化がうまくいかない
  
□投稿者/ TOTO (1回)-(2019/05/23(Thu) 12:52:17)

分類:[.NET 全般] 

https://smdn.jp/programming/netfx/tips/set_volume_of_soundplayer/

このページに音量を調整可能な
WaveStreamのクラスのコードが載っています。

複数の音声を扱うために、
これを以下のようにクラス化しました。



Public Class SoundClass

    Public strm As WaveStream

    Public player As System.Media.SoundPlayer = Nothing

    Public Sub Start()

        If player IsNot Nothing Then Exit Sub

        player = New System.Media.SoundPlayer(strm)

        player.PlayLooping()


    End Sub


    Public Sub Stop0()

        If player IsNot Nothing Then
            player.Stop()
            player.Dispose()
            player = Nothing
        End If
    End Sub

End Class



    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        Dim myAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
        Dim kkk = New SoundClass With {.strm = New WaveStream(myAssembly.GetManifestResourceStream("WindowsApplication1.test.wav"))}

        kkk.Start()
        Thread.Sleep(1000)
        kkk.Stop0()
        Thread.Sleep(1000)
        kkk.Start()			’←ここでエラーが発生する


  End Class


しかし、一回目の再生はうまくいくのですが、
一度、停止してから再度再生しようとすると


        player.PlayLooping()

WAVEヘッダーが壊れています
というエラーが出てうまくいきません。


Public Class SoundClassの中で、


        Dim myAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
        Dim strm As New WaveStream(myAssembly.GetManifestResourceStream("WindowsApplication1.test.wav"))}

の宣言を行うとなぜかうまくいきます。

なぜ、このエラーが発生するのでしょうか?

引用返信 編集キー/
■91061 / inTopicNo.2)  Re[1]: WaveStreamのクラス化がうまくいかない
□投稿者/ 魔界の仮面弁士 (2183回)-(2019/05/23(Thu) 13:20:14)
No91060 (TOTO さん) に返信
> Public Class SoundClass
>  Public strm As WaveStream
>  Public player As System.Media.SoundPlayer = Nothing

これらのクラスを内包させるのであれば、SoundClass クラスは
Components を継承させて作るか、もしくは
IDisposable インターフェイスを実装することをお奨めします。


> Thread.Sleep(1000)

Windows メッセージループを阻害することになるため、
フォーム上(というか、UI スレッド)上で Sleep メソッドを呼び出すのは厳禁です。



> kkk.Start() ’←ここでエラーが発生する

その直前の処理で SoundPlayer を Dispose していますよね。
肝心のインスタンスが廃棄されていませんか?

廃棄済みのオブジェクトを操作するのはマズイと思いますよ。
引用返信 編集キー/
■91063 / inTopicNo.3)  Re[2]: WaveStreamのクラス化がうまくいかない
□投稿者/ TOTO (2回)-(2019/05/23(Thu) 22:09:20)
ありがとうございます。

Components を継承させて作るか、もしくは
IDisposable インターフェイスを実装することをお奨めします。

これの方法をお教えいただけないでしょうか?

引用返信 編集キー/
■91080 / inTopicNo.4)  Re[3]: WaveStreamのクラス化がうまくいかない
□投稿者/ キングダム (28回)-(2019/05/26(Sun) 19:22:26)
2019/05/26(Sun) 19:24:03 編集(投稿者)

No91063 (TOTO さん) に返信

●エラーが発生する原因を知るにはどうすればよいか

仮説を立てましょー

SoundPlayerにStreamを渡すようになっており
Streamは一定の方向に進んでいくというものです

PlayLoopingでStreamが一定の方向に進んでいく
StopでそれがストップするけれどもStreamの位置はリセットされない

次にSoundPlayerにStreamを渡したときには
Streamの読み込み位置が最初とは違っている

Waveのヘッダはファイルの特定の場所に存在していて
読み出す位置が違うと正常に読み出せない

WAVEヘッダーが壊れていますというエラーが投げられる

という感じじゃないかなと思います

●仮説を検証するにはどうすればよいか

StopのあとにStream.Positionを出力してみる、0ではないはず

New System.Media.SoundPlayer(strm)の前のところで
strm.Position = 0を実行してみる、エラーがでないはず

ということを確認すれば良さそうですね

●エラーがでないようにするにはどうすればよいか

やり方はいくつかありそうですね

・PlayごとにStreamのインスタンスを作成する
・Streamが変わらない場合はSoundPlayerのコンストラクタを呼ばない
・Stream.Position = 0を挿入する

●Componentsの継承、IDisposableの実装について

継承の仕方、インターフェースの実装のしかたは
プログラミングの一般的な事柄なので↓こういうところを読むのがいんじゃないかと思います

第4回 継承を使うために知っておくべきこと (1/4):連載 オブジェクト指向プログラミング超入門 - @IT
https://www.atmarkit.co.jp/ait/articles/0409/25/news010.html

VB開発者のためのインターフェイス入門(1/2) - @IT
https://www.atmarkit.co.jp/fdotnet/bookpreview/kisokaravb_0802/kisokaravb_0802_01.html

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ