417 lines
15 KiB
C#
417 lines
15 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using System.Runtime.InteropServices;
|
||
|
||
namespace ryCommon
|
||
{
|
||
/// <summary>
|
||
/// SOURCE CODE FROM THE WEBSITE.
|
||
/// LAST UPDATE:WWW.VJSDN.COMÒ×ѧÂÛ̳,2009/08/03 by Jonny Sun
|
||
/// </summary>
|
||
class SoundControl_XP
|
||
{
|
||
#region declarations
|
||
const int MAXPNAMELEN = 32;
|
||
const int MIXER_SHORT_NAME_CHARS = 16;
|
||
const int MIXER_LONG_NAME_CHARS = 64;
|
||
|
||
[Flags]
|
||
enum MIXERLINE_LINEF : uint
|
||
{
|
||
ACTIVE = 0x00000001,
|
||
DISCONNECTED = 0x00008000,
|
||
SOURCE = 0x80000000
|
||
}
|
||
|
||
[Flags]
|
||
enum MIXER : uint
|
||
{
|
||
GETLINEINFOF_DESTINATION = 0x00000000,
|
||
GETLINEINFOF_SOURCE = 0x00000001,
|
||
GETLINEINFOF_LINEID = 0x00000002,
|
||
GETLINEINFOF_COMPONENTTYPE = 0x00000003,
|
||
GETLINEINFOF_TARGETTYPE = 0x00000004,
|
||
GETLINEINFOF_QUERYMASK = 0x0000000F,
|
||
|
||
GETLINECONTROLSF_ALL = 0x00000000,
|
||
GETLINECONTROLSF_ONEBYID = 0x00000001,
|
||
GETLINECONTROLSF_ONEBYTYPE = 0x00000002,
|
||
GETLINECONTROLSF_QUERYMASK = 0x0000000F,
|
||
|
||
GETCONTROLDETAILSF_VALUE = 0x00000000,
|
||
GETCONTROLDETAILSF_LISTTEXT = 0x00000001,
|
||
GETCONTROLDETAILSF_QUERYMASK = 0x0000000F,
|
||
|
||
OBJECTF_MIXER = 0x00000000,
|
||
OBJECTF_WAVEOUT = 0x10000000,
|
||
OBJECTF_WAVEIN = 0x20000000,
|
||
OBJECTF_MIDIOUT = 0x30000000,
|
||
OBJECTF_MIDIIN = 0x40000000,
|
||
OBJECTF_AUX = 0x50000000,
|
||
OBJECTF_HANDLE = 0x80000000,
|
||
OBJECTF_HMIXER = OBJECTF_HANDLE | OBJECTF_MIXER,
|
||
OBJECTF_HWAVEOUT = OBJECTF_HANDLE | OBJECTF_WAVEOUT,
|
||
OBJECTF_HWAVEIN = OBJECTF_HANDLE | OBJECTF_WAVEIN,
|
||
OBJECTF_HMIDIOUT = OBJECTF_HANDLE | OBJECTF_MIDIOUT,
|
||
OBJECTF_HMIDIIN = OBJECTF_HANDLE | OBJECTF_MIDIIN
|
||
}
|
||
|
||
[Flags]
|
||
enum MIXERCONTROL_CT : uint
|
||
{
|
||
CLASS_MASK = 0xF0000000,
|
||
CLASS_CUSTOM = 0x00000000,
|
||
CLASS_METER = 0x10000000,
|
||
CLASS_SWITCH = 0x20000000,
|
||
CLASS_NUMBER = 0x30000000,
|
||
CLASS_SLIDER = 0x40000000,
|
||
CLASS_FADER = 0x50000000,
|
||
CLASS_TIME = 0x60000000,
|
||
CLASS_LIST = 0x70000000,
|
||
|
||
SUBCLASS_MASK = 0x0F000000,
|
||
|
||
SC_SWITCH_BOOLEAN = 0x00000000,
|
||
SC_SWITCH_BUTTON = 0x01000000,
|
||
|
||
SC_METER_POLLED = 0x00000000,
|
||
|
||
SC_TIME_MICROSECS = 0x00000000,
|
||
SC_TIME_MILLISECS = 0x01000000,
|
||
|
||
SC_LIST_SINGLE = 0x00000000,
|
||
SC_LIST_MULTIPLE = 0x01000000,
|
||
|
||
UNITS_MASK = 0x00FF0000,
|
||
UNITS_CUSTOM = 0x00000000,
|
||
UNITS_BOOLEAN = 0x00010000,
|
||
UNITS_SIGNED = 0x00020000,
|
||
UNITS_UNSIGNED = 0x00030000,
|
||
UNITS_DECIBELS = 0x00040000, /* in 10ths */
|
||
UNITS_PERCENT = 0x00050000, /* in 10ths */
|
||
}
|
||
|
||
[Flags]
|
||
enum MIXERCONTROL_CONTROLTYPE : uint
|
||
{
|
||
CUSTOM = MIXERCONTROL_CT.CLASS_CUSTOM | MIXERCONTROL_CT.UNITS_CUSTOM,
|
||
BOOLEANMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_BOOLEAN,
|
||
SIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_SIGNED,
|
||
PEAKMETER = SIGNEDMETER + 1,
|
||
UNSIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_UNSIGNED,
|
||
BOOLEAN = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BOOLEAN | MIXERCONTROL_CT.UNITS_BOOLEAN,
|
||
ONOFF = BOOLEAN + 1,
|
||
MUTE = BOOLEAN + 2,
|
||
MONO = BOOLEAN + 3,
|
||
LOUDNESS = BOOLEAN + 4,
|
||
STEREOENH = BOOLEAN + 5,
|
||
BASS_BOOST = BOOLEAN + 0x00002277,
|
||
BUTTON = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BUTTON | MIXERCONTROL_CT.UNITS_BOOLEAN,
|
||
DECIBELS = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_DECIBELS,
|
||
SIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_SIGNED,
|
||
UNSIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_UNSIGNED,
|
||
PERCENT = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_PERCENT,
|
||
SLIDER = MIXERCONTROL_CT.CLASS_SLIDER | MIXERCONTROL_CT.UNITS_SIGNED,
|
||
PAN = SLIDER + 1,
|
||
QSOUNDPAN = SLIDER + 2,
|
||
FADER = MIXERCONTROL_CT.CLASS_FADER | MIXERCONTROL_CT.UNITS_UNSIGNED,
|
||
VOLUME = FADER + 1,
|
||
BASS = FADER + 2,
|
||
TREBLE = FADER + 3,
|
||
EQUALIZER = FADER + 4,
|
||
SINGLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_SINGLE | MIXERCONTROL_CT.UNITS_BOOLEAN,
|
||
MUX = SINGLESELECT + 1,
|
||
MULTIPLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_MULTIPLE | MIXERCONTROL_CT.UNITS_BOOLEAN,
|
||
MIXER = MULTIPLESELECT + 1,
|
||
MICROTIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MICROSECS | MIXERCONTROL_CT.UNITS_UNSIGNED,
|
||
MILLITIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MILLISECS | MIXERCONTROL_CT.UNITS_UNSIGNED
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||
struct MIXERLINE
|
||
{
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||
public struct TargetInfo
|
||
{
|
||
public uint dwType;
|
||
public uint dwDeviceID;
|
||
public ushort wMid;
|
||
public ushort wPid;
|
||
public uint vDriverVersion;
|
||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN)]
|
||
public string szPname;
|
||
}
|
||
|
||
public uint cbStruct;
|
||
public uint dwDestination;
|
||
public uint dwSource;
|
||
public uint dwLineID;
|
||
public MIXERLINE_LINEF fdwLine;
|
||
public uint dwUser;
|
||
public uint dwComponentType;
|
||
public uint cChannels;
|
||
public uint cConnection;
|
||
public uint cControls;
|
||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
|
||
public string szShortName;
|
||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
|
||
public string szName;
|
||
public TargetInfo Target;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||
struct MIXERCONTROL
|
||
{
|
||
[StructLayout(LayoutKind.Explicit)]
|
||
public struct BoundsInfo
|
||
{
|
||
[FieldOffset(0)]
|
||
public int lMinimum;
|
||
[FieldOffset(4)]
|
||
public int lMaximum;
|
||
[FieldOffset(0)]
|
||
public uint dwMinimum;
|
||
[FieldOffset(4)]
|
||
public uint dwMaximum;
|
||
[FieldOffset(8), MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||
public uint[] dwReserved;
|
||
}
|
||
[StructLayout(LayoutKind.Explicit)]
|
||
public struct MetricsInfo
|
||
{
|
||
[FieldOffset(0)]
|
||
public uint cSteps;
|
||
[FieldOffset(0)]
|
||
public uint cbCustomData;
|
||
[FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||
public uint[] dwReserved;
|
||
}
|
||
|
||
public uint cbStruct;
|
||
public uint dwControlID;
|
||
public MIXERCONTROL_CONTROLTYPE dwControlType;
|
||
public uint fdwControl;
|
||
public uint cMultipleItems;
|
||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
|
||
public string szShortName;
|
||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
|
||
public string szName;
|
||
public BoundsInfo Bounds;
|
||
public MetricsInfo Metrics;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Explicit)]
|
||
struct MIXERLINECONTROLS
|
||
{
|
||
[FieldOffset(0)]
|
||
public uint cbStruct;
|
||
[FieldOffset(4)]
|
||
public uint dwLineID;
|
||
[FieldOffset(8)]
|
||
public uint dwControlID;
|
||
[FieldOffset(8)] // not a typo! overlaps previous field
|
||
public uint dwControlType;
|
||
[FieldOffset(12)]
|
||
public uint cControls;
|
||
[FieldOffset(16)]
|
||
public uint cbmxctrl;
|
||
[FieldOffset(20)]
|
||
public IntPtr pamxctrl;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Explicit)]
|
||
struct MIXERCONTROLDETAILS
|
||
{
|
||
[FieldOffset(0)]
|
||
public uint cbStruct;
|
||
[FieldOffset(4)]
|
||
public uint dwControlID;
|
||
[FieldOffset(8)]
|
||
public uint cChannels;
|
||
[FieldOffset(12)]
|
||
public IntPtr hwndOwner;
|
||
[FieldOffset(12)] // not a typo!
|
||
public uint cMultipleItems;
|
||
[FieldOffset(16)]
|
||
public uint cbDetails;
|
||
[FieldOffset(20)]
|
||
public IntPtr paDetails;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential)]
|
||
struct VOLUME
|
||
{
|
||
public int left;
|
||
public int right;
|
||
}
|
||
|
||
public struct MixerInfo
|
||
{
|
||
public uint volumeCtl;
|
||
public uint muteCtl;
|
||
public int minVolume;
|
||
public int maxVolume;
|
||
}
|
||
|
||
[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
|
||
static extern uint mixerGetLineInfo(IntPtr hmxobj, ref MIXERLINE pmxl, MIXER flags);
|
||
|
||
[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
|
||
static extern uint mixerGetLineControls(IntPtr hmxobj, ref MIXERLINECONTROLS pmxlc, MIXER flags);
|
||
|
||
[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
|
||
static extern uint mixerGetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags);
|
||
|
||
[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
|
||
static extern uint mixerSetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags);
|
||
|
||
#endregion declarations
|
||
|
||
#region private methods
|
||
|
||
public static MixerInfo GetMixerControls()
|
||
{
|
||
MIXERLINE mxl = new MIXERLINE();
|
||
MIXERLINECONTROLS mlc = new MIXERLINECONTROLS();
|
||
mxl.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINE));
|
||
mlc.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINECONTROLS));
|
||
|
||
mixerGetLineInfo(IntPtr.Zero, ref mxl, MIXER.OBJECTF_MIXER | MIXER.GETLINEINFOF_DESTINATION);
|
||
|
||
mlc.dwLineID = mxl.dwLineID;
|
||
mlc.cControls = mxl.cControls;
|
||
mlc.cbmxctrl = (uint)Marshal.SizeOf(typeof(MIXERCONTROL));
|
||
mlc.pamxctrl = Marshal.AllocHGlobal((int)(mlc.cbmxctrl * mlc.cControls));
|
||
|
||
mixerGetLineControls(IntPtr.Zero, ref mlc, MIXER.OBJECTF_MIXER | MIXER.GETLINECONTROLSF_ALL);
|
||
|
||
MixerInfo rtn = new MixerInfo();
|
||
|
||
for (int i = 0; i < mlc.cControls; i++)
|
||
{
|
||
MIXERCONTROL mxc = (MIXERCONTROL)Marshal.PtrToStructure((IntPtr)((int)mlc.pamxctrl + (int)mlc.cbmxctrl * i), typeof(MIXERCONTROL));
|
||
switch (mxc.dwControlType)
|
||
{
|
||
case MIXERCONTROL_CONTROLTYPE.VOLUME:
|
||
rtn.volumeCtl = mxc.dwControlID;
|
||
rtn.minVolume = mxc.Bounds.lMinimum;
|
||
rtn.maxVolume = mxc.Bounds.lMaximum;
|
||
break;
|
||
case MIXERCONTROL_CONTROLTYPE.MUTE:
|
||
rtn.muteCtl = mxc.dwControlID;
|
||
break;
|
||
}
|
||
}
|
||
|
||
Marshal.FreeHGlobal(mlc.pamxctrl);
|
||
|
||
return rtn;
|
||
}
|
||
static VOLUME GetVolume(MixerInfo mi)
|
||
{
|
||
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
|
||
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
|
||
mcd.dwControlID = mi.volumeCtl;
|
||
mcd.cMultipleItems = 0;
|
||
mcd.cChannels = 2;
|
||
mcd.cbDetails = (uint)Marshal.SizeOf(typeof(VOLUME));
|
||
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);
|
||
|
||
mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);
|
||
|
||
VOLUME rtn = (VOLUME)Marshal.PtrToStructure(mcd.paDetails, typeof(VOLUME));
|
||
|
||
Marshal.FreeHGlobal(mcd.paDetails);
|
||
|
||
return rtn;
|
||
}
|
||
public static bool IsMuted(MixerInfo mi)
|
||
{
|
||
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
|
||
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
|
||
mcd.dwControlID = mi.muteCtl;
|
||
mcd.cMultipleItems = 0;
|
||
mcd.cChannels = 1;
|
||
mcd.cbDetails = 4;
|
||
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);
|
||
|
||
mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);
|
||
|
||
int rtn = Marshal.ReadInt32(mcd.paDetails);
|
||
|
||
Marshal.FreeHGlobal(mcd.paDetails);
|
||
|
||
return rtn != 0;
|
||
}
|
||
|
||
static void MuteIt(MixerInfo mi, bool left, bool right)
|
||
{
|
||
VOLUME volume = GetVolume(mi);
|
||
if (!left && !right) // mute off
|
||
{
|
||
volume.left = 65530;
|
||
volume.right = 65530;
|
||
}
|
||
else if (left) //mute left channel
|
||
{
|
||
volume.left = 0;
|
||
volume.right = 65530;
|
||
}
|
||
else if (right) // mute right channel
|
||
{
|
||
volume.left = 65530;
|
||
volume.right = 0;
|
||
}
|
||
|
||
SetVolume(mi, volume);
|
||
}
|
||
|
||
static void SetVolume(MixerInfo mi, VOLUME volume)
|
||
{
|
||
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
|
||
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
|
||
mcd.dwControlID = mi.volumeCtl;
|
||
mcd.cMultipleItems = 0;
|
||
mcd.cChannels = 2;
|
||
mcd.cbDetails = (uint)Marshal.SizeOf(typeof(VOLUME));
|
||
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);
|
||
|
||
Marshal.StructureToPtr(volume, mcd.paDetails, false);
|
||
|
||
mixerSetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);
|
||
|
||
Marshal.FreeHGlobal(mcd.paDetails);
|
||
}
|
||
|
||
#endregion private methods
|
||
|
||
#region public methods
|
||
|
||
/// <summary>
|
||
/// Mutes the left hand channel and transfers audio fully to the right
|
||
/// </summary>
|
||
public void MuteLeftChannel()
|
||
{
|
||
MixerInfo mi = GetMixerControls();
|
||
MuteIt(mi, false, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Mutes the right hand channel and transfers audio fully to the left
|
||
/// </summary>
|
||
public void MuteRightChannel()
|
||
{
|
||
MixerInfo mi = GetMixerControls();
|
||
MuteIt(mi, true, false);
|
||
}
|
||
|
||
public void MuteOff()
|
||
{
|
||
MixerInfo mi = GetMixerControls();
|
||
MuteIt(mi, false, false);
|
||
}
|
||
|
||
#endregion public methods
|
||
}
|
||
} |