OS
Windows10
開発環境
Visual studio 2019
実現したいこと
関数SetPixelVを使って、サンプリング周期ごとに配列WaveDataのデータをプロットし正弦波をウィンドウに描画したい。
疑問点
うまく正弦波が描画できていない原因がわからない。
波形を描画するためのコードの説明
//波形の描画 時間領域
8ビットと16ビットで場合分けして波形を表示したい。
data_x: len_xに描画するx軸の長さ、LENGTHに再生する正弦波の長さを設定し、len_x/LENGTHによって、クライアント領域での座標に変換する。
data_y: len_yに描画するy軸の長さを設定し、振幅の最大値(8ビットのときは255、16ビットのときは32767)で割ることによってクライアント
領域での座標に変換する。
結果
c++ ソースコード ```#include<windows.h> #include<tchar.h> #include<math.h> #include"resource.h" #pragma comment(lib,"winmm.lib") #define FS 48000 //再生用オーディオデバイスのサンプリング周波数[Hz] #define BITS 8 //再生用オーディオデバイスのビット数[bit] #define CHANNELS 1 //再生用オーディオデバイスのチャンネル数 #define F0 440 //再生する正弦波の周波数[Hz] #define LENGTH 3 //再生する正弦波の長さ[s] LRESULT CALLBACK windowfunc(HWND, UINT, WPARAM, LPARAM); static const TCHAR szWinName[] = _T("waveout"); unsigned char WaveData8[FS * LENGTH]; // 0 ~ 255 short int WaveData16[FS * LENGTH]; HWAVEOUT hWaveOut; WAVEHDR Whdr; //WinMain関数 int WINAPI WinMain(_In_ HINSTANCE hThisInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPSTR lpszArgs, _In_ int nWinMode) { HWND hwnd; MSG msg; WNDCLASSEX wcl; HACCEL haccel; //ウィンドウクラスの定義 wcl.cbSize = sizeof(WNDCLASSEX); //WNDCLASSEX構造体のサイズ wcl.style = 0; //ウィンドウクラススタイル wcl.lpfnWndProc = windowfunc; //ウィンドウ関数 wcl.cbClsExtra = 0; //ウィンドウクラスのエキストラ wcl.cbWndExtra = 0; //ウィンドウインスタンスのエキストラ wcl.hInstance = hThisInst; //このプログラムのインスタンスへのハンドル wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION); //アイコンへのハンドル wcl.hCursor = LoadCursor(NULL, IDC_ARROW); //カーソルへのハンドル wcl.hbrBackground = (HBRUSH)COLOR_WINDOW; //背景ブラシへのハンドル wcl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); //メニュー wcl.lpszClassName = szWinName; //ウィンドウクラス名 wcl.hIconSm = LoadIcon(NULL, IDI_WINLOGO); //スモールアイコンへのハンドル //ウィンドウクラスの登録 if (!RegisterClassEx(&wcl)) { return(0); } //ウィンドウの生成 hwnd = CreateWindow( szWinName, //ウィンドウクラス名 szWinName, //ウィンドウ名 WS_OVERLAPPEDWINDOW, //ウィンドウスタイル CW_USEDEFAULT, //x座標 CW_USEDEFAULT, //y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ HWND_DESKTOP, //親ウィンドウへのハンドル NULL, //メニューへのハンドル hThisInst, //このプログラムのインスタンスへのハンドル NULL //追加引数 ); //ウィンドウの表示 ShowWindow(hwnd, nWinMode); UpdateWindow(hwnd); //キーボードアクセラレータのロード haccel = LoadAccelerators(hThisInst, MAKEINTRESOURCE(IDR_ACCELERATOR1)); //メッセージループの生成 while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, haccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return((int)msg.wParam); } //ウィンドウ関数 LRESULT CALLBACK windowfunc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { WAVEFORMATEX wf; MMRESULT result; int k, x0, y0, len_x, len_y; double tmp, data_x, data_y; switch (message) { case WM_COMMAND: switch (LOWORD(wparam)) { case ID_MENU_PLAY: //WAVEデータの再生 //再生用データの生成 for (k = 0; k < FS * LENGTH; k++) { tmp = sin(2.0 * M_PI * (double)F0 / (double)FS * (double)k); if (BITS == 8) { WaveData8[k] = (unsigned char)(tmp * 127.0 + 128.0); } else { WaveData16[k] = (short int)(tmp * 32767.0); } } //WAVEデータの形式の設定 wf.wFormatTag = WAVE_FORMAT_PCM; wf.nSamplesPerSec = FS; wf.wBitsPerSample = BITS; wf.nChannels = CHANNELS; wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8; wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; wf.cbSize = 0; //WAVEデータ出力デバイスのオープン result = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wf, (DWORD)hwnd, 0, CALLBACK_WINDOW); if (result != MMSYSERR_NOERROR) { MessageBox(hwnd, _T("音声出力装置が応答しません"), _T("エラー"), MB_OK); break; } //WAVEデータ出力デバイスの一時停止 waveOutPause(hWaveOut); //WAVEデータ出力バッファの準備 Whdr.dwUser = 0; Whdr.dwLoops = 1; Whdr.dwFlags = 0; Whdr.lpNext = 0; Whdr.dwBufferLength = FS * LENGTH * wf.nBlockAlign; if (BITS == 8) { Whdr.lpData = (LPSTR)WaveData8; } else if (BITS == 16) { Whdr.lpData = (LPSTR)WaveData16; } //WAVEデータ出力バッファの書き込み waveOutPrepareHeader(hWaveOut, &Whdr, sizeof(WAVEHDR)); waveOutWrite(hWaveOut, &Whdr, sizeof(WAVEHDR)); //WAVEデータ出力デバイスの再開 waveOutRestart(hWaveOut); break; case ID_MENU_EXIT: //プログラムの終了 DestroyWindow(hwnd); break; } break; case WM_PAINT: // WAVデータの波形表示 PAINTSTRUCT ps; RECT rc; HDC hdc; int k, i; COLORREF cRed; cRed = RGB(255, 0, 0); //WAVデータの生成 for (k = 0; k < FS * LENGTH; k++) { tmp = sin(2.0 * M_PI * (double)F0 * (double)k / (double)FS); if (BITS == 8) { WaveData8[k] = (unsigned char)(tmp * 127.0 + 128.0); } else { WaveData16[k] = (short int)(tmp * 32767.0); } } //描画の開始 GetClientRect(hwnd, &rc); //クライアント領域のサイズ取得 hdc = BeginPaint(hwnd, &ps); //原点の設定 x0 = rc.right / 20; y0 = rc.bottom / 2; //X軸の描画 MoveToEx(hdc, 0, y0, NULL); LineTo(hdc, 19 * x0, y0); //Y軸の描画 MoveToEx(hdc, x0, 0, NULL); LineTo(hdc, x0, 2 * y0); //x軸とY軸の長さを算出 len_x = 19 * x0 - x0; len_y = y0; //波形の描画 時間領域 if (BITS == 8) { for (i = 0; i < FS * LENGTH; i++) { data_x = x0 + (double)len_x * (double)i / ((double)LENGTH * (double)FS); data_y = y0 - (double)len_y * WaveData8[i] / 255.0; SetPixelV(hdc, data_x, data_y, cRed); } } if (BITS == 16) { for (i = 1; i < FS * LENGTH; i++) { data_x = x0 + (double)len_x * (double)i / ((double)LENGTH * (double)FS); data_y = y0 - (double)len_y * WaveData16[i] / 32767.0; SetPixelV(hdc, data_x, data_y, cRed); } } EndPaint(hwnd, &ps); return 0; case MM_WOM_DONE: //WAVEデータ出力バッファの処理 //WAVEデータ出力デバイスのクローズ waveOutReset(hWaveOut); waveOutUnprepareHeader(hWaveOut, &Whdr, sizeof(WAVEHDR)); waveOutClose(hWaveOut); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hwnd, message, wparam, lparam)); } return(0); }
あなたの回答
tips
プレビュー