No.003 - 02 WAVE再生 正弦波 |
正弦波を生成するプログラムを紹介します。
Windowsのwaveの仕組みを知るにはいいサンプルだと思います。
Borland C++ Compiler でコンパイルして下さい
sinwave.c |
#include <windows.h> #include <math.h> #define IDC_STATIC -1 #define IDC_SCROLL 1000 #define IDC_TEXT 1001 #define IDC_ONOFF 1002 #define SAMPLE_RATE 11025 #define FREQ_MIN 20 #define FREQ_MAX 5000 #define FREQ_INIT 440 #define OUT_BUFFER_SIZE 4096 #define PI 3.14159 TCHAR app_name [] = TEXT("SineWave"); // 正弦波データをバッファに書きこむ VOID set_sin(PWAVEHDR p_whdr, int i_freq){ static double angle; int i; PBYTE p_buffer=p_whdr->lpData; for(i=0; i<OUT_BUFFER_SIZE; i++) { p_buffer [i] =(BYTE)(127 + 127 * sin(angle)); angle += 2 * PI * i_freq / SAMPLE_RATE; if(angle > 2 * PI) angle -= 2 * PI; } } // プロシージャ BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){ static HWAVEOUT hwave; // WAVEデバイス・ハンドル static PBYTE p_buffer1, p_buffer2; // 音データ格納バッファ(ポインタ) static PWAVEHDR p_whdr1, p_whdr2; // 音データ・ヘッダ(ポインタ) static WAVEFORMATEX waveformat; // WAVEデバイス初期化構造体(WAVEデバイスを開くため専用) static int i_freq = FREQ_INIT; // 正弦波生成Hz数 static BOOL shut_off_flag, app_closing_flag; // 音の再生停止フラグ、プログラム終了フラグ static HWND hwnd_scroll; // スクロールバー・ハンドル int i_dummy; // スクロールバー関数用ダミー引数 switch(msg) { case WM_CREATE: // プログラム起動時 hwnd_scroll = CreateWindow(TEXT("SCROLLBAR"), TEXT(""), WS_CHILD | WS_VISIBLE | SBS_HORZ, 8,8,150,18, hwnd, (HMENU)IDC_SCROLL, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL ); SetScrollRange(hwnd_scroll, SB_CTL, FREQ_MIN, FREQ_MAX, FALSE); SetScrollPos (hwnd_scroll, SB_CTL, FREQ_INIT, TRUE); CreateWindow( TEXT("STATIC"), TEXT("0"), WS_CHILD | WS_VISIBLE | SS_LEFT, 170,10,35,18, hwnd, (HMENU)IDC_TEXT, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL ); SetDlgItemInt(hwnd, IDC_TEXT, FREQ_INIT, FALSE); // 表示Hz値の初期設定 CreateWindow( TEXT("STATIC"), TEXT("Hz"), WS_CHILD | WS_VISIBLE | SS_RIGHT, 202,10,22,18, hwnd, (HMENU)IDC_TEXT, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL ); CreateWindow(TEXT("BUTTON"), TEXT("オン"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 80,33,50,28, hwnd, (HMENU)IDC_ONOFF, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL ); return TRUE; case WM_HSCROLL: // スクロールバー (==周波数の操作) switch(LOWORD(wparam)) { case SB_LINELEFT: i_freq -= 1; break; case SB_LINERIGHT: i_freq += 1; break; case SB_PAGELEFT: i_freq /= 2; break; case SB_PAGERIGHT: i_freq *= 2; break; case SB_THUMBTRACK: i_freq = HIWORD(wparam); break; case SB_TOP: GetScrollRange(hwnd_scroll, SB_CTL, &i_freq, &i_dummy); break; case SB_BOTTOM: GetScrollRange(hwnd_scroll, SB_CTL, &i_dummy, &i_freq); break; } i_freq = max(FREQ_MIN, min(FREQ_MAX, i_freq)); SetScrollPos(hwnd_scroll, SB_CTL, i_freq, TRUE); SetDlgItemInt(hwnd, IDC_TEXT, i_freq, FALSE); // 表示Hz値の更新 return TRUE; case WM_COMMAND: // コマンド・メッセージ(このプログラムでは IDC_ONOFF のみ) switch(LOWORD(wparam)) { case IDC_ONOFF: // hwave が NULLなら(まだWAVEデバイスを開いてまいなら) WAVEデバイスを開く if(hwave == NULL) { // 2 ヘッダ(WAVEHDR) と 2 バッファの メモリ確保 // 音データ・バッファ確保 p_whdr1 = malloc(sizeof(WAVEHDR)); p_whdr2 = malloc(sizeof(WAVEHDR)); p_buffer1 = malloc(OUT_BUFFER_SIZE); p_buffer2 = malloc(OUT_BUFFER_SIZE); if(!p_whdr1 || !p_whdr2 || !p_buffer1 || !p_buffer2) { // メモリ確保に失敗した時 if(!p_whdr1) free(p_whdr1); if(!p_whdr2) free(p_whdr2); if(!p_buffer1) free(p_buffer1); if(!p_buffer2) free(p_buffer2); MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, TEXT("メモリ確保に失敗しました!"), app_name, MB_ICONEXCLAMATION | MB_OK); return TRUE; } shut_off_flag = FALSE; // 音を出力してるかどうかのフラグ // WAVEデバイスを開く waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat.nChannels = 1; waveformat.nSamplesPerSec = SAMPLE_RATE; waveformat.nAvgBytesPerSec = SAMPLE_RATE; waveformat.nBlockAlign = 1; waveformat.wBitsPerSample = 8; waveformat.cbSize = 0; if(waveOutOpen(&hwave, WAVE_MAPPER, &waveformat,(DWORD) hwnd, 0, CALLBACK_WINDOW) != MMSYSERR_NOERROR){ // WAVEデバイスを開くのに失敗したとき free(p_whdr1); free(p_whdr2); free(p_buffer1); free(p_buffer2); hwave = NULL; MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, TEXT("WAVEデバイスのオープンに失敗しました!"), app_name, MB_ICONEXCLAMATION | MB_OK); return TRUE; } // ヘッダの準備とセットアップ p_whdr1->lpData = p_buffer1; p_whdr1->dwBufferLength = OUT_BUFFER_SIZE; p_whdr1->dwBytesRecorded = 0; p_whdr1->dwUser = 0; p_whdr1->dwFlags = 0; p_whdr1->dwLoops = 1; p_whdr1->lpNext = NULL; p_whdr1->reserved = 0; waveOutPrepareHeader(hwave, p_whdr1, sizeof(WAVEHDR)); // スワップアウト不可にする p_whdr2->lpData = p_buffer2; p_whdr2->dwBufferLength = OUT_BUFFER_SIZE; p_whdr2->dwBytesRecorded = 0; p_whdr2->dwUser = 0; p_whdr2->dwFlags = 0; p_whdr2->dwLoops = 1; p_whdr2->lpNext = NULL; p_whdr2->reserved = 0; waveOutPrepareHeader(hwave, p_whdr2, sizeof(WAVEHDR)); // スワップアウト不可にする } else { // 音を止める shut_off_flag = TRUE; waveOutReset(hwave); } return TRUE; } break; case MM_WOM_OPEN: // WAVEデバイス開く SetDlgItemText(hwnd, IDC_ONOFF, TEXT("オフ")); // WAVEデバイスに2バッファ 送信 set_sin(p_whdr1, i_freq); waveOutWrite(hwave, p_whdr1, sizeof(WAVEHDR)); set_sin(p_whdr2, i_freq); waveOutWrite(hwave, p_whdr2, sizeof(WAVEHDR)); return TRUE; case MM_WOM_DONE: // WAVEデバイス出力分の再生終了 if(shut_off_flag) { waveOutClose(hwave); // MM_WOM_CLOSEメッセージ送信 return TRUE; } set_sin((PWAVEHDR)lparam, i_freq); waveOutWrite(hwave,(PWAVEHDR)lparam, sizeof(WAVEHDR)); // 再生後、MM_WOM_DONEメッセージ送信 return TRUE; case MM_WOM_CLOSE: // WAVEデバイス閉じる // p_whdr1、p_whdr2 のスワップアウト禁止状態を解除 waveOutUnprepareHeader(hwave, p_whdr1, sizeof(WAVEHDR)); waveOutUnprepareHeader(hwave, p_whdr2, sizeof(WAVEHDR)); free(p_whdr1); free(p_whdr2); free(p_buffer1); free(p_buffer2); hwave = NULL; SetDlgItemText(hwnd, IDC_ONOFF, TEXT("オン")); if(app_closing_flag) SendMessage(hwnd, WM_CLOSE, 0, 0L); // 1度閉じるボタンが押されている break; case WM_CLOSE: if(hwave != NULL) { // WAVEデバイスを開いてるなら shut_off_flag = TRUE; app_closing_flag = TRUE; waveOutReset(hwave); // 再生停止後、MM_WOM_DONEメッセージ送信( → MM_WOM_CLOSE → 終了) } else DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, msg, wparam, lparam); return FALSE; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) { HWND hWnd; MSG msg; WNDCLASS winc; winc.style = CS_HREDRAW | CS_VREDRAW; winc.lpfnWndProc = DlgProc; winc.cbClsExtra = winc.cbWndExtra = 0; winc.hInstance = hInstance; winc.hIcon = LoadIcon(NULL, IDI_APPLICATION); winc.hCursor = LoadCursor(NULL, IDC_ARROW); winc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE ); winc.lpszMenuName = NULL; winc.lpszClassName = TEXT("sin_wave_winc"); if (!RegisterClass(&winc)) return 1; hWnd = CreateWindow( TEXT("sin_wave_winc"), app_name, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 100, NULL, NULL, hInstance, NULL ); if (hWnd == NULL) return 1; while (GetMessage(&msg, NULL, 0, 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } |
上記ソースは全て自由に改編して使ってかまいませんが必ず自己責任でね。
2004.3.28 G丸 |