home *** CD-ROM | disk | FTP | other *** search
/ Cubase Magazine 30 / Issue #30.iso / pc / 2-SOFTWARE / RTEQ 3.0 / SRC / EQUALIZER.CPP next >
Encoding:
C/C++ Source or Header  |  2000-12-10  |  40.7 KB  |  1,484 lines

  1. /**********************************************************************************
  2. *                                                                                 *
  3. *    EQUALIZER.CPP: The main program, the core of this application                *
  4. *                                                                                 *
  5. *    Copyright (C) 2000  Andrei Grecu                                             *
  6. *                                                                                 *
  7. *    This program is free software; you can redistribute it and/or modify         *
  8. *    it under the terms of the GNU General Public License as published by         *
  9. *    the Free Software Foundation; either version 2 of the License, or            *
  10. *    (at your option) any later version.                                          *
  11. *                                                                                 *
  12. *    This program is distributed in the hope that it will be useful,              *
  13. *    but WITHOUT ANY WARRANTY; without even the implied warranty of               *
  14. *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
  15. *    GNU General Public License for more details.                                 *
  16. *                                                                                 *
  17. *    You should have received a copy of the GNU General Public License            *
  18. *    along with this program; if not, write to the Free Software                  *
  19. *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    *
  20. *                                                                                 *
  21. *    If you have questions, bug reports regarding my code please contact me at:   *
  22. *    andrei.grecu@aon.at                                                          *
  23. *                                                                                 *
  24. *    Home page:                                                                   *
  25. *    http://members.aon.at/grxpage/index.htm                                      *
  26. *                                                                                 *
  27. **********************************************************************************/
  28.  
  29. #include "precomp.h"
  30. #include "resource.h"
  31. #include "commctrl.h"
  32. #include "process.h"
  33.  
  34. #include "misc.h"
  35. #include "fdt.h"
  36. #include "sound.h"
  37.  
  38. #define MAX_LOADSTRING 100
  39.  
  40. #define WM_TASKBARICON        (WM_USER + 1)
  41.  
  42. extern HANDLE hEvent;
  43. extern DWORD REC_FREQ; 
  44. extern DWORD REC_BASEBUFSIZE; 
  45. extern BYTE REC_CHANNELS; 
  46.  
  47. // Global Variables:
  48. HINSTANCE hInst;                                // current instance
  49. TCHAR szTitle[MAX_LOADSTRING];                    // The title bar text
  50. TCHAR szWindowClass[MAX_LOADSTRING];            // The title bar text
  51. HWND hWnd;
  52.  
  53. // Handles of the Sliders
  54. LPHWND LSliders;
  55. LPHWND RSliders;
  56. LPHWND LVolumeDesc;
  57. LPHWND LFreqDesc;
  58. WORD NumSliders = 32 + 1; // number of sliders -  **can be changed**
  59. HFONT ControlFont;
  60. HICON AppIcon;
  61.  
  62. // Values of the Sliders
  63. LPDOUBLE LSlidersVal;
  64. LPDOUBLE RSlidersVal;
  65. DOUBLE LMaster, RMaster; 
  66.  
  67. LONG ProcessTimer = FALSE;
  68. BOOL EQonTaskBar = FALSE;
  69.  
  70. // Position of RTEQ on desktop
  71. DWORD APPXPOS, APPYPOS, APPWIDTH, APPHEIGHT;
  72.  
  73. // FFT vars
  74. DWORD REC_PERIOD = 2048; // sample block size - must be a power of 2
  75.                          // a higher value means better quality, but
  76.                          // more processor load **can be changed**        
  77.  
  78. DOUBLE DYNAMIC_RANGE_SCALE = 0.25; // The scale factor in %, can take
  79.                                    // any value in range of double
  80.                                    // **can be changed**    
  81.  
  82. // The program priority the higher, the better the sound, but the
  83. // worse the system responds. **can be changed**    
  84. DWORD PROGRAM_PRIORITY = NORMAL_PRIORITY_CLASS; 
  85.  
  86. // Dynamic equalizing options
  87. BOOL  DynamicEqualizing, BlurEQImpact;
  88. COEF  DYNAMIC_TRESHOLD;
  89.  
  90. // Equalizing variables
  91. LPSHORT *lpsrc;
  92. LPCOEF  *lpdest;
  93. LPCOEF  *lpLScale;
  94. LPCOEF   lpRScale;
  95. LPSHORT *lpbuf_src;
  96.  
  97. // Dynamic equalizing variables
  98. LPCOEF lpCorrLScale;
  99. LPCOEF *lpNLScale;
  100. LPCOEF lpChannelNorm;
  101.  
  102. LPDWORD lpchannel_startfreq, lpchannel_bandwidth, lpchannel_halffreq;
  103. LPCOEF lptsrc, lpimpact, lpspectrum_power;
  104.  
  105. // Equalizing variables
  106. LPCOEF lpweight;
  107.  
  108. // EQ Thread variables
  109. BOOL EQThreadValid;
  110. HANDLE hEQThread;
  111.  
  112. ATOM RTEQTrackBarRegisterClass(HINSTANCE hInstance);
  113. LRESULT CALLBACK Preferences(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  114.  
  115. // Foward declarations of functions included in this code module:
  116. ATOM                MyRegisterClass(HINSTANCE hInstance);
  117. BOOL                InitInstance(HINSTANCE, int);
  118. void                InitEqualizer(void);
  119. void                DestroyEqualizer(void);
  120. void                LoadEqualizer(void);
  121. void                SaveEqualizer(void);
  122. void                GetStartValues(void);
  123. void                SetStartValues(void);
  124.  
  125. void                PerformChannel(UINT channel);
  126. void                ChannelAlgorithms(WORD channel, WORD period);
  127. RECT                GetChannelPos(RECT src, DWORD i);
  128. double                EqFunc(LONG i);
  129. DOUBLE                EqVal(INT Val);
  130.  
  131. LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
  132. LRESULT CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
  133.  
  134. LPVOID                AllocMemory(DWORD dwsize);
  135. LPVOID                AllocChannels(DWORD dwsize);
  136. #define                FreeMemory(ptr)                 GlobalFree((HGLOBAL)ptr)
  137. void                FreeChannels(LPVOID *ptr);
  138. LPVOID                AllocChannels_Time(DWORD dwdepth, DWORD dwsize);
  139. void                FreeChannels_Time(LPVOID **ptr, DWORD dwdepth);
  140.  
  141. void                SetControlFont(HFONT *ControlFont, DWORD width);
  142. void                InsertMenuItemEasy(HMENU hMenu, DWORD dwInsertAfter, DWORD dwType, DWORD dwId, LPCSTR lpStr);
  143. void                TaskbarIcon(DWORD dwAction);
  144. DWORD WINAPI        EQThread(void);
  145.  
  146. BOOL nopaint = FALSE;
  147.  
  148. int APIENTRY WinMain(HINSTANCE hInstance,
  149.                      HINSTANCE hPrevInstance,
  150.                      LPSTR     lpCmdLine,
  151.                      int       nCmdShow)
  152. {
  153.     MSG msg;
  154.     HACCEL hAccelTable;
  155.  
  156.     // Initialize global strings
  157.     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  158.     LoadString(hInstance, IDC_EQUALIZER, szWindowClass, MAX_LOADSTRING);
  159.     MyRegisterClass(hInstance);
  160.     RTEQTrackBarRegisterClass(hInstance);
  161.  
  162.     // Perform application initialization:
  163.     if (!InitInstance (hInstance, nCmdShow)) 
  164.     {    
  165.         return FALSE;
  166.     }
  167.  
  168.     hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_EQUALIZER);
  169.  
  170.  
  171.     // Remains from priority options
  172.     //    SetPriorityClass(GetCurrentProcess(), PROGRAM_PRIORITY);
  173.  
  174.     // Main message loop:
  175.     while (GetMessage(&msg, NULL, 0, 0)) {
  176.  
  177.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
  178.         {
  179.             TranslateMessage(&msg);
  180.             DispatchMessage(&msg);
  181.         }
  182.  
  183.     }
  184.  
  185.     return msg.wParam;
  186. }
  187.  
  188. void PerformChannel(UINT channel) {
  189.  
  190.     DWORD i;
  191.  
  192.     LPSHORT  src      = lpsrc[channel * 2];
  193.     LPSHORT  src2     = lpsrc[channel * 2 + 1];
  194.     LPDOUBLE dest     = lpdest[channel * 2];
  195.     LPDOUBLE dest2    = lpdest[channel * 2 + 1];
  196.     LPSHORT  buf_src  = lpbuf_src[channel * 2];
  197.     LPSHORT  buf_src2 = lpbuf_src[channel * 2 + 1];
  198.  
  199.     // Perform the first frequency block
  200.     CopyMemory(&buf_src[REC_PERIOD / 2], src, (REC_PERIOD / 2) * 2);
  201.     FDT(buf_src, dest2);               
  202.     ChannelAlgorithms(channel, 1);
  203.     IFDT(dest2, src2);    
  204.     CopyMemory(buf_src, &src[REC_PERIOD / 2], (REC_PERIOD / 2) * 2);
  205.  
  206.     // Perform the second frequency block
  207.     FDT(src, dest);               
  208.     ChannelAlgorithms(channel, 0);
  209.     IFDT(dest, src);
  210.  
  211.     CopyMemory(&src[REC_PERIOD / 2], src, REC_PERIOD*2);
  212.  
  213.     // Mixing first and second frequency block
  214.     for(i = 0; i < REC_PERIOD; i++) {
  215.         if(i < REC_PERIOD / 2) {
  216.             src[i] = (SHORT)((1 - lpweight[i]) * buf_src2[i] + lpweight[i] * src2[i]);
  217.         }
  218.         else {
  219.             src[i] = (SHORT)((1 - lpweight[i]) * src[i] + lpweight[i] * src2[i]);
  220.         }
  221.     }
  222.  
  223.     CopyMemory(buf_src2, &src[REC_PERIOD], (REC_PERIOD / 2) * 2);
  224.  
  225. }
  226.  
  227. void ChannelAlgorithms(WORD channel, WORD period) {
  228.  
  229.     DWORD i;
  230.  
  231.     LPDOUBLE dest     = lpdest[channel * 2 + period];
  232.     LPDOUBLE *lpScale  = lpLScale;
  233.     DOUBLE   Master   = LMaster;
  234.     
  235.     // The algorithm for the equalizer: scaling the frequency coefficients
  236.     /*dest[0] *= lpScale[0] * Master;
  237.     for(i = 1; i < REC_PERIOD / 2; i++)     dest[i]                  *= lpScale[i * 2] * Master;
  238.     for(i = 0; i < REC_PERIOD / 2 - 1; i++) dest[i + REC_PERIOD / 2] *= lpScale[(i + 1) * 2] * Master;
  239.     dest[REC_PERIOD - 1] *= lpScale[REC_PERIOD - 1] * Master;*/
  240. //    dest[0] *= Master;
  241. //    for(i = 0; i < REC_PERIOD-1; i++)    dest[i + 1] *= lpScale[(DWORD)floor(i / 2) * 2] * Master;
  242.     //dest[0] *= Master;
  243.     //dest[0] *= 0;
  244.     //for(i = 0; i < (DWORD)(32 * ((DOUBLE)REC_PERIOD/REC_FREQ)); i++)    dest[i] *= 0;
  245. ///////    for(i = 0; i < REC_PERIOD; i++)    dest[i] *= lpScale[(i / 2) * 2] * Master;
  246. //    LPDOUBLE src = (LPDOUBLE) AllocMemory(REC_PERIOD * sizeof(LPDOUBLE));
  247.  
  248.     if(!DynamicEqualizing) {
  249.         // *** Perform normal equalizing
  250.  
  251.         for(i = 0; i < REC_PERIOD; i++) {
  252.             dest[i] *= lpCorrLScale[i];
  253.         }
  254.  
  255.     }
  256.     else {
  257.         // *** Perform dynamic equalizing
  258.  
  259.         // Calculate power spectrum in lptsrc
  260.         // !REC_PERIOD MAY NOT EXHIBIT 65535 (i * i)
  261.         for(i = 0; i < REC_PERIOD; i++) {
  262.             lptsrc[i] = (dest[i] * dest[i]) * (i * i);
  263.         }
  264.  
  265.         // Calculate the power on each channel
  266.         for(i = 1; i < NumSliders; i++)    {
  267.             COEF var = 0;
  268.             for(DWORD j = 0; j < lpchannel_bandwidth[i]; j++) {
  269.                 var += lptsrc[lpchannel_startfreq[i] + j] * lpNLScale[i][j];
  270.             }
  271.             lpspectrum_power[i] = var / lpChannelNorm[i];
  272.         }
  273.  
  274.         // Calculate impact on the frequency spectrum
  275.         ZeroMemory(lpimpact, REC_PERIOD * sizeof(COEF));
  276.  
  277.         COEF treshold = DYNAMIC_TRESHOLD;
  278.         for(i = 1; i < NumSliders; i++)    {
  279.             for(DWORD j = 0; j < lpchannel_bandwidth[i]; j++) {
  280.                 DWORD pos = lpchannel_startfreq[i] + j;
  281.                 COEF signal_to_spectrum_power = lptsrc[pos] / lpspectrum_power[i];
  282.                 
  283.                 if(signal_to_spectrum_power < treshold) lpimpact[pos] = 1;//+= (1 - signal_to_spectrum_power / treshold) * lpNLScale[i][j];
  284.             }
  285.         }
  286.  
  287.         if(BlurEQImpact) {
  288.             // Blur the impact across the frequency spectrum
  289.             for(i = 1; i < REC_PERIOD - 1; i++) {
  290.                 if(lpimpact[i] > 0) {
  291.                     lpimpact[i - 1] += lpimpact[i] / 2;
  292.                     if(lpimpact[i - 1] > 1) lpimpact[i - 1] = 1;
  293.                     lpimpact[i + 1] += lpimpact[i] / 2;
  294.                     if(lpimpact[i + 1] > 1) lpimpact[i + 1] = 1;
  295.                 }    
  296.             }
  297.         }
  298.  
  299.         // Equalize the sound according to the impact
  300.         for(i = 0; i < REC_PERIOD; i++) {
  301.             if(lpimpact[i] > 0) {
  302.                 // Idea:
  303.                 // dest[i] = (1 - lpimpact[i]) * dest[i] + lpimpact[i] * dest[i] * lpCorrLScale[i];
  304.                 dest[i] = dest[i] * (1 + lpimpact[i] * (lpCorrLScale[i] - 1));
  305.             }
  306.         }
  307.  
  308.     }
  309.  
  310.     //    for(i = 0; i < REC_PERIOD; i++) dest[i] *= lpScale[i] * Master;
  311.  
  312. }
  313.  
  314. //
  315. //  FUNCTION: MyRegisterClass()
  316. //
  317. //  PURPOSE: Registers the window class.
  318. //
  319. //  COMMENTS:
  320. //
  321. //    This function and its usage is only necessary if you want this code
  322. //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
  323. //    function that was added to Windows 95. It is important to call this function
  324. //    so that the application will get 'well formed' small icons associated
  325. //    with it.
  326. //
  327. ATOM MyRegisterClass(HINSTANCE hInstance)
  328. {
  329.     WNDCLASSEX wcex;
  330.  
  331.     wcex.cbSize = sizeof(WNDCLASSEX); 
  332.  
  333.     wcex.style            = CS_HREDRAW | CS_VREDRAW;
  334.     wcex.lpfnWndProc    = (WNDPROC)WndProc;
  335.     wcex.cbClsExtra        = 0;
  336.     wcex.cbWndExtra        = 0;
  337.     wcex.hInstance        = hInstance;
  338.     wcex.hIcon            = LoadIcon(hInstance, (LPCTSTR)IDI_EQUALIZER);
  339.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
  340.     wcex.hbrBackground    = CreateSolidBrush(RGB(192, 192, 192));
  341.     wcex.lpszMenuName    = NULL;
  342.     wcex.lpszClassName    = szWindowClass;
  343.     wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
  344.  
  345.     AppIcon = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
  346.  
  347.     return RegisterClassEx(&wcex);
  348. }
  349.  
  350. //
  351. //   FUNCTION: InitInstance(HANDLE, int)
  352. //
  353. //   PURPOSE: Saves instance handle and creates main window
  354. //
  355. //   COMMENTS:
  356. //
  357. //        In this function, we save the instance handle in a global variable and
  358. //        create and display the main program window.
  359. //
  360. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  361. {
  362.    DWORD i;
  363.    RECT rc, dest;
  364.  
  365.    hInst = hInstance; // Store instance handle in our global variable
  366.  
  367.    // Load the configuration parameters
  368.    LoadEqualizer();
  369.  
  370.     // Create the RTEQ window
  371.    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  372.       APPXPOS, APPYPOS, APPWIDTH, APPHEIGHT, NULL, NULL, hInstance, NULL);
  373.  
  374.    if (!hWnd)
  375.    {
  376.       return FALSE;
  377.    }
  378.  
  379.    // Show splash screen
  380.    HWND hSplashScreen = CreateDialog(hInst, (LPCTSTR)IDD_SPLASHSCREEN, hWnd, (DLGPROC)About);
  381.  
  382.    HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
  383.  
  384.    InsertMenuItemEasy(hSysMenu, SC_CLOSE, MFT_STRING,    IDM_PREFERENCES, "&Preferences...");
  385.    InsertMenuItemEasy(hSysMenu, SC_CLOSE, MFT_SEPARATOR, NULL,            NULL);
  386.    InsertMenuItemEasy(hSysMenu, SC_CLOSE, MFT_STRING,    IDM_ABOUT,       "&About...");
  387.    InsertMenuItemEasy(hSysMenu, SC_CLOSE, MFT_SEPARATOR, NULL,            NULL);
  388.  
  389.    // Init the equalizer content
  390.    InitEqualizer();
  391.  
  392.    // Destroy splash screen
  393.    DestroyWindow(hSplashScreen);
  394.  
  395.    return TRUE;
  396. }
  397.  
  398. void GetStartValues(void) {
  399.  
  400.     WORD i;
  401.     LONG val; 
  402.     char value[10], key[10];
  403.  
  404.     // Read parameters from EQUALIZER.INI
  405.  
  406.     GetPrivateProfileString("DSE_Init",
  407.                             "Master",
  408.                             "0",
  409.                             value,
  410.                             10,
  411.                             "EQUALIZER.INI");
  412.  
  413.     val = atoi(value);
  414.     
  415.     // Set the positions of the sliders
  416.     SendMessage(LSliders[0], TBM_SETPOS, TRUE, val);
  417.     SendMessage(RSliders[0], TBM_SETPOS, TRUE, val);
  418.     PostMessage(hWnd, WM_VSCROLL, 0, (LPARAM) LSliders[0]);
  419.  
  420.     for(i = NumSliders - 1; i > 0; i--) {
  421.         GetPrivateProfileString("DSE_Init",
  422.                                 itoa(i, key, 10),
  423.                                 "0",
  424.                                 value,
  425.                                 10,
  426.                                 "EQUALIZER.INI");
  427.         val = atoi(value);
  428.     
  429.         SendMessage(LSliders[i], TBM_SETPOS, TRUE, val);
  430.         SendMessage(RSliders[i], TBM_SETPOS, TRUE, val);
  431.         PostMessage(hWnd, WM_VSCROLL, 0, (LPARAM) LSliders[i]);
  432.     }
  433.  
  434. }
  435.  
  436. void SetStartValues(void) {
  437.  
  438.     WORD i; 
  439.     INT val;
  440.     char key[10], value[10];
  441.  
  442.     // Write parameters to EQUALIZER.INI
  443.  
  444.     itoa(SendMessage(LSliders[0], TBM_GETPOS, 0, 0), key, 10);
  445.     WritePrivateProfileString("DSE_Init",
  446.                             "Master",
  447.                             key,
  448.                             "EQUALIZER.INI");
  449.  
  450.     
  451.     // Get the positions of the sliders
  452.     for(i = 1; i < NumSliders; i++) {
  453.         val = SendMessage(LSliders[i], TBM_GETPOS, 0, 0);
  454.         itoa(i, key, 10),
  455.         itoa(val, value, 10),
  456.         WritePrivateProfileString("DSE_Init",
  457.                                 key,
  458.                                 value,
  459.                                 "EQUALIZER.INI");
  460.     }
  461.  
  462. }
  463.  
  464. void LoadEqualizer(void) {
  465.  
  466.     char value[50];
  467.  
  468.     // Read parameters from EQUALIZER.INI
  469.     REC_FREQ = GetPrivateProfileInt("DSE_Init",
  470.                                     "REC_FREQ",
  471.                                     22050,
  472.                                     "EQUALIZER.INI");
  473.  
  474.     REC_CHANNELS = GetPrivateProfileInt("DSE_Init",
  475.                                     "REC_CHANNELS",
  476.                                     2,
  477.                                     "EQUALIZER.INI");
  478.  
  479.     REC_PERIOD = GetPrivateProfileInt("DSE_Init",
  480.                                     "REC_BLOCKSIZE",
  481.                                     2048,
  482.                                     "EQUALIZER.INI");
  483.  
  484.     GetPrivateProfileString("DSE_Init",
  485.                             "REC_BASEBUFSIZE",
  486.                             "65536",
  487.                             value,
  488.                             10,
  489.                             "EQUALIZER.INI");
  490.  
  491.     if((REC_BASEBUFSIZE = atol(value)) < 32768) REC_BASEBUFSIZE = 32768;
  492.  
  493.     //*********************************************************************
  494.  
  495.     GetPrivateProfileString("DSE_Init",
  496.                             "DYNAMIC_RANGE_SCALE",
  497.                             "0.25",
  498.                             value,
  499.                             10,
  500.                             "EQUALIZER.INI");
  501.  
  502.     if(!(DYNAMIC_RANGE_SCALE = atof(value))) DYNAMIC_RANGE_SCALE = 0.25;
  503.  
  504.     //*********************************************************************
  505.  
  506.     GetPrivateProfileString("DSE_Init",
  507.                             "DYNAMIC_TRESHOLD",
  508.                             "0.1",
  509.                             value,
  510.                             10,
  511.                             "EQUALIZER.INI");
  512.  
  513.     if(!(DYNAMIC_TRESHOLD = atof(value))) DYNAMIC_TRESHOLD = 0.1;
  514.  
  515.     //*********************************************************************
  516.  
  517.     DynamicEqualizing = GetPrivateProfileInt("DSE_Init",
  518.                                     "DYNAMIC_EQUALIZING",
  519.                                     0,
  520.                                     "EQUALIZER.INI");
  521.  
  522.     BlurEQImpact      = GetPrivateProfileInt("DSE_Init",
  523.                                     "BLUR_EQ_IMPACT",
  524.                                     0,
  525.                                     "EQUALIZER.INI");
  526.  
  527.     NumSliders = GetPrivateProfileInt("DSE_Init",
  528.                                     "EQ_FREQBANDS",
  529.                                     32,
  530.                                     "EQUALIZER.INI");
  531.     NumSliders++;
  532.  
  533.     GetPrivateProfileString("DSE_Init",
  534.                             "PRIORITY",
  535.                             "NORMAL_PRIORITY",
  536.                             value,
  537.                             50,
  538.                             "EQUALIZER.INI");
  539.  
  540.     if(!_stricmp(value, "IDLE_PRIORITY")) {
  541.         PROGRAM_PRIORITY = IDLE_PRIORITY_CLASS;
  542.     }
  543.     else if(!_stricmp(value, "NORMAL_PRIORITY")) {
  544.         PROGRAM_PRIORITY = NORMAL_PRIORITY_CLASS;
  545.     }
  546.     else if(!_stricmp(value, "HIGH_PRIORITY")) {
  547.         PROGRAM_PRIORITY = HIGH_PRIORITY_CLASS;
  548.     }
  549.     else if(!_stricmp(value, "REALTIME_PRIORITY")) {
  550.         PROGRAM_PRIORITY = REALTIME_PRIORITY_CLASS;
  551.     }
  552.     else { // if the user typed something wrong in the INI
  553.         PROGRAM_PRIORITY = NORMAL_PRIORITY_CLASS;
  554.     }
  555.  
  556.     APPXPOS = GetPrivateProfileInt("DSE_Init",
  557.                                     "window_Xpos",
  558.                                     40,
  559.                                     "EQUALIZER.INI");
  560.  
  561.     APPYPOS = GetPrivateProfileInt("DSE_Init",
  562.                                     "window_Ypos",
  563.                                     40,
  564.                                     "EQUALIZER.INI");
  565.  
  566.     APPWIDTH = GetPrivateProfileInt("DSE_Init",
  567.                                     "window_width",
  568.                                     500,
  569.                                     "EQUALIZER.INI");
  570.  
  571.     APPHEIGHT = GetPrivateProfileInt("DSE_Init",
  572.                                     "window_height",
  573.                                     400,
  574.                                     "EQUALIZER.INI");
  575.  
  576. }
  577.  
  578. void SaveEqualizer(void) {
  579.  
  580.     char value[50];
  581.  
  582.     // Write parameters to EQUALIZER.INI
  583.  
  584.     WritePrivateProfileString("DSE_Init",
  585.                             "REC_FREQ",
  586.                             itoa(REC_FREQ, value, 10),
  587.                             "EQUALIZER.INI");
  588.  
  589.     WritePrivateProfileString("DSE_Init",
  590.                             "REC_CHANNELS",
  591.                             itoa(REC_CHANNELS, value, 10),
  592.                             "EQUALIZER.INI");
  593.  
  594.     WritePrivateProfileString("DSE_Init",
  595.                             "REC_BLOCKSIZE",
  596.                             itoa(REC_PERIOD, value, 10),
  597.                             "EQUALIZER.INI");
  598.  
  599.     WritePrivateProfileString("DSE_Init",
  600.                             "REC_BASEBUFSIZE",
  601.                             itoa(REC_BASEBUFSIZE, value, 10),
  602.                             "EQUALIZER.INI");
  603.  
  604.     WritePrivateProfileString("DSE_Init",
  605.                             "DYNAMIC_RANGE_SCALE",
  606.                             _gcvt(DYNAMIC_RANGE_SCALE, 3, value),
  607.                             "EQUALIZER.INI");
  608.  
  609.     WritePrivateProfileString("DSE_Init",
  610.                             "DYNAMIC_TRESHOLD",
  611.                             _gcvt(DYNAMIC_TRESHOLD, 3, value),
  612.                             "EQUALIZER.INI");
  613.  
  614.     WritePrivateProfileString("DSE_Init",
  615.                             "DYNAMIC_EQUALIZING",
  616.                             itoa(DynamicEqualizing, value, 10),
  617.                             "EQUALIZER.INI");
  618.  
  619.     WritePrivateProfileString("DSE_Init",
  620.                             "BLUR_EQ_IMPACT",
  621.                             itoa(BlurEQImpact, value, 10),
  622.                             "EQUALIZER.INI");
  623.  
  624.     WritePrivateProfileString("DSE_Init",
  625.                             "EQ_FREQBANDS",
  626.                             itoa(NumSliders - 1, value, 10),
  627.                             "EQUALIZER.INI");
  628.  
  629.     switch(PROGRAM_PRIORITY) {
  630.         case IDLE_PRIORITY_CLASS:
  631.             strcpy(value, "IDLE_PRIORITY");
  632.             break;
  633.         case NORMAL_PRIORITY_CLASS:
  634.             strcpy(value, "NORMAL_PRIORITY");
  635.             break;
  636.         case HIGH_PRIORITY_CLASS:
  637.             strcpy(value, "HIGH_PRIORITY");
  638.             break;
  639.         case REALTIME_PRIORITY_CLASS:
  640.             strcpy(value, "REALTIME_PRIORITY");
  641.             break;
  642.     }
  643.  
  644.     WritePrivateProfileString("DSE_Init",
  645.                             "PRIORITY",
  646.                             value,
  647.                             "EQUALIZER.INI");
  648.  
  649.     // Save window position only if the window is not hidden
  650.     if(APPXPOS || APPYPOS || APPWIDTH || APPHEIGHT) {
  651.  
  652.         WritePrivateProfileString("DSE_Init",
  653.                                 "window_Xpos",
  654.                                 itoa(APPXPOS, value, 10),
  655.                                 "EQUALIZER.INI");
  656.  
  657.         WritePrivateProfileString("DSE_Init",
  658.                                 "window_Ypos",
  659.                                 itoa(APPYPOS, value, 10),
  660.                                 "EQUALIZER.INI");
  661.  
  662.         WritePrivateProfileString("DSE_Init",
  663.                                 "window_width",
  664.                                 itoa(APPWIDTH, value, 10),
  665.                                 "EQUALIZER.INI");
  666.  
  667.         WritePrivateProfileString("DSE_Init",
  668.                                 "window_height",
  669.                                 itoa(APPHEIGHT, value, 10),
  670.                                 "EQUALIZER.INI");
  671.     }
  672.  
  673. }
  674.  
  675. //
  676. //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
  677. //
  678. //  PURPOSE:  Processes messages for the main window.
  679. //
  680. //  WM_COMMAND    - process the application menu
  681. //  WM_PAINT    - Paint the main window
  682. //  WM_DESTROY    - post a quit message and return
  683. //
  684. //
  685. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  686. {
  687.     int wmId, wmEvent;
  688.     DOUBLE scale, xpos1, xpos2;
  689.     WORD i, j;
  690.     RECT rc;
  691.  
  692.     switch (message) 
  693.     {
  694.         case WM_COMMAND:
  695.             message = WM_SYSCOMMAND;
  696.         case WM_SYSCOMMAND:
  697.             wmId    = LOWORD(wParam); 
  698.             wmEvent = HIWORD(wParam); 
  699.             // Parse the menu selections:
  700.             switch (wmId)
  701.             {
  702.                 case IDM_ABOUT:
  703.                    DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
  704.                    break;
  705.                 case IDM_PREFERENCES:
  706.                     if(DialogBox(hInst, (LPCTSTR)IDD_PREFERENCES, hWnd, (DLGPROC)Preferences)) {
  707.  
  708.                         // Apply the preferences: restart RTEQ
  709.  
  710.                         ProcessTimer = TRUE;
  711.                     
  712.                         DestroyEqualizer();
  713.                         InitEqualizer();
  714.  
  715.                         for(DWORD i = 0; i < NumSliders; i++) {
  716.                             SendMessage(hWnd, WM_VSCROLL, NULL, (LPARAM)LSliders[i]);
  717.                         }
  718.                     
  719.                         ProcessTimer = FALSE;
  720.  
  721.                     }
  722.                    break;
  723.                 default:
  724.                    return DefWindowProc(hWnd, message, wParam, lParam);
  725.             }
  726.             break;
  727.         case WM_VSCROLL:
  728.             // If a slider was touched
  729.             i = 0;
  730.             while(LSliders[i] != (HWND)lParam && i < NumSliders) i++;
  731.             if(i < NumSliders) { 
  732.                 LSlidersVal[i] = SendMessage((HWND)lParam, TBM_GETPOS, 0, 0);
  733.  
  734.                 DOUBLE Value;
  735.  
  736.                 scale = LSlidersVal[i];
  737.                 Value = EqVal((INT)scale);
  738.  
  739.                 {
  740.                     // Determine the Volume in dB
  741.                     char ch[10];
  742.  
  743.                     if(Value > 0) gcvt(10 * log10(Value), 3, ch);
  744.                     else strcpy(ch, "-INF");                    
  745.                     if(!i) strcat(ch, "dB");
  746.  
  747.                     //SetWindowText(LVolumeDesc[i], ch);
  748.                     SendMessage(LVolumeDesc[i], WM_SETTEXT, 0, (LPARAM)(LPCSTR)ch);
  749.                     SendMessage(LVolumeDesc[i], WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  750.                 }
  751.  
  752.                 if(i == 0) {
  753.                     LMaster = Value;
  754.                 }
  755.                 else {
  756.  
  757.                     // The first half of the channel (linear)
  758.                     if(i > 1) {
  759.                         for(j = 0; j < lpchannel_halffreq[i]; j++) {
  760.                             lpRScale[lpchannel_startfreq[i] + j] = ((COEF)j / lpchannel_halffreq[i]) * Value;
  761.                         }
  762.                     }
  763.                     else {
  764.                         for(j = 0; j < lpchannel_halffreq[i]; j++) {
  765.                             lpRScale[j] = Value;
  766.                         }
  767.                     }
  768.  
  769.                     // The second half of the channel (linear)
  770.                     if(i < NumSliders - 1) {
  771.                         for(j = lpchannel_halffreq[i]; j < lpchannel_bandwidth[i]; j++) {
  772.                             lpRScale[lpchannel_startfreq[i] + j] = (1 - (((COEF)j - lpchannel_halffreq[i]) / ((COEF)lpchannel_bandwidth[i] - lpchannel_halffreq[i]))) * Value;
  773.                         }
  774.                     }
  775.                     else {
  776.                         for(j = lpchannel_halffreq[i]; j < lpchannel_bandwidth[i]; j++) {
  777.                             lpRScale[lpchannel_startfreq[i] + j] = Value;
  778.                         }
  779.                     }
  780.  
  781.                     for(j = 0; j < lpchannel_bandwidth[i]; j++) {
  782.                         lpLScale[i][j] = lpRScale[lpchannel_startfreq[i] + j];
  783.                     }
  784.  
  785.                 }
  786.  
  787.                 // *** Calculate variables for dynamic equalizing
  788.  
  789.                 // Calculate the Scale in a single array
  790.                 ZeroMemory(lpCorrLScale, REC_PERIOD * sizeof(DOUBLE));
  791.  
  792.                 for(i = 1; i < NumSliders; i++)    {
  793.                     for(DWORD j = 0; j < lpchannel_bandwidth[i]; j++) {
  794.                         lpCorrLScale[lpchannel_startfreq[i] + j] += lpLScale[i][j] * LMaster;
  795.                     }
  796.                 }
  797.                 
  798.                 // Calculate a normalized the scale array
  799.  
  800.                 for(i = 1; i < NumSliders; i++)    {
  801.                     COEF norm_var = 0;
  802.                     for(DWORD j = 0; j < lpchannel_bandwidth[i]; j++) {
  803.                         if(lpLScale[i][lpchannel_halffreq[i]] > 0) {
  804.                             lpNLScale[i][j] = lpLScale[i][j] / lpLScale[i][lpchannel_halffreq[i]];
  805.                         }
  806.                         else {
  807.                             lpNLScale[i][j] = 0;
  808.                         }
  809.                         norm_var += lpNLScale[i][j];
  810.                     }
  811.                     lpChannelNorm[i] = norm_var;
  812.                 }
  813.  
  814.             }
  815.             break;
  816.         case WM_SIZE:
  817.             {
  818.                 if(wParam == SIZE_MINIMIZED) {
  819.                     TaskbarIcon(NIM_ADD);
  820.  
  821.                     ShowWindow(hWnd, SW_HIDE);
  822.  
  823.                     EQonTaskBar = TRUE;
  824.                 }
  825.  
  826.                 // Reorder and resize all sliders
  827.                 if((wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) && LSliders) {
  828.  
  829.                     if(EQonTaskBar) {
  830.                         TaskbarIcon(NIM_DELETE);
  831.  
  832.                         ShowWindow(hWnd, SW_SHOW);
  833.  
  834.                         EQonTaskBar = FALSE;
  835.                     }
  836.             
  837.                     for(DWORD i = 0; i < NumSliders; i++) {
  838.                         rc.left = 0;
  839.                         rc.top = 0;
  840.                         rc.right = LOWORD(lParam);
  841.                         rc.bottom = HIWORD(lParam);
  842.  
  843.                         rc = GetChannelPos(rc, i);
  844.                         MoveWindow(LSliders[i], 
  845.                                 rc.left,
  846.                                 rc.top,
  847.                                 rc.right,
  848.                                 rc.bottom,
  849.                                 FALSE);
  850.  
  851.                         MoveWindow(LVolumeDesc[i], 
  852.                                 rc.left,
  853.                                 rc.top - 20,
  854.                                 rc.right,
  855.                                 20,
  856.                                 FALSE);
  857.  
  858.                         MoveWindow(LFreqDesc[i], 
  859.                                 rc.left,
  860.                                 rc.top + rc.bottom,
  861.                                 rc.right,
  862.                                 20,
  863.                                 FALSE);
  864.                         
  865.                         SetControlFont(&ControlFont, rc.right);
  866.                         SendMessage(LVolumeDesc[i], WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  867.                         SendMessage(LFreqDesc[i],   WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  868.  
  869.                         HDC hdc = GetDC(LSliders[i]);
  870.                         SendMessage(LSliders[i], WM_PAINT, (WPARAM) hdc, 0);
  871.                         ReleaseDC(LSliders[i], hdc);
  872.                     }
  873.                     
  874.                     for(i = 0; i < NumSliders; i++) {
  875.                         HDC hdc = GetDC(LSliders[i]);
  876.                         SendMessage(LSliders[i], WM_PAINT, (WPARAM) hdc, 0);
  877.                         ReleaseDC(LSliders[i], hdc);
  878.                     }
  879.                     HDC hdc = GetDC(hWnd);
  880.                     SendMessage(hWnd, WM_ERASEBKGND, (WPARAM) hdc, 0);
  881.                     ReleaseDC(hWnd, hdc);
  882.                 }
  883.             }
  884.             return(TRUE);
  885.         case WM_DESTROY:
  886.  
  887.             if(EQonTaskBar) {
  888.                 // Delete the Icon on the task bar
  889.                 TaskbarIcon(NIM_DELETE);
  890.  
  891.                 EQonTaskBar = FALSE;
  892.             }
  893.     
  894.             // Calculate the window position on the desktop
  895.             WINDOWPLACEMENT lpwplace;
  896.             GetWindowPlacement(hWnd, &lpwplace);
  897.             if(lpwplace.showCmd != SW_HIDE && lpwplace.showCmd != SW_SHOWMINIMIZED) {
  898.                 RECT rc;
  899.                 GetWindowRect(hWnd, &rc);
  900.                 APPXPOS = rc.left;
  901.                 APPYPOS = rc.top;
  902.                 APPWIDTH = rc.right - rc.left;
  903.                 APPHEIGHT = rc.bottom - rc.top;
  904.             }
  905.             else  {
  906.                 APPXPOS = APPYPOS = APPWIDTH = APPHEIGHT = 0;
  907.             }
  908.  
  909.             // Save the preferences and free memory
  910.             DestroyEqualizer();
  911.  
  912.             PostQuitMessage(0);
  913.             break;
  914.         case WM_ERASEBKGND:
  915.             /*if(nopaint) { nopaint = FALSE; break; }
  916.             {
  917.                 for(i = 0; i < NumSliders; i++) {
  918.                     HDC hdc = GetDC(LSliders[i]);
  919.                     SendMessage(LSliders[i], WM_PAINT, (WPARAM)hdc, 0);
  920.                     ReleaseDC(LSliders[i], hdc);
  921.                     SendMessage(LVolumeDesc[i], WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  922.                     SendMessage(LFreqDesc[i],   WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  923.                 }
  924.             }*/
  925.             return DefWindowProc(hWnd, message, wParam, lParam);
  926.             //return(1);
  927.  
  928.         case WM_PAINT:
  929.             for(i = 0; i < NumSliders; i++) {
  930.                 SendMessage(LVolumeDesc[i], WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  931.                 SendMessage(LFreqDesc[i],   WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  932.             }
  933.             return(DefWindowProc(hWnd, message, wParam, lParam));
  934.  
  935.         case WM_TASKBARICON:
  936.             if(lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK) {
  937.                 // Show the RTEQ window if left clicked
  938.                 ShowWindow(hWnd, SW_SHOWNORMAL);
  939.                 SetWindowPos(hWnd, HWND_TOPMOST,   0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  940.                 SetActiveWindow(hWnd);
  941.                 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  942.             }
  943.             else if(lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK) {
  944.                 // Show a menu when right clicked
  945.                 HMENU hSysmenu = CreatePopupMenu();
  946.             
  947.                 InsertMenuItemEasy(hSysmenu, FALSE,    MFT_STRING,    SC_CLOSE,        "&Close");
  948.                 InsertMenuItemEasy(hSysmenu, SC_CLOSE, MFT_STRING,    SC_RESTORE,      "&Show RTEQ");
  949.                 InsertMenuItemEasy(hSysmenu, SC_CLOSE, MFT_STRING,    IDM_PREFERENCES, "&Preferences...");
  950.                 InsertMenuItemEasy(hSysmenu, SC_CLOSE, MFT_STRING,    IDM_ABOUT,       "&About...");
  951.                 InsertMenuItemEasy(hSysmenu, SC_CLOSE, MFT_SEPARATOR, NULL,             NULL);
  952.                 
  953.                 POINT lpcrPoint;
  954.                 GetCursorPos(&lpcrPoint); 
  955.                 TrackPopupMenu(hSysmenu, TPM_RIGHTALIGN | TPM_TOPALIGN, lpcrPoint.x, lpcrPoint.y, 0, hWnd, 0);
  956.             }
  957.             break;
  958.  
  959.         case WM_NCLBUTTONDOWN:
  960.             if(wParam & HTSYSMENU == HTSYSMENU) nopaint = TRUE;
  961.         default:
  962.             return DefWindowProc(hWnd, message, wParam, lParam);
  963.    }
  964.    return 0;
  965. }
  966.  
  967. // Mesage handler for about box.
  968. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  969. {
  970.     switch (message)
  971.     {
  972.         case WM_INITDIALOG:
  973.                 return TRUE;
  974.  
  975.         case WM_COMMAND:
  976.             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
  977.             {
  978.                 EndDialog(hDlg, LOWORD(wParam));
  979.                 return TRUE;
  980.             }
  981.             break;
  982.     }
  983.     return FALSE;
  984. }
  985.  
  986. double EqFunc(LONG i) {
  987.  
  988.     double x;
  989.  
  990.     // Calculate the position of a channel in an array 
  991.  
  992.     x = (pow(2, (double)i / (NumSliders - 1) * 8) - 1) / (pow(2, 8) - 1);
  993.  
  994.     return(x);
  995.  
  996. }
  997.  
  998. // Recalculates the position and the size of the slider
  999. RECT GetChannelPos(RECT src, DWORD i) {
  1000.  
  1001.     WORD j, sliders_pro_row;
  1002.     RECT rc;
  1003.     FLOAT width, height, top;
  1004.  
  1005.     j = 0;
  1006.     do {
  1007.         j++;
  1008.         width = (FLOAT)((FLOAT)src.right / NumSliders * j);
  1009.     } while((width < 15) && (j < NumSliders));
  1010.     
  1011.     sliders_pro_row = (WORD)ceil((FLOAT)NumSliders / j);
  1012.     width = (FLOAT)((FLOAT)src.right / sliders_pro_row);
  1013.  
  1014.     height = (FLOAT)(src.bottom/* - 20*/) / j;
  1015.     top = /*20 + */(FLOAT)(i / sliders_pro_row) * (src.bottom/* - 20*/) / j;
  1016.     i %= sliders_pro_row;
  1017.  
  1018.     rc.left = (LONG)floor(((FLOAT)i * width));
  1019.     rc.top = (LONG)top + 20;
  1020.     rc.right = (LONG)ceil(width);
  1021.     rc.bottom = (LONG)height - 40;
  1022.  
  1023.     return(rc);
  1024.  
  1025. }
  1026.  
  1027. // Memory allocating routines
  1028.  
  1029. LPVOID AllocMemory(DWORD dwsize) {
  1030.  
  1031.     LPVOID ptr;
  1032.  
  1033.     while(!(ptr = GlobalAlloc(GPTR, dwsize))) {
  1034.         UINT response;
  1035.         TCHAR err[MAX_LOADSTRING];
  1036.  
  1037.         LoadString(hInst, IDS_ERR_MEMORY, err, MAX_LOADSTRING);
  1038.         response = MessageBox(NULL, err, szTitle, MB_APPLMODAL | MB_RETRYCANCEL | MB_ICONEXCLAMATION);
  1039.         if(response == IDCANCEL) exit(1);
  1040.     };
  1041.     
  1042.     return(ptr);
  1043.  
  1044. }
  1045.  
  1046. LPVOID AllocChannels(DWORD dwsize) {
  1047.  
  1048.     LPVOID *ptr;
  1049.     WORD i;
  1050.  
  1051.     ptr = (LPVOID *) AllocMemory(REC_CHANNELS * 2 * sizeof(LPVOID));
  1052.     for(i = 0; i < REC_CHANNELS * 2; i++) {
  1053.         ptr[i] = AllocMemory(dwsize);
  1054.     }
  1055.  
  1056.     return(ptr);
  1057.  
  1058. }
  1059.  
  1060. void FreeChannels(LPVOID *ptr) {
  1061.  
  1062.     WORD i;
  1063.  
  1064.     for(i = 0; i < REC_CHANNELS * 2; i++) {
  1065.         FreeMemory(ptr[i]);
  1066.     }
  1067.     FreeMemory(ptr);
  1068.  
  1069. }
  1070.  
  1071. LPVOID AllocChannels_Time(DWORD dwdepth, DWORD dwsize) {
  1072.  
  1073.     LPVOID **ptr;
  1074.     WORD i, j;
  1075.  
  1076.     ptr = (LPVOID **) AllocMemory(REC_CHANNELS * 2 * sizeof(LPVOID));
  1077.     for(i = 0; i < REC_CHANNELS * 2; i++) {
  1078.         ptr[i] = (LPVOID *) AllocMemory(dwdepth * sizeof(LPVOID));
  1079.         for(j = 0; j < dwdepth; j++) {
  1080.             ptr[i][j] = AllocMemory(dwsize);
  1081.         }
  1082.     }
  1083.  
  1084.     return(ptr);
  1085.  
  1086. }
  1087.  
  1088. void FreeChannels_Time(LPVOID **ptr, DWORD dwdepth) {
  1089.  
  1090.     WORD i, j;
  1091.  
  1092.     for(i = 0; i < REC_CHANNELS * 2; i++) {
  1093.         for(j = 0; j < dwdepth; j++) {
  1094.             FreeMemory((LPVOID *)ptr[i][j]);
  1095.         }
  1096.         FreeMemory((LPVOID *)ptr[i]);
  1097.     }
  1098.     FreeMemory((LPVOID *)ptr);
  1099.  
  1100. }
  1101.  
  1102. void SetControlFont(HFONT *ControlFont, DWORD width) {
  1103.  
  1104.     DOUBLE abswidth, absheight;
  1105.  
  1106.     // Create a font according to the slider width 
  1107.  
  1108.     abswidth = (DOUBLE)width / 5; // 5 characters have place 
  1109.     absheight = abswidth * 2;
  1110.     if(absheight > 20) {
  1111.         absheight = 20;
  1112.         abswidth = 10;
  1113.     }
  1114.  
  1115.     DeleteObject(*ControlFont);
  1116.     if(absheight < 12) {
  1117.         *ControlFont = CreateFont(-(int)absheight, (int)floor(abswidth), 0, 0, 
  1118.                                   FW_THIN, 0, 0, 0, 
  1119.                                   DEFAULT_CHARSET, 
  1120.                                   OUT_DEFAULT_PRECIS, 
  1121.                                   CLIP_DEFAULT_PRECIS, 
  1122.                                   DRAFT_QUALITY, 
  1123.                                   DEFAULT_PITCH | FF_DONTCARE, 
  1124.                                   "Small Fonts");
  1125.     }
  1126.     else {
  1127.         *ControlFont = CreateFont(-(int)absheight, (int)floor(abswidth), 0, 0, 
  1128.                                   FW_MEDIUM, 0, 0, 0, 
  1129.                                   DEFAULT_CHARSET, 
  1130.                                   OUT_DEFAULT_PRECIS, 
  1131.                                   CLIP_DEFAULT_PRECIS, 
  1132.                                   DRAFT_QUALITY, 
  1133.                                   DEFAULT_PITCH | FF_DONTCARE, 
  1134.                                   "Arial");
  1135.     }
  1136.  
  1137. }
  1138.  
  1139. DOUBLE EqVal(INT Val) 
  1140. {
  1141.  
  1142.     DOUBLE scale = Val, Value;
  1143.  
  1144.     // Calculates the scaling of a signal from a slider value
  1145.  
  1146.     if(scale > 99.9999999 && scale <= 100) Value = 0; // (due to rounding errors)
  1147.     else if(scale == 0) Value = 1;
  1148.     else {
  1149.         scale *= (DOUBLE)(DYNAMIC_RANGE_SCALE);
  1150.         if(scale < 0) Value = fabs(scale - 1);
  1151.         else Value = (DOUBLE)1 / fabs(scale + 1);
  1152.     }
  1153.  
  1154.     return(Value);
  1155.     
  1156. }
  1157.  
  1158. void InsertMenuItemEasy(HMENU hMenu, DWORD dwInsertAfter, DWORD dwType, DWORD dwId, LPCSTR lpStr) {
  1159.  
  1160.     // Inserts a menu item in a menu
  1161.  
  1162.     MENUITEMINFO mii;
  1163.  
  1164.     if(dwType == MFT_SEPARATOR) {
  1165.  
  1166.         mii.cbSize = sizeof(MENUITEMINFO); 
  1167.         mii.fMask = MIIM_TYPE | MIIM_STATE;
  1168.         mii.fType = MFT_SEPARATOR; 
  1169.         mii.fState = MFS_ENABLED; 
  1170.         mii.wID = NULL;  
  1171.         mii.hSubMenu = NULL; 
  1172.         mii.hbmpChecked = NULL; 
  1173.         mii.hbmpUnchecked = NULL; 
  1174.         mii.dwItemData = NULL; 
  1175.         mii.dwTypeData = NULL; 
  1176.         mii.cch = NULL; 
  1177.  
  1178.     }
  1179.     else {
  1180.         
  1181.         mii.cbSize = sizeof(MENUITEMINFO); 
  1182.         mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  1183.         mii.fType = MFT_STRING; 
  1184.         mii.fState = MFS_ENABLED; 
  1185.         mii.wID = dwId;  
  1186.         mii.hSubMenu = NULL; 
  1187.         mii.hbmpChecked = NULL; 
  1188.         mii.hbmpUnchecked = NULL; 
  1189.         mii.dwItemData = NULL; 
  1190.         mii.dwTypeData = (LPSTR)lpStr; 
  1191.         mii.cch = sizeof(mii.dwTypeData); 
  1192.  
  1193.     }
  1194.     
  1195.     InsertMenuItem(hMenu, dwInsertAfter, FALSE, &mii);
  1196.  
  1197. }
  1198.  
  1199. void TaskbarIcon(DWORD dwAction) {
  1200.  
  1201.     NOTIFYICONDATA Icon;
  1202.  
  1203.     // Perfroms actions on the task bar icon of RTEQ
  1204.  
  1205.     Icon.cbSize = sizeof(NOTIFYICONDATA);
  1206.     Icon.hWnd = hWnd;
  1207.     Icon.uID = 300;
  1208.     Icon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  1209.     Icon.uCallbackMessage = WM_TASKBARICON;
  1210.     Icon.hIcon = AppIcon;
  1211.     strcpy((LPSTR)&Icon.szTip, "RTEQ - Real Time Equalizer");
  1212.  
  1213.     Shell_NotifyIcon(dwAction, &Icon);
  1214.  
  1215. }
  1216.  
  1217. void InitEqualizer(void) {
  1218.  
  1219.     HINSTANCE hInstance = hInst;
  1220.  
  1221.     // Alloc the handles and variables for the sliders
  1222.     LSliders    = (LPHWND) AllocMemory(NumSliders * sizeof(HWND));
  1223.     RSliders    = (LPHWND) AllocMemory(NumSliders * sizeof(HWND));
  1224.     LVolumeDesc = (LPHWND) AllocMemory(NumSliders * sizeof(HWND));
  1225.     LFreqDesc   = (LPHWND) AllocMemory(NumSliders * sizeof(HWND));
  1226.     LSlidersVal = (LPDOUBLE) AllocMemory(NumSliders * sizeof(DOUBLE));
  1227.     RSlidersVal = (LPDOUBLE) AllocMemory(NumSliders * sizeof(DOUBLE));
  1228.  
  1229.     // Hide the main window while intializing it
  1230.     ShowWindow(hWnd, SW_HIDE);
  1231.    
  1232.     RECT rc, dest;
  1233.  
  1234.     // Create sliders
  1235.     GetClientRect(hWnd, &rc);    
  1236.  
  1237.     for(DWORD i = 0; i < NumSliders; i++) {
  1238.         dest = GetChannelPos(rc, i);
  1239.         SetControlFont(&ControlFont, dest.right);
  1240.  
  1241.         LSliders[i] = CreateWindow(/*"scrollbar",*/ "RTEQTrackBar",/* "msctls_trackbar32",*/
  1242.                                 "",
  1243.                                 WS_VISIBLE | WS_OVERLAPPED | WS_CHILD | TBS_VERT | TBS_NOTICKS | TBS_LEFT | TBS_TOOLTIPS,
  1244.                                 dest.left,
  1245.                                 dest.top,
  1246.                                 dest.right,
  1247.                                 dest.bottom,
  1248.                                 hWnd, (HMENU)i, hInstance, NULL);
  1249.  
  1250.         LVolumeDesc[i] = CreateWindow("static",
  1251.                                 "",
  1252.                                 WS_VISIBLE | WS_OVERLAPPED | WS_CHILD | SS_CENTER,
  1253.                                 dest.left,
  1254.                                 dest.top - 20,
  1255.                                 dest.right,
  1256.                                 20,
  1257.                                 hWnd, (HMENU)i, hInstance, NULL);
  1258.  
  1259.         LFreqDesc[i] = CreateWindow("static",
  1260.                                 "",
  1261.                                 WS_VISIBLE | WS_OVERLAPPED | WS_CHILD | SS_CENTER,
  1262.                                 dest.left,
  1263.                                 dest.bottom + 20,
  1264.                                 dest.right,
  1265.                                 20,
  1266.                                 hWnd, (HMENU)i, hInstance, NULL);
  1267.  
  1268.         {
  1269.             char ch[10], tch[10];
  1270.  
  1271.             if(i > 0) {
  1272.                 DOUBLE Value = (EqFunc(i) + EqFunc(i - 1)) / 2; // Center frequency
  1273.  
  1274.                 Value *= REC_FREQ / 2; // Scale to real frequency (/ 2 because of Nyquist freq)
  1275.                
  1276.                 if(Value < 1000) {
  1277.                     ltoa((DWORD) Value, ch, 10);
  1278.                 }
  1279.                 else {
  1280.                     ltoa((DWORD)Value / 1000, ch, 10);
  1281.                     strcat(ch, "K");
  1282.                     ltoa(((DWORD)Value % 1000), tch, 10);
  1283.                     tch[1] = '\0';
  1284.                     strcat(ch, tch);
  1285.                 }
  1286.             }
  1287.             else strcpy(ch, "M");
  1288.  
  1289.             SetWindowText(LFreqDesc[i], ch);
  1290.             SendMessage(LVolumeDesc[i], WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  1291.             SendMessage(LFreqDesc[i],   WM_SETFONT, (WPARAM)ControlFont, MAKELPARAM(TRUE, 0));
  1292.  
  1293.         }
  1294.  
  1295.         //RedrawWindow(LSliders[i], NULL, NULL, RDW_INTERNALPAINT);
  1296.         SendMessage(LSliders[i], TBM_SETRANGE, TRUE, MAKELONG(-100, 100));
  1297.         LSlidersVal[i] = 1;
  1298.         RSlidersVal[i] = 0;
  1299.     }
  1300.  
  1301.     ShowWindow(hWnd, SW_SHOW);
  1302.     UpdateWindow(hWnd);
  1303.  
  1304.     // Load equalizer values
  1305.     GetStartValues();
  1306.  
  1307.     // Initializing buffers for later usage
  1308.     lpsrc = (LPSHORT *) AllocChannels(REC_PERIOD * 2 * sizeof(SHORT));
  1309.     lpdest = (LPCOEF *) AllocChannels(REC_PERIOD * sizeof(COEF));
  1310.     lpbuf_src = (LPSHORT *) AllocChannels(REC_PERIOD * sizeof(SHORT));
  1311.     lpRScale = (LPCOEF) AllocMemory(REC_PERIOD * sizeof(COEF));
  1312.     lpweight = (LPCOEF) AllocMemory(REC_PERIOD * sizeof(COEF));
  1313.     lpimpact = (LPCOEF) AllocMemory(REC_PERIOD * sizeof(COEF));
  1314.     lptsrc   = (LPCOEF) AllocMemory(REC_PERIOD * sizeof(COEF));
  1315.     lpCorrLScale = (LPCOEF) AllocMemory(REC_PERIOD * sizeof(COEF));
  1316.     lpspectrum_power= (LPCOEF) AllocMemory(NumSliders * sizeof(COEF));
  1317.     lpChannelNorm = (LPCOEF) AllocMemory(NumSliders * sizeof(COEF));
  1318.  
  1319.     // Initializing variables for dynamic equalizing
  1320.     lpchannel_halffreq = (LPDWORD) AllocMemory(NumSliders * sizeof(DWORD));
  1321.     for(i = 1; i < NumSliders; i++) { 
  1322.         COEF begin = EqFunc(i - 1) * REC_PERIOD;
  1323.         COEF end   = EqFunc(i)     * REC_PERIOD;
  1324.         lpchannel_halffreq[i] = (end + begin) / 2;
  1325.     }
  1326.  
  1327.     lpchannel_startfreq = (LPDWORD) AllocMemory(NumSliders * sizeof(DWORD));
  1328.     for(i = 1; i < NumSliders; i++) {
  1329.         if(i == 1) lpchannel_startfreq[i] = 0;
  1330.         else       lpchannel_startfreq[i] = lpchannel_halffreq[i - 1];
  1331.     }
  1332.  
  1333.     lpchannel_bandwidth = (LPDWORD) AllocMemory(NumSliders * sizeof(DWORD));
  1334.     for(i = 1; i < NumSliders; i++) {
  1335.         if(i == NumSliders - 1) lpchannel_bandwidth[i] = REC_PERIOD                - lpchannel_startfreq[i];
  1336.         else                       lpchannel_bandwidth[i] = lpchannel_halffreq[i + 1] - lpchannel_startfreq[i];
  1337.     }
  1338.  
  1339.     lpLScale = (LPCOEF *) AllocMemory(NumSliders * sizeof(LPCOEF));
  1340.     for(i = 1; i < NumSliders; i++) {
  1341.         lpLScale[i] = (LPCOEF) AllocMemory(lpchannel_bandwidth[i] * sizeof(COEF));
  1342.     }
  1343.  
  1344.     lpNLScale = (LPCOEF *) AllocMemory(NumSliders * sizeof(LPCOEF));
  1345.     for(i = 1; i < NumSliders; i++) {
  1346.         lpNLScale[i] = (LPCOEF) AllocMemory(lpchannel_bandwidth[i] * sizeof(COEF));
  1347.     }
  1348.  
  1349.     for(i = 1; i < NumSliders; i++) {
  1350.          lpchannel_halffreq[i] -= lpchannel_startfreq[i];
  1351.     }
  1352.  
  1353.     // Initializing variables for normal equalizing
  1354.  
  1355.     LMaster = 0; RMaster = 0;
  1356.  
  1357.     for(i = 0; i < REC_PERIOD; i++) {
  1358.          lpRScale[i] = 0;
  1359.     }
  1360.  
  1361.     for(i = 1; i < NumSliders; i++) {
  1362.         for(DWORD j = 0; j < lpchannel_bandwidth[i]; j++) {
  1363.             lpLScale[i][j] = 0;
  1364.         }
  1365.  
  1366.     }
  1367.  
  1368.     for(i = 0; i < REC_PERIOD; i++) {
  1369.         lpweight[i] = (DOUBLE)1 - (cos(2 * pi * i / REC_PERIOD) + 1) / 2;
  1370.     }
  1371.  
  1372.     // Init DirectX input and output
  1373.     InitInput();
  1374.     InitOutput(hWnd);
  1375.  
  1376.     // Initializer Discrete Cosine Transform matrix
  1377.     gen_DCTmatrix(REC_PERIOD);
  1378.  
  1379.     // Create the equalizer thread which will perform the equalizing work
  1380.     EQThreadValid = TRUE;
  1381.     DWORD EQThreadID;
  1382.     hEQThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) EQThread, NULL, 0, &EQThreadID);
  1383.  
  1384. }
  1385.  
  1386. void DestroyEqualizer(void) {
  1387.  
  1388.     if(EQThreadValid) {
  1389.         // Destroy the equalizer thread
  1390.         EQThreadValid = FALSE;
  1391.         // Wait for thread to terminate (EQThreadValid = TRUE)
  1392.         while(EQThreadValid != TRUE);
  1393.         EQThreadValid = FALSE;
  1394.         CloseHandle(hEQThread);
  1395.     }
  1396.  
  1397.     // Save preferences and equalizer variables
  1398.     SaveEqualizer();
  1399.     SetStartValues();
  1400.             
  1401.     // Release DirectX input and output
  1402.     DestroyInput();
  1403.     DestroyOutput();
  1404.  
  1405.     destr_DCTmatrix();
  1406.  
  1407.     // Free the allocated memory
  1408.  
  1409.     {        
  1410.         for(DWORD i = 0; i < GlobalSize(LSliders) / sizeof(HWND); i++) {
  1411.             DestroyWindow(LSliders[i]);
  1412.             DestroyWindow(LVolumeDesc[i]);
  1413.             DestroyWindow(LFreqDesc[i]);
  1414.         }
  1415.     
  1416.         ////////////////////////////////////////////////////////////////
  1417.         
  1418.         for(i = 1; i < GlobalSize(LSliders) / sizeof(HWND); i++) {
  1419.             FreeMemory(lpLScale[i]);
  1420.         }
  1421.         FreeMemory(lpLScale);
  1422.  
  1423.         for(i = 1; i < GlobalSize(LSliders) / sizeof(HWND); i++) {
  1424.             FreeMemory(lpNLScale[i]);
  1425.         }
  1426.         FreeMemory(lpNLScale);
  1427.  
  1428.         FreeMemory(lpCorrLScale);
  1429.     }
  1430.  
  1431.     FreeMemory(LSliders);
  1432.     FreeMemory(RSliders);
  1433.     FreeMemory(LSlidersVal);
  1434.     FreeMemory(RSlidersVal);
  1435.     FreeMemory(LVolumeDesc);
  1436.     FreeMemory(LFreqDesc);
  1437.  
  1438.     FreeChannels((LPVOID *)lpsrc);
  1439.     FreeChannels((LPVOID *)lpdest);
  1440.  
  1441.     FreeMemory(lpRScale);
  1442.     FreeChannels((LPVOID *)lpbuf_src);
  1443.     FreeMemory(lpweight);
  1444.     FreeMemory(lptsrc);
  1445.     FreeMemory(lpimpact);
  1446.     FreeMemory(lpspectrum_power);
  1447.     FreeMemory(lpChannelNorm);
  1448.  
  1449.     FreeMemory(lpchannel_startfreq);
  1450.     FreeMemory(lpchannel_halffreq);
  1451.     FreeMemory(lpchannel_bandwidth);
  1452.                     
  1453. }
  1454.  
  1455. DWORD WINAPI EQThread(void) {
  1456.  
  1457.     switch(PROGRAM_PRIORITY) {
  1458.         case IDLE_PRIORITY_CLASS:     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);          break;
  1459.         case NORMAL_PRIORITY_CLASS:   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);        break;
  1460.         case HIGH_PRIORITY_CLASS:     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);       break;
  1461.         case REALTIME_PRIORITY_CLASS: SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); break;
  1462.     }
  1463.  
  1464.     // Process the equalizing work
  1465.     while(EQThreadValid) {
  1466.         if(!ProcessTimer) {
  1467.             while(Input(lpsrc[0], lpsrc[2])) {
  1468.     
  1469.                 for(DWORD i = 0; i < REC_CHANNELS; i++) PerformChannel(i);
  1470.     
  1471.                 Output(lpsrc[0], lpsrc[2]);
  1472.                 if(!EQThreadValid) break;
  1473.             }
  1474.             while(Output(NULL, NULL)); if(!EQThreadValid) break;
  1475.         }    
  1476.         if(!EQThreadValid) break;
  1477.         Sleep(((COEF)REC_PERIOD / REC_FREQ) * 1000 / 2);
  1478.     }
  1479.  
  1480.     EQThreadValid = TRUE;
  1481.  
  1482.     return(0);
  1483.     
  1484. }