C#でwavファイルの再生方法

このQ&Aのポイント
  • C#でのwavファイルの再生方法について困っています。現在、学校の卒業制作でC#を使用してゲームの開発を行っているのですが、音楽ファイルの再生がうまくいきません。
  • playsoundを使用したループ再生は非同期とループを指定することでできるとわかりましたが、うまく動作しませんでした。
  • 現在はThreadとsleepを使用して擬似的にループ再生を実現していますが、他の方法を探しています。C#でwavファイルをループ再生する方法を教えてください。
回答を見る
  • ベストアンサー

C# wavファイルの再生について

C#に関しての質問なのでこちらでいいのかわからないのですが、タイトル通りwavファイルの再生についてです。 環境は .NET2003 です。 現在、学校の卒業制作としてC#でゲームの開発を行っているのですが、音楽ファイルの再生の仕方で困っています。 検索してみたところ、playsoundを使用したループ再生には非同期とループを指定すればいい、とありましたが うまく動きませんでした。 そこでThreadを使用しsleepを使うことで擬似的にループ再生をさせているのですが、それだと都合の悪いことが多く別の方法を探しています。 お力になっていただける方がいれば、宜しくお願いします。 ↓は現在のソースから抜き出したものです。 [DllImport("winmm.dll")] private static extern bool PlaySound(string pszSound, int hmod, uint fdwSound); static void Main(){    Thread t1 = new Thread(new ThreadStart(play)); t1.Start(); Thread.Sleep(1000000000); } public static void play(){ PlaySound("daichi.wav", 0, 0x00001 | 0x00008 ); }

  • ganho
  • お礼率100% (3/3)

質問者が選んだベストアンサー

  • ベストアンサー
noname#30727
noname#30727
回答No.3

#2です。 Thread.Sleepについて誤解があるようですね。 Thread.Sleepを使ったのは、ループ再生が確認できるだけの時間、Main()から戻りたくなかったからです。ゲームはいきなり終了する事はないわけですから、Thread.Sleepを入れる必要はありません。ボタンが押された時や、その他なんらかの条件でPlaySoundを呼び出しやればいいだけです。 PlaySoundを非同期指定で呼び出すと、内部でスレッドを作成しバックグラウンドで動作しますが、その事とThread.Sleepを使う事とは全く関係ありません。ファイルを読み続けていても、画面を更新しつづけていても、その結果に大きな違いはありません。 スレッドというのは、CPUを割り当てる単位です。 CPUは1つだと仮定しますが、スレッドはOSを起動した直後でも数百くらいは存在しています。そしてOSは実行する必要があるスレッドの1つにCPUを割り当てて実行するか、実行すべきスレッドが無ければCPUをスタンバイ状態にします。 Ctrl+Alt+Delteでタスクマネージャーを起動し、パフォーマンスで確認すれば、スレッドの数もわかりますし、CPU使用率もわかります。 CPU使用率が0%であるという事は、全てのスレッドが、Thread.Sleepを呼び出したのと同じような状態になっていて、何もしていない事を意味します。 プログラムを起動するという事は、システム内に1つのプロセス(プログラムを実行する為の4GBのメモリ空間などを指す)を作成し、プロセスに実行ファイルを読み込み、プロセス内に最初に実行されるスレッドが作成される事を意味します。Main()を実行するのは、その最初のスレッドであり、Thread.Sleepを呼び出す事は自分自身を実行しているスレッドを暫くの間停止させるという事を意味します。 例えば while (true) ; を実行すると、CPU使用率は100%になりますが、Thread.Sleepでスレッドを眠らせている間は、そのスレッドのCPU使用率は0%になります。 Thread.Sleepを呼び出すのは、できるだけ省電力の状態で待つという事と、他のスレッドがCPUをより多く使えるようにするという意味しかありません。 わけのわからない説明になってしまったかもしれませんが、何かあれば補足下さい。 もっとも、C#は入門書を読んで実験的に3時間くらいしか使った事がないので、C#の事を聞かれても答えられないかもしれません(笑

ganho
質問者

お礼

非常に詳細な説明をしていただきありがとうございます。 おっしゃる通りThread.Sleepについて誤解をしていました。 Threadの実行時間の調整のようなものだと思いこんでしまい、よく調べずに使用していました・・・ 見当違い・勘違いな質問に丁寧な説明を頂き、気持ちよく解決できました。 今度からはしっかり調べた上で関数サマ達を使いたいと思います; 本当にありがとうございました!

