• ベストアンサー

スレッドのテスト

現在、音声の転送プログラムを作成中なのですが、その中でスレッドを使いたく勉強するためにテストプログラムを作ったのですが、うまく動作しません。 そのソースファイルです(C言語です) http://www.h7.dion.ne.jp/~ishix3/prog.htm ドレミファソラシドと再生したいのですが、一瞬だけ「ド」が再生されそれに続いて再生してくれません。 どこが悪いのでしょうか?どなたか教えてください。

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

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/jpmltimd/html/_win32_waveoutunprepareheader.asp ここを良く読んで。 「waveOutWrite 関数でデバイスドライバにバッファを渡した後、waveOutUnprepareHeader 関数を呼び出す前に、デバイスドライバがバッファでの作業を完了するまで待たなければなりません。」 と書いてあります。つまり 「waveOutWrite 関数を呼ぶとバッファがサウンドデバイスに送られる。サウンドデバイスが再生状態であれば(一時停止状態でなければ)音声が再生される。アプリケーションはデバイスの再生が終るのを待ってwaveOutUnprepareHeader 関数で後始末を行う」 と言う事です。 質問者さんは「デバイスの再生が終るのを待って」いませんので、 「ドをセットしてドが鳴ると同時にバッファを破棄して、レをセットしてデバイスに送った瞬間にバッファを破棄して、ミをセット(以下略)」 と言う状態になります。 まずは、スレッドを作らず、ドレミファソラシドがちゃんと鳴るようにしてから、スレッド作成を試みましょう。 まずは、waveOutOpen 関数のdwCallbackにコールバック関数を、dwCallbackInstanceにインスタンスを、fdwOpenにCALLBACK_FUNCTIONを指定しての「音声再生の制御」を成功させて下さい。 waveOutOpen 関数のfdwOpenにCALLBACK_WINDOWを指定していては、スレッドでの制御が出来ません(再生終了のイベントがウィンドゥに返されるので、メインのWndProcで処理する事になり、スレッドを作る意味がない) スレッドで処理するなら ・メインスレッドで初期化のみ行ったら子スレッドを作る。初期化の時と再生終了メッセージが来た時は、PLAYボタンをイネーブルし、STOPボタンをディセーブルする ・PLAYボタンはスレッドに対してイベントを使って再生をキックする。そして、PLAYボタンをディセーブルし、STOPボタンをイネーブルする ・STOPボタンは、waveOutResetなりを呼んで、後始末して、PLAYボタンをイネーブルし、STOPボタンをディセーブルする ・子スレッドは、イベントハンドラがアクティブになるまでwaitし、イベントがアクティブになったら、イベントを非アクティブにして音声再生する ・音声再生する時は、コールバック関数を指定してwaveOutOpenする ・waveOutOpenで指定したコールバック関数で、鳴り終わったフラグが立ってコールバックされたら、後始末をして、バッファを次の音に更新して、スレッドに対してイベントを使って再生をキックする。次の音が無ければ、メインスレッドに対しメッセージを投げて終ったのを通知する と言う処理になります。 先は長いけど頑張って。

iship-
質問者

お礼

回答ありがとうございます。 すごく理解できました。 がんばります。

関連するQ&A

  • Threadについて

    細かい質問なのですが、 1.一つのthreadを走らせるプログラムを2つ(二回)走らせるのと、 2.同じthreadを2つ走らせるプログラムを一つ走らせるのでは どう違うのでしょうか? 1(●)(●) 2(●●) 一応伝えにくいのですがこの違いについて質問したくなった経緯は以下です。 現在javaでUSB経由の音声の取得を行っています。マイクから拾った音声をそのままイヤホンに出力するプログラムです。USBは2つついています。(仮にA,Bとさせていただきます) 前者の一つのthreadを走らせるプログラム2つですと、まずUSB[A]をライン入力の音源として一つ走らせた後に音源をBに変えてからもう一つを走らせると出力側は2つの音声を同時に再生してくれます。 しかし、後者の場合、Aが選択されている状態で一つスレッドを動かし音源をBに選択し直してから次のスレッドを動かすプログラムにしているにも関わらずBの音声は取得されず、Aのみとなってしまいます。おそらくAを二倍?拾っています。 もし質問内容に違いがなければこのようなことは起きないかと思っています。単純に自分の技術不足かもしれませんが・・・・ 説明が上手く出来なかったのですが、質問は以上です。 特に音が一つになったことは分かりづらかったら気にしないでください。違いが分かればうれしいです。

  • スレッドを再生成する方法

    VBからC言語DLLを呼ぶプログラムを作っています。 DLLでスレッドを生成しているのですが、 VBから1回目の呼び出しではうまく動作するのですが、2回目はスレッドが生成されません。 2回目は1回目のスレッドが終了してから呼び出しているのですがなにか処理が必要なのでしょうか? スレッドは_beginthreadexで生成してスレッド関数内のreturnで終了しています。 closehandleを追加してみましたが駄目でした。

  • C++におけるスレッド制御に関して

    C++初心者です。 スレッド制御の勉強をしておりますが、 なかなかうまくいきません。 下記のソースのようにスレッド生成をしておりますが、 スレッド用メソッドには、*を付けて使用するしか方法はないのでしょうか? pthread_createに渡す第3パラメータをメソッド名のみにして、呼ばれ元のメソッドの戻り値をvoid* ではなく、void のみで実施したいと思っておりますが、方法がわかりません。 大変申し訳ございませんが、ご教授よろしくお願いいたします。 ############################################################## # pthread_test.cc ############################################################## #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h> /* * スレッドパラメータ格納用 */ typedef struct {  char printVal;  int interval; } ThreadParamT; // スレッドイニシャル関数 void *ThreadTest(void *arg) {  ThreadParamT *thread_test_param =(ThreadParamT*)arg;  while(1) {   fprintf(stderr,"%c", thread_test_param->printVal);   sleep(thread_test_param->interval);  }  return NULL; } int main(int argc,char *argv[]) {  int status;  // スレッドのパラメータ  pthread_t thread_test;  ThreadParamT thread_test_param;  thread_test_param.printVal = 'a';  thread_test_param.interval = 1;  // スレッドを生成  status=pthread_create(&thread_test, NULL, ThreadTest, &thread_test_param);  if(status!=0){   fprintf(stderr,"ERR! OUT!\n");   exit(1);  }  // 10s間待つ  sleep(10);  fprintf(stderr, "\n");  return 0; } ##############################################################

  • スレッドとメッセージキューに関して

    現在、下記のようなプログラムを作成しています。 内容は、メッセージキューを受信するスレッドを生成するというイメージです。 処理内容は下記のようになります。  (1)メッセージキューの生成  (2)スレッド生成(メッセージキュー受信側)  (3)スレッド停止  (4)メッセージキューの削除 しかし、(3)のスレッド停止を実施しても、(4)のメッセージキューの削除以降にて、msgrcvのエラーが出力されてしまいます。 スレッド停止を行ったことから、TestThreadは動作しなくなり、(4)のメッセージキューの削除にて、エラーともならずに終了することを望んでりますが、上手くいきません。 下記に作成しているプログラムを記載いたします。 正常終了をするには何がいけないのでしょうか? ご教授宜しくお願い致します。 [test.cc] ---------------------------------------------------------------- #include <time.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <ctype.h> #include <stdlib.h> #include <pthread.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/msg.h> // メソッドポインタ定義 typedef void (*testT); // スレッドID pthread_t threadId; // メッセージキュー識別子 int msqId; // 送受信するメッセージ struct msgbuf{ long int type; char data[BUFSIZ]; }; // テストスレッド void TestThread() { // メッセージ struct msgbuf message; while( 1 ) { printf("### TEST ###\n"); printf("msq start\n"); // 受信 if( msgrcv( msqId, &message, BUFSIZ, 0, 0 ) == -1) { printf("ERR! msgrcv errno[%d]\n", errno); continue; } printf("msq ed\n"); sleep(1); } return; } // メイン int main(int argc, char *argv[]) { // メッセージキュー識別子退避変数 int testMsqid; // スレッド操作リターン値 int status; // スレッドa用のパラメータ pthread_t thread_test; printf("### TEST START ###\n"); // メッセージキューの作成 if( (testMsqid = msgget((key_t)1111, 0666 | IPC_CREAT)) == -1 ) { printf("ERR! CREATE bkMsqId[%d]\n", testMsqid); return 1; } // メッセージキュー識別子を共通変数に設定 msqId = testMsqid; printf("msgget OK\n"); sleep(5); // スレッドを生成 status = pthread_create(&thread_test, NULL, (void*(*)(void*))TestThread, (void*)NULL); if(status!=0) { printf("pthread_create ng\n"); return 1; } printf("pthread_create OK\n"); sleep(5); // スレッド停止 status = pthread_cancel(thread_test); // スレッド停止結果 if ( status != 0 ) { printf("pthread_cancel ng\n"); return 1; } printf("pthread_cancel OK\n"); sleep(5); // メッセージキューの削除 if ( msgctl( msqId, IPC_RMID, NULL) == -1 ) { printf("msqId[%d] errno[%d]\n", msqId, errno); return 1; } printf("msgctl OK\n"); sleep(5); printf("### TEST E N D ###\n"); return 0; } ----------------------------------------------------------------

  • スレッドの意味

    マルチスレッドについて良い資料が見当たらず、教えて下さい。 OSにおけるマルチスレッドと言うと、同一プロセス内でメモリ空間を 共有して独立に動く一連の手続き、と捉えています。(シングルCPU シングルコアだとOSで時分割によって作られた仮想的な並列計算) Javaのようなマルチスレッドのプログラミング言語では「一つの プログラムから作られた二つの一連の手続き」と言うイメージが あります。※裏側の動作ではOSに依頼してJavaのプロセス内で OSのスレッドを生成して処理を渡しているだけ?と思っています。 CPUコアの内部で説明される「マルチスレッド」と言うのは、 どのようなレベルのスレッド(何が並列処理?何処まで並列?) なのでしょうか。

  • [VC++2008].dllが見つからない

    Visual Studio C++ 2008で自作DLLを使用したプログラムを作成しています。 ソースツリーが以下のようにあります。 main.cpp で #pragma comment(lib,"myutil_d.lib") #include "myutil.h" とすると、コンパイルは成功するのですが、prog1.exeを実行すると: 「myutil_d.dllが見つからなかったため、このアプリケーションを開始できませんでした。」 と出てきてプログラムが始まりません。 これを解決する方法をご教授いただけるでしょうか? (MYPROGROOT) |-include | |-myutil.h | |-lib | |-myutil_d.dll | |-myutil_d.exp | |-myutil_d.lib | |-prog1 | |-Debug | | |-prog1.exe | | |-prog1.ilk | | |-prog1.pdb | |-prog1 | | |-Debug | | | |-BuildLog.htm | | | | ... | | | | | | |-main.cpp | | |-prog1.vcproj | | | |-prog1.ncb | |-prog1.sln | |-prog1.suo | |-prog2 |-Debug | |-prog2.exe | |-prog2.ilk | |-prog2.pdb |-prog2 | |-Debug | | |-BuildLog.htm | | | ... | | | | |-main.cpp | |-prog2.vcproj | |-prog2.ncb |-prog2.sln |-prog2.suo 「>ツール>オプション>プロジェクトおよびソリューション」下 インクルード ファイル :$(MYPROGROOT)\bin ライブラリ ファイル :$(MYPROGROOT)\include もちろんmyutil_d.dllを(MYPROGROOT)\prog\Debug\ に配置するとプログラムは動くのですが、prog1, prog2, と多数のプログラムで myutil_d.dllを使用するため、バージョン管理のために統一のディレクトリで .dllファイルを管理したいと考えています。

  • 「インクルードファイル 'pthread.h' をオープンできない」というエラー

    今簡単なサーバ・クライアントシステムをつくっていて、大まかな骨組みはできました。 で、骨組みができたところで先生が、「並列処理を可能にするため、スレッドを使ってみましょう。スレッドについては次回までに各自勉強してきておいてください。」といったので、帰ってからインターネットで調べてみた結果、マルチスレッドの例みたいなプログラムのソースをいくつか見付けました。 私はスレッドというものを全く知らなかったので(というかそもそもC言語についてもそれほど詳しくないのですが)、とりあえずそのソースをコピーしてどのような動作をするのか確認しようと思いました。 ところがコンパイルするときに、 「インクルードファイル 'pthread.h' をオープンできない」 というエラーがでてきてしまうのです。 ちなみに家で使っている CPad for Borland C++Compiler と、 学校で使っている Microsoft Visual C++ (だったかな?) の両方でコンパイルしてみましたが、両方とも同じエラーが起こります。 どうすればいいのでしょうか?

  • マルチスレッドのスレッド数を増やしたい

    <プログラム環境> Windows XP VC++6.0 MFC AppWizard(exe) ダイアログベース <質問概略> CWinThread*を使って無限ループのスレッドを作ったのですが、 無限ループのスレッドをもう一つ作り、同時に実行しようとするとアクセスバイオレーションのエラーでます。 複数スレッドの作り方を教えていただけますと幸いです。 <質問詳細> 現状の正常に実行できるソースの必要最小限を書きます。 <.h> class CMyDlg : public CDialog{ public:   static UINT ThreadFunc( LPVOID pParam );   void Thread(); // スレッドの処理 protected:   CWinThread* m_pThread;//スレッドのアドレス }; <.cpp> void CMyDlg::OnButton(){   m_pThread = AfxBeginThread( ThreadFunc, this );   for(;;) /*無限ループ処理1*/ ; } UINT CMyDlg::ThreadFunc( LPVOID pParam ){   ((CMyDlg*)pParam)->Thread();   return 0; } void CMyDlg::Thread(){   for(;;) /*無限ループ処理2*/ ; } これに、 void CMyDlg::Thread2(){   for(;;) /*無限ループ処理3*/ ; } のようなスレッドを追加したいのですが全然出来ません。 宜しければご指摘お願い致します。

  • スレッドの自動終了について。

    スレッドの自動終了について。 クリップをファイルから取得し、[1]キーが押されるとクリップが再生され、クリップ再生中の場合は ファイル名を表示したラベルに色を着けるプログラムを作ってみたのですが 1度のみなら正しく作動するのですが、2回目にキーを押そうとすると、クリップだけ再生しラベルの色は黒いままです。 そして、3回目以降はキーをいくら押してもクリップが再生されません。 これを正しく動作させるにはどのようにしたらよいでしょうか。 キーリスナ、スレッド、アクションリスナの内容を記載しますので、ご指導頂けたらと思います。 class ClipWatching extends Thread { public ClipWatching() { } public void run() { while(clip1.isRunning()) { lb1.setForeground(Color.red); } lb1.setForeground(Color.black); thread = false; } } class SampleKeyListener implements KeyListener { public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_1) { try{ if(thread == false) { cw.join(); } clip1.start(); cw.start(); thread = true; } catch(Exception uu) { } } } public void keyReleased(KeyEvent e){ } public void keyTyped(KeyEvent e){ } } class SampleActionListener implements ActionListener { public void shori() { } public void actionPerformed(ActionEvent e) { try { if(e.getSource() == bt1) { fl1 = new File("001.wav"); lb1.setText(fl1 + ""); ais1 = AudioSystem.getAudioInputStream(fl1); format1 = ais1.getFormat(); info1 = new DataLine.Info(Clip.class, format1); clip1 = (Clip) AudioSystem.getLine(info1); clip1.open(ais1); } } catch(Exception ex) { } }

  • readlineの場所

    readlineをつかったプログラムをつくっています。 C言語のプログラムで"readline/readline.h", "readline/history.h"をつかっています。 OSがUbuntu8.04なんですが、gcc -o test test.c -lreadlineで、readlineがみつかりませんというエラーになってしまいます。 いつもはGNU Readlineのサイトからソースをおとしてきてmake installするんですが、locateしてみると、はじめからいるみたいなのです。 はじめからいるんだけど、/usr/local/includeなどにヘッダーは入っていません。 なにかの作業をすれば、サイトからソースを落としてこなくても-lreadlineは効くようになるのでしょうか?? ご存知のかたがいらっしゃったら助けていただきたいです。

専門家に質問してみよう