[SNDVOL32] Implement the volume and balance trackbar for mono and stereo lines.
[reactos.git] / base / applications / sndvol32 / sndvol32.c
index 4e3523f..29e6dcf 100644 (file)
@@ -94,7 +94,7 @@ PrefDlgAddLine(PSND_MIXER Mixer,
     PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
 
     UNREFERENCED_PARAMETER(Mixer);
-       UNREFERENCED_PARAMETER(DisplayControls);
+    UNREFERENCED_PARAMETER(DisplayControls);
 
     switch (Line->dwComponentType)
     {
@@ -174,7 +174,7 @@ PrefDlgAddConnection(PSND_MIXER Mixer,
     UINT i;
 
     UNREFERENCED_PARAMETER(Mixer);
-       UNREFERENCED_PARAMETER(LineID);
+    UNREFERENCED_PARAMETER(LineID);
 
     if (Line->cControls != 0)
     {
@@ -632,7 +632,7 @@ SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx)
 {
     UINT ControlCount = 0, Index;
     LPMIXERCONTROL Control = NULL;
-    MIXERCONTROLDETAILS_UNSIGNED uDetails;
+    PMIXERCONTROLDETAILS_UNSIGNED puDetails = NULL;
     MIXERCONTROLDETAILS_BOOLEAN bDetails;
     PSET_VOLUME_CONTEXT Context = (PSET_VOLUME_CONTEXT)Ctx;
 
@@ -650,6 +650,10 @@ SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx)
         return FALSE;
     }
 
+    puDetails = HeapAlloc(GetProcessHeap(), 0, Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
+    if (puDetails == NULL)
+        return FALSE;
+
     /* now go through all controls and compare control ids */
     for (Index = 0; Index < ControlCount; Index++)
     {
@@ -657,14 +661,63 @@ SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx)
         {
             if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_FADER)
             {
-                /* FIXME: give me granularity */
-                DWORD Step = 0x10000 / VOLUME_STEPS;
+                DWORD LineOffset, volumePosition, balancePosition;
+                DWORD volumeStep, balanceStep;
 
-                /* set up details */
-                uDetails.dwValue = 0x10000 - Step * Context->SliderPos;
+                LineOffset = Context->SliderPos;
+
+                volumePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0);
+                volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
+
+                if (Line->cChannels == 1)
+                {
+                    /* set up details */
+                    puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+                }
+                else if (Line->cChannels == 2)
+                {
+                    balancePosition = (DWORD)SendDlgItemMessage(Preferences.MixerWindow->hWnd, LineOffset * IDC_LINE_SLIDER_HORZ, TBM_GETPOS, 0, 0);
+                    if (balancePosition == BALANCE_CENTER)
+                    {
+                        puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+                        puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+                    }
+                    else if (balancePosition == BALANCE_LEFT)
+                    {
+                        puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+                        puDetails[1].dwValue = Control[Index].Bounds.dwMinimum;
+                    }
+                    else if (balancePosition == BALANCE_RIGHT)
+                    {
+                        puDetails[0].dwValue = Control[Index].Bounds.dwMinimum;
+                        puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+                    }
+                    else if (balancePosition < BALANCE_CENTER) // Left
+                    {
+                        puDetails[0].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+
+                        balanceStep = (puDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
+
+                        puDetails[1].dwValue = (balancePosition * balanceStep) + Control[Index].Bounds.dwMinimum;
+                    }
+                    else if (balancePosition > BALANCE_CENTER) // Right
+                    {
+                        puDetails[1].dwValue = ((VOLUME_MAX - volumePosition) * volumeStep) + Control[Index].Bounds.dwMinimum;
+
+                        balanceStep = (puDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
+
+                        puDetails[0].dwValue = ((BALANCE_RIGHT - balancePosition) * balanceStep) + Control[Index].Bounds.dwMinimum;
+                    }
+                }
+                else
+                {
+                    SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails);
+
+                    /* FIXME */
+                }
 
                 /* set volume */
-                SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&uDetails);
+                SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)puDetails);
 
                 /* done */
                 break;
@@ -678,19 +731,17 @@ SetVolumeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Ctx)
                 bDetails.fValue = Context->SliderPos;
 
                 /* set volume */
-                SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&bDetails);
+                SndMixerSetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&bDetails);
 
                 /* done */
                 break;
             }
         }
-        else
-        {
-            /* FIXME: implement left - right channel switch support */
-            assert(0);
-        }
     }
 
+    if (puDetails != NULL)
+        HeapFree(GetProcessHeap(), 0, puDetails);
+
     /* free controls */
     HeapFree(GetProcessHeap(), 0, Control);
 
@@ -704,6 +755,7 @@ BOOL
 CALLBACK
 MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVOID Context)
 {
+    PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
     UINT ControlCount = 0, Index;
     LPMIXERCONTROL Control = NULL;
 
@@ -721,6 +773,12 @@ MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVO
         return FALSE;
     }
 
+    pVolumeDetails = HeapAlloc(GetProcessHeap(),
+                               0,
+                               Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
+    if (pVolumeDetails == NULL)
+        goto done;
+
     /* now go through all controls and compare control ids */
     for (Index = 0; Index < ControlCount; Index++)
     {
@@ -731,7 +789,7 @@ MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVO
                 MIXERCONTROLDETAILS_BOOLEAN Details;
 
                 /* get volume control details */
-                if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
+                if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
                 {
                     /* update dialog control */
                     UpdateDialogLineSwitchControl(&Preferences, Line, Details.fValue);
@@ -739,26 +797,75 @@ MixerControlChangeCallback(PSND_MIXER Mixer, DWORD LineID, LPMIXERLINE Line, PVO
             }
             else if ((Control[Index].dwControlType & MIXERCONTROL_CT_CLASS_MASK) == MIXERCONTROL_CT_CLASS_FADER)
             {
-                MIXERCONTROLDETAILS_UNSIGNED Details;
-
                 /* get volume control details */
-                if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)&Details) != -1)
+                if (SndMixerGetVolumeControlDetails(Preferences.MixerWindow->Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
                 {
                     /* update dialog control */
-                    DWORD Position;
-                    DWORD Step = 0x10000 / VOLUME_STEPS;
+                    DWORD volumePosition, volumeStep, maxVolume, i;
+                    DWORD balancePosition, balanceStep;
+
+                    volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
+
+                    maxVolume = 0;
+                    for (i = 0; i < Line->cChannels; i++)
+                    {
+                        if (pVolumeDetails[i].dwValue > maxVolume)
+                            maxVolume = pVolumeDetails[i].dwValue;
+                    }
+
+                    volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
+
+                    if (Line->cChannels == 1)
+                    {
+                        balancePosition = BALANCE_CENTER;
+                    }
+                    else if (Line->cChannels == 2)
+                    {
+                        if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
+                        {
+                            balancePosition = BALANCE_CENTER;
+                        }
+                        else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
+                        {
+                            balancePosition = BALANCE_RIGHT;
+                        }
+                        else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
+                        {
+                            balancePosition = BALANCE_LEFT;
+                        }
+                        else
+                        {
+                            balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
 
-                    /* FIXME: give me granularity */
-                    Position = VOLUME_STEPS - (Details.dwValue / Step);
+                            if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
+                            {
+                                balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
+                                balancePosition = BALANCE_RIGHT - balancePosition;
+                            }
+                            else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
+                            {
+                                balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
+                                balancePosition = BALANCE_LEFT + balancePosition;
+                            }
+                        }
+                    }
+
+                    /* Update the volume control slider */
+                    UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_VERT, VOLUME_MAX - volumePosition);
 
-                    /* update volume control slider */
-                    UpdateDialogLineSliderControl(&Preferences, Line, Control[Index].dwControlID, IDC_LINE_SLIDER_VERT, Position);
+                    /* Update the balance control slider */
+                    UpdateDialogLineSliderControl(&Preferences, Line, IDC_LINE_SLIDER_HORZ, balancePosition);
                 }
             }
             break;
         }
     }
 
+done:
+    /* Free the volume details */
+    if (pVolumeDetails)
+        HeapFree(GetProcessHeap(), 0, pVolumeDetails);
+
     /* free controls */
     HeapFree(GetProcessHeap(), 0, Control);
 
@@ -879,23 +986,23 @@ MainWindowProc(HWND hwnd,
                     /* check if the message is from the line switch */
                     if (HIWORD(wParam) == BN_CLICKED && (CtrlID % IDC_LINE_SWITCH == 0))
                     {
-                         /* compute line offset */
-                         LineOffset = CtrlID / IDC_LINE_SWITCH;
+                        /* compute line offset */
+                        LineOffset = CtrlID / IDC_LINE_SWITCH;
 
                         /* compute window id of line name static control */
                         CtrlID = LineOffset * IDC_LINE_NAME;
 
-                       /* get line name */
-                       if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
-                       {
-                           /* setup context */
-                           Context.SliderPos = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
-                           Context.bVertical = FALSE;
-                           Context.bSwitch = TRUE;
-
-                           /* set volume */
-                           SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
-                       }
+                        /* get line name */
+                        if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
+                        {
+                            /* setup context */
+                            Context.SliderPos = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
+                            Context.bVertical = FALSE;
+                            Context.bSwitch = TRUE;
+
+                            /* set volume */
+                            SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
+                        }
                     }
                 }
 