その他の回答 (2)

noname#30727
noname#30727
回答No.2

#1です。 試してみましたが、ループしてますね。 何か別の理由があるのかもしれませんが、得られている情報だけでは、なんとも言えません。 using System; using System.Runtime.InteropServices; using System.Threading; class Sound { [DllImport("Winmm.dll")] private static extern bool PlaySound(string pszSound, int hmod, uint fdwSound); public static void Play() { PlaySound("C:\\Windows\\media\\chimes.wav", 0, 0x00001 | 0x00008 | 0x20000); } public static void Stop() { PlaySound(null, 0, 0); } } class Test { public static void Main() { Sound.Play(); Thread.Sleep(5000); Sound.Stop(); Thread.Sleep(2000); Sound.Play(); Thread.Sleep(3000); Sound.Stop(); } }

ganho
質問者

お礼

お礼が大変遅くなり申し訳ありませんでした。 わざわざソースを組んでいただきありがとうございます。 恐らく私の説明不足のせいなのですが、Thread.Sleep()を使わずに音楽を永久ループ再生させる方法を探していました。 音楽再生については今回初めて取り扱った為、まだ知識に乏しく Thread.Sleep()を使う以外に方法があるのかどうかもわかりません。 VBではPlaySoundのみでループ再生が出来るようなので、 C#でもそのままサポートされているかと思ったのですが・・・。 もしまたお時間いただけるようでしたら、御教授願えれば幸いです。 もちろん自分でも解決方法を探してみます。

noname#30727
noname#30727
回答No.1

>うまく動きませんでした。 本格的に勉強しているなら、こんな説明の仕方をしてはいけません。何がうまくて、何がまずいかは、本人にしかわからないです。 ちなみに、"daichi.wav"がファイル名だとしたら、fdwSoundには、SND_FILENAMEを指定する必要があります。加えて、ファイル名はフルパスで指定した方が安全です。

ganho
質問者

お礼

ありがとうございます。 実務に携わっている方からのアドバイスとても為になります。 >>こんな説明の仕方をしてはいけません よく肝に命じておきます。 うまく動かないというのは、ループ再生がされず1度の再生でストップしてしまう、という事です。 daichi.wavおっしゃる通りファイル名です。 Debugに格納してあるので、あのような表記になっていますが、フルパスで指定できるよう修正したいと思います。

