home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / vidcap / rlmeter.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  8.3 KB  |  259 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) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *   rlmeter.c: Audio recording level window
  14.  *
  15.  *   Vidcap32 Source code
  16.  *
  17.  ***************************************************************************/
  18.  
  19. /*
  20.  * This window class acts as a 'VU Meter' showing the current and peak
  21.  * volume. Set the volume via the WMRL_SETLEVEL message (lParam is new level).
  22.  * The peak level will be tracked by the control by means of a 2-second timer.
  23.  */
  24.  
  25. #include <windows.h>
  26. #include <windowsx.h>
  27.  
  28. #include "rlmeter.h"
  29.  
  30. #ifdef _WIN32
  31. #ifndef EXPORT
  32. #define EXPORT
  33. #endif
  34. #endif
  35.  
  36. LONG FAR PASCAL EXPORT
  37. RLMeterProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  38.  
  39. /*
  40.  * generic window class to support a volume level display.
  41.  *
  42.  * The window has a white background, and draws a black filled
  43.  * rectangle to show the current volume level, and a red line at the
  44.  * peak. Every two seconds on a timer we lower the peak (we set the
  45.  * saved peak value to 0 so that at the next update we move the line to
  46.  * whatever is the current level.
  47.  *
  48.  * We store the pen and brush handles and the current and maximum levels
  49.  * as window words using SetWindowWord on win16 and SetWindowLong on win32.
  50.  */
  51.  
  52. // window data layout
  53. #define WD_MAX      0                           // current max
  54. #define WD_PREVMAX  (WD_MAX + sizeof(UINT))     // currently drawn max
  55. #define WD_PREVLVL  (WD_PREVMAX + sizeof(UINT)) // currently drawn level
  56.  
  57. #define WD_PEN      (WD_PREVLVL + sizeof(UINT)) // pen for max line
  58.  
  59. #define WDBYTES     (WD_PEN + sizeof(UINT))     // window bytes to alloc
  60.  
  61. #ifdef _WIN32
  62. #define SetWindowUINT     SetWindowLong
  63. #define GetWindowUINT     GetWindowLong
  64. #else
  65. #define SetWindowUINT     SetWindowWord
  66. #define GetWindowUINT     GetWindowWord
  67. #endif
  68.  
  69.  
  70. // call (if first instance) to register class
  71. BOOL
  72. RLMeter_Register(HINSTANCE hInstance)
  73. {
  74.     WNDCLASS cls;
  75.  
  76.     cls.hCursor        = LoadCursor(NULL,IDC_ARROW);
  77.     cls.hIcon          = NULL;
  78.     cls.lpszMenuName   = NULL;
  79.     cls.lpszClassName  = RLMETERCLASS;
  80.     cls.hbrBackground  = GetStockObject(WHITE_BRUSH);
  81.     cls.hInstance      = hInstance;
  82.     cls.style          = CS_HREDRAW | CS_VREDRAW;
  83.     cls.lpfnWndProc    = RLMeterProc;
  84.     cls.cbClsExtra     = 0;
  85.     cls.cbWndExtra     = WDBYTES;
  86.  
  87.     return RegisterClass(&cls);
  88.  
  89.  
  90. }
  91.  
  92.  
  93. LONG FAR PASCAL EXPORT
  94. RLMeterProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  95. {
  96.     switch(message) {
  97.     case WM_CREATE:
  98.         // init current level and max to 0
  99.         SetWindowUINT(hwnd, WD_MAX, 0);
  100.         SetWindowUINT(hwnd, WD_PREVMAX, 0);
  101.         SetWindowUINT(hwnd, WD_PREVLVL, 0);
  102.  
  103.         // create a red pen for the max line and store this
  104.         SetWindowUINT(hwnd, WD_PEN,
  105.                 (UINT) CreatePen(PS_SOLID, 2, RGB(255, 0, 0)));
  106.  
  107.         break;
  108.  
  109.     case WM_DESTROY:
  110.         // destroy the pen we created
  111.         {
  112.             HPEN hpen = (HPEN) GetWindowUINT(hwnd, WD_PEN);
  113.             if (hpen) {
  114.                 DeleteObject(hpen);
  115.                 SetWindowUINT(hwnd, WD_PEN, 0);
  116.             }
  117.  
  118.             // also kill the timer we created
  119.             KillTimer(hwnd, 0);
  120.         }
  121.         break;
  122.  
  123.     case WM_PAINT:
  124.         /*
  125.          * paint the entire control
  126.          *
  127.          * nb we must paint exactly as it is currently drawn because we
  128.          * may be clipped to only part of the control. Thus we must draw
  129.          * the max at WD_PREVMAX as it is currently drawn, since WD_MAX
  130.          * may have been set to 0 and not yet drawn - in this case, with
  131.          * some unfortunate timing and clipping, we would have two max lines.
  132.          */
  133.         {
  134.             PAINTSTRUCT ps;
  135.             HDC hdc;
  136.             RECT rc, rcFill;
  137.             HPEN hpenOld, hpen;
  138.  
  139.             hdc = BeginPaint(hwnd, &ps);
  140.  
  141.             GetClientRect(hwnd, &rc);
  142.  
  143.             // treat the level as a percentage and fill that much of the
  144.             // control with black (from left)
  145.             rcFill = rc;
  146.             rcFill.right = (rc.right * GetWindowUINT(hwnd, WD_PREVLVL)) / 100;
  147.             SetBkColor(hdc, RGB(0,0,0));
  148.             // easy way to fill without creating a brush
  149.             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  150.  
  151.             // draw the max line
  152.             rcFill.right = (rc.right * GetWindowUINT(hwnd, WD_PREVLVL)) / 100;
  153.             hpen = (HPEN) GetWindowUINT(hwnd, WD_PEN);
  154.             hpenOld = SelectObject(hdc, hpen);
  155.             MoveToEx(hdc, rcFill.right, rcFill.top, NULL);
  156.             LineTo(hdc, rcFill.right, rcFill.bottom);
  157.             SelectObject(hdc, hpenOld);
  158.  
  159.             EndPaint(hwnd, &ps);
  160.  
  161.         }
  162.         break;
  163.  
  164.     case WMRL_SETLEVEL:
  165.         // set new level, and update the displayed level block and max line
  166.         {
  167.             RECT rc, rcFill;
  168.             UINT uMax, uPrevMax, uPrevLevel, uLevel;
  169.             HDC hdc;
  170.  
  171.             // new level is lParam
  172.             uLevel = (UINT) lParam;
  173.  
  174.             // fetch other parameters
  175.             uMax = GetWindowUINT(hwnd, WD_MAX);
  176.             uPrevMax = GetWindowUINT(hwnd, WD_PREVMAX);
  177.             uPrevLevel = GetWindowUINT(hwnd, WD_PREVLVL);
  178.  
  179.  
  180.             // decay the max level. This rate works best if we are called
  181.             // to update every 1/20th sec - in this case the decay will be
  182.             // 64% in a second.
  183.             if (uMax > 0) {
  184.                 uMax = (uMax * 2007) / 2048;     // = 0.98 * uMax
  185.             }
  186.  
  187.             hdc = GetDC(hwnd);
  188.  
  189.             GetClientRect(hwnd, &rc);
  190.             rcFill = rc;
  191.  
  192.             // is the current level a new peak ?
  193.             if (uLevel > uMax) {
  194.                 uMax = uLevel;
  195.             }
  196.  
  197.             SetWindowUINT(hwnd, WD_MAX, uMax);
  198.  
  199.             // if the max has moved, erase the old line
  200.             if (uMax != uPrevMax) {
  201.                 // white out the line by filling a 2-pixel wide rect
  202.                 rcFill.right = ((rc.right * uPrevMax) / 100) + 1;
  203.                 rcFill.left = rcFill.right - 2;
  204.                 SetBkColor(hdc, RGB(255, 255, 255));
  205.                 ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  206.             }
  207.  
  208.             // calculate the area to update
  209.             rcFill.right = (rc.right * uPrevLevel) / 100;
  210.             rcFill.left = (rc.right * uLevel) / 100;
  211.  
  212.             // are we erasing (lowering level) or drawing more black?
  213.             if (rcFill.right > rcFill.left) {
  214.  
  215.                 // level has dropped - so fill with white down to new level
  216.                 SetBkColor(hdc, RGB(255, 255, 255));
  217.             } else {
  218.                 // level has gone up so fill with black up to new level
  219.                 int t;
  220.  
  221.                 t = rcFill.right;
  222.                 rcFill.right = rcFill.left;
  223.                 rcFill.left = t;
  224.  
  225.                 SetBkColor(hdc, RGB(0, 0, 0));
  226.  
  227.                 // fill a little extra to ensure no rounding gaps
  228.                 if (rcFill.left > 0) {
  229.                     rcFill.left -= 1;
  230.                 }
  231.             }
  232.             ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcFill, NULL, 0, NULL);
  233.             SetWindowUINT(hwnd, WD_PREVLVL, uLevel);
  234.  
  235.             // draw the new max line if needed
  236.             if (uMax != uPrevMax) {
  237.                 HPEN hpen, hpenOld;
  238.  
  239.                 rcFill.right = (rc.right * uMax) /100;
  240.  
  241.                 hpen = (HPEN) GetWindowUINT(hwnd, WD_PEN);
  242.                 hpenOld = SelectObject(hdc, hpen);
  243.                 MoveToEx(hdc, rcFill.right, rcFill.top, NULL);
  244.                 LineTo(hdc, rcFill.right, rcFill.bottom);
  245.                 SelectObject(hdc, hpenOld);
  246.  
  247.                 SetWindowUINT(hwnd, WD_PREVMAX, uMax);
  248.             }
  249.             ReleaseDC(hwnd, hdc);
  250.             return(0);
  251.         }
  252.  
  253.     }
  254.     return DefWindowProc(hwnd, message, wParam, lParam);
  255. }
  256.  
  257.  
  258.  
  259.