|
|
1.1 ! root 1: /* midimon.c - WinMain() and WndProc() functions for MIDIMon, along ! 2: * with some initialization and error reporting functions. ! 3: * ! 4: * MIDIMon is a Windows with Multimedia application that records and displays ! 5: * incoming MIDI information. It uses a low-level callback function to ! 6: * get timestamped MIDI input. The callback function puts the incoming ! 7: * MIDI event information (source device, timestamp, and raw MIDI ! 8: * data) in a circular input buffer and notifies the application by posting ! 9: * a MM_MIDIINPUT message. When the application processes the MM_MIDIINPUT ! 10: * message, it removes the MIDI event from the input buffer and puts it in ! 11: * a display buffer. Information in the display buffer is converted to ! 12: * text and displayed in a scrollable window. Incoming MIDI data can be sent ! 13: * to the MIDI Mapper if the user chooses. Filtering is provided for the ! 14: * display buffer, but not for data sent to the Mapper. ! 15: * ! 16: * (C) Copyright Microsoft Corp. 1991. All rights reserved. ! 17: * ! 18: * You have a royalty-free right to use, modify, reproduce and ! 19: * distribute the Sample Files (and/or any modified version) in ! 20: * any way you find useful, provided that you agree that ! 21: * Microsoft has no warranty obligations or liability for any ! 22: * Sample Application Files which are modified. ! 23: * ! 24: */ ! 25: ! 26: #include <windows.h> ! 27: #include <mmsystem.h> ! 28: #include <stdio.h> ! 29: #include "midimon.h" ! 30: #include "about.h" ! 31: #include "circbuf.h" ! 32: #include "display.h" ! 33: #include "prefer.h" ! 34: #include "instdata.h" ! 35: #include "callback.h" ! 36: #include "filter.h" ! 37: ! 38: HANDLE hInst; // Instance handle for application ! 39: char szAppName[20]; // Application name ! 40: HWND hMainWnd; // Main window handle ! 41: HMIDIOUT hMapper = 0; // Handle to MIDI Mapper ! 42: UINT wNumDevices = 0; // Number of MIDI input devices opened ! 43: BOOL bRecordingEnabled = 1; // Enable/disable recording flag ! 44: LONG nNumBufferLines = 0; // Number of lines in display buffer ! 45: RECT rectScrollClip; // Clipping rectangle for scrolling ! 46: ! 47: LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure ! 48: LPDISPLAYBUFFER lpDisplayBuffer; // Display buffer structure ! 49: PREFERENCES preferences; // User preferences structure ! 50: EVENT incomingEvent; // Incoming MIDI event structure ! 51: ! 52: MIDIINCAPS midiInCaps[MAX_NUM_DEVICES]; // Device capabilities structures ! 53: HMIDIIN hMidiIn[MAX_NUM_DEVICES]; // MIDI input device handles ! 54: ! 55: // Callback instance data pointers ! 56: LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAX_NUM_DEVICES]; ! 57: ! 58: // Display filter structure ! 59: FILTER filter = { ! 60: 0, 0, 0, 0, 0, 0, 0, 0, ! 61: 0, 0, 0, 0, 0, 0, 0, 0, ! 62: 0, 0, 0, 0, 0, 0, 0, 0, ! 63: 0, 0, 0, 0, 0, 0, 0, 0 ! 64: }; ! 65: ! 66: // Virtual key to scroll message translation structure ! 67: KEYTOSCROLL keyToScroll [] = { ! 68: VK_HOME, WM_VSCROLL, SB_TOP, ! 69: VK_END, WM_VSCROLL, SB_BOTTOM, ! 70: VK_PRIOR, WM_VSCROLL, SB_PAGEUP, ! 71: VK_NEXT, WM_VSCROLL, SB_PAGEDOWN, ! 72: VK_UP, WM_VSCROLL, SB_LINEUP, ! 73: VK_DOWN, WM_VSCROLL, SB_LINEDOWN, ! 74: VK_LEFT, WM_HSCROLL, SB_LINEUP, ! 75: VK_RIGHT, WM_HSCROLL, SB_LINEDOWN ! 76: }; ! 77: ! 78: #define NUMKEYS (sizeof (keyToScroll) / sizeof (keyToScroll[0])) ! 79: ! 80: ! 81: // ! 82: /* WinMain - Entry point for MIDIMon. ! 83: */ ! 84: int PASCAL WinMain(hInstance,hPrevInstance,lpszCmdLine,cmdShow) ! 85: HANDLE hInstance,hPrevInstance; ! 86: LPSTR lpszCmdLine; ! 87: int cmdShow; ! 88: { ! 89: MSG msg; ! 90: UINT wRtn; ! 91: PREFERENCES preferences; ! 92: char szErrorText[256]; ! 93: unsigned int i; ! 94: ! 95: UNREFERENCED_PARAMETER(lpszCmdLine); ! 96: ! 97: hInst = hInstance; ! 98: ! 99: /* Get preferred user setup. ! 100: */ ! 101: getPreferences(&preferences); ! 102: ! 103: /* Initialize application. ! 104: */ ! 105: LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName)); ! 106: if (hPrevInstance || !InitFirstInstance(hInstance)) ! 107: return 0; ! 108: ! 109: /* Create a display window. ! 110: */ ! 111: hMainWnd = CreateWindow(szAppName, ! 112: szAppName, ! 113: WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, ! 114: preferences.iInitialX, ! 115: preferences.iInitialY, ! 116: preferences.iInitialW, ! 117: preferences.iInitialH, ! 118: (HWND)NULL, ! 119: (HMENU)NULL, ! 120: hInstance, ! 121: (LPSTR)NULL); ! 122: ! 123: if (!hMainWnd) ! 124: return 1; ! 125: ! 126: /* Hide scroll bars for now. ! 127: */ ! 128: SetScrollRange(hMainWnd, SB_VERT, 0, 0, FALSE); ! 129: SetScrollRange(hMainWnd, SB_HORZ, 0, 0, FALSE); ! 130: ! 131: /* Show the display window. ! 132: */ ! 133: ShowWindow(hMainWnd, cmdShow); ! 134: UpdateWindow(hMainWnd); ! 135: ! 136: /* Get the number of MIDI input devices. Then get the capabilities of ! 137: * each device. We don't use the capabilities information right now, ! 138: * but we could use it to report the name of the device that received ! 139: * each MIDI event. ! 140: */ ! 141: wNumDevices = midiInGetNumDevs(); ! 142: if (!wNumDevices) { ! 143: Error("There are no MIDI input devices."); ! 144: PostQuitMessage(0); ! 145: } ! 146: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) { ! 147: wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &midiInCaps[i], ! 148: sizeof(MIDIINCAPS)); ! 149: if(wRtn) { ! 150: midiInGetErrorText(wRtn, (LPSTR)szErrorText, ! 151: sizeof(szErrorText)); ! 152: Error(szErrorText); ! 153: } ! 154: } ! 155: ! 156: /* Allocate a circular buffer for low-level MIDI input. This buffer ! 157: * is filled by the low-level callback function and emptied by the ! 158: * application when it receives MM_MIDIINPUT messages. ! 159: */ ! 160: lpInputBuffer = AllocCircularBuffer( ! 161: (DWORD)(INPUT_BUFFER_SIZE * sizeof(EVENT))); ! 162: if (lpInputBuffer == NULL) { ! 163: Error("Not enough memory available for input buffer."); ! 164: return 1; ! 165: } ! 166: ! 167: /* Allocate a display buffer. Incoming events from the circular input ! 168: * buffer are put into this buffer for display. ! 169: */ ! 170: lpDisplayBuffer = AllocDisplayBuffer((DWORD)(DISPLAY_BUFFER_SIZE)); ! 171: if (lpDisplayBuffer == NULL) { ! 172: Error("Not enough memory available for display buffer."); ! 173: FreeCircularBuffer(lpInputBuffer); ! 174: return 1; ! 175: } ! 176: ! 177: /* Open all MIDI input devices after allocating and setting up ! 178: * instance data for each device. The instance data is used to ! 179: * pass buffer management information between the application and ! 180: * the low-level callback function. It also includes a device ID, ! 181: * a handle to the MIDI Mapper, and a handle to the application's ! 182: * display window, so the callback can notify the window when input ! 183: * data is available. A single callback function is used to service ! 184: * all opened input devices. ! 185: */ ! 186: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) ! 187: { ! 188: if ((lpCallbackInstanceData[i] = AllocCallbackInstanceData()) == NULL) ! 189: { ! 190: Error("Not enough memory available."); ! 191: FreeCircularBuffer(lpInputBuffer); ! 192: FreeDisplayBuffer(lpDisplayBuffer); ! 193: return 1; ! 194: } ! 195: lpCallbackInstanceData[i]->hWnd = hMainWnd; ! 196: lpCallbackInstanceData[i]->dwDevice = i; ! 197: lpCallbackInstanceData[i]->lpBuf = lpInputBuffer; ! 198: lpCallbackInstanceData[i]->hMapper = hMapper; ! 199: ! 200: wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[i], ! 201: i, ! 202: (DWORD)midiInputHandler, ! 203: (DWORD)lpCallbackInstanceData[i], ! 204: CALLBACK_FUNCTION); ! 205: if(wRtn) ! 206: { ! 207: FreeCallbackInstanceData(lpCallbackInstanceData[i]); ! 208: midiInGetErrorText(wRtn, (LPSTR)szErrorText, sizeof(szErrorText)); ! 209: Error(szErrorText); ! 210: } ! 211: } ! 212: ! 213: /* Start MIDI input. ! 214: */ ! 215: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) { ! 216: if (hMidiIn[i]) ! 217: midiInStart(hMidiIn[i]); ! 218: } ! 219: ! 220: /* Standard Windows message processing loop. We don't drop out of ! 221: * this loop until the user quits the application. ! 222: */ ! 223: while (GetMessage(&msg, NULL, 0, 0)) { ! 224: TranslateMessage(&msg); ! 225: DispatchMessage(&msg); ! 226: } ! 227: ! 228: /* Stop, reset, close MIDI input. Free callback instance data. ! 229: */ ! 230: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) { ! 231: if (hMidiIn[i]) { ! 232: midiInStop(hMidiIn[i]); ! 233: midiInReset(hMidiIn[i]); ! 234: midiInClose(hMidiIn[i]); ! 235: FreeCallbackInstanceData(lpCallbackInstanceData[i]); ! 236: } ! 237: } ! 238: ! 239: /* Close the MIDI Mapper, if it's open. ! 240: */ ! 241: if (hMapper) ! 242: midiOutClose(hMapper); ! 243: ! 244: /* Free input and display buffers. ! 245: */ ! 246: FreeCircularBuffer(lpInputBuffer); ! 247: FreeDisplayBuffer(lpDisplayBuffer); ! 248: ! 249: return (msg.wParam); ! 250: } ! 251: ! 252: // ! 253: /* WndProc - Main window procedure function. ! 254: */ ! 255: LRESULT FAR PASCAL WndProc( ! 256: HWND hWnd, ! 257: UINT message, ! 258: WPARAM wParam, ! 259: LPARAM lParam) ! 260: { ! 261: PAINTSTRUCT ps; ! 262: HFONT hFont; ! 263: HBRUSH hBrush; ! 264: //!! HPEN hPen; ! 265: HDC hDC; ! 266: TEXTMETRIC tm; ! 267: static BOOL bWindowCreated = 0; ! 268: static LONG wChar, hChar; ! 269: static LONG maxClientWidth; ! 270: static LONG wClient, hClient; ! 271: static LONG nVscrollMax = 0; ! 272: static LONG nHscrollMax = 0; ! 273: static LONG nVscrollPos = 0; ! 274: static LONG nHscrollPos = 0; ! 275: static LONG nNumCharsPerLine = 0; ! 276: static LONG nNumDisplayLines = 0; ! 277: static LONG nNumDisplayChars = 0; ! 278: BOOL bNeedToUpdate = FALSE; ! 279: LONG nVscrollInc, nHscrollInc; ! 280: LONG nPaintBeg, nPaintEnd; ! 281: LONG i; ! 282: SIZE size; ! 283: ! 284: char szDisplayTextBuffer[120]; ! 285: ! 286: switch(message) ! 287: { ! 288: case WM_CREATE: ! 289: hDC = GetDC(hWnd); ! 290: ! 291: /* Set the font we want to use. ! 292: */ ! 293: hFont = GetStockObject(ANSI_FIXED_FONT); ! 294: SelectObject(hDC, hFont); ! 295: ! 296: /* Get text metrics and calculate the number of characters ! 297: * per line and the maximum width required for the client area. ! 298: */ ! 299: GetTextMetrics(hDC, &tm); ! 300: wChar = (LONG) tm.tmAveCharWidth; ! 301: hChar = (LONG) (tm.tmHeight + tm.tmExternalLeading); ! 302: nNumCharsPerLine = sizeof(LABEL) - 1; ! 303: ! 304: GetTextExtentPoint(hDC, ! 305: szDisplayTextBuffer, ! 306: sprintf(szDisplayTextBuffer, LABEL), ! 307: &size); ! 308: maxClientWidth = size.cx; ! 309: ! 310: ReleaseDC(hWnd, hDC); ! 311: ! 312: bWindowCreated = 1; ! 313: break; ! 314: ! 315: case WM_SIZE: ! 316: hClient = (LONG) HIWORD(lParam); ! 317: wClient = (LONG) LOWORD(lParam); ! 318: ! 319: /* Get new client area and adjust scroll clip rectangle. ! 320: */ ! 321: GetClientRect(hWnd, (LPRECT)&rectScrollClip); ! 322: rectScrollClip.top += hChar; ! 323: ! 324: /* Calculate new display metrics. We subtract 1 from ! 325: * nNumDisplayLines to allow room for the label line. ! 326: */ ! 327: nNumDisplayLines = hClient / hChar - 1; ! 328: nNumDisplayChars = wClient / wChar; ! 329: ! 330: /* Calculate and set new scroll bar calibrations. ! 331: */ ! 332: nVscrollMax = (LONG) max(0, nNumBufferLines - nNumDisplayLines); ! 333: nVscrollPos = (LONG) min(nVscrollPos, nVscrollMax); ! 334: nHscrollMax = (LONG) max(0, nNumCharsPerLine - nNumDisplayChars); ! 335: nHscrollPos = (LONG) min(nHscrollPos, nHscrollMax); ! 336: SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE); ! 337: SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE); ! 338: SetScrollRange(hWnd, SB_HORZ, 0, nHscrollMax, FALSE); ! 339: SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE); ! 340: break; ! 341: ! 342: case WM_GETMINMAXINFO: ! 343: /* Limit the maximum width of the window. ! 344: */ ! 345: if(bWindowCreated) { ! 346: ((LPPOINT)lParam)[4].x = maxClientWidth + ! 347: (2 * GetSystemMetrics(SM_CXFRAME)) + ! 348: (GetSystemMetrics(SM_CXVSCROLL)); ! 349: } ! 350: ! 351: // *((LPWORD)lParam + 8) = maxClientWidth + ! 352: // (2 * GetSystemMetrics(SM_CXFRAME)) + ! 353: // (GetSystemMetrics(SM_CXVSCROLL)); ! 354: break; ! 355: ! 356: case WM_COMMAND: ! 357: /* Process menu messages. ! 358: */ ! 359: CommandMsg(hWnd, wParam, lParam); ! 360: break; ! 361: ! 362: case WM_VSCROLL: ! 363: /* Determine how much to scroll vertically. ! 364: */ ! 365: switch (LOWORD(wParam)) ! 366: { ! 367: case SB_TOP: ! 368: nVscrollInc = -nVscrollPos; ! 369: break; ! 370: ! 371: case SB_BOTTOM: ! 372: nVscrollInc = nVscrollMax - nVscrollPos; ! 373: break; ! 374: ! 375: case SB_LINEUP: ! 376: nVscrollInc = -1; ! 377: break; ! 378: ! 379: case SB_LINEDOWN: ! 380: nVscrollInc = 1; ! 381: break; ! 382: ! 383: case SB_PAGEUP: ! 384: nVscrollInc = min (-1, -nNumDisplayLines); ! 385: break; ! 386: ! 387: case SB_PAGEDOWN: ! 388: nVscrollInc = (LONG) max(1, nNumDisplayLines); ! 389: break; ! 390: ! 391: case SB_THUMBTRACK: ! 392: nVscrollInc = ((LONG)HIWORD(wParam) - nVscrollPos); ! 393: break; ! 394: ! 395: default: ! 396: nVscrollInc = 0; ! 397: ! 398: } ! 399: ! 400: /* Limit the scroll range and do the scroll. We use the ! 401: * rectScrollClip rectangle because we don't want to scroll ! 402: * the entire window, only the part below the display label line. ! 403: */ ! 404: if(nVscrollInc = max(-nVscrollPos, ! 405: min(nVscrollInc, ! 406: nVscrollMax - nVscrollPos))) ! 407: { ! 408: nVscrollPos += nVscrollInc; ! 409: ScrollWindow(hWnd, 0, -hChar * nVscrollInc, ! 410: (LPRECT)&rectScrollClip, ! 411: (LPRECT)&rectScrollClip); ! 412: UpdateWindow(hWnd); ! 413: SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE); ! 414: } ! 415: break; ! 416: ! 417: case WM_HSCROLL: ! 418: /* Determine how much to scroll horizontally. ! 419: */ ! 420: switch (LOWORD(wParam)) ! 421: { ! 422: case SB_LINEUP: ! 423: nHscrollInc = -1; ! 424: break; ! 425: ! 426: case SB_LINEDOWN: ! 427: nHscrollInc = 1; ! 428: break; ! 429: ! 430: case SB_PAGEUP: ! 431: nHscrollInc = (LONG) min(-1, -nNumDisplayChars); ! 432: break; ! 433: ! 434: case SB_PAGEDOWN: ! 435: nHscrollInc = (LONG) max(1, nNumDisplayChars); ! 436: break; ! 437: ! 438: case SB_THUMBTRACK: ! 439: nHscrollInc = ((LONG)HIWORD(wParam) - nHscrollPos); ! 440: break; ! 441: ! 442: default: ! 443: nHscrollInc = 0; ! 444: } ! 445: ! 446: /* Limit the scroll range and to the scroll. ! 447: */ ! 448: if(nHscrollInc = max(-nHscrollPos, ! 449: min(nHscrollInc, ! 450: nHscrollMax - nHscrollPos))) ! 451: { ! 452: nHscrollPos += nHscrollInc; ! 453: ScrollWindow(hWnd, -wChar * nHscrollInc, 0, NULL, NULL); ! 454: UpdateWindow(hWnd); ! 455: SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE); ! 456: } ! 457: break; ! 458: ! 459: case WM_KEYDOWN: ! 460: /* Translate keystrokes to scroll message. ! 461: */ ! 462: for (i = 0; i < NUMKEYS; i++) ! 463: if (wParam == keyToScroll[i].wVirtKey) ! 464: { ! 465: SendMessage(hWnd, keyToScroll[i].iMessage, ! 466: keyToScroll[i].wRequest, 0L); ! 467: break; ! 468: } ! 469: break; ! 470: ! 471: case WM_PAINT: ! 472: BeginPaint(hWnd, &ps); ! 473: ! 474: hBrush = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE)); ! 475: FillRect(ps.hdc, &ps.rcPaint, hBrush); ! 476: DeleteObject(hBrush); ! 477: ! 478: /* Set up text attributes. ! 479: */ ! 480: hFont = GetStockObject(ANSI_FIXED_FONT); ! 481: SelectObject(ps.hdc, hFont); ! 482: SetBkMode(ps.hdc, TRANSPARENT); ! 483: ! 484: /* Put up the display label if we're asked to repaint the ! 485: * top line of the screen. ! 486: */ ! 487: if(ps.rcPaint.top < hChar) ! 488: { ! 489: TextOut(ps.hdc, wChar * (0 - nHscrollPos), ! 490: 0, szDisplayTextBuffer, ! 491: sprintf(szDisplayTextBuffer, LABEL)); ! 492: MoveToEx(ps.hdc, wChar * (0 - nHscrollPos), hChar - 1, NULL); ! 493: LineTo(ps.hdc, wClient, hChar - 1); ! 494: ! 495: ps.rcPaint.top = hChar; ! 496: } ! 497: ! 498: /* Calculate the beginning and ending line numbers that we need ! 499: * to paint. These line numbers refer to lines in the display ! 500: * buffer, not to lines in the display window. ! 501: */ ! 502: nPaintBeg = max (0, nVscrollPos + ps.rcPaint.top / hChar - 1); ! 503: nPaintEnd = min(nNumBufferLines, ! 504: nVscrollPos + ps.rcPaint.bottom / hChar + 1); ! 505: ! 506: /* Get the appropriate events from the display buffer, convert ! 507: * to a text string and paint the text on the display. ! 508: */ ! 509: for (i = nPaintBeg; i < nPaintEnd; i++) ! 510: { ! 511: GetDisplayEvent(lpDisplayBuffer, (LPEVENT)&incomingEvent, i); ! 512: TextOut(ps.hdc, ! 513: wChar * (0 - nHscrollPos), ! 514: hChar * (1 - nVscrollPos + i), ! 515: szDisplayTextBuffer, ! 516: GetDisplayText(szDisplayTextBuffer, ! 517: (LPEVENT)&incomingEvent)); ! 518: } ! 519: ! 520: EndPaint(hWnd, &ps); ! 521: break; ! 522: ! 523: case WM_DESTROY: ! 524: PostQuitMessage(0); ! 525: break; ! 526: ! 527: case MM_MIDIINPUT: ! 528: /* This is a custom message sent by the low level callback ! 529: * function telling us that there is at least one MIDI event ! 530: * in the input buffer. We empty the input buffer, and put ! 531: * each event in the display buffer, if it's not filtered. ! 532: * If the input buffer is being filled as fast we can empty ! 533: * it, then we'll stay in this loop and not process any other ! 534: * Windows messages, or yield to other applications. We need ! 535: * something to restrict the amount of time we spend here... ! 536: */ ! 537: while(GetEvent(lpInputBuffer, (LPEVENT)&incomingEvent)) ! 538: { ! 539: if(!bRecordingEnabled) ! 540: continue; ! 541: ! 542: if(!CheckEventFilter((LPEVENT)&incomingEvent, ! 543: (LPFILTER)&filter)) ! 544: { ! 545: AddDisplayEvent(lpDisplayBuffer, ! 546: (LPEVENT)&incomingEvent); ! 547: ++nNumBufferLines; ! 548: nNumBufferLines = min(nNumBufferLines, ! 549: DISPLAY_BUFFER_SIZE - 1); ! 550: bNeedToUpdate = TRUE; ! 551: } ! 552: } ! 553: ! 554: /* Recalculate vertical scroll bar range, and force ! 555: * the display to be updated. ! 556: */ ! 557: ! 558: if (bNeedToUpdate) { ! 559: nVscrollMax = (LONG) max(0, nNumBufferLines - nNumDisplayLines); ! 560: nVscrollPos = nVscrollMax; ! 561: SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE); ! 562: SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE); ! 563: InvalidateRect(hMainWnd, (LPRECT)&rectScrollClip, 0); ! 564: UpdateWindow(hMainWnd); ! 565: } ! 566: ! 567: break; ! 568: ! 569: default: ! 570: return DefWindowProc(hWnd, message, wParam, lParam); ! 571: break; ! 572: } ! 573: return NULL; ! 574: } ! 575: ! 576: // ! 577: /* CommandMsg - Processes WM_COMMAND messages. ! 578: * ! 579: * Params: hWnd - Handle to the window receiving the message. ! 580: * wParam - Parameter of the WM_COMMAND message. ! 581: * lParam - Parameter of the WM_COMMAND message. ! 582: * ! 583: * Return: void ! 584: */ ! 585: VOID CommandMsg( ! 586: HWND hWnd, ! 587: WPARAM wParam, ! 588: LPARAM lParam) ! 589: { ! 590: PREFERENCES preferences; ! 591: RECT rectWindow; ! 592: UINT wRtn; ! 593: HMENU hMenu; ! 594: unsigned int i; ! 595: char szErrorText[80]; ! 596: WORD wCommand; ! 597: ! 598: UNREFERENCED_PARAMETER(lParam); ! 599: ! 600: wCommand = LOWORD(wParam); ! 601: ! 602: /* Process any WM_COMMAND messages we want */ ! 603: switch (wCommand) { ! 604: case IDM_ABOUT: ! 605: About(hInst, hWnd); ! 606: break; ! 607: ! 608: case IDM_EXIT: ! 609: PostMessage(hWnd, WM_CLOSE, 0, 0l); ! 610: break; ! 611: ! 612: case IDM_SENDTOMAPPER: ! 613: /* We use hMapper as a toggle between sending events to the ! 614: * Mapper and not sending events. ! 615: */ ! 616: if(hMapper) { ! 617: /* Close the Mapper and reset hMapper. Uncheck the menu item. ! 618: * Clear Mapper handle in the instance data for each device. ! 619: */ ! 620: wRtn = midiOutClose(hMapper); ! 621: if(wRtn != 0) ! 622: { ! 623: midiOutGetErrorText(wRtn, (LPSTR)szErrorText, ! 624: sizeof(szErrorText)); ! 625: Error(szErrorText); ! 626: } ! 627: hMapper = 0; ! 628: ! 629: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) ! 630: lpCallbackInstanceData[i]->hMapper = hMapper; ! 631: ! 632: DoMenuItemCheck(hWnd, wCommand, FALSE); ! 633: } ! 634: ! 635: else { ! 636: /* Open the MIDI Mapper, put the Mapper handle in the instance ! 637: * data for each device and check the menu item. ! 638: */ ! 639: wRtn = midiOutOpen((LPHMIDIOUT) &hMapper, (UINT) MIDIMAPPER, ! 640: 0L, 0L, 0L); ! 641: ! 642: if(wRtn != 0) { // error opening Mapper ! 643: midiOutGetErrorText(wRtn, (LPSTR)szErrorText, ! 644: sizeof(szErrorText)); ! 645: Error(szErrorText); ! 646: hMapper = 0; ! 647: } ! 648: ! 649: else { // Mapper opened successfully ! 650: for (i=0; (i<wNumDevices) && (i<MAX_NUM_DEVICES); i++) ! 651: lpCallbackInstanceData[i]->hMapper = hMapper; ! 652: ! 653: DoMenuItemCheck(hWnd, wCommand, TRUE); ! 654: } ! 655: } ! 656: ! 657: break; ! 658: ! 659: case IDM_SAVESETUP: ! 660: /* Save the current location and size of the display window ! 661: * in the MIDIMON.INI file. ! 662: */ ! 663: GetWindowRect(hMainWnd, (LPRECT)&rectWindow); ! 664: preferences.iInitialX = rectWindow.left; ! 665: preferences.iInitialY = rectWindow.top; ! 666: preferences.iInitialW = rectWindow.right - rectWindow.left; ! 667: preferences.iInitialH = rectWindow.bottom - rectWindow.top; ! 668: ! 669: setPreferences((LPPREFERENCES) &preferences); ! 670: break; ! 671: ! 672: case IDM_STARTSTOP: ! 673: /* Toggle between recording into the display buffer and not ! 674: * recording. Toggle the menu item between "Start" to "Stop" ! 675: * accordingly. ! 676: */ ! 677: hMenu = GetMenu(hWnd); ! 678: if(bRecordingEnabled) ! 679: { ! 680: ModifyMenu(hMenu, IDM_STARTSTOP, MF_BYCOMMAND, IDM_STARTSTOP, ! 681: "&Start"); ! 682: bRecordingEnabled = 0; ! 683: } ! 684: else ! 685: { ! 686: ModifyMenu(hMenu, IDM_STARTSTOP, MF_BYCOMMAND, IDM_STARTSTOP, ! 687: "&Stop"); ! 688: bRecordingEnabled = 1; ! 689: } ! 690: DrawMenuBar(hWnd); ! 691: break; ! 692: ! 693: case IDM_CLEAR: ! 694: /* Reset the display buffer, recalibrate the scroll bars, ! 695: * and force an update of the display. ! 696: */ ! 697: ResetDisplayBuffer(lpDisplayBuffer); ! 698: nNumBufferLines = 0; ! 699: SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE); ! 700: ! 701: InvalidateRect(hWnd, (LPRECT)&rectScrollClip, 0); ! 702: UpdateWindow(hWnd); ! 703: ! 704: break; ! 705: ! 706: /* Set up filter structure for MIDI channel filtering. ! 707: */ ! 708: case IDM_FILTCHAN0: ! 709: case IDM_FILTCHAN1: ! 710: case IDM_FILTCHAN2: ! 711: case IDM_FILTCHAN3: ! 712: case IDM_FILTCHAN4: ! 713: case IDM_FILTCHAN5: ! 714: case IDM_FILTCHAN6: ! 715: case IDM_FILTCHAN7: ! 716: case IDM_FILTCHAN8: ! 717: case IDM_FILTCHAN9: ! 718: case IDM_FILTCHAN10: ! 719: case IDM_FILTCHAN11: ! 720: case IDM_FILTCHAN12: ! 721: case IDM_FILTCHAN13: ! 722: case IDM_FILTCHAN14: ! 723: case IDM_FILTCHAN15: ! 724: filter.channel[wCommand - IDM_FILTCHAN0] = ! 725: !filter.channel[wCommand - IDM_FILTCHAN0]; ! 726: DoMenuItemCheck(hWnd, wCommand, ! 727: filter.channel[wCommand - IDM_FILTCHAN0]); ! 728: break; ! 729: ! 730: /* Setup filter structure for MIDI event filtering. ! 731: */ ! 732: case IDM_NOTEOFF: ! 733: filter.event.noteOff = !filter.event.noteOff; ! 734: DoMenuItemCheck(hWnd, wCommand, filter.event.noteOff); ! 735: break; ! 736: case IDM_NOTEON: ! 737: filter.event.noteOn = !filter.event.noteOn; ! 738: DoMenuItemCheck(hWnd, wCommand, filter.event.noteOn); ! 739: break; ! 740: case IDM_POLYAFTERTOUCH: ! 741: filter.event.keyAftertouch = !filter.event.keyAftertouch; ! 742: DoMenuItemCheck(hWnd, wCommand, filter.event.keyAftertouch); ! 743: break; ! 744: case IDM_CONTROLCHANGE: ! 745: filter.event.controller = !filter.event.controller; ! 746: DoMenuItemCheck(hWnd, wCommand, filter.event.controller); ! 747: break; ! 748: case IDM_PROGRAMCHANGE: ! 749: filter.event.progChange = !filter.event.progChange; ! 750: DoMenuItemCheck(hWnd, wCommand, filter.event.progChange); ! 751: break; ! 752: case IDM_CHANNELAFTERTOUCH: ! 753: filter.event.chanAftertouch = !filter.event.chanAftertouch; ! 754: DoMenuItemCheck(hWnd, wCommand, filter.event.chanAftertouch); ! 755: break; ! 756: case IDM_PITCHBEND: ! 757: filter.event.pitchBend = !filter.event.pitchBend; ! 758: DoMenuItemCheck(hWnd, wCommand, filter.event.pitchBend); ! 759: break; ! 760: case IDM_CHANNELMODE: ! 761: filter.event.channelMode = !filter.event.channelMode; ! 762: DoMenuItemCheck(hWnd, wCommand, filter.event.channelMode); ! 763: break; ! 764: case IDM_SYSTEMEXCLUSIVE: ! 765: filter.event.sysEx = !filter.event.sysEx; ! 766: DoMenuItemCheck(hWnd, wCommand, filter.event.sysEx); ! 767: break; ! 768: case IDM_SYSTEMCOMMON: ! 769: filter.event.sysCommon = !filter.event.sysCommon; ! 770: DoMenuItemCheck(hWnd, wCommand, filter.event.sysCommon); ! 771: break; ! 772: case IDM_SYSTEMREALTIME: ! 773: filter.event.sysRealTime = !filter.event.sysRealTime; ! 774: DoMenuItemCheck(hWnd, wCommand, filter.event.sysRealTime); ! 775: break; ! 776: case IDM_ACTIVESENSE: ! 777: filter.event.activeSense = !filter.event.activeSense; ! 778: DoMenuItemCheck(hWnd, wCommand, filter.event.activeSense); ! 779: break; ! 780: ! 781: default: ! 782: break; ! 783: } ! 784: } ! 785: ! 786: // ! 787: /* InitFirstInstance - Performs initializaion for the first instance ! 788: * of the application. ! 789: * ! 790: * Params: hInstance - Instance handle. ! 791: * ! 792: * Return: Returns 1 if there were no errors. Otherwise, returns 0. ! 793: */ ! 794: BOOL InitFirstInstance(hInstance) ! 795: HANDLE hInstance; ! 796: { ! 797: WNDCLASS wc; ! 798: ! 799: /* Define the class of window we want to register. ! 800: */ ! 801: wc.lpszClassName = szAppName; ! 802: wc.style = CS_HREDRAW | CS_VREDRAW; ! 803: wc.hCursor = LoadCursor(NULL, IDC_ARROW); ! 804: wc.hIcon = LoadIcon(hInstance,"Icon"); ! 805: wc.lpszMenuName = "Menu"; ! 806: wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); ! 807: wc.hInstance = hInstance; ! 808: wc.lpfnWndProc = WndProc; ! 809: wc.cbClsExtra = 0; ! 810: wc.cbWndExtra = 0; ! 811: ! 812: if(!RegisterClass(&wc)) ! 813: return FALSE; ! 814: ! 815: return TRUE; ! 816: } ! 817: ! 818: // ! 819: /* DoMenuItemCheck - Checks and unchecks menu items. ! 820: * ! 821: * Params: hWnd - Window handle for window associated with menu items. ! 822: * wMenuItem - The menu ID for the menu item. ! 823: * newState - The new checked/unchecked state of the menu item. ! 824: * ! 825: * Return: void ! 826: */ ! 827: void DoMenuItemCheck( ! 828: HWND hWnd, ! 829: WORD wMenuItem, ! 830: BOOL newState) ! 831: { ! 832: HMENU hMenu; ! 833: ! 834: hMenu = GetMenu(hWnd); ! 835: CheckMenuItem(hMenu, wMenuItem, (newState ? MF_CHECKED: MF_UNCHECKED)); ! 836: } ! 837: ! 838: ! 839: /* Error - Beeps and shows an error message. ! 840: * ! 841: * Params: szMsg - Points to a NULL-terminated string containing the ! 842: * error message. ! 843: * ! 844: * Return: Returns the return value from the MessageBox() call. ! 845: * Since this message box has only a single button, the ! 846: * return value isn't too meaningful. ! 847: */ ! 848: int Error(szMsg) ! 849: LPSTR szMsg; ! 850: { ! 851: MessageBeep(0); ! 852: return MessageBox(hMainWnd, szMsg, szAppName, MB_OK); ! 853: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.