関連するQ&A

  • c# スレッド間でのデータの共有

    C#でメインプロセスと生成されたスレッド間でデータの共有をさせたいのですがどのようにすればいいのでしょうか。ご教授お願い致します。 ・メインプロセス(A) ・Aから生成されたスレッド(B) 例えば、AとBで変数の値をそれぞれ読み書きさせたい場合 どのようにすればよいのでしょうか。 class TEST { public int flag; // メインプロセス(A) public static void Main() { Thread t = new Thread(new ThreadStart(abc)); t.IsBackground = true; t.Start(); while(ture) { Thread.Sleep(10); Console.WriteLine("A:{0}",flag); } } // Aから生成されたスレッド(B) public void abc() { Console.WriteLine("B:{0}",flag); flag++; } }

  • C#で引数を渡して、スレッド用の関数をよびだすには?

    C#でスレッドを使う場合、引数が渡せません。 具体的には、 Thread temp=new Thread(new ThreadStart(message)); temp.Start(); private void message(){ ~} と、なり、ThreadStart(message)の部分で、 ThreadStart(message(mystr))とし、 private void message(string s){} 書くことができないのです。 しかし、関数に、引数を渡せないのは、不便です。 何か、方法は、ないでしょうか。

  • Threadの終了

    http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/index.html を見ると,スレッドの止め方が書いてありますが, これは,スレッドblinker内でループが回っていて初めてうまく行く, と(間違ってるかもしれませんが)理解しています. では下記のように,Thread2でループが回っていない場合は (*)の位置でThread2を止めるにはどうすればいいのか, 教えてくださる方はいらっしゃいませんでしょうか. (**)のClassAではSWTでGUIを表示させていて, それをThread1から閉じるというのが目的です. GUIを閉じない限りその先には進まないので, ループを回しThread2のrun()内で待機させることが出来なくて. public class Thread1 { Thread1(){ Thread2 t2 = new Thread2(); t2.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { } (*)ここでThread2を終了させたい. } public static void main(String args[]){ new Thread1(); } class Thread2 extends Thread { public void run() { new ClassA(); ・・・(**) } } }

    • ベストアンサー
    • Java
  • C# スレッド終了の監視について

    お世話になります。 C#2005でプログラムを作成しております。 マルチスレッドでの、スレッドの終了の監視のことでご質問させていただきます。 下記のコードを実行すると、問題なく実行されます。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ このスレッドの終了を監視したく、下記のコードを追加してデバッグしてみましたが、 スレッドが実行されませんでした。 ------------------------------------------------------------------------------------ int isRcvSearchFlg = 0; private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する for (; ; ) { if (isRcvSearchFlg == 1) { break; } } } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入 */ isRcvSearchFlg = 1; } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ また、以下も試してみましたが、結果は同じでした。 ------------------------------------------------------------------------------------ private int SetDataTreeView() { Thread RcvSetThread = new Thread(new ThreadStart(this.RcvDataSet)); RcvSetThread.Start(); // スレッドが終了するまで待機する RcvSetThread.Join(); } delegate void RcvDataSetDelegate(); void RcvDataGridSet() { /* フォーム内のDatagidviewへの値の代入処理 */ } void RcvDataSet() { Invoke(new RcvDataSetDelegate(RcvDataGridSet)); } ------------------------------------------------------------------------------------ スレッドの終了を監視する方法がわからず困っております。 お手数ですが、ご教授いただきたくよろしくお願い申し上げます。

  • C# パラメータが消える

    以下の様に 共通変数クラスSystemStartDEC を作成し、変数セットまではできてますが Login_Loadでは変数がクリアされています。 なぜでしょうか? public Login() { InitializeComponent(); Login_Load(); this.BtnCancel.Click += new System.EventHandler(this.BtnCancel_Click); this.BtnLogin.Click += new System.EventHandler(this.BtnLogin_Click); } private void Login_Load() { string[] strParam; //iniファイル読込 if (InspecTool004_02.GetIni(this.lVerComVal) == false) { clsEnc.DeleteFile(strSettingIniName); MessageBox.Show("INIファイルの読み込みに失敗しました。" + "/r/n" + "終了します。"); return; } } public class InspecTool004_02 { class IniFileHandler { [DllImport("KERNEL32.DLL")] public static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName); [DllImport("KERNEL32.DLL", EntryPoint="GetPrivateProfileStringA")] public static extern uint GetPrivateProfileStringByByteArray(string lpAppName, string lpKeyName, string lpDefault, byte [] lpReturnedString, uint nSize, string lpFileName); [DllImport("KERNEL32.DLL")] public static extern uint GetPrivateProfileInt( string lpAppName, string lpKeyName, int nDefault, string lpFileName ); [DllImport("KERNEL32.DLL")] public static extern uint WritePrivateProfileString( string lpAppName, string lpKeyName, string lpString, string lpFileName); [DllImport("winmm.dll")] public static extern uint timeGetTime(); } //INIファイル読み込み public static Boolean GetIni(SystemStartDEC.strCom lVerComVal ) { StringBuilder sb_1 = new StringBuilder(1024); string strIniName ; string strBuffer ; Boolean bRtn ; strIniName = ".\\" + SystemStartDEC.strCom.SettingIniName; //DB Section IniFileHandler.GetPrivateProfileString("DB", "ConStr", "default", sb_1, sb_1.Capacity, strIniName); if( sb_1.ToString() == "default" ) { MessageBox.Show("SettingINIファイルDBセクションのConStrが読めません。"); return false; } lVerComVal.IniParam.DBStr = sb_1.ToString(); } public class SystemStartDEC { ////// <summary> ////// 全体共通 ////// </summary> ////// <remarks></remarks> public struct strCom { public strIniParam IniParam; public strUserInfo UserInfo ; public strDispInfo DispInfo ; public strMailInfo MailInfo ; } }

  • デッドロックに関して1

    下記のサンプルソースは、デッドロックを起こすソース なのですが、 public class Deadlock extends Thread { public static Object l1 = new Object(); public static Object l2 = new Object(); private int index; public static void main(String[] a) { Thread t1 = new ThreadA(); Thread t2 = new ThreadB(); t1.start(); t2.start(); } private static class ThreadA extends Thread { public void run() { synchronized (l1) { System.out.println("スレッド1: l1に対するロックを取得"); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("スレッド1: l2のロックの開放待ち"); synchronized (l2) { System.out.println("スレッド1: l1、l2に対するロックを取得"); } } } } private static class ThreadB extends Thread { 文字数オーばーのため削除 } これを参考に、Junitでデッドロックを起こすサンプルを作りたいです。 MultithreadedTestCaseと ControllableTestThreadを使い サンプルを作りたいのですが、 英語が良くわからず苦戦しております。 なにか、よいアドバイスをいただけませんでしょうか? よろしくお願いします

    • ベストアンサー
    • Java
  • ServletContextLisntener#contextDest

    ServletContextLisntener#contextDestroyedついて 下記の様なコードがあったとします。 Tomcat上で動くServletContextListenerImpl#contextDestroyed内の処理にて ポイント1とポイント2を確実に通過するには どのような設定orコーディングが必要ですか? ※宿題ではありません。月曜に製造完です。(..); class ThreadManager {   private static final ThreadManager manager = new ThreadManager();   private final Thread t;   private boolean isStop;   pulbic ThreadManger () {     isStop = false;     final Thread t = new Thread () {       public void run () {         for ( ; ! this.isStop ; ) {           Thread.sleep(300000);         }       }       //ポイント1     }     t.start();     this.t = t;   }   public static ThreadManager getInstance () {     return manager;   }   public void stop () {     this.isStop = true;   }   public void isAlive () {     return this.isAlive();   } } public class ServletContextListenerImpl implements ServletContextListener {   public void contextInitialzed () {}   public void contextDestroyed () {     final ThreadManager manager = ThreadManager.getInstance();     manager.stop();     while (manager.isAlive()) {       //Thread.sleep(2000)する     }     //ポイント2   } }

    • ベストアンサー
    • Java
  • hashCode

    ObjectのhashCodeはどういう規則で生成されているのでしょうか? あるオブジェクトにおいて、オブジェクトの生成順番が実行毎に同じならばhashCodeは同一になるかと思っていたのですが、どうも違うようなので気になりました。 例えば、マルチスレッドでObjectの生成順序を毎回違うよう生成しても、ob配列ojbs1,objs2中の要素のhashCode()は同じになります。 public class HashCodeMultiThreadTest {  public static void main(String[] args) {   final Object[] objs1 = new Object[20];   final Object[] objs2 = new Object[20];   int one_or_two = (int) (Math.random()*2+1);   final long sleep_time1 = 100 * one_or_two;   final long sleep_time2 = 100 * (3-one_or_two);      Thread t1 = new Thread() {    public void run() { try{     for (int i=0; i<objs1.length; i++) {      objs1[i] = new Object();      Thread.sleep(sleep_time1);     }    }catch(Exception e){}}   };   Thread t2 = new Thread() {    public void run() { try {     for (int i=0; i<objs2.length; i++) {      objs2[i] = new Object();      Thread.sleep(sleep_time2);     }    }catch(Exception e){}}   };   try {    t1.start();    t2.start();    t1.join();    t2.join();   }catch(Exception e){}   for (Object o : objs2)    System.out.println(o.hashCode());  } }

    • ベストアンサー
    • Java
  • C#のnew Thread以下のコード分解

    new Thread以下のコードを分解できますか? ====================== private void button1_Click(object sender,EventArgs e) { new Thread(new ThreadStart(delegate() { AllocConsole(); //開始============== for(uint i = 0;i < 100;++i) { Console.WriteLine("Hello " + i); } FreeConsole(); //終了============== })).Start(); } =================== 以上

  • Thread.Abortメソッド後の処理について

    Thread.abortメソッドについて分からないことがあったので,助言が頂けると嬉しいです. Thread.Abort () を発生させると,通常そこでスレッドが終了するということなので,その後のスレッド内の処理はスルーされると思っていたのですが,下記コードですとその後の pictureBox1.Image = null;も実行されている様です. mainでスレッド作成→threadAの停止になると考えていたのですが,delegate内では反映されないのでしょうか? Thread thread_a; //スレッド delegate void Del(); private void main(object sender, EventArgs e) { //スレッドを開始 thread_a = new Thread(new ThreadStart(threadA)); thread_a.Start(); } private void threadA() { new Thread(new ThreadStart(delegate { Invoke((Del)delegate { thread_a.Abort(); //画像を消去する pictureBox1.Image = null; }); })).Start(); }

専門家に質問してみよう