オーディオキャプチャ
パソコンのサウンドカードから、オーディオデータをキャプチャする。また、ストリーミングアプリケーションへの応用を念頭に、一定周期毎にキャプチャデータをバッファに書き出すようにする。
オーディオ圧縮、インターネットストリーミング。
オペレーテイングシステムに依存し、専用の 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 版: 準備中