003-01  前へ←  ホームへ  →次へ  003-03

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丸
 003-01  前へ←  ホームへ  →次へ  003-03