Web1.cpp


    0: // Web1.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
    1: //
    2: 
    3: #include "stdafx.h"
    4: 
    5: #define OGG_FILE _T("sample.ogg")
    6: #define BUFFER_SIZE (1024 * 1024) /* 1024 kBytes */
    7: #define BUF_COUNT 3
    8: 
    9: static bool last = false;
   10: 
   11: FILE *fp;
   12: static int bitstream;
   13: 
   14: static char buffer[BUF_COUNT][BUFFER_SIZE];
   15: WAVEHDR wavehdrs[BUF_COUNT];
   16: /* if WAVEHDR::dwUser is 1, this is last data. */
   17: 
   18: int bufferIdx = 0;
   19: int playIdx = 0;
   20: 
   21: /**
   22:  *   バッファをデコードした PCM で埋めます。
   23:  *   @param   vf     デコードのための Vorbisfile 構造体へのポインタ
   24:  *   @param   wavehdr     PCM を格納するバッファを管理する WAVEHDR 構造体へのポインタ
   25:  */
   26: long fillBuffer(OggVorbis_File *vf, WAVEHDR *wavehdr)
   27: {
   28:     long count = 0;
   29:     int ret;
   30:     char *buffer = (char *)wavehdr->lpData;
   31: 
   32:     while (count < BUFFER_SIZE) {
   33:         ret = ov_read(vf, buffer + count, BUFFER_SIZE - count, 0, 2, 1, &bitstream);
   34:         if (ret <= 0) {
   35:             wavehdr->dwUser = 1; /* End of data. */
   36:             break;
   37:         }
   38:         count += ret;
   39:     }
   40:     wavehdr->dwBufferLength = count;
   41:     return count;
   42: }
   43: 
   44: /**
   45:  *   Windows メディア API で使用されるコールバック。
   46:  */
   47: void CALLBACK waveCallback(HWAVEOUT hwo,
   48:                            UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
   49: {
   50:     static int winret;
   51: 
   52:     switch(uMsg) {
   53:         case WOM_CLOSE:
   54:             break;
   55:         case WOM_DONE:
   56:             /* 再生 */
   57:             winret = waveOutWrite(hwo, &(wavehdrs[playIdx]), sizeof(WAVEHDR) );
   58:             if (winret != MMSYSERR_NOERROR) {
   59:                 exit(1);
   60:             }
   61: 
   62:             _tprintf(_T("Callback called.\n") );
   63:             Sleep(1000);
   64:             {
   65:             OggVorbis_File *vf = (OggVorbis_File *)dwInstance;
   66:             /* 最終データが再生完了 */
   67:             if (last) {
   68:                 /* VorbisFile 後処理 */
   69:                 ov_clear(vf);
   70: 
   71:                 /* サウンド出力後処理 */
   72:                 for (int i = 0; i < BUF_COUNT; i++) {
   73:                     waveOutUnprepareHeader(hwo, &(wavehdrs[i]), sizeof(WAVEHDR) );
   74:                 }
   75:                 winret = waveOutClose(hwo);
   76:                 exit(0);
   77:             }
   78:             /* 先ほどの再生データが最終 */
   79:             if (wavehdrs[playIdx].dwUser == 1) {
   80:                 last = true;
   81:             }
   82: 
   83:             playIdx = (playIdx + 1) % (BUF_COUNT);
   84: 
   85:             /* 次のバッファを読む */
   86:             fillBuffer(vf, &(wavehdrs[bufferIdx]));
   87:             bufferIdx = (bufferIdx + 1) % (BUF_COUNT);
   88:             }
   89:             break;
   90:         case WOM_OPEN:
   91:             break;
   92:         default:
   93:             break;
   94:     }
   95: }
   96: 
   97: /**
   98:  *   メイン。
   99:  */
  100: int _tmain(int argc, _TCHAR* argv[])
  101: {
  102:     int ret;
  103: 
  104:     OggVorbis_File vf;
  105:     vorbis_info *vi;
  106: 
  107:     /* Ogg ファイルのオープン */
  108: //    fp = fopen(argv[1], "r+b");
  109:     fp = fopen(OGG_FILE, "rb");
  110:     if (NULL == fp) {
  111:         _ftprintf(stderr, _T("ERROR: Can not open file.\n") );
  112:         exit(1);
  113:     }
  114: 
  115:     /* OggVorbils_File 構造体 */
  116:     ret = ov_open(fp, &vf, NULL, 0);
  117:     if (ret < 0) {
  118:         _ftprintf(stderr, _T("ERROR: ov_open()\n") );
  119:         fclose(fp);
  120:         exit(1);
  121:     }
  122: 
  123:     /* Vorbis 情報 */
  124:     vi = ov_info(&vf, -1);
  125:     if (NULL == vi) {
  126:         _ftprintf(stderr, _T("ERROR: ov_info()\n") );
  127:         fclose(fp);
  128:         ov_clear(&vf);
  129:         exit(1);
  130:     }
  131: 
  132:     /* サウンド出力初期化 */
  133:     HWAVEOUT hwo;
  134:     WAVEFORMATEX wfmx = {
  135:         WAVE_FORMAT_PCM,
  136:         vi->channels,
  137:         vi->rate,
  138:         vi->rate * vi->channels * (16 / 8),
  139:         vi->channels * 16 / 8,
  140:         16,
  141:         0
  142:     };
  143:     MMRESULT winret = waveOutOpen(&hwo, WAVE_MAPPER, &wfmx,
  144:         (DWORD)waveCallback, (DWORD)&vf, CALLBACK_FUNCTION);
  145:     if (MMSYSERR_NOERROR != winret) {
  146:         _ftprintf(stderr, _T("ERROR: waveOutOpen()\n") );
  147:         fclose(fp);
  148:         ov_clear(&vf);
  149:         exit(1);
  150:     }
  151: 
  152:     /* WAVEHDR 初期化 */
  153:     for (int i = 0; i < BUF_COUNT; i++) {
  154:         memset( (void *)&(wavehdrs[i]), 0, sizeof(WAVEHDR) );
  155:         wavehdrs[i].lpData = buffer[i];
  156:         wavehdrs[i].dwBufferLength = BUFFER_SIZE;
  157:         winret = waveOutPrepareHeader(hwo, &(wavehdrs[i]), sizeof(WAVEHDR) );
  158:         if (MMSYSERR_NOERROR != winret) {
  159:             _ftprintf(stderr, _T("ERROR: waveOutPrepareHeader() [i = %d]\n"), i);
  160:             fclose(fp);
  161:             ov_clear(&vf);
  162:             exit(1);
  163:         }
  164:         wavehdrs[i].dwLoops = 1;
  165:         /* 初期 PCM データ */
  166:         fillBuffer(&vf, &(wavehdrs[i]) );
  167:     }
  168: 
  169:     /* 再生開始 (コールバックのトリガー) */
  170:     winret = waveOutWrite(hwo, &(wavehdrs[0]), sizeof(WAVEHDR) );
  171:     if (winret != MMSYSERR_NOERROR) {
  172:         exit(1);
  173:     }
  174:     playIdx = (playIdx + 1) % (BUF_COUNT);
  175:     bufferIdx = 0;  /* 次にデータを入れるのは 0 番目 */
  176: 
  177:     /* main を終わらせないため */
  178:     while(1) {
  179:         _sleep(1000);
  180:     }
  181: 
  182:     return 0;
  183: }
  184: 
  185: