オーディオ再生
パソコンから、オーディオデータをサウンドカードに再生させる。ストリーミングアプリケーションへの応用を念頭に、一定周期毎にオーディオデータをサウンドカードに書き出すようにする。
オーディオ再生プレーヤ、インターネットストリーミング。
オペレーテイングシステムに依存し、専用の API 群が用意されている。
Windows | |
MCI | Media Control Interface |
DirectSound | DirectX ファミリ |
Linux | |
OSS | Open Sound System |
ほか |
以下は、一定周期毎にファイルからオーディオデータを読出し、同じく一定周期毎にサウンドカードに書き出して再生させるプログラムである。一連の手順として、
サンプリング周波数、サンプル当たりのビット数、チャネル数の指定 | |
サウンドデバイスの初期化 | |
サウンド再生の開始 | |
サウンドデバイスの終了処理 |
を基本とする。ただし、エラー処理は行っておらず、また GUI も貧弱な、あまりよくないプログラムである。
Windows MCI 版: waveOutXXX 関数群の使用、リンクオプションに winmm.lib を加える。
main.c (GUIプログラム 参照)
#include <windows.h> // サウンド再生関数 (sound.c) BOOL initSound(int hertz, int bits, int channels, int interval, char *name); BOOL startSound(); BOOL closeSound(); // // イベント処理 // LRESULT APIENTRY WndProc (HWND hWnd, UINT msg, UINT wParam, LONG lParam) { // イベントに応じて処理を実行 switch (msg) { case WM_CREATE: /* サウンド再生開始 */ /* サンプリング周波数、ビット数、チャネル数、キャプチャ周期、入力ファイル名、を指定 */ /* 下の例では、8KHzサンプリング、8ビットサンプル、ステレオ、50msec毎の再生 */ /* キャプチャプログラムのパラメータに合わせること */ initSound(8000, 8, 2, 50, "sample.pcm"); startSound(); return 0; case WM_CLOSE: /* サウンド再生終了 */ closeSound(); DestroyWindow(hWnd); return 0; case WM_DESTROY: PostQuitMessage (0); break; } return DefWindowProc (hWnd, msg, wParam, lParam); } // // 制御部 (main 関数) // int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hDummy, LPSTR lpStr, int nShowCmd) { WNDCLASS wc; MSG msg; HWND hWnd; // ウィンドウクラスの定義 wc.lpfnWndProc = WndProc; wc.hInstance = hInst; wc.hIcon = LoadIcon (NULL, IDI_APPLICATION); wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.lpszClassName = "Player"; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.style = 0; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.lpszMenuName = 0; RegisterClass (&wc); // ウィンドウの生成 hWnd = CreateWindow( wc.lpszClassName, "Sound Capture Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 256, 256, 0, 0, hInst, 0 ); if (hWnd == NULL) ExitThread (1); ShowWindow (hWnd, SW_SHOWNOACTIVATE); UpdateWindow (hWnd); // 無限ループ (イベントが発生するたびに WndProc を呼び出す) while (GetMessage (&(msg), NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage (&msg); } return msg.wParam; } |
sound.c
#include <windows.h> #include <stdio.h> /* バッファ定数 */ #define BUFFER_NUMBER 100 #define BUFFER_SIZE 4800 /* サウンドバッファ */ char sound_out[BUFFER_NUMBER][BUFFER_SIZE]; /* サウンドパラメータ */ WAVEFORMATEX waveForm; HWAVEOUT hwo; WAVEHDR wvhdr_out[BUFFER_NUMBER]; /* 出力ファイル、制御フラグ、各種制御パラメータ */ FILE *fp; BOOL bSound = FALSE; int nInterval; int nLength; int nWritePosition = 0; int nReadPosition = 0; MMRESULT hEvRead; MMRESULT hEvPlay; // ------------------------------------------- // 初期化 // ------------------------------------------- BOOL initSound(int hertz, int bits, int channels, int interval, char *name) { int i; int res; /* ファイルオープン */ fp = fopen(name, "rb"); if(fp == NULL) return FALSE; /* バッファ初期化 */ for(i=0; i<BUFFER_NUMBER; i++) memset(sound_out[i], 0, BUFFER_SIZE); /* WAVEFORMATEX 設定 (サンプリング周波数、ビット数、チャネル数) */ waveForm.wFormatTag = WAVE_FORMAT_PCM; waveForm.nChannels = channels; waveForm.nSamplesPerSec = hertz; waveForm.wBitsPerSample = bits; waveForm.nBlockAlign = waveForm.nChannels * waveForm.wBitsPerSample / 8; waveForm.nAvgBytesPerSec = waveForm.nSamplesPerSec * waveForm.nBlockAlign; /* waveOut オープン */ res = waveOutOpen(&hwo, WAVE_MAPPER, &waveForm, 0, 0, WAVE_ALLOWSYNC); if(res != MMSYSERR_NOERROR) return FALSE; /* 再生バッファ確保 */ nInterval = interval; nLength = waveForm.nAvgBytesPerSec * nInterval / 1000; for(i=0; i<BUFFER_NUMBER; i++) { wvhdr_out[i].lpData = sound_out[i]; wvhdr_out[i].dwBufferLength = waveForm.nAvgBytesPerSec * nInterval / 1000; wvhdr_out[i].dwBytesRecorded = 0; wvhdr_out[i].dwUser = 0; wvhdr_out[i].dwFlags = 0; wvhdr_out[i].dwLoops = 0; waveOutPrepareHeader(hwo, &wvhdr_out[i], sizeof(WAVEHDR)); } return TRUE; } // ------------------------------------------- // 再生開始 // ------------------------------------------- // ファイルからデータ読出し static void CALLBACK readEvent(UINT timerID, UINT msg, DWORD usrParam, DWORD dw1, DWORD dw2) { char sound_data[BUFFER_SIZE]; /* サウンドデータの読みこみ */ if(feof(fp)) fseek(fp, 0, SEEK_SET); fread(sound_data, 1, nLength, fp); memcpy(sound_out[nWritePosition % BUFFER_NUMBER], sound_data, nLength); nWritePosition++; } // サウンドの再生実行 static void CALLBACK playEvent(UINT timerID, UINT msg, DWORD usrParam, DWORD dw1, DWORD dw2) { int index; /* フラグ制御 */ if(bSound == FALSE) return; /* サウンドデータの書きこみ */ if(nReadPosition < nWritePosition) { index = nReadPosition % BUFFER_NUMBER; waveOutWrite(hwo, &wvhdr_out[index], sizeof(WAVEHDR)); waveOutUnprepareHeader(hwo, &wvhdr_out[index], sizeof(WAVEHDR)); waveOutPrepareHeader(hwo, &wvhdr_out[index], sizeof(WAVEHDR)); nReadPosition++; } } BOOL startSound() { /* フラグ制御 */ bSound = TRUE; /* タイムイベント起動 */ // readEvent hEvRead = timeSetEvent(nInterval, 1, (LPTIMECALLBACK) readEvent, (DWORD) NULL, TIME_PERIODIC); // playEvent hEvPlay = timeSetEvent(nInterval, 1, (LPTIMECALLBACK) playEvent, (DWORD) NULL, TIME_PERIODIC); return TRUE; } // ------------------------------------------- // 終了処理 // ------------------------------------------- BOOL closeSound() { int i; /* フラグ制御 */ bSound = FALSE; /* waveOut 終了 */ for(i=0; i<BUFFER_NUMBER; i++) { wvhdr_out[i].lpData = NULL; waveOutUnprepareHeader(hwo, &wvhdr_out[i], sizeof(WAVEHDR)); } waveOutPause(hwo); waveOutReset(hwo); waveOutClose(hwo); /* ファイルクローズ */ fclose(fp); return TRUE; } |
Windows DirectSound 版: 準備中
Linux OSS 版: 準備中