Jyaiko1.1を使ってwave file に書き込む



 1.DirectShowを使った録音の調子が、悪い

    どうも、調子がよくありません....

   

    音声は、正確に再生されるのですが、帯域が狭くなってしまいます.....

    DirectShowの使用を、諦めましょう、涙 (-_-)

 2.ほんじゃ、どうする?

   前節で、fread関数を使いました。

   fread関数をfwrite関数に書き換えると、殆ど同じプログラムが使えます。

   write_wave_format_chunk関数を、以下のように作ります。

       所で、fmt size=16 に指定すると、PowerSDRでも、再生できるようになります。

FILE* write_wave_format_chunk(wchar_t* filename,bool is_sampling_high  )
{
 FILE *fp2;
 WAVE_HDR whd;

//48KHz、96KHz samplingに共通の設定 
 whd.wfm.cbSize=0;
  whd.wfm.wFormatTag=3;
  whd.wfm.nChannels=2;
  whd.wfm.nBlockAlign=8;
  whd.wfm.wBitsPerSample=32;
  whd.fmt_size=16;

  whd.chunk_ID =0x46464952;//"RIFF"
  whd.file_type=0x45564157;//"WAVE"  
  whd.fmt_ID   =0x20746d66;//"fmt"
  whd.fmt_size=16;
  whd.data_ID  =0x61746164;//"data"
  whd.data_size=0;
  whd.file_size=0;
 
 if(is_sampling_high)
 {
  whd.wfm.nSamplesPerSec=96000;
  whd.wfm.nAvgBytesPerSec=768000;
    
 }
 else
 {
  whd.wfm.nSamplesPerSec=48000;
  whd.wfm.nAvgBytesPerSec=384000;
 }
 
 errno_t err;

 if( (err=_wfopen_s(&fp2, filename,L"wb")) !=0)
  return NULL;
 
 if(!fwrite(&whd.chunk_ID,sizeof(DWORD),1,fp2))//RIFF
  return NULL;

 if(!fwrite(&whd.file_size,sizeof(DWORD),1,fp2))
  return NULL;
 
 if(!fwrite(&whd.file_type,sizeof(DWORD),1,fp2))//WAVE
  return NULL;

 if(!fwrite(&whd.fmt_ID,sizeof(DWORD),1,fp2))//fmt
  return NULL;

 if(!fwrite(&whd.fmt_size,sizeof(DWORD),1,fp2))//fmt size=16
  return NULL;
 //fmt size=16
 if(!fwrite(&whd.wfm.wFormatTag,sizeof(WORD),1,fp2))
  return NULL;
 if(!fwrite(&whd.wfm.nChannels,sizeof(WORD),1,fp2))
  return NULL;
 if(!fwrite(&whd.wfm.nSamplesPerSec,sizeof(DWORD),1,fp2))
  return NULL;
 if(!fwrite(&whd.wfm.nAvgBytesPerSec,sizeof(DWORD),1,fp2))
  return NULL;
 if(!fwrite(&whd.wfm.nBlockAlign,sizeof(WORD),1,fp2))
  return NULL;
 if(!fwrite(&whd.wfm.wBitsPerSample,sizeof(WORD),1,fp2))
  return NULL;

 if(!fwrite(&whd.data_ID,sizeof(DWORD),1,fp2))//data
  return NULL;
 //data size
 if(!fwrite(&whd.data_size,sizeof(DWORD),1,fp2))
  return NULL;

 return fp2;
}

    で、write_wave_data関数も、以下のように作っておきます。

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

}
    ほとんど,前節の read_wave_data関数が使えます。

    ほんで、Rec ボタンを押すと、 IDC_BUTTON_WAVE_WRITE イベントが発生します。

  case IDC_BUTTON_WAVE_WRITE:
   {
    if(wav_read_data.isWaveReadOn) // 再生している時は、録音しない。
     break;
    wav_write_data.isWaveWriteOn=!wav_write_data.isWaveWriteOn; //bool isWaveWriteOnと bool isWaveWriteStartedを使うのはタイミングの問題回避のため

    if(wav_write_data.isWaveWriteOn)
    {
     g_ControlDlg.GetButton(IDC_BUTTON_WAVE_WRITE)->GetElement(1)->TextureColor.States[ DXUT_STATE_NORMAL ]
      =g_ControlDlg.GetButton(IDC_BUTTON_WAVE_WRITE)->GetElement(1)->TextureColor.States[ DXUT_STATE_MOUSEOVER ]
      =D3DCOLOR_ARGB(255,255,0,0);
     wave_filename=L"temp.wav"; //ファイルネームは、今の所、決め打ち
     wav_write_data.loop_number=0;
     wav_write_data.fp=write_wave_format_chunk(wave_filename,sampling_high);

     if(wav_write_data.fp !=NULL)
     {
      wav_write_data.wave_data_start_pos=ftell(wav_write_data.fp); //write_wave_format_chunk関数を実行したので、今のファイルポインタは、dataの先頭
      wav_write_data.k=0;
      ::ResumeThread(g_wave_write_thread); //書き込みスレッド開始
      wav_write_data.isWaveWriteStarted=true;
      wav_write_data.total_sec=0; //録音開始秒=0
      g_ControlDlg.GetStatic(IDC_STATIC_SHOW_TIME)->SetVisible(true); //録音時間表示

     }
    }

    そんで、録音終了の時に、ファイルサイズ、dataサイズを、format chunkの所定位置に、書き込みます。

    ファイルをcloseするまでは、ここでも、fseek関数 が使えて、便利です。

     wav_write_data.k_stop_number=ftell(wav_write_data.fp); //終了ボタンを押した時の、ファイルポインタの位置= ファイルサイズ
     DWORD data_size[2]={0,0};
     data_size[0]=wav_write_data.k_stop_number-4; //file size -4("RIFF")
     data_size[1]=wav_write_data.k_stop_number-44;//file size-44(chunk size)
     //write file size
     fseek(wav_write_data.fp,4,SEEK_SET);//after "RIFF"
     fwrite(&data_size[0],4,1,wav_write_data.fp);
     fseek(wav_write_data.fp,40,SEEK_SET);//after "data"
     fwrite(&data_size[1],4,1,wav_write_data.fp);
      
     wav_read_data.k_start_number=0;
     wav_read_data.isStartPos_Set=false;
     wav_read_data.k_stop_number=wav_read_data.k;
     wav_read_data.isStopPos_Set=false;

     close_file(wav_write_data.fp);

    今の所、ファイルネームは、固定で、メモ録音みたいに使っています。

    結局、DirectShowを使い切れませんでしたね....ちょっと、くやしい。

    DirectShowの解説本、でないかな......(かの有名な本は、MSDNの、解説の域を出ないそうな...)


        最後に、Jyaiko1.1 で、録音した IQ wave ファイルを添付いたします。(7MHz帯) [ PowerSDR等で、再生してもらわないと、何も聞こえません。]

          96KHz  IEEE_FLOAT32bits example

          48KHz   IEEE_FLOAT32bits example

    使用しているアンテナは、広帯域のものですので、感度は、よくありません。

    format は、 IEEE_FLOAT 32ビット、96KHz and 48KHzサンプリングですので、注意

    Jyaiko1.1では、入力段で録音しているだけですので、 結果として

    使用している Soft66DB2の優秀さを表すものだと思います。

 H.20.6.1