[MMSYS] Take the balance between channels into account for the master volume trackbar.
[reactos.git] / dll / cpl / mmsys / speakervolume.c
index 270cdfc..a21c940 100644 (file)
@@ -7,30 +7,49 @@
 
 #include "mmsys.h"
 
+typedef struct _PAGE_DATA
+{
+    HMIXER hMixer;
+    DWORD volumeControlID;
+    DWORD volumeChannels;
+    DWORD volumeMinimum;
+    DWORD volumeMaximum;
+    DWORD volumeStep;
+    PMIXERCONTROLDETAILS_UNSIGNED volumeValues;
+    BOOL volumeSync;
+} PAGE_DATA, *PPAGE_DATA;
+
+
 static
 BOOL
 OnInitDialog(
-    HWND hwndDlg,
-    LPARAM lParam)
+    PPAGE_DATA pPageData,
+    HWND hwndDlg)
 {
     TCHAR szBuffer[256];
     MIXERLINE mxln;
     MIXERCONTROL mxc;
     MIXERLINECONTROLS mxlctrl;
     MIXERCONTROLDETAILS mxcd;
-    MIXERCONTROLDETAILS_UNSIGNED mxcdVolume[8];
     INT i, j;
-    DWORD dwStep;
-    HMIXER hMixer;
 
-    hMixer = (HMIXER)((LPPROPSHEETPAGE)lParam)->lParam;
+    /* Open the mixer */
+    if (mixerOpen(&pPageData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
+    {
+        MessageBox(hwndDlg, _T("Cannot open mixer"), NULL, MB_OK);
+        return FALSE;
+    }
 
+    /* Retrieve the mixer information */
     mxln.cbStruct = sizeof(MIXERLINE);
     mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
 
-    if (mixerGetLineInfo((HMIXEROBJ)hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
+    if (mixerGetLineInfo((HMIXEROBJ)pPageData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
         return FALSE;
 
+    pPageData->volumeChannels = mxln.cChannels;
+
+    /* Retrieve the line information */
     mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
     mxlctrl.dwLineID = mxln.dwLineID;
     mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
@@ -38,39 +57,46 @@ OnInitDialog(
     mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
     mxlctrl.pamxctrl = &mxc;
 
-    if (mixerGetLineControls((HMIXEROBJ)hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
+    if (mixerGetLineControls((HMIXEROBJ)pPageData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
         return FALSE;
 
-//    pGlobalData->volumeMinimum = mxc.Bounds.dwMinimum;
-//    pGlobalData->volumeMaximum = mxc.Bounds.dwMaximum;
-//    pGlobalData->volumeControlID = mxc.dwControlID;
-//    pGlobalData->volumeStep = (pGlobalData->volumeMaximum - pGlobalData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
-    dwStep = (mxc.Bounds.dwMaximum - mxc.Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
+    pPageData->volumeControlID = mxc.dwControlID;
+    pPageData->volumeMinimum = mxc.Bounds.dwMinimum;
+    pPageData->volumeMaximum = mxc.Bounds.dwMaximum;
+    pPageData->volumeStep = (pPageData->volumeMaximum - pPageData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
 
+    /* Allocate a buffer for all channel volume values */
+    pPageData->volumeValues = HeapAlloc(GetProcessHeap(),
+                                        0,
+                                        mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
+    if (pPageData->volumeValues == NULL)
+        return FALSE;
+
+    /* Retrieve the channel volume values */
     mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
     mxcd.dwControlID = mxc.dwControlID;
     mxcd.cChannels = mxln.cChannels;
     mxcd.cMultipleItems = 0;
     mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
-    mxcd.paDetails = &mxcdVolume;
+    mxcd.paDetails = pPageData->volumeValues;
 
-    if (mixerGetControlDetails((HMIXEROBJ)hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
+    if (mixerGetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
         return FALSE;
 
-//    pGlobalData->volumeValue[i] = mxcdVolume[i].dwValue;
-
     /* Initialize the channels */
     for (i = 0; i < min(mxln.cChannels, 5); i++)
     {
         j = i * 4;
-        LoadString(hApplet, 5792 + i, szBuffer, _countof(szBuffer));
+
+        /* Set the channel name */
+        LoadString(hApplet, IDS_SPEAKER_LEFT + i, szBuffer, _countof(szBuffer));
         SetWindowText(GetDlgItem(hwndDlg, 9472 + j), szBuffer);
 
+        /* Initialize the channel trackbar */
         SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
         SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETTICFREQ, VOLUME_TICFREQ, 0);
         SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPAGESIZE, 0, VOLUME_PAGESIZE);
-//        SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pGlobalData->volumeValue - pGlobalData->volumeMinimum) / pGlobalData->volumeStep);
-        SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(mxcdVolume[i].dwValue - mxc.Bounds.dwMinimum) / dwStep);
+        SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pPageData->volumeValues[i].dwValue - pPageData->volumeMinimum) / pPageData->volumeStep);
     }
 
     /* Hide the unused controls */
@@ -87,6 +113,118 @@ OnInitDialog(
 }
 
 
+static
+VOID
+OnMixerControlChange(
+    PPAGE_DATA pPageData,
+    HWND hwndDlg)
+{
+    MIXERCONTROLDETAILS mxcd;
+    INT i, j;
+
+    /* Retrieve the channel volume values */
+    mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+    mxcd.dwControlID = pPageData->volumeControlID;
+    mxcd.cChannels = pPageData->volumeChannels;
+    mxcd.cMultipleItems = 0;
+    mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+    mxcd.paDetails = pPageData->volumeValues;
+
+    if (mixerGetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
+        return;
+
+    for (i = 0; i < pPageData->volumeChannels; i++)
+    {
+        j = i * 4;
+
+        SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pPageData->volumeValues[i].dwValue - pPageData->volumeMinimum) / pPageData->volumeStep);
+    }
+}
+
+
+static
+VOID
+OnHScroll(
+    PPAGE_DATA pPageData,
+    HWND hwndDlg,
+    WPARAM wParam,
+    LPARAM lParam)
+{
+    MIXERCONTROLDETAILS mxcd;
+    DWORD dwValue, dwPosition;
+    INT id, idx, i, j;
+
+    id = (INT)GetWindowLongPtr((HWND)lParam, GWLP_ID);
+    if (id < 9475 && id > 9503)
+        return;
+
+    if ((id - 9475) % 4 != 0)
+        return;
+
+    dwPosition = (DWORD)SendDlgItemMessage(hwndDlg, id, TBM_GETPOS, 0, 0);
+
+    if (dwPosition == VOLUME_MIN)
+        dwValue = pPageData->volumeMinimum;
+    else if (dwPosition == VOLUME_MAX)
+        dwValue = pPageData->volumeMaximum;
+    else
+        dwValue = (dwPosition * pPageData->volumeStep) + pPageData->volumeMinimum;
+
+    if (pPageData->volumeSync)
+    {
+        for (i = 0; i < pPageData->volumeChannels; i++)
+        {
+            j = 9475 + (i * 4);
+            if (j != id)
+                SendDlgItemMessage(hwndDlg, j, TBM_SETPOS, (WPARAM)TRUE, dwPosition);
+
+            pPageData->volumeValues[i].dwValue = dwValue;
+        }
+    }
+    else
+    {
+        idx = (id - 9475) / 4;
+        pPageData->volumeValues[idx].dwValue = dwValue;
+    }
+
+    mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+    mxcd.dwControlID = pPageData->volumeControlID;
+    mxcd.cChannels = pPageData->volumeChannels;
+    mxcd.cMultipleItems = 0;
+    mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+    mxcd.paDetails = pPageData->volumeValues;
+
+    if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
+        return;
+}
+
+
+static
+VOID
+OnSetDefaults(
+    PPAGE_DATA pPageData,
+    HWND hwndDlg)
+{
+    MIXERCONTROLDETAILS mxcd;
+    DWORD dwValue, i;
+
+    dwValue = ((VOLUME_MAX - VOLUME_MIN) / 2 * pPageData->volumeStep) + pPageData->volumeMinimum;
+
+    for (i = 0; i < pPageData->volumeChannels; i++)
+        pPageData->volumeValues[i].dwValue = dwValue;
+
+    mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+    mxcd.dwControlID = pPageData->volumeControlID;
+    mxcd.cChannels = pPageData->volumeChannels;
+    mxcd.cMultipleItems = 0;
+    mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+    mxcd.paDetails = pPageData->volumeValues;
+
+    if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
+        return;
+}
+
+
 INT_PTR
 CALLBACK
 SpeakerVolumeDlgProc(
@@ -95,19 +233,69 @@ SpeakerVolumeDlgProc(
     WPARAM wParam,
     LPARAM lParam)
 {
+    PPAGE_DATA pPageData;
+
     UNREFERENCED_PARAMETER(wParam);
 
+    pPageData = (PPAGE_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
+
     switch(uMsg)
     {
         case WM_INITDIALOG:
-            OnInitDialog(hwndDlg, lParam);
+            pPageData = (PPAGE_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PAGE_DATA));
+            SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pPageData);
+
+            if (pPageData)
+            {
+                OnInitDialog(pPageData, hwndDlg);
+            }
             break;
 
         case WM_DESTROY:
+            if (pPageData)
+            {
+                if (pPageData->volumeValues)
+                    HeapFree(GetProcessHeap(), 0, pPageData->volumeValues);
+
+                if (pPageData->hMixer)
+                    mixerClose(pPageData->hMixer);
+
+                HeapFree(GetProcessHeap(), 0, pPageData);
+                pPageData = NULL;
+                SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
+            }
+            break;
+
+        case WM_HSCROLL:
+            if (pPageData)
+            {
+                OnHScroll(pPageData, hwndDlg, wParam, lParam);
+                PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+            }
+            break;
+
+        case WM_COMMAND:
+            switch (LOWORD(wParam))
+            {
+                case 9504:
+                    if (HIWORD(wParam) == BN_CLICKED)
+                        pPageData->volumeSync = (SendDlgItemMessage(hwndDlg, 9504, BM_GETCHECK, 0, 0) == BST_CHECKED);
+                    break;
+
+                case 9505:
+                    OnSetDefaults(pPageData, hwndDlg);
+                    PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+                    break;
+            }
             break;
 
         case WM_NOTIFY:
             return TRUE;
+
+        case MM_MIXM_CONTROL_CHANGE:
+            if (pPageData)
+                OnMixerControlChange(pPageData, hwndDlg);
+            break;
     }
 
     return FALSE;
@@ -116,8 +304,7 @@ SpeakerVolumeDlgProc(
 
 INT_PTR
 SpeakerVolume(
-    HWND hwnd,
-    HMIXER hMixer)
+    HWND hwndDlg)
 {
     PROPSHEETPAGE psp[1];
     PROPSHEETHEADER psh;
@@ -128,14 +315,16 @@ SpeakerVolume(
     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
     psh.dwSize = sizeof(PROPSHEETHEADER);
     psh.dwFlags =  PSH_PROPSHEETPAGE;
-    psh.hwndParent = hwnd;
+    psh.hwndParent = hwndDlg;
     psh.hInstance = hApplet;
     psh.pszCaption = Caption;
     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
     psh.nStartPage = 0;
     psh.ppsp = psp;
 
-    InitPropSheetPage(&psp[0], IDD_MULTICHANNEL, SpeakerVolumeDlgProc, (LPARAM)hMixer);
+    InitPropSheetPage(&psp[0], IDD_MULTICHANNEL, SpeakerVolumeDlgProc);
+    psp[0].dwFlags |= PSP_USETITLE;
+    psp[0].pszTitle = Caption;
 
     return (LONG)(PropertySheet(&psh) != -1);
 }