WaveGraph
Visual C++ 2005 Express Edition
Windows Server 2003 SP1 Platform SDK
Windowsアプリケーション / 空のプロジェクト
WaveGraph.c
// マルチバイト文字セット #include
#include
#include "resource.h" #include "WaveIO.h" #define CLASS_GRAPH "Graph" // グローバル変数 static HINSTANCE g_hInstance; static HWND g_hDlgMain; static HWND g_hGraph; static HWND g_hLblDataPos; static SCROLLINFO g_siHorz; static char g_acFile[_MAX_PATH] = ""; static WaveIO g_wioSrc; static int g_iGraphY; static int* g_piWavLen = NULL; static int g_iPlayFlag = 0; static int g_iCursorX = -1; static int g_iStart; static int g_iEnd; // プロトタイプ宣言 INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); void OnFileSaveAs(HWND hWnd); void OnBtnPlay(HWND hDlg); void OnRad2(HWND hDlg); void OnDropFiles(HWND hWnd, WPARAM wParam); void OnGetMinMaxInfo(LPARAM lParam); void OnSize(HWND hDlg, WPARAM wParam); void OnInitDialog(HWND hDlg); void CenterWindow(HWND hWnd); void PlayStop(HWND hDlg); void SetFileInfo(HWND hWnd); LRESULT CALLBACK WndProcGraph(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void OnMouseMove(HWND hWnd, LPARAM lParam); void OnLButtonUp(HWND hWnd); void OnPaint(HWND hWnd); void OnHScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; g_hInstance = hInstance; if (2 <= __argc) { if (WioRead(&g_wioSrc, __argv[1]) == 0) { strcpy_s(g_acFile, sizeof(g_acFile), __argv[1]); g_iStart = 0; g_iEnd = g_wioSrc.dwSampleLength - 1; } } // Graph wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProcGraph; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = g_hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_CROSS); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = CLASS_GRAPH; wcex.hIconSm = NULL; RegisterClassEx(&wcex); DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN_DIALOG), NULL, DlgProc); if (g_wioSrc.psWaveformData) { free(g_wioSrc.psWaveformData); } if (g_piWavLen) { free(g_piWavLen); } return 0; } //////////////////////////////////////////////////////////////////////////////// INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL bRetVal = TRUE; switch (uMsg) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_FILE_SAVE_AS: OnFileSaveAs(hDlg); break; case IDC_BTN_STOP: PlayStop(hDlg); break; case IDC_BTN_PLAY: OnBtnPlay(hDlg); break; case IDC_RAD_1: case IDC_RAD_2: OnRad2(hDlg); InvalidateRect(g_hGraph, NULL, TRUE); g_iCursorX = -1; break; } break; case WM_DROPFILES: OnDropFiles(hDlg, wParam); DragFinish((HDROP)wParam); break; case WM_GETMINMAXINFO: OnGetMinMaxInfo(lParam); break; case WM_SIZE: OnSize(hDlg, wParam); break; case WM_INITDIALOG: OnInitDialog(hDlg); bRetVal = TRUE; // TRUEならデフォルトフォーカスを使用 break; case WM_CLOSE: PlayStop(hDlg); EndDialog(hDlg, IDOK); break; case MM_WOM_DONE: PlayStop(hDlg); break; default: bRetVal = FALSE; } return bRetVal; } void OnFileSaveAs(HWND hWnd) { OPENFILENAME ofn; char acPath[_MAX_PATH]; acPath[0] = '\0'; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "wave(*.wav)\0*.wav\0\0"; ofn.lpstrFile = acPath; ofn.nMaxFile = _MAX_PATH; ofn.Flags = OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = "wav"; if (GetSaveFileName(&ofn) == FALSE) { return; } WioWrite(&g_wioSrc, acPath, g_iStart, g_iEnd); } void OnBtnPlay(HWND hDlg) { if (WioPlay(&g_wioSrc, hDlg, g_iStart, g_iEnd)) { return; } g_iPlayFlag = 1; EnableWindow(GetDlgItem(hDlg, IDC_BTN_PLAY), FALSE); } void OnRad2(HWND hDlg) { double dTop; double dSum; short* psDataSrc; int iSrcLen; int iWavLenMin; int iWavLenMax; int iWavLenNum; int iOffsetSrc; int iWavLen; int iLen; int i; if (g_piWavLen) { free(g_piWavLen); g_piWavLen = NULL; } if (SendMessage(GetDlgItem(hDlg, IDC_RAD_2), BM_GETCHECK, 0, 0) == BST_UNCHECKED) { return; } iSrcLen = g_wioSrc.dwSampleLength; psDataSrc = g_wioSrc.psWaveformData; if (psDataSrc == NULL) { return; } // 波長 iWavLenMin = g_wioSrc.dwSamplesPerSec / 320; // 8KHzの場合320Hz->25 iWavLenMax = g_wioSrc.dwSamplesPerSec / 80; // 8KHzの場合80Hz->100 if (iSrcLen < iWavLenMax * 2) { return; } iWavLenNum = 2 + (iSrcLen - iWavLenMax * 2) / (iWavLenMin * 2); g_piWavLen = malloc(iWavLenNum * sizeof(int)); if (g_piWavLen == NULL) { return; } // 自己相関により波長を求める iWavLenNum = 0; iOffsetSrc = 0; while (iOffsetSrc + iWavLenMax * 2 <= iSrcLen) { iWavLen = 0; for (iLen = iWavLenMin; iLen <= iWavLenMax; iLen++) { dSum = 0.0; for (i = 0; i < iLen; i++) { dSum += psDataSrc[iOffsetSrc + i] * psDataSrc[iOffsetSrc + iLen + i]; } dSum = dSum / iLen; if (iWavLen == 0 || dTop < dSum) { iWavLen = iLen; dTop = dSum; } } g_piWavLen[iWavLenNum++] = iWavLen; iOffsetSrc += iWavLen * 2; } g_piWavLen[iWavLenNum] = 0; // 波長=0(終端) } void OnDropFiles(HWND hWnd, WPARAM wParam) { HDROP hDrop; char acFile[_MAX_PATH]; hDrop = (HDROP)wParam; DragQueryFile(hDrop, 0, acFile, _MAX_PATH); g_acFile[0] = '\0'; if (WioRead(&g_wioSrc, acFile) == 0) { strcpy_s(g_acFile, sizeof(g_acFile), acFile); g_iStart = 0; g_iEnd = g_wioSrc.dwSampleLength - 1; } g_siHorz.nPos = 0; SetFileInfo(hWnd); OnRad2(hWnd); InvalidateRect(g_hGraph, NULL, TRUE); g_iCursorX = -1; } void OnGetMinMaxInfo(LPARAM lParam) { MINMAXINFO *pmmi; pmmi = (MINMAXINFO*)lParam; pmmi->ptMinTrackSize.x = 480; pmmi->ptMinTrackSize.y = 240; } void OnSize(HWND hDlg, WPARAM wParam) { RECT rc; int iWidth; int iHeight; if (wParam == SIZE_MINIMIZED) { return; } GetClientRect(hDlg, &rc); iWidth = rc.right - 8; iHeight = rc.bottom - (g_iGraphY + 4); MoveWindow(g_hGraph, 4, g_iGraphY, iWidth, iHeight, TRUE); g_siHorz.nPage = iWidth; SetScrollInfo(g_hGraph, SB_HORZ, &g_siHorz, TRUE); } void OnInitDialog(HWND hDlg) { RECT rc; int iDluY; g_hDlgMain = hDlg; g_hLblDataPos = GetDlgItem(hDlg, IDC_LBL_DATAPOS); // 中央 CenterWindow(hDlg); // DLU rc.top = 8; MapDialogRect(hDlg, &rc); iDluY = rc.top; g_iGraphY = (64 * iDluY) / 8; g_hGraph = CreateWindow(CLASS_GRAPH, NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL, 0, 0, 0, 0, hDlg, NULL, g_hInstance, NULL); // スクロールバー g_siHorz.cbSize = sizeof(SCROLLINFO); g_siHorz.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL; g_siHorz.nMin = 0; g_siHorz.nPos = 0; OnSize(hDlg, 0); SetFileInfo(hDlg); } void CenterWindow(HWND hWnd) { RECT rcParent; RECT rcThis; int iWidth; int iHeight; GetWindowRect(GetDesktopWindow(), &rcParent); GetWindowRect(hWnd, &rcThis); iWidth = rcThis.right - rcThis.left; iHeight = rcThis.bottom - rcThis.top; MoveWindow(hWnd, (rcParent.right - iWidth) / 2, (rcParent.bottom - iHeight) / 2, iWidth, iHeight, FALSE); } void PlayStop(HWND hDlg) { if (g_iPlayFlag) { WioStop(&g_wioSrc); g_iPlayFlag = 0; } EnableWindow(GetDlgItem(hDlg, IDC_BTN_PLAY), TRUE); } void SetFileInfo(HWND hWnd) { char acFname[_MAX_FNAME]; char acExt[_MAX_EXT]; char acBuf[512]; // タイトルバー if (g_acFile[0]) { _splitpath_s(g_acFile, NULL, 0, NULL, 0, acFname, _MAX_FNAME, acExt, _MAX_EXT); strcpy_s(acBuf, sizeof(acBuf), acFname); strcat_s(acBuf, sizeof(acBuf), acExt); } else { strcpy_s(acBuf, sizeof(acBuf), "無題"); } strcat_s(acBuf, sizeof(acBuf), " - WaveGraph"); SetWindowText(hWnd, acBuf); // スクロールバー g_siHorz.nMax = g_wioSrc.dwSampleLength - 1; SetScrollInfo(g_hGraph, SB_HORZ, &g_siHorz, TRUE); // ファイル情報 if (g_wioSrc.dwSampleLength) { sprintf_s(acBuf, sizeof(acBuf), "Bit:%u Ch:%u Rate:%u", g_wioSrc.wBitsPerSample, g_wioSrc.wChannels, g_wioSrc.dwSamplesPerSec); } else { acBuf[0] = '\0'; } SetWindowText(GetDlgItem(hWnd, IDC_LBL_FILEINFO), acBuf); } //////////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK WndProcGraph(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_MOUSEMOVE: OnMouseMove(hWnd, lParam); break; case WM_LBUTTONUP: OnLButtonUp(hWnd); break; case WM_PAINT: OnPaint(hWnd); break; case WM_HSCROLL: OnHScroll(hWnd, wParam, lParam); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } void OnMouseMove(HWND hWnd, LPARAM lParam) { HDC hdc; RECT rc; POINT pt; char acBuf[32]; int iDrawMode; int iDataPos; hdc = GetDC(hWnd); iDrawMode = SetROP2(hdc, R2_NOT); GetClientRect(hWnd, &rc); if (0 <= g_iCursorX) { MoveToEx(hdc, g_iCursorX, 0, NULL); LineTo(hdc, g_iCursorX, rc.bottom); } else { SetCapture(hWnd); } acBuf[0] = '\0'; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); if (PtInRect(&rc, pt)) { g_iCursorX = pt.x; MoveToEx(hdc, g_iCursorX, 0, NULL); LineTo(hdc, g_iCursorX, rc.bottom); iDataPos = g_siHorz.nPos + pt.x; if (iDataPos < (int)g_wioSrc.dwSampleLength) { sprintf_s(acBuf, sizeof(acBuf), "%d / %u", iDataPos, g_wioSrc.dwSampleLength); } } else { g_iCursorX = -1; ReleaseCapture(); } SetROP2(hdc, iDrawMode); ReleaseDC(hWnd, hdc); // データ位置 SetWindowText(g_hLblDataPos, acBuf); } void OnLButtonUp(HWND hWnd) { double dSec; char acBuf[32]; int iDataPos; int iCtrlID; iDataPos = g_siHorz.nPos + g_iCursorX; if (iDataPos < 0 || (int)g_wioSrc.dwSampleLength <= iDataPos) { return; } iCtrlID = GetDlgCtrlID(GetFocus()); switch (iCtrlID) { case IDC_EDT_START: g_iStart = iDataPos; if (g_iEnd < g_iStart) { g_iEnd = g_iStart; } break; case IDC_EDT_END: g_iEnd = iDataPos; if (g_iEnd < g_iStart) { g_iStart = g_iEnd; } break; default: return; } // Start dSec = (double)g_iStart / g_wioSrc.dwSamplesPerSec; sprintf_s(acBuf, sizeof(acBuf), "%.3fs", dSec); SetDlgItemInt(g_hDlgMain, IDC_EDT_START, g_iStart, FALSE); SetDlgItemText(g_hDlgMain, IDC_LBL_START, acBuf); // End dSec = (double)g_iEnd / g_wioSrc.dwSamplesPerSec; sprintf_s(acBuf, sizeof(acBuf), "%.3fs", dSec); SetDlgItemInt(g_hDlgMain, IDC_EDT_END, g_iEnd, FALSE); SetDlgItemText(g_hDlgMain, IDC_LBL_END, acBuf); InvalidateRect(hWnd, NULL, TRUE); g_iCursorX = -1; } void OnPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; RECT rcClient; HPEN hpenBlack; HPEN hpenOld; HPEN ahpen[2]; HPEN hpen; int iCenterLineY; int iBottom; int iCenterY; int iOffset; int iData; int iX; int iIndex; int i; // 描画開始 hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rcClient); iCenterLineY = rcClient.bottom / 2; // 背景 hpen = CreatePen(PS_SOLID, 1, RGB(0xC0, 0xC0, 0xC0)); hpenOld = (HPEN)SelectObject(hdc, hpen); for (i = ps.rcPaint.left; i < ps.rcPaint.right; i++) { iIndex = g_siHorz.nPos + i; if ((int)g_wioSrc.dwSampleLength <= iIndex) { break; } if (iIndex < g_iStart || g_iEnd < iIndex) { MoveToEx(hdc, i, 0, NULL); LineTo(hdc, i, rcClient.bottom); } } SelectObject(hdc, hpenOld); DeleteObject(hpen); // 上下分割線 hpenBlack = (HPEN)GetStockObject(BLACK_PEN); SelectObject(hdc, hpenBlack); MoveToEx(hdc, ps.rcPaint.left, iCenterLineY, NULL); LineTo(hdc, ps.rcPaint.right, iCenterLineY); iBottom = iCenterLineY - 1; iCenterY = iBottom - iCenterLineY / 2; // 波長 if (g_piWavLen) { ahpen[0] = CreatePen(PS_DASH, 1, RGB(0xFF, 0x00, 0x00)); ahpen[1] = CreatePen(PS_SOLID, 1, RGB(0xFF, 0x00, 0x00)); iOffset = 0; for (iIndex = 0; g_piWavLen[iIndex]; iIndex++) { for (i = 0; i < 2; i++) { iOffset += g_piWavLen[iIndex]; iX = iOffset - g_siHorz.nPos - 1; if (iX < ps.rcPaint.left || ps.rcPaint.right <= iX) { continue; } SelectObject(hdc, ahpen[i]); MoveToEx(hdc, iX, 0, NULL); LineTo(hdc, iX, iCenterLineY); } } SelectObject(hdc, hpenOld); DeleteObject(ahpen[0]); DeleteObject(ahpen[1]); } // 波形データ hpen = CreatePen(PS_SOLID, 1, RGB(0x00, 0x00, 0xFF)); SelectObject(hdc, hpen); for (i = ps.rcPaint.left; i < ps.rcPaint.right; i++) { iIndex = g_siHorz.nPos + i; if ((int)g_wioSrc.dwSampleLength <= iIndex) { break; } iData = 32768 + g_wioSrc.psWaveformData[iIndex]; // 0-65535 MoveToEx(hdc, i, iBottom - iData * iCenterLineY / 65536, NULL); LineTo(hdc, i, iCenterY); } SelectObject(hdc, hpenOld); DeleteObject(hpen); // 描画終了 EndPaint(hWnd, &ps); } void OnHScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { SCROLLINFO si; int iPos; int iPosMax; iPos = g_siHorz.nPos; switch (LOWORD(wParam)) { case SB_LINEUP: iPos -= 10; break; case SB_LINEDOWN: iPos += 10; break; case SB_PAGEUP: iPos -= g_siHorz.nPage; break; case SB_PAGEDOWN: iPos += g_siHorz.nPage; break; case SB_THUMBTRACK: si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_TRACKPOS; if (GetScrollInfo(hWnd, SB_HORZ, &si) != 0) { iPos = si.nTrackPos; } break; } iPosMax = g_siHorz.nMax - g_siHorz.nPage + 1; if (iPosMax < iPos) { iPos = iPosMax; } if (iPos < 0) { iPos = 0; } if (iPos == g_siHorz.nPos) { return; } ScrollWindowEx(hWnd, g_siHorz.nPos - iPos, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE | SW_ERASE); g_siHorz.nPos = iPos; SetScrollInfo(hWnd, SB_HORZ, &g_siHorz, TRUE); UpdateWindow(hWnd); }
resource.h
#define IDC_STATIC (-1) #define IDD_MAIN_DIALOG 100 #define IDC_APP 101 #define IDM_FILE_SAVE_AS 102 #define IDM_EXIT 103 #define IDC_LBL_FILEINFO 1000 #define IDC_BTN_STOP 1001 #define IDC_BTN_PLAY 1002 #define IDC_RAD_1 1003 #define IDC_RAD_2 1004 #define IDC_LBL_DATAPOS 1005 #define IDC_EDT_START 1006 #define IDC_LBL_START 1007 #define IDC_EDT_END 1008 #define IDC_LBL_END 1009
WaveGraph.rc
#include
#include
#include "resource.h" IDC_APP MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "名前を付けて保存(&A)...",IDM_FILE_SAVE_AS MENUITEM SEPARATOR MENUITEM "アプリケーションの終了(&X)",IDM_EXIT END END IDD_MAIN_DIALOG DIALOGEX 0, 0, 320, 240 STYLE WS_POPUPWINDOW | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX EXSTYLE WS_EX_APPWINDOW CAPTION "" FONT 9, "MS Pゴシック" BEGIN LTEXT "",IDC_LBL_FILEINFO,4,4,92,8 PUSHBUTTON "■",IDC_BTN_STOP,4,16,24,16 PUSHBUTTON "▲",IDC_BTN_PLAY,32,16,24,16 CONTROL "通常",IDC_RAD_1,WC_BUTTON,BS_AUTORADIOBUTTON | WS_GROUP, 4,36,32,12 CONTROL "波長",IDC_RAD_2,WC_BUTTON,BS_AUTORADIOBUTTON,40,36,32,12 LTEXT "",IDC_LBL_DATAPOS,4,52,100,8,WS_GROUP LTEXT "Start:",IDC_STATIC,100,4,20,8 EDITTEXT IDC_EDT_START,124,4,40,12 LTEXT "",IDC_LBL_START,168,4,40,8 LTEXT "End:",IDC_STATIC,100,20,20,8 EDITTEXT IDC_EDT_END,124,20,40,12 LTEXT "",IDC_LBL_END,168,20,40,8 END
WaveIO.h
typedef struct tagWaveIO { WORD wBitsPerSample; WORD wChannels; DWORD dwSamplesPerSec; // サンプリングレート DWORD dwSampleLength; short* psWaveformData; } WaveIO; // プロトタイプ宣言 int WioRead(WaveIO* pwio, const char* pcFile); int WioWrite(const WaveIO* pwio, const char* pcFile, int iStart, int iEnd); int WioPlay(const WaveIO* pwio, HWND hWnd, int iStart, int iEnd); int WioStop(const WaveIO* pwio);
WaveIO.c
// winmm.lib #include
#include
#include "WaveIO.h" // グローバル変数 static HWAVEOUT g_hwo; static WAVEHDR g_wh; // プロトタイプ宣言 int GetDataLen(const WaveIO* pwio, int iStart, int iEnd); int WioRead(WaveIO* pwio, const char* pcFile) { WAVEFORMATEX wfx; MMCKINFO ckParent; MMCKINFO ckSub; MMRESULT mmr; HMMIO hmmio; long lRead; DWORD dwData; void* pvData; short* psData; u_char* pucData; int i; // クリア pwio->dwSampleLength = 0; if (pwio->psWaveformData) { free(pwio->psWaveformData); pwio->psWaveformData = NULL; } // Open hmmio = mmioOpen((LPSTR)pcFile, NULL, MMIO_READ); if (hmmio == NULL) { return -1; } // RIFF ckParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); mmr = mmioDescend(hmmio, &ckParent, NULL, MMIO_FINDRIFF); if (mmr != MMSYSERR_NOERROR) { return -2; } // fmt ckSub.ckid = mmioFOURCC('f', 'm', 't', ' '); mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK); if (mmr != MMSYSERR_NOERROR) { return -3; } lRead = mmioRead(hmmio, (HPSTR)&wfx, 16); if (lRead != 16) { return -4; } mmioAscend(hmmio, &ckSub, 0); // data ckSub.ckid = mmioFOURCC('d', 'a', 't', 'a'); mmr = mmioDescend(hmmio, &ckSub, &ckParent, MMIO_FINDCHUNK); if (mmr != MMSYSERR_NOERROR) { return -5; } dwData = ckSub.cksize; pvData = malloc(dwData); if (pvData == NULL) { return -6; } lRead = mmioRead(hmmio, pvData, dwData); if (lRead != (long)dwData) { return -7; } mmioAscend(hmmio, &ckSub, 0); // RIFF mmioAscend(hmmio, &ckParent, 0); // Close mmioClose(hmmio, 0); pwio->wChannels = wfx.nChannels; pwio->dwSamplesPerSec = wfx.nSamplesPerSec; pwio->dwSampleLength = dwData; pwio->wBitsPerSample = wfx.wBitsPerSample; if (pwio->wBitsPerSample == 8) { // 1サンプルあたりビット数を16に変換 psData = malloc(dwData * sizeof(short)); if (psData == NULL) { return -8; } pucData = pvData; for (i = 0; i < (int)dwData; i++) { psData[i] = (pucData[i] - 128) * 256; } free(pvData); pwio->psWaveformData = psData; } else { pwio->psWaveformData = pvData; } return 0; } int WioWrite(const WaveIO* pwio, const char* pcFile, int iStart, int iEnd) { WAVEFORMATEX wfx; MMCKINFO ckParent; MMCKINFO ckSub; HMMIO hmmio; DWORD dwData; u_char* pucData; short* psData; int iDataLen; int i; iDataLen = GetDataLen(pwio, iStart, iEnd); if (iDataLen <= 0) { return -1; } // Open hmmio = mmioOpen((LPSTR)pcFile, NULL, MMIO_WRITE | MMIO_CREATE); if (hmmio == NULL) { return -2; } // RIFF ckParent.cksize = 0; // ダミー ckParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); mmioCreateChunk(hmmio, &ckParent, MMIO_CREATERIFF); // fmt ckSub.ckid = mmioFOURCC('f', 'm', 't', ' '); ckSub.cksize = sizeof(WAVEFORMATEX); mmioCreateChunk(hmmio, &ckSub, 0); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wBitsPerSample = pwio->wBitsPerSample; wfx.nChannels = pwio->wChannels; wfx.nSamplesPerSec = pwio->dwSamplesPerSec; wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; wfx.cbSize = 0; mmioWrite(hmmio, (char *)&wfx, sizeof(WAVEFORMATEX)); mmioAscend(hmmio, &ckSub, 0); // fact ckSub.ckid = mmioFOURCC('f', 'a', 'c', 't'); ckSub.cksize = sizeof(DWORD); mmioCreateChunk(hmmio, &ckSub, 0); mmioWrite(hmmio, (char *)&(pwio->dwSampleLength), sizeof(DWORD)); mmioAscend(hmmio, &ckSub, 0); // data ckSub.ckid = mmioFOURCC('d', 'a', 't', 'a'); ckSub.cksize = 0; // ダミー mmioCreateChunk(hmmio, &ckSub, 0); if (pwio->wBitsPerSample == 8) { // 1サンプルあたりビット数を8に変換 dwData = iDataLen * sizeof(u_char); pucData = malloc(dwData); if (pucData == NULL) { return -3; } psData = pwio->psWaveformData; for (i = 0; i < (int)dwData; i++) { pucData[i] = (32768 + psData[iStart + i]) / 256; } mmioWrite(hmmio, pucData, dwData); free(pucData); } else { dwData = iDataLen * sizeof(short); psData = pwio->psWaveformData; mmioWrite(hmmio, (char *)(psData + iStart), dwData); } mmioAscend(hmmio, &ckSub, 0); // RIFF mmioAscend(hmmio, &ckParent, 0); // Close mmioFlush(hmmio, 0); mmioClose(hmmio, 0); return 0; } int WioPlay(const WaveIO* pwio, HWND hWnd, int iStart, int iEnd) { WAVEFORMATEX wfx; MMRESULT mmr; int iDataLen; iDataLen = GetDataLen(pwio, iStart, iEnd); if (iDataLen <= 0) { return -1; } wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wBitsPerSample = 16; // 固定 wfx.nChannels = pwio->wChannels; wfx.nSamplesPerSec = pwio->dwSamplesPerSec; wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; wfx.cbSize = 0; if (hWnd) { mmr = waveOutOpen(&g_hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)hWnd, 0, CALLBACK_WINDOW); } else { mmr = waveOutOpen(&g_hwo, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL); } if (mmr != MMSYSERR_NOERROR) { return -2; } memset(&g_wh, 0, sizeof(WAVEHDR)); g_wh.lpData = (LPSTR)(pwio->psWaveformData) + iStart * wfx.nBlockAlign; g_wh.dwBufferLength = iDataLen * wfx.nBlockAlign; mmr = waveOutPrepareHeader(g_hwo, &g_wh, sizeof(WAVEHDR)); if (mmr != MMSYSERR_NOERROR) { return -3; } mmr = waveOutWrite(g_hwo, &g_wh, sizeof(WAVEHDR)); if (mmr != MMSYSERR_NOERROR) { return -4; } return 0; } int WioStop(const WaveIO* pwio) { MMRESULT mmr; mmr = waveOutReset(g_hwo); if (mmr != MMSYSERR_NOERROR) { return -1; } mmr = waveOutUnprepareHeader(g_hwo, &g_wh, sizeof(WAVEHDR)); if (mmr != MMSYSERR_NOERROR) { return -2; } mmr = waveOutClose(g_hwo); if (mmr != MMSYSERR_NOERROR) { return -3; } return 0; } int GetDataLen(const WaveIO* pwio, int iStart, int iEnd) { // 範囲チェック if (iStart < 0 || (int)pwio->dwSampleLength <= iStart) { return 0; } if (iEnd < 0 || (int)pwio->dwSampleLength <= iEnd) { return 0; } return iEnd - iStart + 1; }