home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / midimon / display.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  10KB  |  315 lines

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (C) 1993 - 1997  Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11.  
  12. /*
  13.  * display.c - Functions to manage the display buffer and convert a
  14.  *      MIDI event to a text string for display.
  15.  *
  16.  *      The display buffer is filled by the application's WndProc()
  17.  *      function when it receives an MM_MIDIINPUT message.  This message
  18.  *      is sent by the low-level callback function upon reception of a
  19.  *      MIDI event.  When the display buffer becomes full, newly added
  20.  *      events overwrite the oldest events in the buffer.
  21.  */
  22.  
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include "midimon.h"
  26. #include "circbuf.h"
  27. #include "display.h"
  28.  
  29. /* MIDI event-name strings
  30.  */
  31. char szEventNames[8][24] =
  32. {
  33.                     "Note Off",
  34.                     "Note On",
  35.                     "Key Aftertouch",
  36.                     "Control Change",
  37.                     "Program Change",
  38.                     "Channel Aftertouch",
  39.                     "Pitch Bend",
  40.                     "System Message"
  41. };
  42.  
  43. char szSysMsgNames[16][24] =
  44. {
  45.                     "System Exclusive",
  46.                     "MTC Quarter Frame",
  47.                     "Song Position Pointer",
  48.                     "Song Select",
  49.                     "Undefined",
  50.                     "Undefined",
  51.                     "Tune Request",
  52.                     "System Exclusive End",
  53.                     "Timing Clock",
  54.                     "Undefined",
  55.                     "Start",
  56.                     "Continue",
  57.                     "Stop",
  58.                     "Undefined",
  59.                     "Active Sensing",
  60.                     "System Reset"
  61. };
  62.  
  63. /* GetDisplayText - Takes a MIDI event and creates a text string for display.
  64.  *
  65.  * Params:  npText - Points to a string that the function fills.
  66.  *          lpEvent - Points to a MIDI event.
  67.  *
  68.  * Return:  The number of characters in the text string pointed to by npText.
  69.  */
  70. int GetDisplayText(NPSTR npText, LPEVENT lpEvent)
  71. {
  72.     BYTE bStatus, bStatusRaw, bChannel, bData1, bData2;
  73.     char chErr;
  74.     DWORD dwTimestamp;
  75.  
  76.     bStatusRaw  = LOBYTE(LOWORD(lpEvent->data));
  77.     bStatus     = (BYTE) (bStatusRaw & (BYTE) 0xf0);
  78.     bChannel    = (BYTE) (bStatusRaw & (BYTE) 0x0f);
  79.     bData1      = HIBYTE(LOWORD(lpEvent->data));
  80.     bData2      = LOBYTE(HIWORD(lpEvent->data));
  81.     dwTimestamp = lpEvent->timestamp;
  82.     chErr       = (lpEvent->fdwEvent & EVNT_F_ERROR) ? '*' : ' ';
  83.  
  84.     switch(bStatus)
  85.     {
  86.         /* Three byte events
  87.          */
  88.         case NOTEOFF:
  89.         case NOTEON:
  90.         case KEYAFTERTOUCH:
  91.         case CONTROLCHANGE:
  92.         case PITCHBEND:
  93.             /* A note on with a velocity of 0 is a note off
  94.              */
  95.             if((bStatus == NOTEON) && (bData2 == 0))
  96.                 bStatus = NOTEOFF;
  97.  
  98.             return(sprintf(npText, FORMAT3, dwTimestamp, bStatusRaw, bData1,
  99.                     bData2, bChannel, chErr, &szEventNames[(bStatus-0x80) >> 4][0]));
  100.             break;
  101.  
  102.         /* Two byte events
  103.          */
  104.         case PROGRAMCHANGE:
  105.         case CHANAFTERTOUCH:
  106.             return(sprintf(npText, FORMAT2, dwTimestamp, bStatusRaw, bData1,
  107.                     bChannel, chErr, &szEventNames[(bStatus-0x80) >> 4][0]));
  108.             break;
  109.  
  110.         /* MIDI system events (0xf0 - 0xff)
  111.          */
  112.         case SYSTEMMESSAGE:
  113.             switch(bStatusRaw)
  114.             {
  115.                 /* Two byte system events
  116.                  */
  117.                 case MTCQUARTERFRAME:
  118.                 case SONGSELECT:
  119.                     return(sprintf(npText, FORMAT2X, dwTimestamp, bStatusRaw,
  120.                             bData1,
  121.                             chErr, 
  122.                             &szSysMsgNames[(bStatusRaw & 0x0f)][0]));
  123.                     break;
  124.  
  125.                 /* Three byte system events
  126.                  */
  127.                 case SONGPOSPTR:
  128.                     return(sprintf(npText, FORMAT3X, dwTimestamp, bStatusRaw,
  129.                             bData1, bData2, chErr, 
  130.                             &szSysMsgNames[(bStatusRaw & 0x0f)][0]));
  131.                     break;
  132.  
  133.                 /* One byte system events
  134.                  */
  135.                 default:
  136.                     return(sprintf(npText, FORMAT1X, dwTimestamp, bStatusRaw,
  137.                             chErr, &szSysMsgNames[(bStatusRaw & 0x0f)][0]));
  138.                     break;
  139.             }
  140.             break;
  141.  
  142.         default:
  143.             return(sprintf(npText, FORMAT3X, dwTimestamp, bStatusRaw, bData1,
  144.                     bData2, chErr, GetStringRes(IDS_UNKNOWN_EVENT)));
  145.             break;
  146.     }
  147. }
  148.  
  149. /* AddDisplayEvent - Puts a MIDI event in the display buffer.  The display
  150.  *      buffer is a circular buffer.  Once it is full, newly added events
  151.  *      overwrite the oldest events in the buffer.
  152.  *
  153.  * Params:  lpBuf - Points to the display buffer.
  154.  *          lpEvent - Points to a MIDI event.
  155.  *
  156.  * Return:  void
  157.  */
  158. void AddDisplayEvent(LPDISPLAYBUFFER lpBuf, LPEVENT lpEvent)
  159. {
  160.     /* Put the event in the buffer, bump the head pointer and byte count.
  161.      */
  162.     *lpBuf->lpHead = *lpEvent;
  163.     ++lpBuf->lpHead;
  164.     ++lpBuf->dwCount;
  165.  
  166.     /* Wrap pointer, if necessary.
  167.      */
  168.     if(lpBuf->lpHead == lpBuf->lpEnd)
  169.         lpBuf->lpHead = lpBuf->lpStart;
  170.  
  171.     /* A full buffer is a full buffer, no more.
  172.      */
  173.     lpBuf->dwCount = min(lpBuf->dwCount, lpBuf->dwSize);
  174. }
  175.  
  176.  
  177. /* GetDisplayEvent - Retrieves a MIDI event from the display buffer.
  178.  *      Unlike the input buffer, the event is not removed from the buffer.
  179.  *
  180.  * Params:  lpBuf - Points to the display buffer.
  181.  *          lpEvent - Points to an EVENT structure that is filled with
  182.  *              the retrieved MIDI event.
  183.  *          wNum - Specifies which event to retrieve.
  184.  *
  185.  * Return:  void
  186.  */
  187. void GetDisplayEvent(LPDISPLAYBUFFER lpBuf, LPEVENT lpEvent, DWORD wNum)
  188. {
  189.     LPEVENT lpFirstEvent, lpThisEvent;
  190.  
  191.     /* Get pointer to the first (oldest) event in buffer.
  192.      */
  193.     if(lpBuf->dwCount < lpBuf->dwSize)      // buffer is not yet full
  194.         lpFirstEvent = lpBuf->lpStart;
  195.  
  196.     else                                    // buffer is full
  197.         lpFirstEvent = lpBuf->lpHead;
  198.  
  199.     /* Offset pointer to point to requested event; wrap pointer.
  200.      */
  201.     lpThisEvent = lpFirstEvent + wNum;
  202.     if(lpThisEvent >= lpBuf->lpEnd)
  203.         lpThisEvent = lpBuf->lpStart + (lpThisEvent - lpBuf->lpEnd);
  204.  
  205.     /* Get the requested event.
  206.      */
  207.     *(lpEvent) = *lpThisEvent;
  208. }
  209.  
  210. /* AllocDisplayBuffer - Allocates memory for a DISPLAYBUFFER structure
  211.  *      and a buffer of the specified size.  Each memory block is allocated
  212.  *      with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags and
  213.  *      locked with GlobalLock().  Since this buffer is only accessed by the
  214.  *      application, and not the low-level callback function, it does not
  215.  *      have to be page locked.
  216.  *
  217.  * Params:  dwSize - The size of the buffer, in events.
  218.  *
  219.  * Return:  A pointer to a DISPLAYBUFFER structure identifying the
  220.  *      allocated display buffer.  NULL if the buffer could not be allocated.
  221. */
  222. LPDISPLAYBUFFER AllocDisplayBuffer(DWORD dwSize)
  223. {
  224.     HANDLE hMem;
  225.     LPDISPLAYBUFFER lpBuf;
  226.     LPEVENT lpMem;
  227.  
  228.     /* Allocate and lock a DISPLAYBUFFER structure.
  229.      */
  230.     hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
  231.                        (DWORD)sizeof(DISPLAYBUFFER));
  232.     if(hMem == NULL)
  233.         return NULL;
  234.  
  235.     lpBuf = (LPDISPLAYBUFFER)GlobalLock(hMem);
  236.     if(lpBuf == NULL)
  237.     {
  238.         GlobalFree(hMem);
  239.         return NULL;
  240.     }
  241.  
  242.     /* Save the handle.
  243.      */
  244.     lpBuf->hSelf = hMem;
  245.  
  246.     /* Allocate and lock memory for the actual buffer.
  247.      */
  248.     hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT));
  249.     if(hMem == NULL)
  250.     {
  251.         GlobalUnlock(lpBuf->hSelf);
  252.         GlobalFree(lpBuf->hSelf);
  253.         return NULL;
  254.     }
  255.     lpMem = (LPEVENT)GlobalLock(hMem);
  256.     if(lpMem == NULL)
  257.     {
  258.         GlobalFree(hMem);
  259.         GlobalUnlock(lpBuf->hSelf);
  260.         GlobalFree(lpBuf->hSelf);
  261.         return NULL;
  262.     }
  263.  
  264.     /* Set up the DISPLAYBUFFER structure.
  265.      */
  266.     lpBuf->hBuffer = hMem;
  267.     lpBuf->wError = 0;
  268.     lpBuf->dwSize = dwSize;
  269.     lpBuf->dwCount = 0L;
  270.     lpBuf->lpStart = lpMem;
  271.     lpBuf->lpEnd = lpMem + dwSize;
  272.     lpBuf->lpTail = lpMem;
  273.     lpBuf->lpHead = lpMem;
  274.  
  275.     return lpBuf;
  276. }
  277.  
  278. /* FreeDisplayBuffer - Frees the memory for a display buffer.
  279.  *
  280.  * Params:  lpBuf - Points to the DISPLAYBUFFER to be freed.
  281.  *
  282.  * Return:  void
  283.  */
  284. void FreeDisplayBuffer(LPDISPLAYBUFFER lpBuf)
  285. {
  286.     HANDLE hMem;
  287.  
  288.     /* Unlock and free the buffer itself.
  289.      */
  290.     GlobalUnlock(lpBuf->hBuffer);
  291.     GlobalFree(lpBuf->hBuffer);
  292.  
  293.     /* Unlock and free the DISPLAYBUFFER structure.
  294.      */
  295.     hMem = lpBuf->hSelf;
  296.     GlobalUnlock(hMem);
  297.     GlobalFree(hMem);
  298. }
  299.  
  300. /* ResetDisplayBuffer - Empties a display buffer.
  301.  *
  302.  * Params:  lpBuf - Points to a display buffer.
  303.  *
  304.  * Return:  void
  305.  */
  306. void ResetDisplayBuffer(LPDISPLAYBUFFER lpBuf)
  307. {
  308.     /* Reset the pointers and event count.
  309.      */
  310.     lpBuf->lpHead = lpBuf->lpStart;
  311.     lpBuf->lpTail = lpBuf->lpStart;
  312.     lpBuf->dwCount = 0L;
  313.     lpBuf->wError = 0;
  314. }
  315.