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, dwPos; 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 dwPos = (DWORD)SendDlgItemMessage(hwndDlg, id, TBM_GETPOS, 0, 0); 165 dwValue = (dwPos * pPageData->volumeStep) + pPageData->volumeMinimum; 166 167 if (pPageData->volumeSync) 168 { 169 for (i = 0; i < pPageData->volumeChannels; i++) 170 { 171 j = 9475 + (i * 4); 172 if (j != id) 173 SendDlgItemMessage(hwndDlg, j, TBM_SETPOS, (WPARAM)TRUE, dwPos); 174 175 pPageData->volumeValues[i].dwValue = dwValue; 176 } 177 } 178 else 179 { 180 idx = (id - 9475) / 4; 181 pPageData->volumeValues[idx].dwValue = dwValue; 182 } 183 184 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 185 mxcd.dwControlID = pPageData->volumeControlID; 186 mxcd.cChannels = pPageData->volumeChannels; 187 mxcd.cMultipleItems = 0; 188 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 189 mxcd.paDetails = pPageData->volumeValues; 190 191 if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 192 return; 193 } 194 195 196 static 197 VOID 198 OnSetDefaults( 199 PPAGE_DATA pPageData, 200 HWND hwndDlg) 201 { 202 MIXERCONTROLDETAILS mxcd; 203 DWORD dwValue, i; 204 205 dwValue = ((VOLUME_MAX - VOLUME_MIN) / 2 * pPageData->volumeStep) + pPageData->volumeMinimum; 206 207 for (i = 0; i < pPageData->volumeChannels; i++) 208 pPageData->volumeValues[i].dwValue = dwValue; 209 210 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); 211 mxcd.dwControlID = pPageData->volumeControlID; 212 mxcd.cChannels = pPageData->volumeChannels; 213 mxcd.cMultipleItems = 0; 214 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 215 mxcd.paDetails = pPageData->volumeValues; 216 217 if (mixerSetControlDetails((HMIXEROBJ)pPageData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) 218 return; 219 } 220 221 222 INT_PTR 223 CALLBACK 224 SpeakerVolumeDlgProc( 225 HWND hwndDlg, 226 UINT uMsg, 227 WPARAM wParam, 228 LPARAM lParam) 229 { 230 PPAGE_DATA pPageData; 231 232 UNREFERENCED_PARAMETER(wParam); 233 234 pPageData = (PPAGE_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 235 236 switch(uMsg) 237 { 238 case WM_INITDIALOG: 239 pPageData = (PPAGE_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PAGE_DATA)); 240 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pPageData); 241 242 if (pPageData) 243 { 244 OnInitDialog(pPageData, hwndDlg); 245 } 246 break; 247 248 case WM_DESTROY: 249 if (pPageData) 250 { 251 if (pPageData->volumeValues) 252 HeapFree(GetProcessHeap(), 0, pPageData->volumeValues); 253 254 if (pPageData->hMixer) 255 mixerClose(pPageData->hMixer); 256 257 HeapFree(GetProcessHeap(), 0, pPageData); 258 pPageData = NULL; 259 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL); 260 } 261 break; 262 263 case WM_HSCROLL: 264 if (pPageData) 265 { 266 OnHScroll(pPageData, hwndDlg, wParam, lParam); 267 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 268 } 269 break; 270 271 case WM_COMMAND: 272 switch (LOWORD(wParam)) 273 { 274 case 9504: 275 if (HIWORD(wParam) == BN_CLICKED) 276 pPageData->volumeSync = (SendDlgItemMessage(hwndDlg, 9504, BM_GETCHECK, 0, 0) == BST_CHECKED); 277 break; 278 279 case 9505: 280 OnSetDefaults(pPageData, hwndDlg); 281 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 282 break; 283 } 284 break; 285 286 case WM_NOTIFY: 287 return TRUE; 288 289 case MM_MIXM_CONTROL_CHANGE: 290 if (pPageData) 291 OnMixerControlChange(pPageData, hwndDlg); 292 break; 293 } 294 295 return FALSE; 296 } 297 298 299 INT_PTR 300 SpeakerVolume( 301 HWND hwndDlg) 302 { 303 PROPSHEETPAGE psp[1]; 304 PROPSHEETHEADER psh; 305 TCHAR Caption[256]; 306 307 LoadString(hApplet, IDS_SPEAKER_VOLUME, Caption, _countof(Caption)); 308 309 ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); 310 psh.dwSize = sizeof(PROPSHEETHEADER); 311 psh.dwFlags = PSH_PROPSHEETPAGE; 312 psh.hwndParent = hwndDlg; 313 psh.hInstance = hApplet; 314 psh.pszCaption = Caption; 315 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); 316 psh.nStartPage = 0; 317 psh.ppsp = psp; 318 319 InitPropSheetPage(&psp[0], IDD_MULTICHANNEL, SpeakerVolumeDlgProc); 320 psp[0].dwFlags |= PSP_USETITLE; 321 psp[0].pszTitle = Caption; 322 323 return (LONG)(PropertySheet(&psh) != -1); 324 } 325