⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unamsmixer.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 4 页
字号:

(*
	----------------------------------------------

	  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 + -