1 /* 2 * PROJECT: ReactOS Multimedia Control Panel 3 * FILE: dll/cpl/mmsys/speakervolume.c 4 * PURPOSE: ReactOS Multimedia Control Panel 5 * PROGRAMMER: Eric Kohl <eric.kohl@reactos.com> 6 */ 7 8 #include "mmsys.h" 9 10 typedef struct _PAGE_DATA 11 { 12 HMIXER hMixer; 13 DWORD volumeControlID; 14 DWORD volumeChannels; 15 DWORD volumeMinimum; 16 DWORD volumeMaximum; 17 DWORD volumeStep; 18 PMIXERCONTROLDETAILS_UNSIGNED volumeValues; 19 BOOL volumeSync; 20 } PAGE_DATA, *PPAGE_DATA; 21 22 23 static 24 BOOL 25 OnInitDialog( 26 PPAGE_DATA pPageData, 27 HWND hwndDlg) 28 { 29 TCHAR szBuffer[256]; 30 MIXERLINE mxln; 31 MIXERCONTROL mxc; 32 MIXERLINECONTROLS mxlctrl; 33 MIXERCONTROLDETAILS mxcd; 34 INT i, j; 35 36 /* Open the mixer */ 37 if (mixerOpen(&pPageData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR) 38 { 39 MessageBox(hwndDlg, _T("Cannot open mixer"), NULL, MB_OK); 40 return FALSE; 41 } 42 43 /* Retrieve the mixer information */ 44 mxln.cbStruct = sizeof(MIXERLINE); 45 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; 46 47 if (mixerGetLineInfo((HMIXEROBJ)pPageData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR) 48 return FALSE; 49 50 pPageData->volumeChannels = mxln.cChannels; 51 52 /* Retrieve the line information */ 53 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS); 54 mxlctrl.dwLineID = mxln.dwLineID; 55 mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; 56 mxlctrl.cControls = 1; 57 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL); 58 mxlctrl.pamxctrl = &mxc; 59 60 if (mixerGetLineControls((HMIXEROBJ)pPageData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) 61 return FALSE; 62 63 pPageData->volumeControlID = mxc.dwControlID; 64 pPageData->volumeMinimum = mxc.Bounds.dwMinimum; 65 pPageData->volumeMaximum = mxc.Bounds.dwMaximum; 66 pPageData->volumeStep = (pPageData->volumeMaximum - pPageData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN); 67 68 /* Allocate a buffer for all channel volume values */ 69 pPageData->volumeValues = HeapAlloc(GetProcessHeap(), 70 0, 71 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 72 if (pPageData->volumeValues == NULL) 73 return FALSE; 74 75 /* Retrieve the channel volume values */ 76 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 77 mxcd.dwControlID = mxc.dwControlID; 78 mxcd.cChannels = mxln.cChannels; 79 mxcd.cMultipleItems = 0; 80 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 81 mxcd.paDetails = pPageData->volumeValues; 82 83 if (mixerGetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 84 return FALSE; 85 86 /* Initialize the channels */ 87 for (i = 0; i < min(mxln.cChannels, 5); i++) 88 { 89 j = i * 4; 90 91 /* Set the channel name */ 92 LoadString(hApplet, IDS_SPEAKER_LEFT + i, szBuffer, _countof(szBuffer)); 93 SetWindowText(GetDlgItem(hwndDlg, 9472 + j), szBuffer); 94 95 /* Initialize the channel trackbar */ 96 SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX)); 97 SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETTICFREQ, VOLUME_TICFREQ, 0); 98 SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPAGESIZE, 0, VOLUME_PAGESIZE); 99 SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pPageData->volumeValues[i].dwValue - pPageData->volumeMinimum) / pPageData->volumeStep); 100 } 101 102 /* Hide the unused controls */ 103 for (i = mxln.cChannels; i < 8; i++) 104 { 105 j = i * 4; 106 ShowWindow(GetDlgItem(hwndDlg, 9472 + j), SW_HIDE); 107 ShowWindow(GetDlgItem(hwndDlg, 9473 + j), SW_HIDE); 108 ShowWindow(GetDlgItem(hwndDlg, 9474 + j), SW_HIDE); 109 ShowWindow(GetDlgItem(hwndDlg, 9475 + j), SW_HIDE); 110 } 111 112 return TRUE; 113 } 114 115 116 static 117 VOID 118 OnMixerControlChange( 119 PPAGE_DATA pPageData, 120 HWND hwndDlg) 121 { 122 MIXERCONTROLDETAILS mxcd; 123 INT i, j; 124 125 /* Retrieve the channel volume values */ 126 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 127 mxcd.dwControlID = pPageData->volumeControlID; 128 mxcd.cChannels = pPageData->volumeChannels; 129 mxcd.cMultipleItems = 0; 130 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 131 mxcd.paDetails = pPageData->volumeValues; 132 133 if (mixerGetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 134 return; 135 136 for (i = 0; i < pPageData->volumeChannels; i++) 137 { 138 j = i * 4; 139 140 SendDlgItemMessage(hwndDlg, 9475 + j, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)(pPageData->volumeValues[i].dwValue - pPageData->volumeMinimum) / pPageData->volumeStep); 141 } 142 } 143 144 145 static 146 VOID 147 OnHScroll( 148 PPAGE_DATA pPageData, 149 HWND hwndDlg, 150 WPARAM wParam, 151 LPARAM lParam) 152 { 153 MIXERCONTROLDETAILS mxcd; 154 DWORD dwValue, dwPosition; 155 INT id, idx, i, j; 156 157 id = (INT)GetWindowLongPtr((HWND)lParam, GWLP_ID); 158 if (id < 9475 || id > 9503) 159 return; 160 161 if ((id - 9475) % 4 != 0) 162 return; 163 164 dwPosition = (DWORD)SendDlgItemMessage(hwndDlg, id, TBM_GETPOS, 0, 0); 165 166 if (dwPosition == VOLUME_MIN) 167 dwValue = pPageData->volumeMinimum; 168 else if (dwPosition == VOLUME_MAX) 169 dwValue = pPageData->volumeMaximum; 170 else 171 dwValue = (dwPosition * pPageData->volumeStep) + pPageData->volumeMinimum; 172 173 if (pPageData->volumeSync) 174 { 175 for (i = 0; i < pPageData->volumeChannels; i++) 176 { 177 j = 9475 + (i * 4); 178 if (j != id) 179 SendDlgItemMessage(hwndDlg, j, TBM_SETPOS, (WPARAM)TRUE, dwPosition); 180 181 pPageData->volumeValues[i].dwValue = dwValue; 182 } 183 } 184 else 185 { 186 idx = (id - 9475) / 4; 187 pPageData->volumeValues[idx].dwValue = dwValue; 188 } 189 190 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 191 mxcd.dwControlID = pPageData->volumeControlID; 192 mxcd.cChannels = pPageData->volumeChannels; 193 mxcd.cMultipleItems = 0; 194 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 195 mxcd.paDetails = pPageData->volumeValues; 196 197 if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 198 return; 199 } 200 201 202 static 203 VOID 204 OnSetDefaults( 205 PPAGE_DATA pPageData, 206 HWND hwndDlg) 207 { 208 MIXERCONTROLDETAILS mxcd; 209 DWORD dwValue, i; 210 211 dwValue = ((VOLUME_MAX - VOLUME_MIN) / 2 * pPageData->volumeStep) + pPageData->volumeMinimum; 212 213 for (i = 0; i < pPageData->volumeChannels; i++) 214 pPageData->volumeValues[i].dwValue = dwValue; 215 216 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 217 mxcd.dwControlID = pPageData->volumeControlID; 218 mxcd.cChannels = pPageData->volumeChannels; 219 mxcd.cMultipleItems = 0; 220 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 221 mxcd.paDetails = pPageData->volumeValues; 222 223 if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 224 return; 225 } 226 227 228 INT_PTR 229 CALLBACK 230 SpeakerVolumeDlgProc( 231 HWND hwndDlg, 232 UINT uMsg, 233 WPARAM wParam, 234 LPARAM lParam) 235 { 236 PPAGE_DATA pPageData; 237 238 UNREFERENCED_PARAMETER(wParam); 239 240 pPageData = (PPAGE_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 241 242 switch(uMsg) 243 { 244 case WM_INITDIALOG: 245 pPageData = (PPAGE_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PAGE_DATA)); 246 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pPageData); 247 248 if (pPageData) 249 { 250 OnInitDialog(pPageData, hwndDlg); 251 } 252 break; 253 254 case WM_DESTROY: 255 if (pPageData) 256 { 257 if (pPageData->volumeValues) 258 HeapFree(GetProcessHeap(), 0, pPageData->volumeValues); 259 260 if (pPageData->hMixer) 261 mixerClose(pPageData->hMixer); 262 263 HeapFree(GetProcessHeap(), 0, pPageData); 264 pPageData = NULL; 265 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL); 266 } 267 break; 268 269 case WM_HSCROLL: 270 if (pPageData) 271 { 272 OnHScroll(pPageData, hwndDlg, wParam, lParam); 273 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 274 } 275 break; 276 277 case WM_COMMAND: 278 switch (LOWORD(wParam)) 279 { 280 case 9504: 281 if (HIWORD(wParam) == BN_CLICKED) 282 pPageData->volumeSync = (SendDlgItemMessage(hwndDlg, 9504, BM_GETCHECK, 0, 0) == BST_CHECKED); 283 break; 284 285 case 9505: 286 OnSetDefaults(pPageData, hwndDlg); 287 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 288 break; 289 } 290 break; 291 292 case WM_NOTIFY: 293 return TRUE; 294 295 case MM_MIXM_CONTROL_CHANGE: 296 if (pPageData) 297 OnMixerControlChange(pPageData, hwndDlg); 298 break; 299 } 300 301 return FALSE; 302 } 303 304 305 INT_PTR 306 SpeakerVolume( 307 HWND hwndDlg) 308 { 309 PROPSHEETPAGE psp[1]; 310 PROPSHEETHEADER psh; 311 312 ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); 313 psh.dwSize = sizeof(PROPSHEETHEADER); 314 psh.dwFlags = PSH_PROPSHEETPAGE; 315 psh.hwndParent = hwndDlg; 316 psh.hInstance = hApplet; 317 psh.pszCaption = MAKEINTRESOURCE(IDS_SPEAKER_VOLUME); 318 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); 319 psh.nStartPage = 0; 320 psh.ppsp = psp; 321 322 InitPropSheetPage(&psp[0], IDD_MULTICHANNEL, SpeakerVolumeDlgProc); 323 psp[0].dwFlags |= PSP_USETITLE; 324 psp[0].hInstance = hApplet; 325 psp[0].pszTitle = MAKEINTRESOURCE(IDS_SPEAKER_VOLUME); 326 327 return (LONG)(PropertySheet(&psh) != -1); 328 } 329