AMixer.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. unit AMixer;
  2. interface
  3. uses
  4. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  5. MMSystem;
  6. (*
  7. * TAudioMixer v1.11 (FREEWARE component)
  8. * -----------------
  9. * Released 4 Jan 1999
  10. *
  11. * This component can cache data from audio mixer. It has direct support for
  12. * getting/setting volume of any control (It can set also set state of that
  13. * "Selected" CheckBox in standard Windows Volume Control program). You can
  14. * better use other features of mixer, but that's more difficult than volume
  15. * setting and you must know something about audio mixer.
  16. *
  17. * The mixer has following structure (as it is in this component) :
  18. *
  19. * Destinations (destinations should be for example: Playback, Recording and Voice commands)
  20. * |
  21. * |--Destination[0] (if you want to get volume of this call GeVolume (<ThisDestinationNum>,-1,...))
  22. * | | (=0) ----
  23. * | |--Data:TMixerLine
  24. * | |--Controls (controls of the line, ex: Master volume, master mute)
  25. * | | |
  26. * | | |--Control[0]
  27. * | | |--Control[1]
  28. * | | |--Control[..]
  29. * | |
  30. * | |--Connections (ex: Wave, MIDI, CD Audio, Line-In,...)
  31. * | |
  32. * | |--Connection[0] (GetVolume (<ThisDestinationNum>,<ThisConnectionNumb>,...))
  33. * | | | (=0) (=0)
  34. * | | |--Data:TMixerLine
  35. * | | |--Controls (here can be volume and mute)
  36. * | | |
  37. * | | |--Control[0]
  38. * | | |--Control[1]
  39. * | | |--Control[..]
  40. * | |
  41. * | |--Connection[1]
  42. * | |--Connection[..]
  43. * |
  44. * |--Destination[1]
  45. * |--Destination[..]
  46. *
  47. *
  48. * There are many types of controls - checkbox, list, slider,... they are
  49. * described in Windows help. Common ones are volume slider, mute checkbox or
  50. * volume meter.
  51. *
  52. * This component is universal, so you can work with all controls through it,
  53. * but this is difficult. You can simply get/set volume level by procedures
  54. * GetVolume or SetVolume (description is near their declaration; use - see
  55. * example program).
  56. *
  57. *
  58. * What's New
  59. * ----------
  60. * 1.11 (4 Jan 1999)
  61. * - now it supports also MIXERCONTROL_CONTROLTYPE_MUX flag
  62. * (I got SB Live! for Christmas (:-)) and my component didn't work
  63. * properly, this corrects that problem)
  64. * 1.1 (16 Nov 1998)
  65. * - made compatible with Delphi 4
  66. * - corrected memory leaks (by Ishida Wataru)
  67. * - some another minor changes (by Ishida Wataru)
  68. * - added another example
  69. * - added AMixer.dcr
  70. * 1.0 (18 Aug 1998)
  71. * - initial version
  72. *
  73. *
  74. * You can use this component freely in your programs. But if you do so, please
  75. * send me an e-mail. I would like to know if it is useful.
  76. *
  77. * ?Vit Kovalcik
  78. *
  79. * e-mail: vkovalcik@iname.com
  80. * WWW: http://www.geocities.com/SiliconValley/Hills/1335/
  81. *)
  82. {Note:
  83. When no mixer is present TAudioMixer.Destinations will be nil.
  84. If you then check Destinations.Count it will raise exception,
  85. so be sure to check TAudioMixer.MixerCount first.}
  86. type
  87. TAudioMixer=class;
  88. TPListFreeItemNotify=procedure (Pntr:Pointer) of object;
  89. TMixerChange=procedure (Sender:TObject;MixerH:HMixer;ID:Integer) of object;
  90. {MixerH is handle of mixer, which sent this message.
  91. ID is ID of changed item (line or control).}
  92. TPointerList=class(TObject)
  93. private
  94. FOnFreeItem:TPListFreeItemNotify;
  95. Items:Tlist;
  96. protected
  97. function GetPointer (Ind:Integer):Pointer;
  98. function GetCount :integer;
  99. public
  100. constructor Create;
  101. destructor Destroy; override;
  102. procedure Clear;
  103. procedure Add (Pntr:Pointer);
  104. property Count:Integer read GetCount;
  105. property Pointer[Ind:Integer]:Pointer read GetPointer; default;
  106. property OnFreeItem:TPListFreeItemNotify read FOnFreeItem write FOnFreeItem; end;
  107. TMixerControls=class(TObject)
  108. private
  109. heap:pointer;
  110. FControls:TPointerList;
  111. protected
  112. function GetControl (Ind:Integer):PMixerControl;
  113. function GetCount:Integer;
  114. public
  115. constructor Create (AMixer:TAudioMixer;AData:TMixerLine);
  116. destructor Destroy; override;
  117. property Control[Ind:Integer]:PMixerControl read GetControl; default;
  118. property Count:Integer read GetCount;
  119. end;
  120. TMixerConnection=class(TObject)
  121. private
  122. XMixer:TAudioMixer;
  123. FData:TMixerLine;
  124. FControls:TMixerControls;
  125. public
  126. constructor Create (AMixer:TAudioMixer;AData:TMixerLine);
  127. destructor Destroy; override;
  128. property Controls:TMixerControls read FControls;
  129. property Data:TMixerLine read FData;
  130. end;
  131. TMixerConnections=class(TObject)
  132. private
  133. XMixer:TAudioMixer;
  134. FConnections:TPointerList;
  135. protected
  136. procedure DoFreeItem (Pntr:Pointer);
  137. function GetConnection (Ind:Integer):TMixerConnection;
  138. function GetCount:Integer;
  139. public
  140. constructor Create (AMixer:TAudioMixer;AData:TMixerLine);
  141. destructor Destroy; override;
  142. property Connection[Ind:Integer]:TMixerConnection read GetConnection; default;
  143. property Count:Integer read GetCount;
  144. end;
  145. TMixerDestination=class(TObject)
  146. private
  147. XMixer:TAudioMixer;
  148. FData:TMixerLine;
  149. FControls:TMixerControls;
  150. FConnections:TMixerConnections;
  151. public
  152. constructor Create (AMixer:TAudioMixer;AData:TMixerLine);
  153. destructor Destroy; override;
  154. property Connections:TMixerConnections read FConnections;
  155. property Controls:TMixerControls read FControls;
  156. property Data:TMixerLine read FData;
  157. end;
  158. TMixerDestinations=class(TObject)
  159. private
  160. FDestinations:TPointerList;
  161. protected
  162. function GetDestination (Ind:Integer):TMixerDestination;
  163. procedure DoFreeItem (Pntr:Pointer);
  164. function GetCount:Integer;
  165. public
  166. constructor Create (AMixer:TAudioMixer);
  167. destructor Destroy; override;
  168. property Count:Integer read GetCount;
  169. property Destination[Ind:Integer]:TMixerDestination read GetDestination; default;
  170. end;
  171. TAudioMixer = class(TComponent)
  172. private
  173. XWndHandle:HWnd;
  174. FDestinations:TMixerDestinations;
  175. FMixersCount:Integer;
  176. FMixerHandle:HMixer;
  177. FMixerID:Integer;
  178. FMixerCaps:TMixerCaps;
  179. FOnLineChange:TMixerChange;
  180. FOnControlChange:TMixerChange;
  181. protected
  182. procedure SetMixerID (Value:Integer);
  183. procedure MixerCallBack (var Msg:TMessage);
  184. procedure CloseMixer;
  185. published
  186. constructor Create (AOwner:TComponent); override;
  187. destructor Destroy; override;
  188. property MixerID:Integer read FMixerID write SetMixerID;
  189. {Opened mixer - value must be in range 0..MixersCount-1
  190. If no mixer is opened this value is -1}
  191. property OnLineChange:TMixerChange read FOnLineChange write FOnLineChange;
  192. property OnControlChange:TMixerChange read FOnControlChange write FOnControlChange;
  193. public
  194. function GetVolume (ADestination,AConnection:Integer;var LeftVol,RightVol,Mute:Integer;var VolDisabled,MuteDisabled:Boolean):Boolean;
  195. {This function return volume of selected Destination and Connection.
  196. ADestination must be from range 0..Destinations.Count-1
  197. AConnection must be in range 0..Destinations[ADestination].Connections.Count-1
  198. If you want to read master volume of some Destination, you have to
  199. set AConnection to -1.
  200. If LeftVol, RightVol or Mute is not supported by queried connection,
  201. it's return value will be -1.
  202. LeftVol and RightVol are in range 0..65536
  203. If Mute is non-zero then the connection is silent.
  204. If specified line is recording source then Mute specifies if programs will
  205. record from this connection (it is copy of "Select" Checkbox in
  206. standard Windows Volume Control program)
  207. VolDisabled or MuteDisabled is True when you cannot apply settings to this
  208. control (but can read it).
  209. Return value of the function is True if no error has occured,
  210. otherwise it returns False.}
  211. function SetVolume (ADestination,AConnection:Integer;LeftVol,RightVol,Mute:Integer):Boolean;
  212. {This function sets volume.
  213. If you set RightVol to -1 and connection is stereo then LeftVol will be
  214. copied to RightVol.
  215. If LeftVol or Mute is -1 then this value will not be set.
  216. Return value is True if ADestination and AConnection ar correct, otherwise False.}
  217. property Destinations:TMixerDestinations read FDestinations;
  218. {Ind must be in range 0..DestinationsCount-1}
  219. property MixerCaps:TMixerCaps read FMixerCaps;
  220. property MixerCount:Integer read FMixersCount;
  221. {Number of mixers present in system; mostly 1}
  222. property MixerHandle:HMixer read FMixerHandle;
  223. {Handle of opened mixer}
  224. end;
  225. procedure Register;
  226. implementation
  227. {------------}
  228. {TPointerList}
  229. {------------}
  230. constructor TPointerList.Create;
  231. begin
  232. items:=tlist.create;
  233. end;
  234. destructor TPointerList.Destroy;
  235. begin
  236. Clear;
  237. items.destroy;
  238. end;
  239. procedure TPointerList.Add (Pntr:Pointer);
  240. begin
  241. items.add(Pntr);
  242. end;
  243. function TPointerList.GetPointer (Ind:Integer):Pointer;
  244. begin
  245. result:=items[Ind];
  246. end;
  247. procedure TPointerList.Clear;
  248. var i:integer;
  249. begin
  250. for i:=0 to items.count-1 do begin
  251. If Assigned (FOnFreeItem) then
  252. FOnFreeItem (items[i])
  253. end;
  254. items.clear;
  255. end;
  256. function TPointerList.GetCount:Integer;
  257. begin
  258. result:=items.count;
  259. end;
  260. {--------------}
  261. {TMixerControls}
  262. {--------------}
  263. constructor TMixerControls.Create (AMixer:TAudioMixer;AData:TMixerLine);
  264. var MLC:TMixerLineControls;
  265. A,B:Integer;
  266. P:PMixerControl;
  267. begin
  268. FControls:=TPointerList.Create;
  269. MLC.cbStruct:=SizeOf(MLC);
  270. MLC.dwLineID:=AData.dwLineID;
  271. MLC.cControls:=AData.cControls;
  272. MLC.cbmxctrl:=SizeOf(TMixerControl);
  273. GetMem (P,SizeOf(TMixerControl)*AData.cControls);
  274. heap:=P;
  275. MLC.pamxctrl:=P;
  276. A:=MixerGetLineControls(AMixer.MixerHandle,@MLC, MIXER_GETLINECONTROLSF_ALL);
  277. If A=MMSYSERR_NOERROR then
  278. begin
  279. For B:=0 to AData.cControls-1 do
  280. begin
  281. FControls.Add (P);
  282. Inc (P);
  283. end;
  284. end;
  285. end;
  286. destructor TMixerControls.Destroy;
  287. begin
  288. FControls.free;
  289. freemem(heap);
  290. inherited;
  291. end;
  292. function TMixerControls.GetControl (Ind:Integer):PMixerControl;
  293. begin
  294. Result:=FControls.Pointer[Ind];
  295. end;
  296. function TMixerControls.GetCount:Integer;
  297. begin
  298. Result:=FControls.Count;
  299. end;
  300. {----------------}
  301. {TMixerConnection}
  302. {----------------}
  303. constructor TMixerConnection.Create (AMixer:TAudioMixer;AData:TMixerLine);
  304. begin
  305. FData:=AData;
  306. XMixer:=AMixer;
  307. FControls:=TMixerControls.Create (AMixer,AData);
  308. end;
  309. destructor TMixerConnection.Destroy;
  310. begin
  311. FControls.Free;
  312. inherited;
  313. end;
  314. {-----------------}
  315. {TMixerConnections}
  316. {-----------------}
  317. constructor TMixerConnections.Create (AMixer:TAudioMixer;AData:TMixerLine);
  318. var A,B:Integer;
  319. ML:TMixerLine;
  320. begin
  321. XMixer:=AMixer;
  322. FConnections:=TPointerList.Create;
  323. FConnections.OnFreeItem:=Dofreeitem;
  324. ML.cbStruct:=SizeOf(TMixerLine);
  325. ML.dwDestination:=AData.dwDestination;
  326. For A:=0 to AData.cConnections-1 do
  327. begin
  328. ML.dwSource:=A;
  329. B:=MixerGetLineInfo (AMixer.MixerHandle,@ML,MIXER_GETLINEINFOF_SOURCE);
  330. If B=MMSYSERR_NOERROR then
  331. FConnections.Add(Pointer(TMixerConnection.Create (XMixer,ML)));
  332. end;
  333. end;
  334. destructor TMixerConnections.Destroy;
  335. begin
  336. FConnections.Free;
  337. inherited;
  338. end;
  339. procedure TMixerConnections.DoFreeItem (Pntr:Pointer);
  340. begin
  341. TMixerConnection(Pntr).Free;
  342. end;
  343. function TMixerConnections.GetConnection (Ind:Integer):TMixerConnection;
  344. begin
  345. Result:=FConnections.Pointer[Ind];
  346. end;
  347. function TMixerConnections.GetCount:Integer;
  348. begin
  349. Result:=FConnections.Count;
  350. end;
  351. {-----------------}
  352. {TMixerDestination}
  353. {-----------------}
  354. constructor TMixerDestination.Create (AMixer:TAudioMixer;AData:TMixerLine);
  355. begin
  356. FData:=AData;
  357. XMixer:=AMixer;
  358. FConnections:=TMixerConnections.Create (XMixer,FData);
  359. FControls:=TMixerControls.Create (XMixer,AData);
  360. end;
  361. destructor TMixerDestination.Destroy;
  362. begin
  363. Fcontrols.free;
  364. FConnections.Free;
  365. inherited;
  366. end;
  367. {------------------}
  368. {TMixerDestinations}
  369. {------------------}
  370. constructor TMixerDestinations.Create (AMixer:TAudioMixer);
  371. var A,B:Integer;
  372. ML:TMixerLine;
  373. begin
  374. FDestinations:=TPointerList.Create;
  375. FDestinations.OnFreeItem:=DoFreeItem;
  376. For A:=0 to AMixer.MixerCaps.cDestinations-1 do
  377. begin
  378. ML.cbStruct:=SizeOf(TMixerLine);
  379. ML.dwDestination:=A;
  380. B:=MixerGetLineInfo (AMixer.MixerHandle,@ML,MIXER_GETLINEINFOF_DESTINATION);
  381. If B=MMSYSERR_NOERROR then
  382. FDestinations.Add(Pointer(TMixerDestination.Create (AMixer,ML)));
  383. end;
  384. end;
  385. procedure TMixerDestinations.DoFreeItem (Pntr:Pointer);
  386. begin
  387. TMixerDestination(Pntr).Free;
  388. end;
  389. destructor TMixerDestinations.Destroy;
  390. begin
  391. FDestinations.Free;
  392. inherited;
  393. end;
  394. function TMixerDestinations.GetDestination (Ind:Integer):TMixerDestination;
  395. begin
  396. Result:=FDestinations.Pointer[Ind];
  397. end;
  398. function TMixerDestinations.GetCount:Integer;
  399. begin
  400. Result:=FDestinations.Count;
  401. end;
  402. {-----------}
  403. {TAudioMixer}
  404. {-----------}
  405. constructor TAudioMixer.Create (AOwner:TComponent);
  406. begin
  407. inherited Create (AOwner);
  408. FDestinations:=nil;
  409. XWndHandle:=AllocateHWnd (MixerCallBack);
  410. FMixersCount:=mixerGetNumDevs;
  411. FMixerID:=-1;
  412. If FMixersCount>0 then
  413. SetMixerID (0);
  414. end;
  415. destructor TAudioMixer.Destroy;
  416. begin
  417. closemixer;
  418. if XWndHandle<>0 then
  419. DeAllocateHwnd(XWndHandle);
  420. inherited;
  421. end;
  422. procedure TAudioMixer.CloseMixer;
  423. begin
  424. If FMixerID>=0 then
  425. begin
  426. mixerClose (FMixerHandle);
  427. FMixerID:=-1;
  428. end;
  429. FDestinations.Free;
  430. FDestinations:=nil;
  431. end;
  432. procedure TAudioMixer.SetMixerID (Value:Integer);
  433. begin
  434. If Value>=FMixersCount then
  435. Exit;
  436. CloseMixer;
  437. If Value>=0 then
  438. If mixerOpen (@FMixerHandle,Value,XWndHandle,0,CALLBACK_WINDOW OR MIXER_OBJECTF_MIXER)=MMSYSERR_NOERROR then
  439. begin
  440. FMixerID:=Value;
  441. mixerGetDevCaps (MixerID,@FMixerCaps,SizeOf (TMixerCaps));
  442. FDestinations:=TMixerDestinations.Create (Self);
  443. end;
  444. end;
  445. procedure TAudioMixer.MixerCallBack (var Msg:TMessage);
  446. begin
  447. case Msg.Msg of
  448. MM_MIXM_LINE_CHANGE:
  449. If Assigned (OnLineChange) then
  450. OnLineChange (Self,Msg.wParam,Msg.lParam);
  451. MM_MIXM_CONTROL_CHANGE:
  452. If Assigned (OnControlChange) then
  453. OnControlChange (Self,Msg.wParam,Msg.lParam);
  454. end;
  455. end;
  456. function TAudioMixer.GetVolume (ADestination,AConnection:Integer;var LeftVol,RightVol,Mute:Integer;var VolDisabled,MuteDisabled:Boolean):Boolean;
  457. var MD:TMixerDestination;
  458. MC:TMixerConnection;
  459. Cntrls:TMixerControls;
  460. MCD:TMixerControlDetails;
  461. Cntrl:PMixerControl;
  462. A,B:Integer;
  463. ML:TMixerLine;
  464. details:array [0..30] of Integer;
  465. begin
  466. Result:=False;
  467. MD:=Destinations[ADestination];
  468. If MD<>nil then
  469. begin
  470. If AConnection=-1 then
  471. begin
  472. Cntrls:=MD.Controls;
  473. ML:=MD.Data;
  474. end
  475. else
  476. begin
  477. MC:=MD.Connections[AConnection];
  478. If MC<>nil then
  479. begin
  480. Cntrls:=MC.Controls;
  481. ML:=MC.Data;
  482. end
  483. else
  484. Cntrls:=nil;
  485. end;
  486. If Cntrls<>nil then
  487. begin
  488. A:=0;
  489. Result:=True;
  490. LeftVol:=-1;
  491. RightVol:=-1;
  492. Mute:=-1;
  493. while ((LeftVol=-1) OR (Mute=-1)) AND (A<Cntrls.Count) do
  494. begin
  495. Cntrl:=Cntrls[A];
  496. If Cntrl<>nil then
  497. begin
  498. If ((Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME) OR
  499. (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE)) AND
  500. (Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_MULTIPLE<>MIXERCONTROL_CONTROLF_MULTIPLE)
  501. then
  502. begin
  503. MCD.cbStruct:=SizeOf(TMixerControlDetails);
  504. MCD.dwControlID:=Cntrl.dwControlID;
  505. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_UNIFORM>0 then
  506. MCD.cChannels:=1
  507. else
  508. MCD.cChannels:=ML.cChannels;
  509. MCD.cMultipleItems:=0;
  510. MCD.cbDetails:=SizeOf(Integer);
  511. MCD.paDetails:=@details;
  512. B:=mixerGetControlDetails (FMixerHandle,@MCD,MIXER_GETCONTROLDETAILSF_VALUE);
  513. If B=MMSYSERR_NOERROR then
  514. begin
  515. If (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME) AND (LeftVol=-1) then
  516. begin
  517. VolDisabled:=Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_DISABLED>0;
  518. If not VolDisabled then
  519. begin
  520. LeftVol:=details[0];
  521. If MCD.cChannels>1 then
  522. RightVol:=Details[1];
  523. end;
  524. end
  525. else
  526. If (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE) AND (Mute=-1) then
  527. begin
  528. MuteDisabled:=Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_DISABLED>0;
  529. If not MuteDisabled then
  530. begin
  531. If Details[0]<>0 then
  532. Mute:=1
  533. else
  534. Mute:=0;
  535. end;
  536. end;
  537. end;
  538. end;
  539. end;
  540. Inc (A);
  541. end;
  542. If Mute=-1 then
  543. begin
  544. If AConnection<>-1 then
  545. begin
  546. Cntrls:=MD.Controls;
  547. ML:=MD.Data;
  548. If Cntrls<>nil then
  549. begin
  550. A:=0;
  551. while (Mute=-1) AND (A<Cntrls.Count) do
  552. begin
  553. Cntrl:=Cntrls[A];
  554. If (Cntrl.dwControlType AND MIXERCONTROL_CONTROLTYPE_MIXER=MIXERCONTROL_CONTROLTYPE_MIXER) OR
  555. (Cntrl.dwControlType AND MIXERCONTROL_CONTROLTYPE_MUX=MIXERCONTROL_CONTROLTYPE_MUX) then
  556. // Mux is similar to mixer, but only one line can be selected at a time
  557. begin
  558. MCD.cbStruct:=SizeOf(TMixerControlDetails);
  559. MCD.dwControlID:=Cntrl.dwControlID;
  560. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_UNIFORM>0 then
  561. MCD.cChannels:=1
  562. else
  563. MCD.cChannels:=ML.cChannels;
  564. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_MULTIPLE=MIXERCONTROL_CONTROLF_MULTIPLE then
  565. MCD.cMultipleItems:=Cntrl.cMultipleItems
  566. else
  567. MCD.cMultipleItems:=0;
  568. MCD.cbDetails:=4;
  569. MCD.paDetails:=@Details;
  570. B:=mixerGetControlDetails (FMixerHandle,@MCD,MIXER_GETCONTROLDETAILSF_VALUE);
  571. If B=MMSYSERR_NOERROR then
  572. Mute:=Details[AConnection];
  573. end;
  574. Inc (A);
  575. end;
  576. end;
  577. end;
  578. end;
  579. If LeftVol=-1 then
  580. VoldIsabled:=True;
  581. If Mute=-1 then
  582. MuteDisabled:=True;
  583. end;
  584. end;
  585. end;
  586. function TAudioMixer.SetVolume (ADestination,AConnection:Integer;LeftVol,RightVol,Mute:Integer):Boolean;
  587. var MD:TMixerDestination;
  588. MC:TMixerConnection;
  589. Cntrls:TMixerControls;
  590. MCD:TMixerControlDetails;
  591. Cntrl:PMixerControl;
  592. A,B:Integer;
  593. ML:TMixerLine;
  594. details:array [0..30] of Integer;
  595. VolSet,MuteSet:Boolean;
  596. begin
  597. Result:=False;
  598. MD:=Destinations[ADestination];
  599. If MD<>nil then
  600. begin
  601. If AConnection=-1 then
  602. begin
  603. Cntrls:=MD.Controls;
  604. ML:=MD.Data;
  605. end
  606. else
  607. begin
  608. MC:=MD.Connections[AConnection];
  609. If MC<>nil then
  610. begin
  611. Cntrls:=MC.Controls;
  612. ML:=MC.Data;
  613. end
  614. else
  615. Cntrls:=nil;
  616. end;
  617. If Cntrls<>nil then
  618. begin
  619. A:=0;
  620. VolSet:=LeftVol=-1;
  621. MuteSet:=Mute=-1;
  622. Result:=True;
  623. while (not VolSet OR not MuteSet) AND (A<Cntrls.Count) do
  624. begin
  625. Cntrl:=Cntrls[A];
  626. If Cntrl<>nil then
  627. begin
  628. If ((Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME) OR
  629. (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE)) AND
  630. (Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_MULTIPLE<>MIXERCONTROL_CONTROLF_MULTIPLE)
  631. then
  632. begin
  633. MCD.cbStruct:=SizeOf(TMixerControlDetails);
  634. MCD.dwControlID:=Cntrl.dwControlID;
  635. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_UNIFORM>0 then
  636. MCD.cChannels:=1
  637. else
  638. MCD.cChannels:=ML.cChannels;
  639. MCD.cMultipleItems:=0;
  640. MCD.cbDetails:=SizeOf(Integer);
  641. MCD.paDetails:=@Details;
  642. If (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME) AND not VolSet then
  643. begin
  644. Details[0]:=LeftVol;
  645. If RightVol=-1 then
  646. Details[1]:=LeftVol
  647. else
  648. Details[1]:=RightVol;
  649. VolSet:=True;
  650. end
  651. else
  652. If (Cntrl.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE) AND not MuteSet then
  653. begin
  654. Details[0]:=Mute;
  655. MuteSet:=True;
  656. end;
  657. mixerSetControlDetails (FMixerHandle,@MCD,MIXER_GETCONTROLDETAILSF_VALUE);
  658. end;
  659. end;
  660. Inc (A);
  661. end;
  662. If not MuteSet then
  663. begin
  664. If AConnection<>-1 then
  665. begin
  666. Cntrls:=MD.Controls;
  667. ML:=MD.Data;
  668. If Cntrls<>nil then
  669. begin
  670. A:=0;
  671. while not MuteSet AND (A<Cntrls.Count) do
  672. begin
  673. Cntrl:=Cntrls[A];
  674. If (Cntrl.dwControlType AND MIXERCONTROL_CONTROLTYPE_MIXER=MIXERCONTROL_CONTROLTYPE_MIXER) OR
  675. (Cntrl.dwControlType AND MIXERCONTROL_CONTROLTYPE_MUX=MIXERCONTROL_CONTROLTYPE_MUX) then
  676. begin
  677. MCD.cbStruct:=SizeOf(TMixerControlDetails);
  678. MCD.dwControlID:=Cntrl.dwControlID;
  679. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_UNIFORM>0 then
  680. MCD.cChannels:=1
  681. else
  682. MCD.cChannels:=ML.cChannels;
  683. If Cntrl.fdwControl AND MIXERCONTROL_CONTROLF_MULTIPLE=MIXERCONTROL_CONTROLF_MULTIPLE then
  684. MCD.cMultipleItems:=Cntrl.cMultipleItems
  685. else
  686. MCD.cMultipleItems:=0;
  687. MCD.cbDetails:=4;
  688. MCD.paDetails:=@Details;
  689. MuteSet:=True;
  690. mixerGetControlDetails (FMixerHandle,@MCD,MIXER_GETCONTROLDETAILSF_VALUE);
  691. For B:=0 to Cntrl.cMultipleItems-1 do
  692. Details[B]:=0;
  693. Details[AConnection]:=Mute;
  694. mixerSetControlDetails (FMixerHandle,@MCD,MIXER_GETCONTROLDETAILSF_VALUE);
  695. end;
  696. Inc (A);
  697. end;
  698. end;
  699. end;
  700. end;
  701. end;
  702. end;
  703. end;
  704. procedure Register;
  705. begin
  706. RegisterComponents('Samples', [TAudioMixer]);
  707. end;
  708. end.