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