📄 unamsmixer.pas
字号:
(*
----------------------------------------------
unaMsMixer.pas
Voice Communicator components version 2.5
MS Mixer interface
----------------------------------------------
This source code cannot be used without
proper permission granted to you as a private
person or an entity by the Lake of Soft, Ltd
Visit http://lakeofsoft.com/ for details.
Copyright (c) 2002-2003 Lake of Soft, Ltd
All rights reserved
----------------------------------------------
created by:
Lake, 04 Mar 2002
modified by:
Lake, Mar-Dec 2002
Lake, Jan-Nov 2003
----------------------------------------------
*)
{$I unaDef.inc}
unit
unaMsMixer;
{DP:UNIT
Contains class wrappers for MS mixer interface API.
Refer to MSDN documentation for more information about mixers.
}
interface
uses
Windows, unaTypes, MMSystem,
unaUtils, unaClasses,
{$IFDEF __SYSUTILS_H_ }
Math,
{$ENDIF}
unaPlacebo;
type
//
// -- unaMsMixerObject --
//
{DP:CLASS
}
unaMsMixerObject = class
private
function checkError(errorCode: MMRESULT{$IFDEF DEBUG}; const method: string{$ENDIF}): bool;
public
end;
//
// -- unaMsMixerControl --
//
unaMsMixerDevice = class;
unaMsMixerSystem = class;
unaMsMixerLine = class;
{DP:CLASS
Mixer control. Every line has several controls connected to it.
}
unaMsMixerControl = class(unaMsMixerObject)
private
f_updateCount: int;
f_controlType: unsigned;
f_controlClass: unsigned;
f_controlSubClass: unsigned;
f_controlUnits: unsigned;
f_multipleItems: unsigned;
f_caps: pMixerControlW;
f_details: pMixerControlDetails;
//
f_master: unaMsMixerLine;
f_listItems: unaList;
f_listItemsText: unaStringList;
f_listItemsFilled: bool;
//
function getDetails(): pMixerControlDetails;
procedure setDetails();
function getIsControl(index: int): bool;
function getIsControlClass(index: int): bool;
function getControlID(): unsigned;
public
constructor create(master: unaMsMixerLine; caps: pMixerControlW);
destructor Destroy(); override;
//
procedure beginUpdate();
procedure endUpdate();
//
function getValue(def: bool; channel: unsigned = 0; index: unsigned = 0): bool; overload;
function getValueInt(def: int; channel: unsigned = 0; index: unsigned = 0): int;
function getValue(const def: string; channel: unsigned = 0; index: unsigned = 0): string; overload;
function getValue(def: unsigned; channel: unsigned = 0; index: unsigned = 0): unsigned; overload;
function getListItem(channel: unsigned = 0; index: unsigned = 0): pMixerControlDetailsListText;
//
procedure setValue(value: bool; channel: int = -1; index: unsigned = 0); overload;
procedure setValueInt(value: int; channel: int = -1; index: unsigned = 0);
procedure setValue(value: unsigned; channel: int = -1; index: unsigned = 0); overload;
//
{DP:METHOD
Returns control caps (should be used as read only).
}
property caps: pMixerControlW read f_caps;
{DP:METHOD
Specifies control ID.
}
property controlID: unsigned read getControlID;
property details: pMixerControlDetails read f_details;
{DP:METHOD
If control is list - stores string items assotiated with list.
}
property listItemsText: unaStringList read f_listItemsText;
//
property isMultiple: bool index MIXERCONTROL_CONTROLF_MULTIPLE read getIsControl;
property isUniform: bool index MIXERCONTROL_CONTROLF_UNIFORM read getIsControl;
property isDisabled: bool index -1{MIXERCONTROL_CONTROLF_DISABLED} read getIsControl;
//
property isCustomClass: bool index MIXERCONTROL_CT_CLASS_CUSTOM read getIsControlClass;
property isFaderClass: bool index MIXERCONTROL_CT_CLASS_FADER read getIsControlClass;
property isListClass: bool index MIXERCONTROL_CT_CLASS_LIST read getIsControlClass;
property isMeterClass: bool index MIXERCONTROL_CT_CLASS_METER read getIsControlClass;
property isNumberClass: bool index MIXERCONTROL_CT_CLASS_NUMBER read getIsControlClass;
property isSliderClass: bool index MIXERCONTROL_CT_CLASS_SLIDER read getIsControlClass;
property isSwitchClass: bool index MIXERCONTROL_CT_CLASS_SWITCH read getIsControlClass;
property isTimeClass: bool index MIXERCONTROL_CT_CLASS_TIME read getIsControlClass;
//
property controlType: unsigned read f_controlType;
property controlClass: unsigned read f_controlClass;
property controlSubClass: unsigned read f_controlSubClass;
property controlUnits: unsigned read f_controlUnits;
//
property multipleItems: unsigned read f_multipleItems;
end;
//
// -- unaMsMixerLine --
//
{DP:CLASS
Mixer line. Every mixer has 0 or more lines connected to it.
}
unaMsMixerLine = class(unaMsMixerObject)
private
f_capsW: pMixerLineW;
//
f_master: unaMsMixerDevice;
f_connections: unaObjectList;
f_controls: unaObjectList;
//
procedure enumConnections();
procedure enumControls();
function getConnection(index: unsigned): unaMsMixerLine;
function getControl(index: unsigned): unaMsMixerControl;
function getCaps(isConnection: bool): pMixerLineW;
function getIsLineType(index: int): bool;
public
constructor create(master: unaMsMixerDevice; destIndex: unsigned; isConnection: bool = false; sourceIndex: unsigned = 0);
destructor Destroy(); override;
//
function getConnectionCount(): unsigned;
function getControlCount(): unsigned;
function getID(): unsigned;
function locateLine(componentType: unsigned): unaMsMixerLine;
//
property caps: pMixerLineW read f_capsW;
property connections[index: unsigned]: unaMsMixerLine read getConnection;
property control[index: unsigned]: unaMsMixerControl read getControl; default;
//
property isActive: bool index MIXERLINE_LINEF_ACTIVE read getIsLineType;
property isDisconnected: bool index MIXERLINE_LINEF_DISCONNECTED read getIsLineType;
property isSource: bool index -1{MIXERLINE_LINEF_SOURCE} read getIsLineType;
end;
//
// -- unaMsMixerDevice --
//
{DP:CLASS
Mixer device.
}
unaMsMixerDevice = class(unaMsMixerObject)
private
f_index: unsigned;
f_handle: hMixer;
f_winHandle: hWnd;
f_caps: pMixerCapsW;
//
f_master: unaMsMixerSystem;
f_lines: unaObjectList;
//
function getActive(): bool;
procedure setActive(value: bool);
//
function getCaps(): pMixerCapsW;
function getLine(index: unsigned): unaMsMixerLine;
protected
procedure doOpen(); virtual;
procedure doClose(); virtual;
public
constructor create(master: unaMsMixerSystem; index: unsigned);
destructor Destroy(); override;
//
procedure open();
procedure close();
procedure enumLines();
function getLineCount(): unsigned;
function getID(): unsigned;
function locateTargetLine(targetType: unsigned): unaMsMixerLine;
function locateDestLine(destination: unsigned): unaMsMixerLine;
function locateComponentLine(componentType: unsigned = MIXERLINE_COMPONENTTYPE_DST_WAVEIN): unaMsMixerLine;
//
property caps: pMixerCapsW read f_caps;
property active: bool read getActive write setActive;
property line[index: unsigned]: unaMsMixerLine read getLine; default;
property winHandle: hWnd read f_winHandle write f_winHandle;
end;
//
// -- unaMsMixerSystem --
//
{DP:CLASS
Mixer system. Use to get access to all mixer devices installed on a system.
}
unaMsMixerSystem = class
private
f_enumOnCreate: bool;
f_enumComplete: bool;
//
f_mixers: unaObjectList;
f_selectedMixer: unaMsMixerDevice;
//
function getMixer(index: unsigned): unaMsMixerDevice;
function getConnection(iline: unsigned; iconn: int): unaMsMixerLine;
//
function getConnectionControl(iline: unsigned; iconn: int; cclass, ctype: unsigned): unaMsMixerControl;
function mapMixerIdWin9x(deviceId: unsigned; isInDevice: bool): unsigned;
protected
procedure enumMixers(); virtual;
public
constructor create(enumOnCreate: bool = true);
destructor Destroy(); override;
procedure AfterConstruction(); override;
//
procedure enumDevices();
{DP:METHOD
returns number of mixers installed on a system.
}
function getMixerCount(): unsigned;
function getMixerId(deviceId: unsigned; isInDevice: bool): int;
function getMixerIndex(mixerId: unsigned): int;
function getDeviceId(isInDevice: bool; alsoCheckMapper: bool = false): int;
//
{DP:METHOD
selects and initializes specified mixer. All other methods works
with selected mixer only. Valid mixer index is from 0 to number of mixers installed - 1.
You can also specify handle of window to receive mixer-related messages.
}
function selectMixer(imixer: unsigned; handle: unsigned = 0): bool; overload;
function selectMixer(deviceId: unsigned; isInDevice: bool; handle: unsigned = 0): bool; overload;
//
{DP:METHOD
returns name of selected mixer.
}
function getMixerName(): wideString;
//
{DP:METHOD
returns number of lines for selected mixer.
Usually mixer has only two lines: recording and playback.
}
function getLineCount(): unsigned;
{DP:METHOD
returns name of specified line. Name can be short of full.
}
function getLineName(iline: unsigned; shortName: bool = false): wideString;
{DP:METHOD
returns index of output (playback) line when isOut is true,
or input (recording) line when isOut is false. Returned value
can be passed as iline parameter for other line-related methods.
recLevel parameter is internal, do not change it.
}
function getLineIndex(isOut: bool = true; recLevel: int = 0): int;
//
{DP:METHOD
returns number of connections for specified line.
}
function getLineConnectionCount(iline: unsigned): unsigned;
{DP:METHOD
returns name of specified connection for specified line.
Name can be short or full.
Valid connection index is from 0 to number returned by
getLineConnectionCount() - 1.
}
function getLineConnectionName(iline: unsigned; iconn: unsigned; shortName: bool = false): wideString;
{DP:METHOD
returns type of specified connection for specified line, or
type of line itself when iconn is -1.
}
function getLineConnectionType(iline: unsigned; iconn: int): unsigned;
{DP:METHOD
returns connection index for specified line with given type.
If no connection with specified type exists, returns -1.
Example: getLineConnectionByType(0, MIXERLINE_COMPONENTTYPE_DST_WAVEIN)
}
function getLineConnectionByType(iline: unsigned; itype: unsigned; checkControlsNum: bool = true): int;
//
{DP:METHOD
returns ID of a control responsible for volume level for specified
connection or line (when iconn = -1).
This ID is useful in window messages handler only.
}
function getVolumeControlID(iline: unsigned; iconn: int): int;
{DP:METHOD
returns volume level for specified connection or line (when iconn = -1).
Returned value ranges from 0 (lowest) to 100 (highest).
}
function getVolume(iline: unsigned; iconn: int): int;
{DP:METHOD
sets volume level for specified control or line (when iconn = -1).
Valid values for level are from 0 (lowest) to 100 (highest).
}
function setVolume(iline: unsigned; iconn: int; value: int): bool;
//
{DP:METHOD
returns control ID responsible for mute checkbox of specified
connection or line (when iconn = -1).
This ID is useful in window messages handler only.
}
function getMuteControlID(iline: unsigned; iconn: int): int;
{DP:METHOD
returns true if specified connection or line (when iconn = -1) is muted.
Otherwise returns false.
}
function isMutedConnection(iline: unsigned; iconn: int): bool;
{DP:METHOD
mutes or unmutes specified connection or line (when iconn = -1).
Returns true if operation was succesfull.
}
function muteConnection(iline: unsigned; iconn: int; doMute: bool): bool;
//
{DP:METHOD
returns connection index selected as current recording source.
If more than one connection can be selected, returns -1.
}
function getRecSource(): int; // returns iconn or -1
{DP:METHOD
sets specified connection as current recording source and optionally
ensures it is not muted if more than one connection can be selected.
}
function setRecSource(iconn: unsigned; ensureNotMuted: bool = true): bool;
//
property mixer[index: unsigned]: unaMsMixerDevice read getMixer; default;
//
property selectedMixer: unaMsMixerDevice read f_selectedMixer;
end;
implementation
{ unaMsMixerObject }
// -- --
function unaMsMixerObject.checkError(errorCode: MMRESULT{$IFDEF DEBUG}; const method: string{$ENDIF}): bool;
begin
if (MMSYSERR_NOERROR <> errorCode) then begin
//
assert(assertLog(className + '.' + {$IFDEF DEBUG}method + {$ENDIF}'() - failure, errorCode=' + int2str(errorCode)));
result := false;
end
else
result := true;
end;
{ unaMsMixerControl }
// -- --
procedure unaMsMixerControl.beginUpdate();
begin
inc(f_updateCount);
end;
// -- --
constructor unaMsMixerControl.create(master: unaMsMixerLine; caps: pMixerControlW);
begin
inherited create();
//
f_master := master;
f_caps := malloc(sizeOf(f_caps^), caps);
//
f_controlType := caps.dwControlType;
f_multipleItems := caps.cMultipleItems;
f_controlClass := (f_controlType and MIXERCONTROL_CT_CLASS_MASK);
f_controlSubClass := (f_controlType and MIXERCONTROL_CT_SUBCLASS_MASK);
f_controlUnits := (f_controlType and MIXERCONTROL_CT_UNITS_MASK);
//
f_listItems := unaRecordList.create();
f_listItemsText := unaStringList.create();
//
f_details := malloc(sizeOf(f_details^), true, 0);
f_details.cbStruct := sizeOf(f_details^);
f_details.dwControlID := controlID;
f_details.cMultipleItems := choice(isMultiple, f_multipleItems, 0);
//
// set cChannels
if (isCustomClass) then begin
//
f_details.cChannels := 0
end
else begin
//
if (isUniform) then
f_details.cChannels := 1
else
// read all the channels
f_details.cChannels := f_master.caps.cChannels;
end;
//
getDetails();
end;
// -- --
destructor unaMsMixerControl.destroy();
begin
inherited;
//
freeAndNil(f_listItems);
freeAndNil(f_listItemsText);
//
mrealloc(f_details.paDetails);
mrealloc(f_details);
mrealloc(f_caps);
end;
type
pBoolArray = ^boolArray;
boolArray = array[byte] of MIXERCONTROLDETAILS_BOOLEAN;
pSignedArray = ^signedArray;
signedArray = array[byte] of MIXERCONTROLDETAILS_SIGNED;
pUnsignedArray = ^unsignedArray;
unsignedArray = array[byte] of MIXERCONTROLDETAILS_UNSIGNED;
// -- --
procedure unaMsMixerControl.endUpdate();
begin
dec(f_updateCount);
//
if (f_updateCount < 0) then
f_updateCount := 0;
//
if (1 > f_updateCount) then
setDetails();
end;
// -- --
function unaMsMixerControl.getControlID(): unsigned;
begin
result := f_caps.dwControlID;
end;
// -- --
function unaMsMixerControl.getDetails(): pMixerControlDetails;
var
Z: unsigned;
i: int;
offs: unsigned;
listItem: pMixerControlDetailsListText;
begin
if (
((MIXERCONTROL_CT_CLASS_LIST = controlClass) or
(MIXERCONTROL_CONTROLTYPE_EQUALIZER = controlType) or
(MIXERCONTROL_CONTROLTYPE_MUX = controlType) or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -