EmptyProjectを使う その5(スレッドの優先度等)

 
0.追加記事  WaitForSingleObjectを、使う

      やっと、WaitForSingleObjectを使う方法を、理解できました。

Pa_CallBack関数の所で、計算スレッドを作動させるには、

   else
   {

      for( i = 0 ;i < Capture_Data_Length;i++ )
      {
       //入力を受け付けるのみ
     
       data->current_Q[i]=gain_left* *in++;//left
       data->current_I[i]=RF_gain* *in++;//right

      }
 
      //計算の、スレッド開始
       ::SetEvent(thread_event);  //manualReset

      //output
 
     for(i=0;i<Capture_Data_Length;i++)
     {
      *out++=data->output[i]*data->gain;
      *out++=-(data->output[i]*data->gain);
     // *out++=data->output[i]*gain;

   } 

と、します。

一方、 計算させるスレッドでは、

//******* thread ***********************************************

DWORD WINAPI myThread(LPVOID x)
{
 

   paTestData* DATA=(paTestData*)x;
   int i=0;
  
   while(1)
   {
  
    ::WaitForSingleObject(thread_event,INFINITE);

      EnterCriticalSection(&section);

    limit=Capture_Data_Length*DATA->circular;

    for(i=0;i<2048;i++)
    {
     DATA->my_data_Q[i+ limit ] =
        DATA->current_Q[i]*cos(keisuu*tune*i) - DATA->current_I[i]*sin(keisuu*tune*i);

     DATA->my_data_I[i+limit] =
        DATA->current_Q[i]*sin(keisuu*tune*i) + DATA->current_I[i]*cos(keisuu*tune*i);

     scope_fft_Q[i]=DATA->current_Q[i]*scope_fft_multify_cos[i] - DATA->current_I[i]*scope_fft_multify_sin[i];
     scope_fft_I[i]=DATA->current_Q[i]*scope_fft_multify_sin [i] + DATA->current_I[i]*scope_fft_multify_cos[i];
    }
  
    DATA->myfir->get_CaptureData_FFT_result(DATA->my_data_Q+Capture_Data_Length*(DATA->circular-1),
                DATA->my_data_I+Capture_Data_Length*(DATA->circular-1),
                4096,DATA->capture_fft, work,ip,w);

    DATA->myfir->multi_FFT_results(DATA->capture_fft,DATA->coef_fft,DATA->result);
  
    DATA->myfir->get_data_from_mulit_FFT_results(DATA->result,2048,
             DATA->output,0,ip,w);


    if(AGC)
    {
     DATA->peak_output=0.0f;

    //peak detect
     for(i=0;i<2048;i++)
      {
       DATA->peak_output=(float)max(DATA->peak_output,DATA->output[i]);
      }

        DATA->gain=exp(0.5f-DATA->peak_output/1.4f);
       else
      DATA->gain=1.0f;
   
    DATA->circular++;
    if(DATA->circular== Buffer_Multi)
     DATA->circular= 1;

      ::Reset_Event(thread_event);

    LeaveCriticalSection(&section);

    }

 return 0;

}

  今回は、プログラムが、固まるのを防止するための ::Sleep(1) が、不要ですね、ええ調子 ♪
  
  なお、Eventを作る時、WinMain関数内で、このeventを、手動リセットに、設定しておきます。

//**** thread **************************************************
   g_thread=::CreateThread(NULL,0,myThread,&data_origin,CREATE_SUSPENDED,&d);

   ::SetThreadPriority(g_thread,THREAD_PRIORITY_TIME_CRITICAL );//THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_ABOVE_NORMAL
              //THREAD_PRIORITY_TIME_CRITICAL
   InitializeCriticalSection(&section);

   thread_event=::CreateEvent(0,true,false,NULL); //manualreset

< p> (sampling_high)?sample_Rate=96000:sample_Rate=48000;

 set_scale();
 InitDlg();
 selected_mode=2;
     

      これで、かなり、安定しました、サンキュー (*^_^*)

  追加記事、終わり。



 

1.スレッド 及び、プロセスの優先度
 

     タスクマネージャーで、選択したプログラムの優先度を、変えられるのを、知りませんでした。


      Rockyの優先度は、リアルタイムに、初期設定されている。


      PowerSDRの優先度は、通常に、初期設定されています。
 

     何故か?
 
      自分のプログラムを、いじって診て、初めて、解りました。

     PortAudio、DirectX等を使う、自作のプログラムで、プロセスの優先度を上げると、うまく動作しませんでした....

     前節で、私は、ぼやいておりました

       「 PortAudioの Callback関数内で、全て処理するのでは無くて、

         Callback関数は、外部入力を受け付けるだけで、そのまま出力し、

          他の場所で、処理する事が、必要と考えます。

         それは、何なのか?と、申しますと、

              よく解ってないのですが、DirectShow なるものでは、ないかと....」

     とにかく、他のプログラムを起動した時に、

     自作のプログラムで、音声が歪んでしまうのが、いやでした。我慢なりませんわ。

    WinMainの最初に

   // TODO: Perform any application-level initialization here
 //このprocessの、優先度を設定する-----------------------------------------
 //::SetPriorityClass(::GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS);

    これは、不発。

 2.DirectShowを使うまでも無い

     負け惜しみを言っておりますが、実は、まだ、よく解ってないのです。

     とにかく、前節で、私が、ぼやいておりましたように、PortAudioのCallBack関数を、丸裸に、いたしました。





     
ほんで、計算部分を、どうするの?

     新しいスレッドを立てて、

     そこに、全部押し込みましたわ。

     しかも、このスレッドの優先度を、最高の優先度である THREAD_PRIORITY_TIME_CRITICAL に設定。

     おまけに、クリティカルセクションなるものを使って、排他的に、動作するように設定しました。

//**** thread **************************************************
 g_thread=::CreateThread(NULL,0,myThread,&data_origin,0,&d);

::SetThreadPriority(g_thread,THREAD_PRIORITY_TIME_CRITICAL );    //THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_ABOVE_NORMAL
                                                    //THREAD_PRIORITY_TIME_CRITICAL
 InitializeCriticalSection(&section);


     このスレッドは、こんな風に、書きました。

//******* thread ***********************************************

DWORD WINAPI myThread(LPVOID x)
{
     paTestData* DATA=(paTestData*)x;
     int i=0;
 
   
 while(1)
    {
       if(DATA->can_fft)
       {

         EnterCriticalSection(&section);

         limit=Capture_Data_Length*DATA->circular;

        for(i=0;i<2048;i++)
        {
          DATA->my_data_Q[i+ limit ] =
              DATA->current_Q[i]*cos(keisuu*tune*i) - DATA->current_I[i]*sin(keisuu*tune*i);

          DATA->my_data_I[i+limit] =
              DATA->current_Q[i]*sin(keisuu*tune*i) + DATA->current_I[i]*cos(keisuu*tune*i);

         scope_fft_Q[i]=DATA->current_Q[i]*scope_fft_multify_cos[i] - DATA->current_I[i]*scope_fft_multify_sin[i];
         scope_fft_I[i]=DATA->current_Q[i]*scope_fft_multify_sin [i] + DATA->current_I[i]*scope_fft_multify_cos[i];
       }
  
       DATA->myfir->get_CaptureData_FFT_result(DATA->my_data_Q+Capture_Data_Length*(DATA->circular-1),
           DATA->my_data_I+Capture_Data_Length*(DATA->circular-1),
              4096,DATA->capture_fft,
              work,ip,w);

       DATA->myfir->multi_FFT_results(DATA->capture_fft,DATA->coef_fft,DATA->result);
  
       DATA->myfir->get_data_from_mulit_FFT_results(DATA->result,2048,
           DATA->output,0,ip,w);


       if(AGC)
       {
          DATA->peak_output=0.0f;

         //peakdetect< br>          for(i=0;i<2048;i++)<br>             DATA->peak_output=(float)max(DATA->peak_output,DATA->output[i]);<br>    <br>         DATA->gain=exp(0.5f-DATA->peak_output/1.4f);//0.64=noise even AGC
        }
      else
    
       DATA->gain=1.0f;
 
       DATA->circular++;
       if(DATA->circular== Buffer_Multi)
           DATA->circular=1;

       LeaveCriticalSection(&section);
    }

    DATA->can_fft=0;
    ::Sleep(1); //他のプログラムの、入る余地を作る、これが無いと固まる
  
  }

 return 0;
}

     要するに、計算部分を、全部詰め込んだ訳ですねん。

     このスレッドが受け取る変数は、 paTestData* 型に、しました。

     この型に、色んなものを、詰め込みました。

          if(DATA->can_fft)で、計算を始め、

       DATA->can_fft=0; と、最後に書いて、計算部分を抜ける訳です。

    PortAudio の CallBack関数内で

    入力を受け取った後

 data->can_fft=1;

        と、書いて、このスレッドの計算部分を、排他的に、働かせる訳です。

    しかも、スレッドの優先度を最高に、設定していますので、

    ここの部分が計算し終わった後、PortAudio の CallBack関数内の、残りの出力部分が、動作すると、期待して....

    (ほんとは、 ここら辺を、きっちり、

      CreateEvent して、WaitforSignalObject()を使って、スケジュールすべき、なんでしょうが、まだ、できてませんねん )


     で、結果は?

     お蔭様で、大体、クラッシュしなく、なりました、 ホッ。

     CW時でも、画面の動きと、出力音声は、一致しています、ヤレヤレです、 V(^_^)

 
    H.19.7.3