@@ -926,33 +1033,94 @@ MainWindowProc(HWND hwnd,
         }
 
         case WM_VSCROLL:
-        {
-            if (LOWORD(wParam) == TB_THUMBTRACK)
+            switch (LOWORD(wParam))
             {
-                /* get dialog item ctrl */
-                CtrlID = GetDlgCtrlID((HWND)lParam);
+                case TB_THUMBTRACK:
+                    /* get dialog item ctrl */
+                    CtrlID = GetDlgCtrlID((HWND)lParam);
 
-                /* get line index */
-                LineOffset = CtrlID / IDC_LINE_SLIDER_VERT;
+                    /* get line index */
+                    LineOffset = CtrlID / IDC_LINE_SLIDER_VERT;
 
-                /* compute window id of line name static control */
-                CtrlID = LineOffset * IDC_LINE_NAME;
+                    /* compute window id of line name static control */
+                    CtrlID = LineOffset * IDC_LINE_NAME;
 
-                /* get line name */
-                if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
-                {
-                    /* setup context */
-                    Context.SliderPos = HIWORD(wParam);
-                    Context.bVertical = TRUE;
-                    Context.bSwitch = FALSE;
+                    /* get line name */
+                    if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
+                    {
+                        /* setup context */
+                        Context.SliderPos = LineOffset;
+                        Context.bVertical = TRUE;
+                        Context.bSwitch = FALSE;
 
-                    /* set volume */
-                    SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
-                }
+                        /* set volume */
+                        SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
+                    }
+                    break;
+
+                case TB_ENDTRACK:
+                    MixerWindow = GetWindowData(hwnd,
+                                                MIXER_WINDOW);
+
+                    /* get dialog item ctrl */
+                    CtrlID = GetDlgCtrlID((HWND)lParam);
+
+                    /* get line index */
+                    LineOffset = CtrlID / IDC_LINE_SLIDER_VERT;
+
+                    if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0)
+                        PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
+                    break;
+
+                default:
+                    break;
             }
+            break;
+
+        case WM_HSCROLL:
+            switch (LOWORD(wParam))
+            {
+                case TB_THUMBTRACK:
+                    /* get dialog item ctrl */
+                    CtrlID = GetDlgCtrlID((HWND)lParam);
+
+                    /* get line index */
+                    LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ;
+
+                    /* compute window id of line name static control */
+                    CtrlID = LineOffset * IDC_LINE_NAME;
+
+                    /* get line name */
+                    if (GetDlgItemTextW(hwnd, CtrlID, Context.LineName, MIXER_LONG_NAME_CHARS) != 0)
+                    {
+                        /* setup context */
+                        Context.SliderPos = LineOffset;
+                        Context.bVertical = TRUE;
+                        Context.bSwitch = FALSE;
+
+                        /* set volume */
+                        SndMixerEnumConnections(Preferences.MixerWindow->Mixer, Preferences.SelectedLine, SetVolumeCallback, (LPVOID)&Context);
+                    }
+                    break;
+
+                case TB_ENDTRACK:
+                    MixerWindow = GetWindowData(hwnd,
+                                                MIXER_WINDOW);
+
+                    /* get dialog item ctrl */
+                    CtrlID = GetDlgCtrlID((HWND)lParam);
+
+                    /* get line index */
+                    LineOffset = CtrlID / IDC_LINE_SLIDER_HORZ;
+
+                    if (LineOffset == 1 && MixerWindow->Mixer->MixerId == 0)
+                        PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
+                    break;
 
+                default:
+                    break;
+            }
             break;
-        }
 
 
         case WM_CREATE:
@@ -1015,6 +1183,9 @@ MainWindowProc(HWND hwnd,
                                    (LPARAM)szProduct);
                     }
                 }
+
+                /* Disable the 'Advanced Controls' menu item */
+                EnableMenuItem(GetMenu(hwnd), IDC_ADVANCED_CONTROLS, MF_BYCOMMAND | MF_GRAYED);
             }
             break;
         }