Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1503 lines
40 KiB

  1. /* (C) Copyright Microsoft Corporation 1993. All Rights Reserved */
  2. #include <windows.h>
  3. #include <mmsystem.h>
  4. #include <string.h>
  5. #include "newvol.h"
  6. #include "volume.h" // for ini file string identifiers
  7. #include "sndcntrl.h"
  8. #ifdef TESTMIX
  9. #include "mixstub.h"
  10. #endif
  11. //
  12. // Globals
  13. //
  14. #define SHOWMUX
  15. int NumberOfDevices = 0;
  16. PVOLUME_CONTROL Vol = NULL;
  17. UINT FirstMasterIndex;
  18. /*
  19. * Profile file, section and key names
  20. */
  21. TCHAR gszVolumeSection[64];
  22. TCHAR gszProfileFile[MAX_PATH];
  23. DWORD AdjustMaster(WORD v)
  24. {
  25. DWORD dwResult;
  26. if (bMuted) {
  27. return 1;
  28. }
  29. dwResult = (v >> 8) + 1;
  30. return dwResult;
  31. }
  32. //
  33. // Add a control to our list
  34. //
  35. // Note that the G..Ptr macros in windowsx.h are inadequate and incorrect -
  36. // especially for multithreaded systems where stuff can move while it is
  37. // temporarily unlocked.
  38. //
  39. PVOLUME_CONTROL AddNewControl(VOID)
  40. {
  41. HGLOBAL hMem;
  42. PVOLUME_CONTROL pVol;
  43. if (Vol == NULL) {
  44. hMem = GlobalAlloc(GHND, sizeof(VOLUME_CONTROL));
  45. if (hMem == NULL) {
  46. return NULL;
  47. } else {
  48. Vol = GlobalLock(hMem);
  49. NumberOfDevices = 1;
  50. }
  51. } else {
  52. HGLOBAL hMemOld;
  53. hMemOld = GlobalHandle((LPVOID)Vol);
  54. GlobalUnlock(hMemOld);
  55. hMem = GlobalReAlloc(hMemOld,
  56. sizeof(VOLUME_CONTROL) * (NumberOfDevices + 1),
  57. GHND);
  58. if (hMem == NULL) {
  59. Vol = GlobalLock(hMemOld);
  60. return NULL;
  61. }
  62. Vol = GlobalLock(hMem);
  63. NumberOfDevices++;
  64. }
  65. pVol = Vol + (NumberOfDevices - 1);
  66. /*
  67. ** Finish initialization
  68. */
  69. pVol->Index = NumberOfDevices - 1;
  70. pVol->MixerId = (HMIXEROBJ)-1;
  71. pVol->ControlId = (DWORD)-1;
  72. pVol->MuxControlId = (DWORD)-1;
  73. pVol->MuteControlId = (DWORD)-1;
  74. pVol->MuxSelectIndex = (DWORD)-1;
  75. return pVol;
  76. }
  77. WORD CombineVolume(WORD Master, WORD Slave)
  78. {
  79. DWORD Result;
  80. //
  81. // treat both numbers as 8-bit volumes, and multiply them
  82. //
  83. Result = AdjustMaster(Master) * (DWORD)(Slave >> 8);
  84. return LOWORD(Result);
  85. }
  86. /*
  87. ** Set the device volume.
  88. **
  89. ** The master volume (and mute setting) are simulated here by
  90. ** scaling the individual device volumes if there is no mixer
  91. ** or the mixer doesn't support the settings
  92. */
  93. BOOL SetDeviceVolume(PVOLUME_CONTROL pVol, DWORD Volume)
  94. {
  95. DWORD dwMaster;
  96. /*
  97. ** Mixer volumes get set when we get the notification
  98. */
  99. if (pVol->VolumeType != VolumeTypeMixerControl) {
  100. pVol->LRVolume = Volume;
  101. }
  102. /*
  103. * If it's not the master volume we're setting then
  104. * combine the setting with the master volume setting
  105. */
  106. if (pVol->Type != MasterVolume) {
  107. /*
  108. ** Only simulate controls which don't have real master controls
  109. */
  110. if (!pVol->NoMasterSimulation) {
  111. /*
  112. * if mute is selected, scale the volume by 1 (not 0)
  113. * as the master volume. This will still result in an
  114. * inaudible volume, but will allow us to recover the volume setting
  115. * from the device when this app restarts.
  116. */
  117. dwMaster = MasterDevice(FALSE)->LRVolume;
  118. Volume = CombineVolume(LOWORD(dwMaster),
  119. LOWORD(Volume)) +
  120. (CombineVolume(HIWORD(dwMaster),
  121. HIWORD(Volume)) << 16);
  122. }
  123. }
  124. switch (pVol->Type) {
  125. case MasterVolume:
  126. {
  127. int i;
  128. for (i = 0; i < NumberOfDevices; i++) {
  129. if (!Vol[i].NoMasterSimulation && Vol[i].Type != MasterVolume) {
  130. SetDeviceVolume(&Vol[i], Vol[i].LRVolume);
  131. }
  132. }
  133. }
  134. if (pVol->VolumeType == VolumeTypeMixerControl) {
  135. SetMixerVolume(pVol->MixerId,
  136. pVol->ControlId,
  137. pVol->Stereo,
  138. Volume);
  139. }
  140. break;
  141. case AuxVolume:
  142. auxSetVolume(pVol->id, Volume);
  143. break;
  144. case MidiOutVolume:
  145. #if (WINVER >= 0x0400)
  146. midiOutSetVolume((HMIDIOUT)pVol->id, Volume);
  147. #else
  148. midiOutSetVolume(pVol->id, Volume);
  149. #endif
  150. break;
  151. case WaveOutVolume:
  152. #if (WINVER >= 0x0400)
  153. waveOutSetVolume((HWAVEOUT)pVol->id, Volume);
  154. #else
  155. waveOutSetVolume(pVol->id, Volume);
  156. #endif
  157. break;
  158. case MixerControlVolume:
  159. SetMixerVolume(pVol->MixerId,
  160. pVol->ControlId,
  161. pVol->Stereo,
  162. Volume);
  163. break;
  164. }
  165. if (pVol->VolumeType != VolumeTypeMixerControl) {
  166. /*
  167. ** Update the slider(s)
  168. */
  169. UpdateVolume(pVol);
  170. }
  171. return TRUE;
  172. }
  173. /*
  174. * Get the volume associated with a mixer device
  175. */
  176. VOID GetMixerVolume(HMIXEROBJ MixerId, DWORD dwControlId, BOOL Stereo, LPDWORD pVolume)
  177. {
  178. MIXERCONTROLDETAILS mxd;
  179. DWORD Volume[2];
  180. Volume[0] = 0;
  181. Volume[1] = 0;
  182. mxd.cbStruct = sizeof(mxd);
  183. mxd.dwControlID = dwControlId;
  184. mxd.cChannels = Stereo ? 2 : 1;
  185. mxd.cMultipleItems = 0;
  186. mxd.cbDetails = sizeof(DWORD);
  187. mxd.paDetails = (LPVOID)Volume;
  188. mixerGetControlDetails(MixerId, &mxd, MIXER_GETCONTROLDETAILSF_VALUE);
  189. if (Stereo) {
  190. *pVolume = (DWORD)MAKELONG(Volume[0], Volume[1]);
  191. } else {
  192. *pVolume = (DWORD)MAKELONG(Volume[0], Volume[0]);
  193. }
  194. }
  195. /*
  196. * Set the volume associated with a mixer device
  197. */
  198. VOID SetMixerVolume(HMIXEROBJ MixerId, DWORD dwControlId, BOOL Stereo, DWORD NewVolume)
  199. {
  200. MIXERCONTROLDETAILS mxd;
  201. DWORD Volume[2];
  202. Volume[0] = LOWORD(NewVolume);
  203. Volume[1] = HIWORD(NewVolume);
  204. mxd.cbStruct = sizeof(mxd);
  205. mxd.dwControlID = dwControlId;
  206. mxd.cChannels = Stereo ? 2 : 1;
  207. mxd.cMultipleItems = 0;
  208. mxd.cbDetails = sizeof(DWORD);
  209. mxd.paDetails = (LPVOID)Volume;
  210. mixerSetControlDetails(MixerId, &mxd, MIXER_SETCONTROLDETAILSF_VALUE);
  211. }
  212. /*
  213. * Get the volume for a given device. Returns the volume
  214. * setting packed in a DWORD
  215. */
  216. DWORD GetDeviceVolume(PVOLUME_CONTROL pVol)
  217. {
  218. DWORD Volume;
  219. DWORD Left;
  220. DWORD Right;
  221. DWORD dwMaster;
  222. PVOLUME_CONTROL pMaster;
  223. //
  224. // Default if calls fail
  225. //
  226. Volume = pVol->LRVolume;
  227. switch (pVol->Type) {
  228. case AuxVolume:
  229. auxGetVolume(pVol->id, &Volume);
  230. break;
  231. case MidiOutVolume:
  232. #if (WINVER >= 0x0400)
  233. midiOutGetVolume((HMIDIOUT)pVol->id, &Volume);
  234. #else
  235. midiOutGetVolume(pVol->id, &Volume);
  236. #endif
  237. break;
  238. case WaveOutVolume:
  239. #if (WINVER >= 0x0400)
  240. waveOutGetVolume((HWAVEOUT)pVol->id, &Volume);
  241. #else
  242. waveOutGetVolume(pVol->id, &Volume);
  243. #endif
  244. break;
  245. case MixerControlVolume:
  246. case MasterVolume:
  247. /*
  248. ** don't scale by master vol in this case
  249. */
  250. if (pVol->VolumeType != VolumeTypeMixerControl) {
  251. return Volume;
  252. }
  253. GetMixerVolume(pVol->MixerId,
  254. pVol->ControlId,
  255. pVol->Stereo,
  256. &Volume);
  257. if (pVol->NoMasterSimulation || pVol->Type == MasterVolume) {
  258. return Volume;
  259. }
  260. break;
  261. }
  262. /*
  263. ** Translate it back through the master volume
  264. ** Use 1 as the master volume if mute is set (see SetDeviceVolume)
  265. */
  266. pMaster = MasterDevice(pVol->RecordControl);
  267. if (!pVol->NoMasterSimulation && pMaster != NULL) {
  268. dwMaster = pMaster->LRVolume;
  269. Left = ((DWORD)LOWORD(Volume)) / AdjustMaster(LOWORD(dwMaster));
  270. Left <<= 8;
  271. if (Left > 65535) {
  272. Left = 65535;
  273. }
  274. Right = ((DWORD)HIWORD(Volume)) / AdjustMaster(HIWORD(dwMaster));
  275. Right <<= 8;
  276. if (Right > 65535) {
  277. Right = 65535;
  278. }
  279. } else {
  280. if (bMuted &&
  281. (pMaster == NULL ||
  282. pMaster->MuteControlId == (DWORD)-1)) {
  283. Left = LOWORD(Volume) >> 8;
  284. Right = HIWORD(Volume) >> 8;
  285. } else {
  286. Left = LOWORD(Volume);
  287. Right = HIWORD(Volume);
  288. }
  289. }
  290. pVol->LRVolume = (DWORD)MAKELONG(Left, Right);
  291. return pVol->LRVolume;
  292. }
  293. /*
  294. ** Update the displayed 'selected' state for a line
  295. */
  296. VOID UpdateSelected(PVOLUME_CONTROL pVol)
  297. {
  298. if (pVol->hCheckBox != NULL) {
  299. BOOL bSelected = ControlSelected(pVol);
  300. if (pVol->Type == MasterVolume) {
  301. SetWindowText(pVol->hCheckBox,
  302. _string(bSelected ? IDS_MUTE : IDS_UNMUTE));
  303. } else {
  304. SendMessage(pVol->hCheckBox,
  305. BM_SETCHECK,
  306. (WPARAM)bSelected,
  307. 0L);
  308. }
  309. }
  310. }
  311. /*
  312. ** Update the displayed volume for a slider by getting the actual level from
  313. ** the device and then updating the local values and informing the window
  314. ** control(s)
  315. */
  316. VOID UpdateVolume(PVOLUME_CONTROL pVol)
  317. {
  318. UINT oldVolume, oldBalance;
  319. DWORD dwVolumes;
  320. UINT max, min, left, right, temp;
  321. oldVolume = pVol->Volume;
  322. oldBalance = pVol->Balance;
  323. dwVolumes = GetDeviceVolume(pVol);
  324. /* figure out pan information */
  325. right = HIWORD(dwVolumes);
  326. left = LOWORD(dwVolumes);
  327. max = (right > left) ? right : left;
  328. min = (right > left) ? left : right;
  329. if (max == 0) {
  330. /* special case since then there's no panning. Therefore
  331. we dont know what the panning level is, therefore
  332. dont change the slider balance */
  333. pVol->Volume = 0;
  334. pVol->Balance = oldBalance; /* centered */
  335. } else {
  336. pVol->Volume = max >> 8;
  337. temp = (UINT) (((DWORD) (max - min) << 7) / max);
  338. if (temp > 0x7f) temp = 0x7f;
  339. if (right > left)
  340. pVol->Balance = 0x80 + temp;
  341. else
  342. pVol->Balance = 0x7f - temp;
  343. }
  344. /* change the slider if necessary */
  345. if (oldVolume != pVol->Volume && pVol->hChildWnd && IsWindow(pVol->hChildWnd)) {
  346. SendMessage(pVol->hChildWnd,SL_PM_SETKNOBPOS,
  347. pVol->Volume, 0);
  348. }
  349. if (oldBalance != pVol->Balance && IsWindow(pVol->hMeterWnd)) {
  350. SendMessage(pVol->hMeterWnd,MB_PM_SETKNOBPOS,
  351. pVol->Balance, 0);
  352. }
  353. }
  354. /*
  355. * Extract pertinent information for a given device type
  356. * If there is an equivalent mixer device don't bother.
  357. */
  358. BOOL ExtractInfo(UINT id,
  359. VOLUME_DEVICE_TYPE Type,
  360. LPBOOL VolSupport,
  361. LPBOOL StereoSupport,
  362. LPTSTR lpName,
  363. PUINT Technology)
  364. {
  365. UINT MixerId;
  366. switch (Type) {
  367. case MasterVolume:
  368. break;
  369. case AuxVolume:
  370. if (mixerGetID((HMIXEROBJ)id, &MixerId, MIXER_OBJECTF_AUX) == MMSYSERR_NOERROR) {
  371. return FALSE;
  372. } else {
  373. AUXCAPS ac;
  374. if (auxGetDevCaps(id, &ac, sizeof(ac)) != MMSYSERR_NOERROR) {
  375. return FALSE;
  376. }
  377. *VolSupport = (ac.dwSupport & AUXCAPS_VOLUME) != 0;
  378. *StereoSupport = (ac.dwSupport & AUXCAPS_LRVOLUME) != 0;
  379. lstrcpyn(lpName, ac.szPname, MAXPNAMELEN);
  380. *Technology =
  381. ac.wTechnology == AUXCAPS_CDAUDIO ? VolumeTypeCD :
  382. ac.wTechnology == AUXCAPS_AUXIN ? VolumeTypeLineIn :
  383. VolumeTypeAux;
  384. }
  385. break;
  386. case MidiOutVolume:
  387. if (mixerGetID((HMIXEROBJ)id, &MixerId, MIXER_OBJECTF_MIDIOUT) == MMSYSERR_NOERROR) {
  388. return FALSE;
  389. } else {
  390. MIDIOUTCAPS mc;
  391. if (midiOutGetDevCaps(id, &mc, sizeof(mc)) != MMSYSERR_NOERROR) {
  392. return FALSE;
  393. }
  394. *VolSupport = (mc.dwSupport & MIDICAPS_VOLUME) != 0;
  395. *StereoSupport = (mc.dwSupport & MIDICAPS_LRVOLUME) != 0;
  396. lstrcpyn(lpName, mc.szPname, MAXPNAMELEN);
  397. *Technology =
  398. mc.wTechnology == MOD_SYNTH || mc.wTechnology == MOD_SQSYNTH ||
  399. mc.wTechnology == MOD_FMSYNTH ? VolumeTypeSynth :
  400. VolumeTypeMidi;
  401. }
  402. break;
  403. case WaveOutVolume:
  404. if (mixerGetID((HMIXEROBJ)id, &MixerId, MIXER_OBJECTF_WAVEOUT) == MMSYSERR_NOERROR) {
  405. return FALSE;
  406. } else {
  407. WAVEOUTCAPS wc;
  408. if (waveOutGetDevCaps(id, &wc, sizeof(wc)) != MMSYSERR_NOERROR) {
  409. return FALSE;
  410. }
  411. *VolSupport = (wc.dwSupport & WAVECAPS_VOLUME) != 0;
  412. *StereoSupport = (wc.dwSupport & WAVECAPS_LRVOLUME) != 0;
  413. lstrcpyn(lpName, wc.szPname, MAXPNAMELEN);
  414. *Technology = VolumeTypeWave;
  415. }
  416. break;
  417. }
  418. return TRUE;
  419. }
  420. /*
  421. ** NonMixerDevices
  422. **
  423. ** Search to see if there is a non-mixer device which is not
  424. ** duplicated by a mixer device
  425. **
  426. ** If there is one return TRUE, otherwise FALSE
  427. */
  428. BOOL NonMixerDevices()
  429. {
  430. VOLUME_DEVICE_TYPE DeviceType;
  431. for (DeviceType = WaveOutVolume;
  432. DeviceType < NumberOfDeviceTypes;
  433. DeviceType++) {
  434. UINT DeviceId;
  435. UINT N;
  436. N = DeviceType == AuxVolume ? auxGetNumDevs() :
  437. DeviceType == MidiOutVolume ? midiOutGetNumDevs() :
  438. waveOutGetNumDevs();
  439. for (DeviceId = 0; DeviceId < N; DeviceId++) {
  440. BOOL VolumeSupport;
  441. BOOL StereoSupport;
  442. TCHAR Pname[MAXPNAMELEN];
  443. UINT Technology;
  444. if (ExtractInfo(DeviceId,
  445. DeviceType,
  446. &VolumeSupport,
  447. &StereoSupport,
  448. Pname,
  449. &Technology) &&
  450. VolumeSupport) {
  451. return TRUE;
  452. }
  453. }
  454. }
  455. return FALSE;
  456. }
  457. /*
  458. ** Returns an allocated array of the controls for a given line
  459. ** Caller must LocalFree it.
  460. */
  461. PMIXERCONTROL GetMixerLineControls(HMIXEROBJ MixerId,
  462. DWORD dwLineID,
  463. DWORD cControls)
  464. {
  465. MIXERLINECONTROLS MixerLineControls;
  466. MixerLineControls.cbStruct = sizeof(MixerLineControls);
  467. MixerLineControls.cControls = cControls;
  468. MixerLineControls.dwLineID = dwLineID;
  469. MixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
  470. MixerLineControls.pamxctrl =
  471. (LPMIXERCONTROL)LocalAlloc(LPTR, cControls * sizeof(MIXERCONTROL));
  472. if (MixerLineControls.pamxctrl == NULL) {
  473. //
  474. // Ulp!
  475. //
  476. return NULL;
  477. }
  478. if (mixerGetLineControls(MixerId,
  479. &MixerLineControls,
  480. MIXER_GETLINECONTROLSF_ALL) != MMSYSERR_NOERROR) {
  481. LocalFree((HLOCAL)MixerLineControls.pamxctrl);
  482. return NULL;
  483. }
  484. return MixerLineControls.pamxctrl;
  485. }
  486. BOOL GetControlByType(
  487. HMIXEROBJ MixerId,
  488. DWORD dwLineId,
  489. DWORD dwControlType,
  490. PMIXERCONTROL MixerControl
  491. )
  492. {
  493. MIXERLINECONTROLS MixerLineControls;
  494. MixerLineControls.cbStruct = sizeof(MixerLineControls);
  495. MixerLineControls.cControls = 1;
  496. MixerLineControls.dwLineID = dwLineId;
  497. MixerLineControls.dwControlType = dwControlType;
  498. MixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
  499. MixerLineControls.pamxctrl = MixerControl;
  500. if (mixerGetLineControls(MixerId,
  501. &MixerLineControls,
  502. MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) {
  503. return FALSE;
  504. }
  505. return TRUE;
  506. }
  507. /*
  508. ** See if a given volume control is selected through its mux/mixer
  509. ** Note that this state can change every time the relevant mux/mixer
  510. ** control changes
  511. */
  512. BOOL ControlSelected(
  513. PVOLUME_CONTROL pVol
  514. )
  515. {
  516. MIXERCONTROLDETAILS mxd;
  517. BOOL bResult;
  518. if (pVol->Type != MixerControlVolume ||
  519. pVol->MuxSelectIndex == (DWORD)-1) {
  520. bResult = TRUE;
  521. } else {
  522. mxd.cbStruct = sizeof(mxd);
  523. mxd.dwControlID = pVol->MuxControlId;
  524. mxd.cChannels = 1;
  525. mxd.cMultipleItems = pVol->MuxItems;
  526. mxd.cbDetails = sizeof(DWORD);
  527. mxd.paDetails =
  528. (LPVOID)LocalAlloc(LPTR, mxd.cbDetails * mxd.cMultipleItems);
  529. if (mxd.paDetails == NULL) {
  530. return FALSE;
  531. }
  532. mixerGetControlDetails(pVol->MixerId, &mxd, MIXER_GETCONTROLDETAILSF_VALUE);
  533. bResult = ((LPDWORD)mxd.paDetails)[pVol->MuxSelectIndex] != 0;
  534. LocalFree((HLOCAL)mxd.paDetails);
  535. }
  536. if (pVol->MuteControlId != (DWORD)-1) {
  537. bResult = bResult && !GetMixerMute(pVol);
  538. }
  539. return bResult;
  540. }
  541. /*
  542. ** The user wants this device to do its thing
  543. */
  544. VOID SelectControl(
  545. PVOLUME_CONTROL pVol,
  546. BOOL Select
  547. )
  548. {
  549. MIXERCONTROLDETAILS mxd;
  550. if (pVol->Type != MixerControlVolume ||
  551. pVol->MuxSelectIndex == (DWORD)-1 &&
  552. pVol->MuteControlId == (DWORD)-1) {
  553. return;
  554. }
  555. if (pVol->MuxSelectIndex == (DWORD)-1) {
  556. SetMixerMute(pVol, !Select);
  557. } else {
  558. mxd.cbStruct = sizeof(mxd);
  559. mxd.dwControlID = pVol->MuxControlId;
  560. mxd.cChannels = 1;
  561. mxd.cMultipleItems = pVol->MuxItems;
  562. mxd.cbDetails = sizeof(DWORD);
  563. mxd.paDetails =
  564. (LPVOID)LocalAlloc(LPTR, mxd.cbDetails * mxd.cMultipleItems);
  565. if (mxd.paDetails == NULL) {
  566. return;
  567. }
  568. if (pVol->MuxOrMixer) {
  569. /*
  570. ** Mux
  571. */
  572. ZeroMemory(mxd.paDetails, sizeof(DWORD) * mxd.cMultipleItems);
  573. } else {
  574. /*
  575. ** Mixer
  576. */
  577. mixerGetControlDetails(pVol->MixerId, &mxd, MIXER_GETCONTROLDETAILSF_VALUE);
  578. }
  579. ((LPDWORD)mxd.paDetails)[pVol->MuxSelectIndex] = (DWORD)Select;
  580. mixerSetControlDetails(pVol->MixerId, &mxd, MIXER_SETCONTROLDETAILSF_VALUE);
  581. /*
  582. ** If we have both mute and mux then turn off the mute if we
  583. ** activate this device
  584. */
  585. if (Select && pVol->MuteControlId != (DWORD)-1) {
  586. SetMixerMute(pVol, FALSE);
  587. }
  588. LocalFree((HLOCAL)mxd.paDetails);
  589. }
  590. }
  591. BOOL GetMixerMute(PVOLUME_CONTROL pVol)
  592. {
  593. MIXERCONTROLDETAILS mxd;
  594. DWORD dwMute;
  595. if (pVol->MuteControlId == (DWORD)-1) {
  596. return FALSE;
  597. }
  598. mxd.cbStruct = sizeof(mxd);
  599. mxd.dwControlID = pVol->MuteControlId;
  600. mxd.cChannels = 1;
  601. mxd.cMultipleItems = 0;
  602. mxd.cbDetails = sizeof(DWORD);
  603. mxd.paDetails = (LPDWORD)&dwMute;
  604. mixerGetControlDetails(pVol->MixerId, &mxd, MIXER_GETCONTROLDETAILSF_VALUE);
  605. if (pVol->Type == MasterVolume) {
  606. bMuted = (BOOL)dwMute;
  607. }
  608. return (BOOL)dwMute;
  609. }
  610. VOID SetMixerMute(PVOLUME_CONTROL pVol, BOOL Set)
  611. {
  612. MIXERCONTROLDETAILS mxd;
  613. if (pVol->MuteControlId == (DWORD)-1) {
  614. return;
  615. }
  616. mxd.cbStruct = sizeof(mxd);
  617. mxd.dwControlID = pVol->MuteControlId;
  618. mxd.cChannels = 1;
  619. mxd.cMultipleItems = 0;
  620. mxd.cbDetails = sizeof(DWORD);
  621. mxd.paDetails = (LPDWORD)&Set;
  622. mixerSetControlDetails(pVol->MixerId, &mxd, MIXER_SETCONTROLDETAILSF_VALUE);
  623. }
  624. /*
  625. ** Add a master control
  626. **
  627. ** Paramters
  628. ** MixerId - The mixer id
  629. ** dwMaster - The control id for volume setting
  630. ** dwMute - The control id for muting
  631. ** Record - whether it's a record or play master
  632. */
  633. VOID
  634. AddMasterControl(
  635. HMIXEROBJ MixerId,
  636. LPMIXERLINE LineInfo,
  637. LPMIXERCONTROL ControlInfo,
  638. DWORD dwMute,
  639. BOOL Record
  640. )
  641. {
  642. PVOLUME_CONTROL pVol;
  643. pVol = AddNewControl();
  644. if (pVol == NULL) {
  645. return;
  646. }
  647. pVol->Type = MasterVolume;
  648. pVol->MixerId = MixerId;
  649. pVol->VolumeType = VolumeTypeMixerControl;
  650. pVol->Stereo = LineInfo->cChannels > 1;
  651. pVol->ControlId = ControlInfo->dwControlID;
  652. pVol->RecordControl = Record;
  653. pVol->MuteControlId = dwMute;
  654. pVol->DestLineId = LineInfo->dwLineID;
  655. lstrcpy(pVol->Name, LineInfo->szShortName);
  656. if (FirstMasterIndex == (DWORD)-1) {
  657. FirstMasterIndex = pVol->Index;
  658. }
  659. if (pVol->MuteControlId != (DWORD)-1) {
  660. bMuted = GetMixerMute(pVol);
  661. }
  662. }
  663. VOID
  664. AddVolumeControl(
  665. HMIXEROBJ MixerId,
  666. BOOL NoMasterSimulation,
  667. LPMIXERLINE LineInfo,
  668. LPMIXERCONTROL ControlInfo,
  669. BOOL Record,
  670. LPMIXERCONTROL MuxControl,
  671. DWORD MuxSelectIndex,
  672. BOOL MuxOrMixer,
  673. DWORD MuteControlId,
  674. DWORD DestLineId
  675. )
  676. {
  677. PVOLUME_CONTROL pVol;
  678. pVol = AddNewControl();
  679. if (pVol == NULL) {
  680. return;
  681. }
  682. pVol->Type = MixerControlVolume;
  683. pVol->MixerId = MixerId;
  684. pVol->VolumeType = VolumeTypeMixerControl;
  685. pVol->Stereo = LineInfo->cChannels > 1;
  686. #ifndef SHOWMUX
  687. pVol->ControlId = ControlInfo->dwControlID;
  688. #else
  689. if (ControlInfo != NULL)
  690. pVol->ControlId = ControlInfo->dwControlID;
  691. else
  692. pVol->ControlId = (DWORD)-1;
  693. #endif
  694. pVol->RecordControl = Record;
  695. pVol->DestLineId = DestLineId;
  696. if (Record) {
  697. bRecordControllable = TRUE;
  698. }
  699. pVol->NoMasterSimulation = NoMasterSimulation;
  700. pVol->MuxSelectIndex = MuxSelectIndex;
  701. pVol->MuteControlId = MuteControlId;
  702. if (MuxSelectIndex != (DWORD)-1) {
  703. pVol->MuxControlId = MuxControl->dwControlID;
  704. pVol->MuxOrMixer = MuxControl->dwControlType ==
  705. MIXERCONTROL_CONTROLTYPE_MUX;
  706. pVol->MuxItems = MuxControl->cMultipleItems;
  707. }
  708. lstrcpy(pVol->Name, LineInfo->szShortName);
  709. }
  710. //
  711. // Get the mixer stuff we're interested in
  712. //
  713. VOID GetMixerControls(HMIXEROBJ MixerId)
  714. {
  715. MIXERCAPS MixerCaps;
  716. DWORD DestLineIndex;
  717. //
  718. // Find the number of dest lines
  719. //
  720. if (mixerGetDevCaps((UINT)MixerId, &MixerCaps, sizeof(MixerCaps)) !=
  721. MMSYSERR_NOERROR) {
  722. return;
  723. }
  724. /*
  725. ** For each destination :
  726. ** If it's an output
  727. ** Find the master and mute controls if there are any
  728. ** Scan the source lines for suitable devices
  729. **
  730. ** NB should this just be for speakers?
  731. */
  732. for (DestLineIndex = 0;
  733. DestLineIndex < MixerCaps.cDestinations;
  734. DestLineIndex++) {
  735. MIXERLINE DestLineInfo;
  736. MIXERCONTROL MasterVolumeControl, MasterMuteControl;
  737. MIXERCONTROL MuxControl;
  738. DWORD dwMute;
  739. DWORD dwMaster;
  740. BOOL MasterFound;
  741. BOOL IncludeLine;
  742. BOOL RecordDestination;
  743. BOOL MuxValid;
  744. DWORD SourceIndex;
  745. MasterFound = FALSE;
  746. dwMute = (DWORD)-1;
  747. dwMaster = (DWORD)-1;
  748. DestLineInfo.cbStruct = sizeof(DestLineInfo);
  749. DestLineInfo.dwDestination = DestLineIndex;
  750. if (mixerGetLineInfo(MixerId,
  751. &DestLineInfo,
  752. MIXER_GETLINEINFOF_DESTINATION) !=
  753. MMSYSERR_NOERROR) {
  754. return; // Bad mixer or something
  755. }
  756. if (DestLineInfo.fdwLine & MIXERLINE_LINEF_DISCONNECTED) {
  757. continue;
  758. }
  759. switch (DestLineInfo.dwComponentType) {
  760. case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
  761. case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES:
  762. RecordDestination = FALSE;
  763. IncludeLine = TRUE;
  764. break;
  765. case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
  766. RecordDestination = TRUE;
  767. IncludeLine = TRUE;
  768. break;
  769. default:
  770. IncludeLine = FALSE;
  771. break;
  772. }
  773. if (!IncludeLine) {
  774. continue;
  775. }
  776. if (GetControlByType(MixerId,
  777. DestLineInfo.dwLineID,
  778. MIXERCONTROL_CONTROLTYPE_MUX,
  779. &MuxControl) ||
  780. GetControlByType(MixerId,
  781. DestLineInfo.dwLineID,
  782. MIXERCONTROL_CONTROLTYPE_MIXER,
  783. &MuxControl)) {
  784. /*
  785. ** Found a mux for this destination.
  786. */
  787. MuxValid = TRUE;
  788. } else {
  789. /*
  790. ** No Mux
  791. */
  792. MuxValid = FALSE;
  793. }
  794. /*
  795. ** Master and mute for all dest types
  796. */
  797. if (GetControlByType(MixerId,
  798. DestLineInfo.dwLineID,
  799. MIXERCONTROL_CONTROLTYPE_VOLUME,
  800. &MasterVolumeControl)) {
  801. MasterFound = TRUE;
  802. dwMaster = MasterVolumeControl.dwControlID;
  803. if (GetControlByType(MixerId,
  804. DestLineInfo.dwLineID,
  805. MIXERCONTROL_CONTROLTYPE_MUTE,
  806. &MasterMuteControl)) {
  807. dwMute = MasterMuteControl.dwControlID;
  808. }
  809. /*
  810. ** Add master information
  811. */
  812. AddMasterControl(MixerId,
  813. &DestLineInfo,
  814. &MasterVolumeControl,
  815. dwMute,
  816. RecordDestination);
  817. }
  818. /*
  819. ** Now find each individual source control we want to
  820. ** control
  821. */
  822. for (SourceIndex = 0;
  823. SourceIndex < DestLineInfo.cConnections;
  824. SourceIndex++) {
  825. MIXERLINE SourceLineInfo;
  826. MIXERCONTROL SourceLineVolumeControl;
  827. LPMIXERCONTROL lpSLVC = &SourceLineVolumeControl;
  828. BOOL IncludeLine;
  829. DWORD MuxSelectIndex;
  830. DWORD MuteControlId;
  831. MuxSelectIndex = (DWORD)-1;
  832. SourceLineInfo.cbStruct = sizeof(SourceLineInfo);
  833. SourceLineInfo.dwDestination = DestLineIndex;
  834. SourceLineInfo.dwSource = SourceIndex;
  835. if (mixerGetLineInfo(MixerId,
  836. &SourceLineInfo,
  837. MIXER_GETLINEINFOF_SOURCE) !=
  838. MMSYSERR_NOERROR) {
  839. return;
  840. }
  841. if (SourceLineInfo.fdwLine & MIXERLINE_LINEF_DISCONNECTED) {
  842. continue;
  843. }
  844. switch (SourceLineInfo.dwComponentType) {
  845. /*
  846. ** Only allow things we understand (and remove things
  847. ** like pc speaker to keep the number of sliders down).
  848. */
  849. case MIXERLINE_COMPONENTTYPE_SRC_LINE:
  850. case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
  851. case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
  852. case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
  853. case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
  854. case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY:
  855. case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE:
  856. case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL:
  857. IncludeLine = TRUE;
  858. break;
  859. default:
  860. IncludeLine = TRUE;
  861. break;
  862. }
  863. if (!IncludeLine) {
  864. continue;
  865. }
  866. /*
  867. ** Try to get the relevant volume control
  868. */
  869. if (!GetControlByType(MixerId,
  870. SourceLineInfo.dwLineID,
  871. MIXERCONTROL_CONTROLTYPE_VOLUME,
  872. &SourceLineVolumeControl)) {
  873. #ifdef SHOWMUX
  874. lpSLVC = NULL;
  875. #else
  876. continue;
  877. #endif
  878. }
  879. /*
  880. ** See if there's a mute
  881. */
  882. {
  883. MIXERCONTROL MuteControl;
  884. if (GetControlByType(MixerId,
  885. SourceLineInfo.dwLineID,
  886. MIXERCONTROL_CONTROLTYPE_MUTE,
  887. &MuteControl)) {
  888. MuteControlId = MuteControl.dwControlID;
  889. } else {
  890. MuteControlId = (DWORD)-1;
  891. }
  892. }
  893. /*
  894. ** See if we need an id to switch the recording on or
  895. ** off
  896. */
  897. if (MuxValid) {
  898. LPMIXERCONTROLDETAILS_LISTTEXT ListText;
  899. ListText = (LPMIXERCONTROLDETAILS_LISTTEXT)
  900. LocalAlloc(LPTR,
  901. sizeof(*ListText) *
  902. MuxControl.cMultipleItems);
  903. if (ListText != NULL) {
  904. MIXERCONTROLDETAILS mxd;
  905. mxd.cbStruct = sizeof(mxd);
  906. mxd.dwControlID = MuxControl.dwControlID;
  907. mxd.cChannels = 1; // Why the ???
  908. mxd.cMultipleItems = MuxControl.cMultipleItems;
  909. mxd.cbDetails = sizeof(*ListText);
  910. mxd.paDetails = (LPVOID)ListText;
  911. if (mixerGetControlDetails(
  912. MixerId,
  913. &mxd,
  914. MIXER_GETCONTROLDETAILSF_LISTTEXT) ==
  915. MMSYSERR_NOERROR) {
  916. UINT i;
  917. /*
  918. ** Look for our line
  919. */
  920. for (i = 0; i < MuxControl.cMultipleItems; i++) {
  921. if (ListText[i].dwParam1 ==
  922. SourceLineInfo.dwLineID) {
  923. MuxSelectIndex = i;
  924. }
  925. }
  926. }
  927. LocalFree((HLOCAL)ListText);
  928. }
  929. }
  930. /*
  931. ** Add this volume control to the list
  932. */
  933. AddVolumeControl(MixerId,
  934. MasterFound || RecordDestination,
  935. &SourceLineInfo,
  936. // &SourceLineVolumeControl,
  937. lpSLVC,
  938. RecordDestination,
  939. MuxValid ? &MuxControl : NULL,
  940. MuxSelectIndex,
  941. MuxValid ? FALSE :
  942. MuxControl.dwControlType ==
  943. MIXERCONTROL_CONTROLTYPE_MUX,
  944. MuteControlId,
  945. DestLineInfo.dwLineID);
  946. }
  947. }
  948. }
  949. //
  950. // Scan through all relevant devices.
  951. // If pVol is 0 just count them, otherwise save away info
  952. // about them as well
  953. //
  954. VOID FindDevices(VOLUME_DEVICE_TYPE Type)
  955. {
  956. UINT N;
  957. UINT id;
  958. N = Type == MasterVolume ? 0 :
  959. Type == AuxVolume ? auxGetNumDevs() :
  960. Type == MidiOutVolume ? midiOutGetNumDevs() :
  961. Type == WaveOutVolume ? waveOutGetNumDevs() :
  962. Type == MixerControlVolume ? mixerGetNumDevs() :
  963. 0;
  964. for (id = 0; id < N; id++) {
  965. if (Type == MixerControlVolume) {
  966. //
  967. // Find out how many suitable volume controls this mixer
  968. // supports.
  969. //
  970. // This is incredibly laborious because we can't just enumerate
  971. // the controls (!).
  972. //
  973. // This next call has the side effect of generating the mixer
  974. // master stuff too and a set of mixer handles.
  975. //
  976. GetMixerControls(MixerId);
  977. return;
  978. } else {
  979. BOOL Volume;
  980. BOOL Stereo;
  981. TCHAR Name[MAXPNAMELEN];
  982. UINT Technology;
  983. if (ExtractInfo(id, Type, &Volume, &Stereo, Name, &Technology)) {
  984. if (Volume) {
  985. PVOLUME_CONTROL pVol;
  986. /*
  987. ** Supports volume setting
  988. */
  989. pVol = AddNewControl();
  990. if (pVol) {
  991. pVol->id = id;
  992. pVol->Type = Type;
  993. pVol->VolumeType = Technology;
  994. pVol->Stereo = Stereo;
  995. pVol++;
  996. }
  997. }
  998. } else {
  999. continue; // Don't use this one
  1000. }
  1001. }
  1002. }
  1003. }
  1004. /*
  1005. * Create and initialize our volume array
  1006. *
  1007. * On exit
  1008. * NumberOfDevices is set to the number of devices we want
  1009. * Vol is an array of size NumberOfDevices (may be 0)
  1010. */
  1011. BOOL VolInit(VOID)
  1012. {
  1013. int i;
  1014. WORD wLeft, wRight, wMax, wMin, wTemp;
  1015. /*
  1016. ** Free any volume stuff currently present
  1017. */
  1018. if (Vol) {
  1019. HGLOBAL hVol;
  1020. int i;
  1021. /*
  1022. ** Free all the windows
  1023. */
  1024. for (i = 0; i < NumberOfDevices; i++) {
  1025. DestroyOurWindow(&Vol[i].hChildWnd);
  1026. DestroyOurWindow(&Vol[i].hMeterWnd);
  1027. DestroyOurWindow(&Vol[i].hStatic);
  1028. DestroyOurWindow(&Vol[i].hCheckBox);
  1029. }
  1030. /*
  1031. ** Free the memory
  1032. */
  1033. hVol = GlobalHandle(Vol);
  1034. GlobalUnlock(hVol);
  1035. GlobalFree(hVol);
  1036. Vol = NULL;
  1037. /*
  1038. ** Initialize globals
  1039. */
  1040. bRecordControllable = FALSE;
  1041. }
  1042. /*
  1043. ** No master volume controls found yet
  1044. */
  1045. FirstMasterIndex = (DWORD)-1;
  1046. /*
  1047. * Scan all the device types we're interested in :
  1048. * wave out
  1049. * midi out
  1050. * aux
  1051. */
  1052. if ((DWORD)MixerId != (DWORD)-1) {
  1053. FindDevices(MixerControlVolume);
  1054. } else {
  1055. for (i = WaveOutVolume; i < NumberOfDeviceTypes; i++) {
  1056. FindDevices(i);
  1057. }
  1058. }
  1059. if (NumberOfDevices == 0) {
  1060. return FALSE;
  1061. }
  1062. if (FirstMasterIndex == (DWORD)-1) {
  1063. PVOLUME_CONTROL pMaster;
  1064. BOOL bStereo;
  1065. /*
  1066. ** Find if any devices are stereo
  1067. */
  1068. bStereo = FALSE;
  1069. for (i = 0; i < NumberOfDevices; i++) {
  1070. if (Vol[i].Stereo) {
  1071. bStereo = TRUE;
  1072. break;
  1073. }
  1074. }
  1075. /*
  1076. ** Create a default volume control
  1077. */
  1078. pMaster = AddNewControl();
  1079. if (pMaster == NULL) {
  1080. return FALSE;
  1081. }
  1082. pMaster->Type = MasterVolume;
  1083. pMaster->VolumeType = -1;
  1084. pMaster->Stereo = bStereo;
  1085. FirstMasterIndex = pMaster->Index;
  1086. wLeft = (WORD)MasterLeft;
  1087. wRight = (WORD)MasterRight;
  1088. pMaster->LRVolume = MAKELONG(wLeft, wRight);
  1089. if (wRight > wLeft) {
  1090. wMax = wRight;
  1091. wMin = wLeft;
  1092. } else {
  1093. wMax = wLeft;
  1094. wMin = wRight;
  1095. }
  1096. if (wMax == 0) {
  1097. pMaster->Volume = 0;
  1098. pMaster->Balance = 0x80; /* centered */
  1099. } else {
  1100. pMaster->Volume = wMax >> 8;
  1101. wTemp = (UINT) (((DWORD) (wMax - wMin) << 7) / wMax);
  1102. if (wTemp > 0x7f) wTemp = 0x7f;
  1103. if (wRight > wLeft)
  1104. pMaster->Balance = 0x80 + wTemp;
  1105. else
  1106. pMaster->Balance = 0x7f - wTemp;
  1107. }
  1108. }
  1109. return TRUE;
  1110. }
  1111. /*
  1112. ** Called when a mixer calls us back with a control change
  1113. */
  1114. VOID ControlChange(HMIXER hMixer, DWORD ControlId)
  1115. {
  1116. UINT i;
  1117. HMIXEROBJ MixerId;
  1118. MMRESULT mmr;
  1119. mmr = mixerGetID((HMIXEROBJ)hMixer, (PUINT)&MixerId, MIXER_OBJECTF_HMIXER);
  1120. if (mmr != MMSYSERR_NOERROR) {
  1121. return;
  1122. }
  1123. for (i = 0; i < (UINT)NumberOfDevices; i++) {
  1124. if (Vol[i].MixerId == MixerId) {
  1125. if (Vol[i].VolumeType == VolumeTypeMixerControl) {
  1126. if (ControlId == Vol[i].ControlId) {
  1127. UpdateVolume(&Vol[i]);
  1128. /*
  1129. ** Volume controls only affect one control
  1130. ** (unlike muxes)
  1131. */
  1132. break;
  1133. } else {
  1134. if (ControlId == Vol[i].MuxControlId ||
  1135. ControlId == Vol[i].MuteControlId) {
  1136. UpdateSelected(&Vol[i]);
  1137. }
  1138. }
  1139. }
  1140. } /* MixerId == Vol[i].MixerId */
  1141. }
  1142. }
  1143. PVOLUME_CONTROL FirstDevice(BOOL bRecord)
  1144. {
  1145. UINT i;
  1146. for (i = 0; i < (UINT)NumberOfDevices; i++) {
  1147. if (Vol[i].Type != MasterVolume &&
  1148. Vol[i].RecordControl == bRecord) {
  1149. return &Vol[i];
  1150. }
  1151. }
  1152. return NULL;
  1153. }
  1154. PVOLUME_CONTROL LastDevice(BOOL bRecord)
  1155. {
  1156. UINT i;
  1157. for (i = NumberOfDevices; i > 0; i--) {
  1158. if (Vol[i - 1].Type != MasterVolume &&
  1159. Vol[i - 1].RecordControl == bRecord) {
  1160. return &Vol[i - 1];
  1161. }
  1162. }
  1163. return NULL;
  1164. }
  1165. PVOLUME_CONTROL NextDevice(PVOLUME_CONTROL pVol)
  1166. {
  1167. UINT i;
  1168. for (i = pVol->Index == (UINT)NumberOfDevices - 1 ? 0 : pVol->Index + 1 ;
  1169. i != pVol->Index;
  1170. i = i == (UINT)NumberOfDevices - 1 ? 0 : i + 1) {
  1171. if (Vol[i].Type != MasterVolume &&
  1172. Vol[i].RecordControl == pVol->RecordControl) {
  1173. break;
  1174. }
  1175. }
  1176. return &Vol[i];
  1177. }
  1178. PVOLUME_CONTROL NextDeviceNoWrap(PVOLUME_CONTROL pVol)
  1179. {
  1180. UINT i;
  1181. for (i = pVol->Index + 1 ;
  1182. i < (UINT)NumberOfDevices;
  1183. i = i + 1) {
  1184. if (Vol[i].Type != MasterVolume &&
  1185. Vol[i].RecordControl == pVol->RecordControl) {
  1186. return &Vol[i];
  1187. }
  1188. }
  1189. return NULL;
  1190. }
  1191. PVOLUME_CONTROL PrevDevice(PVOLUME_CONTROL pVol)
  1192. {
  1193. UINT i;
  1194. for (i = pVol->Index == 0 ? NumberOfDevices - 1 : pVol->Index - 1;
  1195. i != pVol->Index;
  1196. i = i == 0 ? NumberOfDevices - 1 : i - 1) {
  1197. if (Vol[i].Type != MasterVolume &&
  1198. Vol[i].RecordControl == pVol->RecordControl) {
  1199. return &Vol[i];
  1200. }
  1201. }
  1202. return &Vol[i];
  1203. }
  1204. PVOLUME_CONTROL PrevDeviceNoWrap(PVOLUME_CONTROL pVol)
  1205. {
  1206. UINT i;
  1207. for (i = pVol->Index;
  1208. i != 0;
  1209. i = i - 1) {
  1210. if (Vol[i - 1].Type != MasterVolume &&
  1211. Vol[i - 1].RecordControl == pVol->RecordControl) {
  1212. return &Vol[i - 1];
  1213. }
  1214. }
  1215. return NULL;
  1216. }
  1217. PVOLUME_CONTROL MasterDevice(BOOL bRecord)
  1218. {
  1219. UINT i;
  1220. for (i = 0 ; i < (UINT)NumberOfDevices; i++) {
  1221. if (Vol[i].Type == MasterVolume &&
  1222. Vol[i].RecordControl == bRecord) {
  1223. return &Vol[i];
  1224. }
  1225. }
  1226. return NULL;
  1227. }
  1228.