Jyaiko1.1で WAVEファイルを再生する


左側の 'WAV read' ボタンを押してwave fileを再生しています。

 1.Jyaiko1.1で wavefileを再生する

    'WAV_read'のボタンを押すと、wavefileが、Jyaiko1.1上で再生されます。(FFT結果も、橙色の表示に変わります。色は、私の好みですねん。)

    wavefileの最後に到達すると、自動的に終了して、realtimeのFFT結果表示に戻ります。



 2.タイミング関係を、設定する

    先ず、WAVE DATAを、配列 l_channel[2048],r_channel[2048]に移します。

   そのために、先ず別スレッドを立てる。eventも設定します。

INT WINAPI WinMain( HINSTANCE hInstance , HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)

 g_wav_read_thread=::CreateThread(NULL,0,wave_read,(LPVOID)&wav_data,CREATE_SUSPENDED,&d);

 ...........................
 wave_event=::CreateEvent(0,true,false,NULL);
 ............................
}

    wavefileをreadする部分は、こうしました。(適宜、一回だけ、読み込むように、後で仕掛けします。)   

void read_wave_data(FILE *fp,float *l_channel,float *r_channel)
{
  int i=0;
  int j=0;
  for(i;i<4096;i++)
  {
   if(i%2)
   {
    fread(r_channel+j,sizeof(float),1,fp);
    j++; 
   }
  else
  {
   fread(l_channel+j,sizeof(float),1,fp);
  }
 }

}

    この void read_wave_data(FILE *fp,float *l_channel,float *r_channel)を何時、実行するかのタイミングですが

    とにかく、一回実行して、l_channel[] , r_channel[]に読み込ませます。

// ボタンを押したときの eventです。

 case IDC_BUTTON_WAVE_READ:
  {
   wav_data.wave_on=!wav_data.wave_on;

   if(wav_data.wave_on)
   {

    g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_NORMAL ]
    =g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_MOUSEOVER ]
     =D3DCOLOR_ARGB(255,252,202,130);
   
    wav_data.fp=read_wave_format_chunk(L"LSB2.wav",wav_data.loop_number,wav_data.rest_data_number);
      
    if(wav_data.fp !=NULL)
    {
     
     ::ResumeThread(g_wav_read_thread); //wavfileを読み込むスレッドを起動する
     
     ::SetEvent(wave_event);//manual reset //ここで、一回読み込むためのeventをsetする
    }
    wav_data.wave_start=true;
   }
   else
   {
    ::SuspendThread(g_wav_read_thread);
    g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_NORMAL ]
    =g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_MOUSEOVER ]      
    =D3DCOLOR_ARGB(255,121,224,200);
    wav_data.k=0;
    wav_data.wave_start=false;
    close_file(wav_data.fp);

   }
  }
 
     ::SetEvent(wave_event); の部分が、一回読み込むための引き金になります。

    当然、wavfileのデータを読み込む部分には、引き金を受け付ける仕掛けが必要です。

    以下が、wavefileデータを読み込むスレッドです。

DWORD WINAPI wave_read(LPVOID x)
{
 wav_read_data* data=(wav_read_data*)x;
 
 while(1)
 {
  for(data->k=0; data->k < data->loop_number; data->k++)
  {
   ::WaitForSingleObject(wave_event,INFINITE);// ここで、待ち受ける

   read_wave_data(data->fp,l_channel,r_channel);

   ::ResetEvent(wave_event); //一回だけ読み込むために、eventをresetする
  }

// 以下は、最後尾のデータを読み込んで、停止するためのものです。
  if(data->k==data->loop_number) //wave read end  & stop
  {
   ::WaitForSingleObject(wave_event,INFINITE);
   read_rest_wave_data(data->fp,l_channel,r_channel,data->rest_data_number );
   ::ResetEvent(wave_event);
   
   data->k=0;

   g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_NORMAL ]
   =g_ControlDlg.GetButton(IDC_BUTTON_WAVE_READ)->GetElement(1)->TextureColor.States[ DXUT_STATE_MOUSEOVER ]      
    =D3DCOLOR_ARGB(255,121,224,200);

   data->wave_on=false;
   data->wave_start=false;
   close_file(wav_data.fp);
  }
}

