|
|
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: }
1.1.1.2 ! root 573: return 0;
1.1 root 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.