[fpc-pascal] Windows Volume Control
Marc Weustink
marc at dommelstein.nl
Tue Jan 18 10:37:23 CET 2022
On 15-1-2022 19:02, James Richters via fpc-pascal wrote:
> Are there functions to check the current volume level and to set the
> volume with just FPC (not Lazarus) on Windows 10?
>
> All I need is the master system volume, not any of the mixer controls.
This is possible. Please be aware that you can have multiple mixers and
that the presence of the master volume is defined by the audio driver of
the specific device (for a headset you may need to control the wave out).
The following are more or less the routines I use. Other application
logic is stripped, so it won't compile, but it should give you an idea.
This code is used in a context where we can control multiple mixers,
having different left/right volumes (hence the search for a specific
name and a volume array)
Marc
function Initialize: Boolean;
var
n, maxlen, MixerId: Integer;
woc: TWaveOutCaps;
Search, Name: String;
nDest: Integer;
mmr: MMRESULT;
mxcaps: TMixerCaps;
mxl, mxlsrc: TMixerLine;
mxlc: TMixerLineControls;
mxc: TMixerControl;
begin
Result := False;
// == setup volumes ===========================
MixerId := -1;
// only compare the first wic.szPname -1 (==0) len characters,
info.name can be longer
maxlen := SizeOf(woc.szPname) - 1;
Search := Trim(Copy(FName, 1, maxlen));
for n := 0 to Integer(waveOutGetNumDevs) - 1 do
begin
waveOutGetDevCaps(n, @woc, SizeOf(woc));
Name := Trim(woc.szPname);
if not SameText(Search, Name) then Continue;
mixerGetID(n, Cardinal(MixerId), MIXER_OBJECTF_WAVEOUT);
Break;
end;
if MixerID = -1 then Exit;
// === controls ===============================
mmr := mixerGetDevCaps(MixerID, @mxcaps, SizeOf(mxcaps));
if mmr <> MMSYSERR_NOERROR
then begin
Exit;
end;
if mxcaps.cDestinations = 0
then begin
Exit;
end;
mxl.cbStruct := SizeOf(mxl);
for nDest := 0 to mxcaps.cDestinations - 1 do
begin
// loop through the mixer destinations to find a waveout type
mxl.dwDestination := nDest;
mxl.dwSource := 0;
mxl.dwLineID := 0;
mmr := mixerGetLineInfo(MixerID, @mxl, MIXER_OBJECTF_MIXER or
MIXER_GETLINEINFOF_DESTINATION);
if mmr <> 0 then Continue;
if mxl.Target.dwType <> MIXERLINE_TARGETTYPE_WAVEOUT then Continue;
// -- master Volume --
if mxl.cControls > 0
then begin
mxlc.cbStruct := SizeOf(mxlc);
mxlc.dwLineID := mxl.dwLineID;
mxlc.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls := 1;
mxlc.pamxctrl := @mxc;
mxlc.cbmxctrl := SizeOf(mxc);
mmr := mixerGetLineControls(MixerID, @mxlc, MIXER_OBJECTF_MIXER
or MIXER_GETLINECONTROLSF_ONEBYTYPE);
if mmr = MMSYSERR_NOERROR
then begin
// set master volume
SetMixerControlVolume(MixerID, mxc, mxl.cChannels, FMasterVolume);
end;
end;
// -- wave Volume --
if mxl.cConnections > 0
then begin
mxlsrc.cbStruct := SizeOf(mxlsrc);
mxlsrc.dwComponentType := MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
mxlsrc.dwLineID := 0;
mmr := mixerGetLineInfo(MixerID, @mxlsrc, MIXER_OBJECTF_MIXER or
MIXER_GETLINEINFOF_COMPONENTTYPE);
if mmr = MMSYSERR_NOERROR
then begin
// get wave volume
mxlc.cbStruct := SizeOf(mxlc);
mxlc.dwLineID := mxlsrc.dwLineID;
mxlc.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls := 1;
mxlc.cbmxctrl := SizeOf(mxc);
mxlc.pamxctrl := @mxc;
mmr := mixerGetLineControls(MixerID, @mxlc, MIXER_OBJECTF_MIXER
or MIXER_GETLINECONTROLSF_ONEBYTYPE);
if mmr = MMSYSERR_NOERROR
then begin
// set wave volume
SetMixerControlVolume(MixerID, mxc, mxlsrc.cChannels, FVolume);
end;
end;
end;
Break;
end;
end;
procedure SetMixerControlVolume(AMixerID: Integer; AControl:
TMixerControl; AChannels: Cardinal; const AValues: array of Byte);
var
mxcd: TMixerControlDetails;
idx, c: integer;
detailUnsigned: array of MIXERCONTROLDETAILS_UNSIGNED;
begin
if AControl.cbStruct = 0 then Exit; // no volume
if AControl.fdwControl and MIXERCONTROL_CONTROLF_UNIFORM <> 0
then AChannels := 1;
SetLength(detailUnsigned, AChannels);
mxcd.cbStruct := SizeOf(mxcd);
mxcd.dwControlID := AControl.dwControlID;
mxcd.cChannels := AChannels;
mxcd.cMultipleItems := 0;
mxcd.cbDetails := SizeOf(detailUnsigned[0]);
mxcd.paDetails := @detailUnsigned[0];
mixerGetControlDetails(AMixerID, @mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
idx := 0;
for c := 0 to AChannels - 1 do
begin
if idx < Length(AValues)
then detailUnsigned[c].dwValue := MulDiv(AControl.Bounds.dwMaximum,
AValues[idx] , 100)
else detailUnsigned[c].dwValue := 0;
if Length(AValues) > 1
then Inc(idx);
end;
mixerSetControlDetails(AMixerID, @mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
end;
More information about the fpc-pascal
mailing list