return 0;

}

    そして、2048個のデータを読み込んだら、停止するように  ::ResetEvent(wave_event); と、仕掛けておきます。
 
    このデータを正しく再現するために、PortaudioのCallback関数を利用します。

    PortaudioのCallback関数は、そのsampling周期に応じた、データの取り込み、再生を、してくれるはずだからです。

    青色の部分が wavefileデータを読み込む所です。

static int pa_test_Callback(const void *inputBuffer,void *outputBuffer,
         unsigned long framesPerBuffer,
         const PaStreamCallbackTimeInfo* timeInfo,
         PaStreamCallbackFlags statusFlags,
         void *userData)
{
 //paTestData *data = (paTestData*)userData;
 float *out = (float*)outputBuffer;
 float   *in  = (float*)inputBuffer;

     if( inputBuffer == NULL )
  {
   for( i=0; i<Capture_Data_Length; i++ )
   {
    *out++ = SAMPLE_SILENCE; 
   }
  }
  else
  {

   data_origin.gain_left= (g_HUD.GetSlider(IDC_SLIDER_GAIN)->GetValue()/10000.0);

   for( i = 0 ;i < Capture_Data_Length;i++ )
   {
    if(wav_data.wave_start)
    {
    //入力を受け付けるのみ
     scope_fft_Q[i]= data_origin.current_Q[i]=data_origin.gain_left * l_channel[i];//left
     in++;
     scope_fft_I[i]=data_origin.current_I[i]=r_channel[i];//right
     in++;< br>    scope_fft_I[i]=data_origin.current_I[i]=(scope_fft_I[i]+ scope_fft_Q[i]*phase_sin )*inv_cos;
    }
    else
    {
    //リアルタイム時の入力を受け付けるのみ
     scope_fft_Q[i]= data_origin.current_Q[i]=data_origin.gain_left * *in;//left
     in++;
     scope_fft_I[i]=data_origin.current_I[i]=*in;//right
     in++;< br>    scope_fft_I[i]=data_origin.current_I[i]=(scope_fft_I[i]+ scope_fft_Q[i]*phase_sin )*inv_cos; 
    }
   }

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

   for(i=0;i<Capture_Data_Length;i++)
   {
    
    *out++=data_origin.output[i]*data_origin.gain;
    *out++=data_origin.output[i]*data_origin.gain;

   } 
  
  <br>  }


 return paContinue;

}

    そして、赤色の部分  ::SetEvent(thread_event) は、元々存在する、計算のスレッドを起動してくれます。

    この計算のスレッドで、再び、 wavefileデータを読み込むスレッドを起動して、

    一回だけ、(2048個のL_channel, r_channel)読み込みます。

DWORD WINAPI myThread(LPVOID x)
{

 while(1)
 {
  
  ::WaitForSingleObject(thread_event,INFINITE);


  EnterCriticalSection(&section);


  //data ->FFT
  data_origin.myfir->get_CaptureData_FFT_result(data_origin.current_I,data_origin.current_Q,2048,data_origin.result,work,ip,w);
 
  ///////////////////////////////////////////////////////////////
  if(wav_data.wave_start)
   ::SetEvent(wave_event);//manual reset
  ///////////////////////////////////////////////////////////////

  //arrange FFT

  for(i=0;i<2048;i++)
    ..............................

}
     この、タイミングの設定で、無事、wavefileを読み込み、音声データも、正常に再現されました。

    うーむ、とにかく、出来ましたが、物足りませんね.....

    loop できない、部分的に再現できてない....等 キリがないにゃあ。

H.20.5.16