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: