オーディオキャプチャ
パソコンのサウンドカードから、オーディオデータをキャプチャする。また、ストリーミングアプリケーションへの応用を念頭に、一定周期毎にキャプチャデータをバッファに書き出すようにする。
オーディオ圧縮、インターネットストリーミング。
オペレーテイングシステムに依存し、専用の API 群が用意されている。
Windows | |
MCI | Media Control Interface |
DirectSound | DirectX ファミリ |
Linux | |
OSS | Open Sound System |
ほか |
以下は、一定周期毎にサウンドカードからオーディオ信号をキャプチャし、ファイルに書き出すプログラムである。一連の手順として、
サンプリング周波数、サンプル当たりのビット数、チャネル数の指定 | |
サウンドデバイスの初期化 | |
サウンドキャプチャの開始 | |
サウンドデバイスの終了処理 |
を基本とする。ただし、エラー処理は行っておらず、また GUI も貧弱な、あまりよくないプログラムである。
Windows MCI 版: waveInXXX 関数群の使用、リンクオプションに 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 /* サウンドパラメータ */ WAVEFORMATEX waveForm; HWAVEIN hwi; WAVEHDR wvhdr_in[BUFFER_NUMBER]; char sound_in[BUFFER_NUMBER][BUFFER_SIZE]; /* 出力ファイル、制御フラグ */ FILE *fp; BOOL bSound = FALSE; // ------------------------------------------- // キャプチャ・コールバック // ------------------------------------------- void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { LPWAVEHDR lpwvhdr; char sound_data[BUFFER_SIZE]; int length; /* フラグ制御 */ if(bSound == FALSE) return; /* イベント処理 */ switch(uMsg){ case WIM_DATA: /* キャプチャデータをバッファにコピー */ lpwvhdr = (LPWAVEHDR) dwParam1; length = lpwvhdr->dwBufferLength; memcpy(sound_data, lpwvhdr->lpData, length); /* キャプチャバッファ更新 */ waveInUnprepareHeader(hwi, lpwvhdr, sizeof(WAVEHDR)); waveInPrepareHeader(hwi, lpwvhdr, sizeof(WAVEHDR)); waveInAddBuffer(hwi, lpwvhdr, sizeof(WAVEHDR)); /* サウンドデータのファイル書き出し */ fwrite(sound_data, 1, length, fp); break; } } // ------------------------------------------- // 初期化 // ------------------------------------------- BOOL initSound(int hertz, int bits, int channels, int interval, char *name) { int i; int res; /* ファイルオープン */ fp = fopen(name, "wb"); if(fp == NULL) return FALSE; /* バッファ初期化 */ for(i=0; i<BUFFER_NUMBER; i++) memset(sound_in[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; /* waveIn オープン */ res = waveInOpen(&hwi, WAVE_MAPPER, &waveForm, (DWORD)waveInProc, 0, CALLBACK_FUNCTION); if(res != MMSYSERR_NOERROR) return FALSE; /* キャプチャバッファ確保 */ for(i=0; i<BUFFER_NUMBER; i++) { wvhdr_in[i].lpData = sound_in[i]; wvhdr_in[i].dwBufferLength = waveForm.nAvgBytesPerSec * interval / 1000; wvhdr_in[i].dwFlags = 0; wvhdr_in[i].reserved = 0; waveInPrepareHeader(hwi, &wvhdr_in[i], sizeof(WAVEHDR)); waveInAddBuffer(hwi, &wvhdr_in[i], sizeof(WAVEHDR)); } return TRUE; } // ------------------------------------------- // キャプチャ開始 // ------------------------------------------- BOOL startSound() { int res; /* フラグ制御 */ bSound = TRUE; /* waveIn 開始 */ res = waveInStart(hwi); if(res != MMSYSERR_NOERROR) return FALSE; return TRUE; } // ------------------------------------------- // 終了処理 // ------------------------------------------- BOOL closeSound() { int i; /* フラグ制御 */ bSound = FALSE; /* waveIn 終了 */ waveInStop(hwi); for(i=0; i<BUFFER_NUMBER; i++) { wvhdr_in[i].lpData = NULL; waveInUnprepareHeader(hwi, &wvhdr_in[i], sizeof(WAVEHDR)); } waveInReset(hwi); waveInClose(hwi); /* ファイルクローズ */ fclose(fp); return TRUE; } |
Windows DirectSound 版: 準備中
Linux OSS 版: 準備中