Volume Control(音量控制器) |
|
cmf
尊榮會員 發表:84 回覆:918 積分:1032 註冊:2002-06-26 發送簡訊給我 |
資料來源:
本站原创及翻译内容保留版权,欢迎转贴,转贴时请注明转自哈巴狗的小窝 Volume Control(音量控制器)是一个很常用的小程序。但控制器太多摆不下,而且回放和录音之间要经常切换,很不方便。一些朋友编写多媒体播放器,是否想过加个内置混音器呢?你有没有想过自己编写混音器程序呢?下面具体的编写方法。
一、混音器的结构 首先简单介绍混音器的结构。混音器由多个destination(目的单元)组成,如Playback(回放)、Recording(录音)、Voice command(语音命令)等等。 而每个destination又由多个Connections(连接设备), 如回放下有CD Audio、MIDI 、Wave等等。每条 Connection 联系着一个或以上的Control(控制器)。Control是混音器的关键,有Volume Control(音量控制器)、Mute Control(静音控制器)、Meter Control(仪表控制器)等等。 以下是Mixer 的结构及调用的函数 Mixer (mixerGetNumDevs返回mixer 的个数, 后要用Mixeropen打开混音器) | Destinations (destinations should be for example: Playback, Recording and Voice commands) * | (The number of destinations return by mixerGetDevCaps) * |--Destination[0] (调用 mixerGetLineInfo 取得Destination连接的Connections和Controls) * | | * | |--Controls (controls of the line, ex: Master volume, master mute) * | | | (调用MixerGetLineControls 取得 Controls) * | | |--Control[0] * | | |--Control[1] * | | |--Control[..] * | | * | |--Connections (ex: Wave, MIDI, CD Audio, Line-In,...) * | | * | |--Connection[0] * | | |--Controls (here can be volume and mute) * | | | (调用MixerGetLineControls 取得 Controls) * | | |--Control[0] (ex:Wave Volume) * | | |--Control[1] (ex:Wave Mute) * | | |--Control[..] (ex:Wave Meter) * | | * | |--Connection[1] * | |--Connection[..] * | * |--Destination[1] * |--Destination[..] 一步一步的先后取得Destinations、Connections,但最终的目的是取得各种的Controls, 以后的音量、静音的控制都要调用Controls。所以要保存Controls的数据。本程序用一 个三维的动态数组保存Controls。方便以后调用。 二、本程序的函数的作用 getvolume 取得音量, setvolume设置音量; getmute取得设备是否静音, setmute是设备静音。 Getpeak取得设备的peak(振幅) 五个程序都是填写Tmixercontroldetails类型调用 Mixergetcontroldetails,mixersetcontroldetails。 三、关于mixer 的message及Callback Function Mixer 提供 MM_MIXM_CONTROL_CHANGE MM_MIXM_LINE_CHANGE 两个message要在调用 mixeropen 设置Callback Function unit Unit2; //Written by David Jiang(江天送) //july 25th. 1999 interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, ComCtrls, mmsystem, Buttons, ExtCtrls; type Tvolume=record left,right:word; end; type TForm2 = class(TForm) Lines: TComboBox; Controls: TComboBox; Label1: TLabel; lmute: TLabel; lmeter: TLabel; LVolume: TTrackBar; Rvolume: TTrackBar; cmute: TCheckBox; CheckBox1: TCheckBox; About: TSpeedButton; BExit: TSpeedButton; RProgressBar: TProgressBar; Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure getlinecontrol; procedure LinesChange(Sender: TObject); procedure ControlsChange(Sender: TObject); procedure LVolumeChange(Sender: TObject); procedure cmuteClick(Sender: TObject); procedure RvolumeChange(Sender: TObject); procedure AboutClick(Sender: TObject); procedure BExitClick(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } procedure mmixer(var msg:Tmessage); public { Public declarations } end; function getvolume(control:Pmixercontrol;var volume:Tvolume):boolean; function setvolume(control:Pmixercontrol; volume:Tvolume):boolean; function setmute(control:Pmixercontrol; mute:integer):boolean; function getmute(control:Pmixercontrol;var mute:integer):boolean; function getpeak(control:Pmixercontrol;var peak:integer):boolean; procedure Fillstruct(control:Pmixercontrol;var Cdetails:Tmixercontroldetails); var Form2: TForm2; fmixerhandle:hmixer; //混音器的句柄 mcontrols:array of array of array of PMixerControl; line:array of Tstringlist; peaknum:integer; //meter mcontrols的位置 implementation {$R *.DFM} procedure Tform2.mmixer(var msg:Tmessage); var volume:Tvolume; mute:integer; begin if msg.Msg=MM_MIXM_CONTROL_CHANGE then begin if mcontrolS[lines.itemindex][controls.itemindex] [0].dwcontrolID=msg.LParam then if getvolume(mcontrolS[lines.itemindex] [controls.itemindex][0],volume) then begin Rvolume.Position :=-volume.right; Lvolume.Position :=-volume.left; end; if mcontrolS[lines.itemindex][controls.itemindex] [1].dwcontrolid=msg.LParam then if getmute(mcontrolS[lines.itemindex] [controls.itemindex][1],mute) then cmute.Checked:=mute=1; end; end; procedure TForm2.FormCreate(Sender: TObject); begin getlinecontrol; lines.ItemIndex :=0; controls.Items:=line[lines.ItemIndex]; controls.ItemIndex :=0; controls.OnChange (sender); end; procedure Tform2.getlinecontrol; var mixerID:integer; //混音器的ID FMixerCaps:TMixerCaps; n,j,k,i:integer; ml,ml2:TMIXERLINE; MLC:TMixerLineControls; P:PMixerControl; begin if mixerGetNumDevs=0 then exit; //如没有混合器装置,退出 fmixerhandle:=0; mixerID:=0; mixerOpen (@FMixerHandle,mixerID,AllocateHWnd(mmixer), 0,CALLBACK_WINDOW OR MIXER_OBJECTF_MIXER); //打开混音器 mixerGetDevCaps (mixerID,@FMixerCaps,SizeOf (TMixerCaps)); //返回混音器的兼容性 setlength(line,fmixercaps.cDestinations); setlength(mcontrols,fmixercaps.cDestinations ); for i:=0 to fmixercaps.cDestinations-1 do begin ml.dwDestination:=i; ml.cbStruct :=sizeof(tMIXERLINE); mixerGetLineInfo(fmixerhandle,@ml, MIXER_GETLINEINFOF_DESTINATION); //取得混音器的Destinations line[i]:=tstringlist.Create ; setlength(mcontrols[i],ml.cconnections); n:=0; if ml.cControls>1 then begin n:=1; setlength(mcontrols[i],ml.cconnections 1); MLC.cbStruct:=SizeOf(MLC); MLC.dwLineID:=ml.dwLineID; MLC.cControls:=ml.cControls; MLC.cbmxctrl:=SizeOf(TMixerControl); GetMem (P,SizeOf(TMixerControl)*ml.cControls); MLC.pamxctrl:=P; MixerGetLineControls(fMixerHandle,@MLC, MIXER_GETLINECONTROLSF_ALL); setlength(mcontrols[i][0],ml.cControls); line[i].Add(p^.szname); //Master Volume For k:=0 to ml.cControls-1 do begin mcontrols[i][0][k]:=p; mcontrols[i][0][0].Metrics.dwReserved[k 1]:=1; inc(p); end; end; lines.Items.Add(ml.szName); ML2.cbStruct:=SizeOf(TMixerLine); ML2.dwDestination:=ml.dwDestination ; for j:=0 to ml.cConnections -1 do begin ML2.dwSource:=j; MixerGetLineInfo (fmixerHandle,@ML2, MIXER_GETLINEINFOF_SOURCE); MLC.cbStruct:=SizeOf(MLC); MLC.dwLineID:=ml2.dwLineID; MLC.cControls:=ml2.cControls; MLC.cbmxctrl:=SizeOf(TMixerControl); GetMem (P,SizeOf(TMixerControl)*ml2.cControls); MLC.pamxctrl:=P; MixerGetLineControls(fMixerHandle,@MLC, MIXER_GETLINECONTROLSF_ALL); setlength(mcontrols[i][j n],ml2.cControls); For k:=0 to ml2.cControls-1 do begin if p.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME then line[i].add(p^.szName); mcontrols[i][j n][k]:=p; mcontrols[i][j n][0].Metrics.dwReserved[k 1]:=1; inc(p); end;//取得混音器线路的控制器 end; end; end; procedure Fillstruct(control:Pmixercontrol;var Cdetails:Tmixercontroldetails); begin cdetails.cbStruct:=sizeof(cdetails); cdetails.dwControlID:=control.dwControlID ; cdetails.cbDetails:=sizeof(integer); cdetails.hwndOwner :=0; end; function getpeak(control:Pmixercontrol;var peak:integer):boolean; var details:TMIXERCONTROLDETAILSSIGNED; cdetails:TMIXERCONTROLDETAILS; begin result:=false; if control.dwControlType <> MIXERCONTROL_CONTROLTYPE_PEAKMETER then exit; cdetails.cChannels :=1; cdetails.paDetails:=@details; fillstruct(control,cdetails); result:=MIXERGETCONTROLDETAILS(fmixerhandle, @cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0; peak:=abs(details.LValue) div 180; end; function setvolume(control:Pmixercontrol; volume:Tvolume):boolean; var details:array [0..30] of Integer; cdetails:TMIXERCONTROLDETAILS; begin fillstruct(control,cdetails); cdetails.cChannels :=2; cdetails.paDetails:=@details; details[0]:=volume.left; details[1]:=volume.right; result:=MIXERSETCONTROLDETAILS(fmixerhandle, @cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0; end; function getvolume(control:Pmixercontrol;var volume:Tvolume):boolean; var details:array [0..30] of Integer; cdetails:TMIXERCONTROLDETAILS; begin fillstruct(control,cdetails); cdetails.cChannels :=2; cdetails.paDetails:=@details; result:=MIXERGETCONTROLDETAILS(fmixerhandle, @cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0; volume.left:=details[0]; volume.right:=details[1]; end; function setmute(control:Pmixercontrol; mute:integer):boolean; var cdetails:Tmixercontroldetails; details:array [0..30] of Integer; begin fillstruct(control,cdetails); cdetails.cChannels :=1; cdetails.paDetails:=@details; details[0]:=mute; result:=MIXERSETCONTROLDETAILS(fmixerhandle, @cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0; end; function getmute(control:Pmixercontrol;var mute:integer):boolean; var cdetails:Tmixercontroldetails; details:array [0..30] of Integer; begin fillstruct(control,cdetails); cdetails.cChannels :=1; cdetails.cMultipleItems:=0; cdetails.paDetails:=@details; result:=MIXERGETCONTROLDETAILS(fmixerhandle, @cdetails,MIXER_GETCONTROLDETAILSF_VALUE)=0; mute:=details[0]; end; procedure TForm2.LinesChange(Sender: TObject); begin controls.Items:=line[lines.ItemIndex]; if controls.ItemIndex =-1 then controls.ItemIndex :=0; end; procedure TForm2.ControlsChange(Sender: TObject); var mute,k,j:integer; volume:Tvolume; begin lmute.Visible :=false; lmeter.Visible :=false; k:=lines.ItemIndex;j:=controls.ItemIndex; IF mcontrols[k][j][0].Metrics.dwReserved[2]=1 then begin lmute.Visible:=mcontrols[k][j][1].dwcontroltype =MIXERCONTROL_CONTROLTYPE_MUTE; lmeter.Visible:=mcontrols[k][j][1].dwcontroltype =MIXERCONTROL_CONTROLTYPE_PEAKMETER; if lmeter.Visible then peaknum:=1; end; cmute.Enabled :=lmute.Visible ; IF mcontrols[k][j][0].Metrics.dwReserved[3]=1 then begin lmeter.Visible:=mcontrols[k][j][2].dwcontroltype =MIXERCONTROL_CONTROLTYPE_PEAKMETER; if lmeter.Visible then peaknum:=2; end; if getvolume(mcontrols[k][j][0],volume) then begin Rvolume.Position :=-volume.right; Lvolume.Position :=-volume.left; end; if getmute(mcontrols[k][j][1],mute) then cmute.Checked :=mute=1; RProgressbar.Visible :=lmeter.Visible;; timer1.Enabled:=lmeter.Visible; end; procedure TForm2.LVolumeChange(Sender: TObject); var volume:tvolume; begin if checkbox1.Checked then Rvolume.Position :=Lvolume.Position ; volume.right :=-Rvolume.Position; volume.left:=-Lvolume.Position ; setvolume(mcontrolS[lines.itemindex][controls.itemindex][0], volume); end; procedure TForm2.cmuteClick(Sender: TObject); var mute:integer; begin if cmute.checked then mute:=1 else mute:=0; setmute(mcontrolS[lines.itemindex][controls.itemindex][1],mute); end; procedure TForm2.RvolumeChange(Sender: TObject); begin if checkbox1.Checked then Lvolume.Position :=Rvolume.Position ; Lvolume.OnChange (sender); end; procedure TForm2.AboutClick(Sender: TObject); begin showmessage('Mixer Demo version 1.0 ' chr(13) 'Written by David Jiang'); end; procedure TForm2.BExitClick(Sender: TObject); begin close; end; procedure TForm2.Timer1Timer(Sender: TObject); var peak:integer; begin IF mcontrols[lines.itemindex][controls.itemindex] [0].Metrics.dwReserved[peaknum 1]=1 then if getpeak(mcontrols[lines.itemindex][controls.itemindex] [peaknum],peak) then Rprogressbar.Position :=peak; end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin mixerclose(fmixerhandle); end; end.發表人 - cmf 於 2003/09/11 13:34:57
------
︿︿ |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |