📄 mixer.cpp
字号:
//**********************************************************************
//
// Filename: mixer.h
//
// Description:
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to
// use this source code. For a copy of the EULA, please see the
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2005, All Rights Reserved
//
//**********************************************************************
#include "wavecommon.h"
#define ZONE_HWMIXER ZONE_VERBOSE
#define ZONE_VOLUME ZONE_VERBOSE
#define LOGICAL_VOLUME_MAX 0xFFFF
#define LOGICAL_VOLUME_MIN 0
#define LOGICAL_VOLUME_STEPS 16
// only support Mic, LineIn as inputs
#define INPUT_SELECT_COUNT 2
#define DEVICE_NAME L"Cirrus Ep93xx Audio Mixer"
#define DRIVER_VERSION 0x100
#define NELEMS(x) (sizeof(x)/sizeof((x)[0]))
// mixer line ID are 16-bit values formed by concatenating the source and destination line indices
//
#define MXLINEID(dst,src) ((USHORT) ((USHORT)(dst) | (((USHORT) (src)) << 8)))
#define GET_MXLINE_SRC(lineid) ((lineid) >> 8)
#define GET_MXLINE_DST(lineid) ((lineid) & 0xff)
#define GET_MXCONTROL_ID(ctl) ((ctl)-g_controls)
#ifdef DEBUG
// DEBUG-only support for displaying control type codes in readable form
typedef struct
{
DWORD val;
PWSTR str;
} MMSYSCODE;
#define MXCTYPE(typ) {typ, TEXT(#typ)}
MMSYSCODE ctype_table[] =
{
MXCTYPE(MIXERCONTROL_CONTROLTYPE_CUSTOM),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_BASS),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_EQUALIZER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_FADER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_TREBLE),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_VOLUME),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MIXER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MUX),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_SINGLESELECT),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_PEAKMETER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_DECIBELS),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_PERCENT),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_SIGNED),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_UNSIGNED),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_PAN),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_SLIDER),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_BOOLEAN),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_BUTTON),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_LOUDNESS),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MONO),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MUTE),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_ONOFF),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_STEREOENH),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MICROTIME),
MXCTYPE(MIXERCONTROL_CONTROLTYPE_MILLITIME),
};
PWSTR
COMPTYPE(DWORD dwValue)
{ int i;
for (i = 0; i < NELEMS(ctype_table); i++) {
if (ctype_table[i].val == dwValue) {
return ctype_table[i].str;
}
}
return TEXT("<unknown>");
}
#else
#define COMPTYPE(n) TEXT("<>")
#endif
// Destinations:
// LINE_OUT - line out jack
// PCM_IN - input to ADC
// Sources:
// MIC - MIC jack
// LINE_IN - LINE_IN jack
enum {
LINE_OUT = 0x80,
PCM_IN,
LINE_IN,
MIC,
NOLINE = 0xff // doesn't HAVE to be FF, but makes it easier to see
};
const USHORT
g_dst_lines[] =
{
MXLINEID(LINE_OUT,NOLINE),
MXLINEID(PCM_IN,NOLINE)
};
const USHORT
g_PCM_IN_sources[] =
{
MXLINEID(PCM_IN,LINE_IN),
MXLINEID(PCM_IN,MIC),
};
// MXLINEDESC corresponds to MIXERLINE, but is designed to conserve space
typedef struct tagMXLINEDESC const * PMXLINEDESC, MXLINEDESC;
typedef struct tagMXCONTROLDESC const * PMXCONTROLDESC, MXCONTROLDESC;
struct tagMXLINEDESC {
DWORD dwComponentType;
PCWSTR szShortName;
PCWSTR szName;
DWORD ucFlags;
USHORT const * pSources;
USHORT usLineID;
UINT8 ucChannels;
UINT8 ucConnections;
UINT8 ucControls;
DWORD dwTargetType;
UINT8 ucDstIndex;
UINT8 ucSrcIndex;
} ;
// MXCONTROLDESC is driver shorthand for Volume and Mute MIXERCONTROL
struct tagMXCONTROLDESC
{
PWSTR szName;
DWORD dwType;
USHORT usLineID; // line that owns this control
USHORT usPddMsg; // Mixer PDD message to send for this control
};
// mixerline ID
#define _MXLE(id,dst,src,flags,comptype,nch,ncnx,nctrl,sname,lname,target,sarray)\
{comptype,\
TEXT(sname),TEXT(lname),\
flags, \
sarray,\
id,\
nch,ncnx,nctrl,\
target,\
dst,src}
// declare a destination line
#define MXLED(id,dst,flags,comptype,nch,nctrl,sname,lname,target,srcarray,nsrcs)\
_MXLE(MXLINEID(id,NOLINE),dst,NOLINE,flags,comptype,nch,nsrcs,nctrl,sname,lname,target,srcarray)\
// declare a source line
#define MXSLE(id,dst,src,flags,comptype,nch,nctrl,sname,lname,target)\
_MXLE(id,dst,src,flags,comptype,nch,0,nctrl,sname,lname,target,NULL)\
MXLINEDESC
g_mixerline[] =
{
// dst line 0 - speaker out
MXLED(LINE_OUT, 0,
MIXERLINE_LINEF_ACTIVE, // no flags
MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,
2, // stereo
2, // controls: volume + mute
"Volume Control","Volume Control",
MIXERLINE_TARGETTYPE_WAVEOUT,
NULL, 0
),
// dst line 1 - PCM input
MXLED(PCM_IN, 1,
MIXERLINE_LINEF_ACTIVE, // flags
MIXERLINE_COMPONENTTYPE_DST_WAVEIN,
2, // stereo
1, // 1 control (MUX) - the record gain is virtualized across all mux inputs
"Recording Contr","Recording Control",
MIXERLINE_TARGETTYPE_WAVEIN,
g_PCM_IN_sources, NELEMS(g_PCM_IN_sources)
),
// ----------------------
// PCM_IN Sources Lines
// ----------------------
// src line 1 - LINE IN
MXSLE(MXLINEID(PCM_IN, LINE_IN), 1, 1,
MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE, // flags
MIXERLINE_COMPONENTTYPE_SRC_LINE,
2, // stereo
1, // controls: volume, mute
"Line In","Line In",
MIXERLINE_TARGETTYPE_UNDEFINED
),
// src line 2 - Microphone
MXSLE(MXLINEID(PCM_IN, MIC), 1, 2,
MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE, // flags
MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE,
1, // mono
2, // controls: volume, mute
"Microphone","Microphone",
MIXERLINE_TARGETTYPE_WAVEIN
),
};
const int nlines = NELEMS(g_mixerline);
#undef _MXLE
#undef MXLED
#undef MXSLE
#define MXCE(dst,src,nme,type,reg) {TEXT(nme),type,MXLINEID(dst,src),reg}
MXCONTROLDESC
g_controls[] =
{
MXCE(LINE_OUT, NOLINE, "Master Volume", MIXERCONTROL_CONTROLTYPE_VOLUME, WPDMX_MASTER_VOL),
MXCE(LINE_OUT, NOLINE, "Master Mute", MIXERCONTROL_CONTROLTYPE_MUTE, WPDMX_MASTER_MUTE),
MXCE(PCM_IN, NOLINE, "Input Select", MIXERCONTROL_CONTROLTYPE_MUX, WPDMX_INPUT_MUX),
MXCE(PCM_IN, LINE_IN, "Line In Volume", MIXERCONTROL_CONTROLTYPE_VOLUME, WPDMX_LINEIN_VOL),
MXCE(PCM_IN, LINE_IN, "Line In Mute", MIXERCONTROL_CONTROLTYPE_MUTE, WPDMX_LINEIN_MUTE),
MXCE(PCM_IN, MIC, "Mic Volume", MIXERCONTROL_CONTROLTYPE_VOLUME, WPDMX_MIC_VOL),
MXCE(PCM_IN, MIC, "Mic Mute", MIXERCONTROL_CONTROLTYPE_MUTE, WPDMX_MIC_MUTE),
};
const UINT ncontrols = NELEMS(g_controls);
#undef MXCE
PMXLINEDESC
LookupMxLine(USHORT usLineID)
{
// scan for mixer line
int i;
for (i = 0; i < nlines; i++) {
if (g_mixerline[i].usLineID == usLineID) {
return &g_mixerline[i];
}
}
return NULL;
}
int
LookupMxControl (USHORT usLineID, DWORD dwControlType)
{
UINT i;
for (i = 0; i < ncontrols; i++) {
PMXCONTROLDESC pSrcControl = &g_controls[i];
if ( pSrcControl->usLineID == usLineID
&& pSrcControl->dwType == dwControlType) {
break;
}
}
return i;
}
void
CopyMixerControl(PMIXERCONTROL pDst, PMXCONTROLDESC pSrc, DWORD dwIndex)
{
// all of our lines have a volume and a mute.
// in addition, the PCM_IN has a MUX control
// fill in the volume:
pDst->cbStruct = sizeof(MIXERCONTROL);
pDst->dwControlID = dwIndex;
wcscpy(pDst->szName, pSrc->szName);
wcscpy(pDst->szShortName, pSrc->szName);
pDst->dwControlType = pSrc->dwType;
pDst->cMultipleItems = 0;
switch(pSrc->dwType) {
case MIXERCONTROL_CONTROLTYPE_VOLUME:
pDst->fdwControl = 0;
pDst->Metrics.cSteps = LOGICAL_VOLUME_STEPS;
pDst->Bounds.lMaximum = LOGICAL_VOLUME_MAX;
pDst->Bounds.lMinimum = LOGICAL_VOLUME_MIN;
break;
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_MUTE:
pDst->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
pDst->Metrics.cSteps = 0;
pDst->Bounds.lMaximum = 1;
pDst->Bounds.lMinimum = 0;
break;
case MIXERCONTROL_CONTROLTYPE_MUX:
// this better be Record Select...
pDst->cMultipleItems = INPUT_SELECT_COUNT;
pDst->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
pDst->Metrics.cSteps = 2;
pDst->Bounds.lMaximum = 2;
pDst->Bounds.lMinimum = 0;
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("Unexpected control type %08x\r\n"), pSrc->dwType));
ASSERT(0);
}
}
DWORD
MixerDevice::wdev_MXDM_GETDEVCAPS (PMIXERCAPS pCaps, DWORD dwSize)
{
pCaps->wMid = MM_MICROSOFT;
pCaps->wPid = MM_MSFT_WSS_MIXER;
wcscpy(pCaps->szPname, DEVICE_NAME);
pCaps->vDriverVersion = DRIVER_VERSION;
pCaps->cDestinations = NELEMS(g_dst_lines);
pCaps->fdwSupport = 0;
return MMSYSERR_NOERROR;
}
DWORD
MixerDevice::wdev_MXDM_OPEN (PDWORD phMixer, PMIXEROPENDESC pMOD, DWORD dwFlags ,CodecInterface * pAudioDriver)
{
m_pAudioCodec= pAudioDriver;
m_hmx = (DWORD) pMOD->hmx;
if (dwFlags & CALLBACK_FUNCTION) {
m_pfnCallback = (PFNDRIVERCALL) pMOD->dwCallback;
}
else {
m_pfnCallback = NULL;
}
*phMixer = (DWORD) this;
return MMSYSERR_NOERROR;
}
DWORD
MixerDevice::wdev_MXDM_CLOSE (DWORD dwHandle)
{
return MMSYSERR_NOERROR;
}
DWORD
MixerDevice::wdev_MXDM_GETLINEINFO(PMIXERLINE pQuery, DWORD dwFlags)
{
int i;
// pQuery is validated by API - points to accessible, properly sized MIXERLINE structure
// result - assume failure
PMXLINEDESC pFound = NULL;
MMRESULT mmRet = MIXERR_INVALLINE;
USHORT usLineID;
switch (dwFlags & MIXER_GETLINEINFOF_QUERYMASK) {
case MIXER_GETLINEINFOF_DESTINATION:
DEBUGMSG(ZONE_HWMIXER, (TEXT("GetMixerLineInfo DESTINATION %x\r\n"), pQuery->dwDestination));
{
if (pQuery->dwDestination >= NELEMS(g_dst_lines)) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid destination line %d\r\n"), pQuery->dwDestination));
return MIXERR_INVALLINE;
}
usLineID = g_dst_lines[pQuery->dwDestination];
}
break;
case MIXER_GETLINEINFOF_LINEID:
DEBUGMSG(ZONE_HWMIXER, (TEXT("GetMixerLineInfo LINEID %x\r\n"), pQuery->dwLineID));
usLineID = (USHORT) pQuery->dwLineID;
break;
case MIXER_GETLINEINFOF_SOURCE:
DEBUGMSG(ZONE_HWMIXER, (TEXT("GetMixerLineInfo SOURCE %x %x\r\n"), pQuery->dwDestination, pQuery->dwSource));
{
PMXLINEDESC pLine;
// look up the destination line, then index into it's source table
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -