Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2072 lines
62 KiB

/*****************************************************************************
*
* Component: sndvol32.exe
* File: mixer.c
* Purpose: mixer api specific implementations
*
* Copyright (C) Microsoft Corporation 1985-1995. All rights reserved.
*
*****************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <commctrl.h>
#include <math.h>
#include "volumei.h"
#include "volids.h"
#include "vu.h"
extern void Mixer_Advanced(PMIXUIDIALOG pmxud, DWORD dwLineID, LPTSTR szName);
/*****************************************************************************
*
* INIT SPECIFIC CODE
*
*****************************************************************************/
/*
* Mixer_GetNumDevs
*
* */
int Mixer_GetNumDevs()
{
return mixerGetNumDevs();
}
/*
* Mixer_GetDeviceName()
*
* */
BOOL Mixer_GetDeviceName(
PMIXUIDIALOG pmxud)
{
MIXERCAPS mxcaps;
MMRESULT mmr;
mmr = mixerGetDevCaps( pmxud->mxid, &mxcaps, sizeof(mxcaps));
if (mmr != MMSYSERR_NOERROR)
return FALSE;
lstrcpy(pmxud->szMixer, mxcaps.szPname);
return TRUE;
}
/*
* Mixer_SetLines
*
* Locate mixer/mux relationships. Fix up uninitialized volume description
* information.
*
* */
static void Mixer_SetLines(
HMIXEROBJ hmx,
PVOLCTRLDESC pvcd,
UINT cPvcd)
{
LPMIXERCONTROLDETAILS_LISTTEXT pmcd_lt;
PMIXERCONTROLDETAILS_BOOLEAN pmcd_b;
MIXERCONTROLDETAILS mxd;
MMRESULT mmr;
UINT i,j;
MIXERLINE mxl;
DWORD dwDst;
//
// Another stupid test for stupid drivers. Some drivers (Mediavision)
// don't return the proper destination / source index in the
// mixerGetLineInfo call. Tag a workaround.
//
mxl.cbStruct = sizeof(mxl);
mxl.dwLineID = pvcd[0].dwLineID;
mmr = mixerGetLineInfo(hmx
, &mxl
, MIXER_GETLINEINFOF_LINEID);
if (mmr == MMSYSERR_NOERROR)
{
dwDst = mxl.dwDestination;
for (i = 1; i < cPvcd; i++)
{
mxl.cbStruct = sizeof(mxl);
mxl.dwLineID = pvcd[i].dwLineID;
mmr = mixerGetLineInfo(hmx
, &mxl
, MIXER_GETLINEINFOF_LINEID);
if (mmr != MMSYSERR_NOERROR)
{
pvcd[0].dwSupport |= VCD_SUPPORTF_BADDRIVER;
break;
}
if (mxl.dwDestination != dwDst)
{
pvcd[0].dwSupport |= VCD_SUPPORTF_BADDRIVER;
break;
}
}
}
//
// for the first pvcd (destination), propogate the mixer/mux control
// id's to those controls that are part of the list. 0 out the rest.
// The UI can just do a mixerXXXControlDetails on the control ID to
// locate the state information
//
if (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MIXER)
{
pmcd_lt = GlobalAllocPtr(GHND, sizeof(MIXERCONTROLDETAILS_LISTTEXT)
* pvcd->cMixer);
pmcd_b = GlobalAllocPtr(GHND, sizeof(MIXERCONTROLDETAILS_BOOLEAN)
* pvcd->cMixer);
if (!pmcd_lt || !pmcd_b)
return;
mxd.cbStruct = sizeof(mxd);
mxd.dwControlID = pvcd->dwMixerID;
mxd.cChannels = 1;
mxd.cMultipleItems = pvcd->cMixer;
mxd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
mxd.paDetails = pmcd_lt;
mmr = mixerGetControlDetails(hmx
, &mxd
, MIXER_GETCONTROLDETAILSF_LISTTEXT);
if (mmr == MMSYSERR_NOERROR)
{
//
// iterate over all source lines s.t. dwMixerID points to the
// correct control id on the destination and iMixer is the
// correct index into the value list
//
pvcd[0].amcd_bMixer = pmcd_b;
for (i = 1; i < cPvcd; i++)
{
for (j = 0; j < pvcd->cMixer; j++)
{
if (!lstrcmp(pmcd_lt[j].szName,pvcd[i].szName))
{
pvcd[i].dwMixerID = pvcd->dwMixerID;
pvcd[i].iMixer = j;
pvcd[i].cMixer = pvcd->cMixer;
pvcd[i].dwSupport |= VCD_SUPPORTF_MIXER_MIXER;
pvcd[i].dwVisible |= VCD_VISIBLEF_MIXER_MIXER;
pvcd[i].dwVisible &= ~VCD_VISIBLEF_MIXER_MUTE;
pvcd[i].amcd_bMixer = pmcd_b;
}
}
}
}
GlobalFreePtr(pmcd_lt);
}
if (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUX)
{
pmcd_lt = GlobalAllocPtr(GHND, sizeof(MIXERCONTROLDETAILS_LISTTEXT)
* pvcd->cMux);
pmcd_b = GlobalAllocPtr(GHND, sizeof(MIXERCONTROLDETAILS_BOOLEAN)
* pvcd->cMux);
if (!pmcd_lt || !pmcd_b)
return;
mxd.cbStruct = sizeof(mxd);
mxd.dwControlID = pvcd->dwMuxID;
mxd.cChannels = 1;
mxd.cMultipleItems = pvcd->cMux;
mxd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
mxd.paDetails = pmcd_lt;
mmr = mixerGetControlDetails(hmx
, &mxd
, MIXER_GETCONTROLDETAILSF_LISTTEXT);
if (mmr == MMSYSERR_NOERROR)
{
//
// iterate over all source lines s.t. dwMuxID points to the
// correct control id on the destination and iMux is the
// correct index into the value list
//
pvcd[0].amcd_bMux = pmcd_b;
for (i = 1; i < cPvcd; i++)
{
for (j = 0; j < pvcd->cMux; j++)
{
if (!lstrcmp(pmcd_lt[j].szName,pvcd[i].szName))
{
pvcd[i].dwMuxID = pvcd->dwMuxID;
pvcd[i].iMux = j;
pvcd[i].cMux = pvcd->cMux;
pvcd[i].dwSupport |= VCD_SUPPORTF_MIXER_MUX;
pvcd[i].dwVisible |= VCD_VISIBLEF_MIXER_MUX;
pvcd[i].dwVisible &= ~VCD_VISIBLEF_MIXER_MUTE;
pvcd[i].amcd_bMux = pmcd_b;
}
}
}
}
GlobalFreePtr(pmcd_lt);
}
}
/*
* Mixer_CheckdDriver
*
* Consistency check for bad mixer drivers.
* */
static DWORD Mixer_CheckBadDriver(
HMIXEROBJ hmx,
PMIXERLINECONTROLS pmxlc,
PMIXERCONTROL pmxc,
DWORD dwControlID,
DWORD dwLineID)
{
MMRESULT mmr;
pmxlc->cbStruct = sizeof(MIXERLINECONTROLS);
pmxlc->dwControlID = dwControlID;
pmxlc->cControls = 1;
pmxlc->cbmxctrl = sizeof(MIXERCONTROL);
pmxlc->pamxctrl = pmxc;
mmr = mixerGetLineControls(hmx
, pmxlc
, MIXER_GETLINECONTROLSF_ONEBYID);
if (mmr != MMSYSERR_NOERROR)
return VCD_SUPPORTF_BADDRIVER;
if (pmxlc->dwLineID != dwLineID)
return VCD_SUPPORTF_BADDRIVER;
return 0L;
}
/*
* Mixer_InitLineControls
*
* Initialize the mixer api specific part of the volume control description
* mark hidden lines.
* */
static void Mixer_InitLineControls(
HMIXEROBJ hmx,
PVOLCTRLDESC pvcd,
DWORD dwLineID)
{
MIXERLINECONTROLS mxlc;
MIXERCONTROL mxc;
MMRESULT mmr;
int iType;
const DWORD dwAdvTypes[] = {
MIXERCONTROL_CONTROLTYPE_BOOLEAN,
MIXERCONTROL_CONTROLTYPE_ONOFF,
MIXERCONTROL_CONTROLTYPE_MONO,
MIXERCONTROL_CONTROLTYPE_LOUDNESS,
MIXERCONTROL_CONTROLTYPE_STEREOENH,
MIXERCONTROL_CONTROLTYPE_BASS,
MIXERCONTROL_CONTROLTYPE_TREBLE
};
pvcd->dwLineID = dwLineID;
pvcd->dwMeterID = 0;
pvcd->dwVolumeID = 0;
pvcd->dwMuteID = 0;
pvcd->dwMixerID = 0;
pvcd->dwMuxID = 0;
//
// advanced controls
//
for (iType = 0;
iType < SIZEOF(dwAdvTypes);
iType++)
{
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = dwAdvTypes[iType];
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_ADVANCED;
break;
}
}
//
// stock controls
//
//
// peakmeter
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwMeterID = mxc.dwControlID;
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_METER;
pvcd->dwSupport |= Mixer_CheckBadDriver(hmx
, &mxlc
, &mxc
, mxc.dwControlID
, dwLineID);
}
//
// mute
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwMuteID = mxc.dwControlID;
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_MUTE;
pvcd->dwVisible |= VCD_VISIBLEF_MIXER_MUTE;
pvcd->dwSupport |= Mixer_CheckBadDriver(hmx
, &mxlc
, &mxc
, mxc.dwControlID
, dwLineID);
}
//
// volume
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwVolumeID = mxc.dwControlID;
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_VOLUME;
pvcd->dwSupport |= Mixer_CheckBadDriver(hmx
, &mxlc
, &mxc
, mxc.dwControlID
, dwLineID);
}
//
// mixer
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwMixerID = mxc.dwControlID;
pvcd->cMixer = mxc.cMultipleItems;
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_MIXER;
pvcd->dwSupport |= Mixer_CheckBadDriver(hmx
, &mxlc
, &mxc
, mxc.dwControlID
, dwLineID);
}
//
// mux
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = dwLineID;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls(hmx
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->dwMuxID = mxc.dwControlID;
pvcd->cMux = mxc.cMultipleItems;
pvcd->dwSupport |= VCD_SUPPORTF_MIXER_MUX;
pvcd->dwSupport |= Mixer_CheckBadDriver(hmx
, &mxlc
, &mxc
, mxc.dwControlID
, dwLineID);
}
if (!(pvcd->dwSupport & ( VCD_SUPPORTF_MIXER_MUTE
| VCD_SUPPORTF_MIXER_METER
| VCD_SUPPORTF_MIXER_VOLUME)))
{
//
// make it invisible in the UI.
//
pvcd->dwSupport |= VCD_SUPPORTF_HIDDEN;
}
else
{
//
// Visible, and not hidden
//
pvcd->dwSupport |= VCD_SUPPORTF_VISIBLE;
}
}
/*
* Mixer_CreateVolumeDescription
*
* */
PVOLCTRLDESC Mixer_CreateVolumeDescription(
HMIXEROBJ hmx,
int iDest,
DWORD* pcvd )
{
MMRESULT mmr;
PVOLCTRLDESC pvcdPrev = NULL, pvcd = NULL;
MIXERLINE mlDst;
DWORD cLines = 0;
DWORD dwSupport = 0L;
UINT iSrc;
ZeroMemory(&mlDst, sizeof(mlDst));
mlDst.cbStruct = sizeof(mlDst);
mlDst.dwDestination = iDest;
mmr = mixerGetLineInfo(hmx
, &mlDst
, MIXER_GETLINEINFOF_DESTINATION);
if (mmr == MMSYSERR_NOERROR)
{
if (mlDst.cChannels == 1L)
dwSupport |= VCD_SUPPORTF_MONO;
if (mlDst.fdwLine & MIXERLINE_LINEF_DISCONNECTED)
dwSupport |= VCD_SUPPORTF_DISABLED;
//
// a default type
//
dwSupport |= VCD_SUPPORTF_DEFAULT;
}
else
{
//
// we need to add it anyway s.t. a UI comes up
//
dwSupport = VCD_SUPPORTF_DISABLED;
}
pvcd = PVCD_AddLine(NULL
, iDest
, VCD_TYPE_MIXER
, mlDst.szShortName
, mlDst.szName
, dwSupport
, &cLines );
if (!pvcd)
return NULL;
Mixer_InitLineControls( hmx, pvcd, mlDst.dwLineID );
pvcdPrev = pvcd;
for (iSrc = 0; iSrc < mlDst.cConnections; iSrc++)
{
MIXERLINE mlSrc;
mlSrc.cbStruct = sizeof(mlSrc);
mlSrc.dwDestination = iDest;
mlSrc.dwSource = iSrc;
mmr = mixerGetLineInfo(hmx
, &mlSrc
, MIXER_GETLINEINFOF_SOURCE);
dwSupport = 0L;
if (mmr == MMSYSERR_NOERROR)
{
if (mlSrc.cChannels == 1L)
{
dwSupport |= VCD_SUPPORTF_MONO;
}
if (mlSrc.fdwLine & MIXERLINE_LINEF_DISCONNECTED)
dwSupport |= VCD_SUPPORTF_DISABLED;
//
// Mark these types as "default" just to lessen the shock on
// some advanced sound cards.
//
if (mlDst.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
|| mlDst.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES)
{
switch (mlSrc.dwComponentType)
{
case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
case MIXERLINE_COMPONENTTYPE_SRC_LINE:
dwSupport |= VCD_SUPPORTF_DEFAULT;
break;
}
}
else if (mlDst.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN
|| mlDst.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_VOICEIN)
{
switch (mlSrc.dwComponentType)
{
case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
case MIXERLINE_COMPONENTTYPE_SRC_LINE:
dwSupport |= VCD_SUPPORTF_DEFAULT;
break;
}
}
}
else
{
//
// we need to add it anyway s.t. lookups aren't under counted
//
dwSupport = VCD_SUPPORTF_DISABLED;
}
pvcd = PVCD_AddLine(pvcdPrev
, iDest
, VCD_TYPE_MIXER
, mlSrc.szShortName
, mlSrc.szName
, dwSupport
, &cLines );
if (pvcd)
{
Mixer_InitLineControls( hmx, &pvcd[cLines-1], mlSrc.dwLineID );
pvcdPrev = pvcd;
}
}
//
// Fixup dependencies
//
Mixer_SetLines(hmx, pvcdPrev, cLines);
*pcvd = cLines;
return pvcdPrev;
}
/*
* Mixer_CleanupVolumeDescription
*
* */
void Mixer_CleanupVolumeDescription(
PVOLCTRLDESC avcd,
DWORD cvcd)
{
if (cvcd == 0)
return;
if (avcd[0].dwSupport & VCD_SUPPORTF_MIXER_MIXER)
{
if (avcd[0].amcd_bMixer)
GlobalFreePtr(avcd[0].amcd_bMixer);
}
if (avcd[0].dwSupport & VCD_SUPPORTF_MIXER_MUX)
{
if (avcd[0].amcd_bMux)
GlobalFreePtr(avcd[0].amcd_bMux);
}
}
/*****************************************************************************
*
* ACTIVE GET/SET CODE
*
*****************************************************************************/
/*
* Mixer_GetMixerVolume
*
* */
static MMRESULT Mixer_GetMixerVolume(
HMIXEROBJ hmx,
PMIXERCONTROLDETAILS pmxcd,
DWORD * adwVolume,
BOOL fMono)
{
MMRESULT mmr;
pmxcd->cChannels = fMono?1:2;
pmxcd->cMultipleItems = 0;
pmxcd->cbDetails = sizeof(DWORD);
pmxcd->paDetails = (LPVOID)adwVolume;
mmr = mixerGetControlDetails(hmx
, pmxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR && fMono)
adwVolume[1] = adwVolume[0];
return mmr;
}
static MMRESULT Mixer_Mute(
HMIXEROBJ hmx,
PVOLCTRLDESC pvcd,
PMIXERCONTROLDETAILS pmxcd,
DWORD fMute)
{
pmxcd->cbStruct = sizeof(*pmxcd);
pmxcd->dwControlID = pvcd->dwMuteID ;
pmxcd->cChannels = 1;
pmxcd->cMultipleItems = 0;
pmxcd->cbDetails = sizeof(DWORD);
pmxcd->paDetails = (LPVOID)&fMute;
return mixerSetControlDetails(hmx
, pmxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
}
/*
* Mixer_GetControl
*
* Change a UI control in response to a device or initialization event
*
* */
#define VOLUME_MIN 0L
#define VOLUME_MAX 65535L
void Mixer_GetControl(
PMIXUIDIALOG pmxud,
HWND hctl,
int imxul,
int itype)
{
PMIXUILINE pmxul = &pmxud->amxul[imxul];
PVOLCTRLDESC pvcd = pmxul->pvcd;
DWORD dwID = 0L;
BOOL fSet = FALSE;
switch (itype)
{
case MIXUI_VUMETER:
fSet = (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_METER);
if (fSet)
dwID = pmxul->pvcd->dwMeterID;
break;
case MIXUI_SWITCH:
fSet = (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE)
&& (pmxul->pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUTE);
if (fSet)
{
dwID = pmxul->pvcd->dwMuteID;
break;
}
fSet = (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUX)
&& (pmxul->pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUX);
if (fSet)
{
dwID = pmxul->pvcd->dwMuxID;
break;
}
fSet = (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_MIXER)
&& (pmxul->pvcd->dwVisible & VCD_VISIBLEF_MIXER_MIXER);
if (fSet)
{
dwID = pmxul->pvcd->dwMixerID;
break;
}
break;
case MIXUI_VOLUME:
case MIXUI_BALANCE:
fSet = (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_VOLUME);
if (fSet)
dwID = pmxul->pvcd->dwVolumeID;
break;
default:
return;
}
if (fSet)
Mixer_GetControlFromID(pmxud, dwID);
}
/*
* Mixer_GetControlFromID
*
* */
void Mixer_GetControlFromID(
PMIXUIDIALOG pmxud,
DWORD dwControlID)
{
MIXERLINE mxl;
MIXERLINECONTROLS mxlc;
MIXERCONTROL mxc;
MIXERCONTROLDETAILS mxcd;
PMIXUILINE pmxul;
PMIXUICTRL pmxuc;
PVOLCTRLDESC pvcd;
DWORD ivcd;
BOOL fBarf = FALSE;
MMRESULT mmr;
//
// Retrieve the control information
//
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwControlID = dwControlID;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(mxc);
mxlc.pamxctrl = &mxc;
mmr = mixerGetLineControls((HMIXEROBJ)(pmxud->hmx)
, &mxlc
, MIXER_GETLINECONTROLSF_ONEBYID);
if (mmr != MMSYSERR_NOERROR)
return;
if (!(pmxud->dwFlags & MXUD_FLAGSF_BADDRIVER))
{
//
// The *correct* code for this lookup using the mixer API.
//
// Is this our current destination line?
//
mxl.cbStruct = sizeof(mxl);
mxl.dwLineID = mxlc.dwLineID;
mmr = mixerGetLineInfo((HMIXEROBJ)(pmxud->hmx)
, &mxl
, MIXER_GETLINEINFOF_LINEID);
if (mmr != MMSYSERR_NOERROR)
return;
if (mxl.dwDestination != pmxud->iDest)
return;
//
// Is this a source line or a destination line?
//
ivcd = (mxl.fdwLine & MIXERLINE_LINEF_SOURCE)? 1 + mxl.dwSource : 0;
pvcd = &pmxud->avcd[ivcd];
//
// a bad driver was detected!
//
if (pvcd->dwLineID != mxlc.dwLineID)
{
pmxud->dwFlags |= MXUD_FLAGSF_BADDRIVER;
}
}
if (pmxud->dwFlags & MXUD_FLAGSF_BADDRIVER)
{
PVOLCTRLDESC pvcdTmp;
//
// take evasive action if this was a bad driver by doing a brute force
// search.
//
pvcd = NULL;
for (ivcd = 0; ivcd < pmxud->cvcd; ivcd ++)
{
pvcdTmp = &pmxud->avcd[ivcd];
if ( ( (pvcdTmp->dwSupport & VCD_SUPPORTF_MIXER_VOLUME)
&& pvcdTmp->dwVolumeID == dwControlID )
|| ( (pvcdTmp->dwSupport & VCD_SUPPORTF_MIXER_MUTE)
&& pvcdTmp->dwMuteID == dwControlID )
|| ( (pvcdTmp->dwSupport & VCD_SUPPORTF_MIXER_MIXER)
&& pvcdTmp->dwMixerID == dwControlID )
|| ( (pvcdTmp->dwSupport & VCD_SUPPORTF_MIXER_MUX)
&& pvcdTmp->dwMuxID == dwControlID )
|| ( (pvcdTmp->dwSupport & VCD_SUPPORTF_MIXER_METER)
&& pvcdTmp->dwMeterID == dwControlID ) )
{
pvcd = pvcdTmp;
break;
}
}
if (pvcd == NULL)
return;
}
pmxul = pvcd->pmxul;
//
// Go through our visible lines to determine if this control affects
// any visible control and change them.
//
switch (mxc.dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_VOLUME:
{
DWORD adwVolume[2];
DWORD dwVolume;
//
// A nonvisible line should be shunned
//
if (pmxul == NULL)
return;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = dwControlID ;
if (Mixer_GetMixerVolume((HMIXEROBJ)(pmxud->hmx),
&mxcd, adwVolume,
pvcd->dwSupport & VCD_SUPPORTF_MONO)
!= MMSYSERR_NOERROR)
return;
dwVolume = max(adwVolume[0], adwVolume[1]);
dwVolume = (255 * (dwVolume - VOLUME_MIN))
/ (VOLUME_MAX - VOLUME_MIN);
dwVolume = 255 - dwVolume;
pmxuc = &pmxul->acr[MIXUI_VOLUME];
if (pmxuc->state)
{
SendMessage(pmxuc->hwnd, TBM_SETPOS, TRUE, dwVolume);
}
// we have no real balance for very low volumes
pmxuc = &pmxul->acr[MIXUI_BALANCE];
if (pmxuc->noset > 0)
{
//
// Don't worry about adjusting the balance value. We
// just set it "noset" times, so ignore the callback
// "noset" times.
//
pmxuc->noset--;
}
else if (dwVolume < 255 && pmxuc->state)
{
LONG lBalance;
lBalance = (32 * ((LONG)adwVolume[0]-(LONG)adwVolume[1]))
/ (LONG)(max(adwVolume[0], adwVolume[1])
- VOLUME_MIN);
lBalance = 32 - lBalance;
SendMessage(pmxuc->hwnd, TBM_SETPOS, TRUE, lBalance);
}
break;
}
case MIXERCONTROL_CONTROLTYPE_MIXER:
{
DWORD i;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMixerID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = pvcd->cMixer;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = (LPVOID)pvcd->amcd_bMixer;
mmr = mixerGetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
for (i = 0; i < pmxud->cvcd; i++)
{
pvcd = &pmxud->avcd[i];
if ( (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MIXER)
&& (pvcd->dwVisible & VCD_VISIBLEF_MIXER_MIXER)
&& pvcd->pmxul)
{
pmxuc = &pvcd->pmxul->acr[MIXUI_SWITCH];
if (pmxuc->state == MIXUI_CONTROL_INITIALIZED)
{
SendMessage(pmxuc->hwnd
, BM_SETCHECK
, pvcd->amcd_bMixer[pvcd->iMixer].fValue, 0);
}
}
}
}
break;
}
case MIXERCONTROL_CONTROLTYPE_MUX:
{
DWORD i;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMuxID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = pvcd->cMux;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = (LPVOID)pvcd->amcd_bMux;
mmr = mixerGetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
for (i = 0; i < pmxud->cvcd; i++)
{
pvcd = &pmxud->avcd[i];
if ( (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUX)
&& (pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUX)
&& pvcd->pmxul)
{
pmxuc = &pvcd->pmxul->acr[MIXUI_SWITCH];
if (pmxuc->state == MIXUI_CONTROL_INITIALIZED)
SendMessage(pmxuc->hwnd
, BM_SETCHECK
, pvcd->amcd_bMux[pvcd->iMux].fValue, 0);
}
}
}
break;
}
case MIXERCONTROL_CONTROLTYPE_MUTE:
{
DWORD fChecked;
//
// A nonvisible line should be shunned
//
if (pmxul == NULL)
return;
if (! (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE
&& pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUTE))
return;
pmxuc = &pmxul->acr[MIXUI_SWITCH];
if (pmxuc->state != MIXUI_CONTROL_INITIALIZED)
break;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMuteID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&fChecked;
mmr = mixerGetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr != MMSYSERR_NOERROR)
break;
SendMessage(pmxuc->hwnd, BM_SETCHECK, fChecked, 0);
break;
}
case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
{
LONG lVol;
DWORD dwVol;
//
// A nonvisible line should be shunned
//
if (pmxul == NULL)
return;
pmxuc = &pmxul->acr[MIXUI_VUMETER];
if (pmxuc->state != MIXUI_CONTROL_INITIALIZED)
break;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMeterID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&lVol;
mmr = mixerGetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr != MMSYSERR_NOERROR)
break;
dwVol = (DWORD)abs(lVol);
dwVol = (255 * dwVol) / 32768;
SendMessage(pmxuc->hwnd, VU_SETPOS, 0, dwVol);
break;
}
default:
return;
}
}
/*
* Mixer_SetControl
*
* - Change a mixerControl in response to a user event
* */
void Mixer_SetControl(
PMIXUIDIALOG pmxud, // app instance
HWND hctl, // hwnd of control that changed
int iLine, // visible line index of control that changed
int iCtl) // control id%line of control that changed
{
MMRESULT mmr;
MIXERCONTROLDETAILS mxcd;
PMIXUILINE pmxul;
PMIXUICTRL pmxuc;
PVOLCTRLDESC pvcd = NULL;
if ((DWORD)iLine >= pmxud->cmxul)
return;
pmxul = &pmxud->amxul[iLine];
pvcd = pmxul->pvcd;
if (iCtl <= MIXUI_LAST)
{
pmxuc = &pmxul->acr[iCtl];
}
switch (iCtl)
{
case MIXUI_ADVANCED:
Mixer_Advanced(pmxud, pvcd->dwLineID, pvcd->szName);
break;
case MIXUI_VOLUME:
case MIXUI_BALANCE:
{
DWORD adwVolume[2];
DWORD dwVolume;
LONG lBalance;
BOOL fJustScale = FALSE;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwVolumeID;
//
// get current volume so we preserve either balance or volume
//
if ( Mixer_GetMixerVolume((HMIXEROBJ)(pmxud->hmx), &mxcd, adwVolume
, pvcd->dwSupport & VCD_SUPPORTF_MONO )
!= MMSYSERR_NOERROR )
return;
if ( pmxul->acr[MIXUI_VOLUME].state != MIXUI_CONTROL_UNINITIALIZED)
{
dwVolume = SendMessage( pmxul->acr[MIXUI_VOLUME].hwnd
, TBM_GETPOS
, 0
, 0 );
dwVolume = 255 - dwVolume;
dwVolume = VOLUME_MIN
+ ((VOLUME_MAX - VOLUME_MIN)*dwVolume)/255;
}
else
{
//
// no volume slider
//
dwVolume = max(adwVolume[0],adwVolume[1]);
}
if ( pmxul->acr[MIXUI_BALANCE].state != MIXUI_CONTROL_UNINITIALIZED)
{
lBalance = SendMessage(pmxul->acr[MIXUI_BALANCE].hwnd
, TBM_GETPOS
, 0
, 0);
// lBalance is a value between 0 and 63
lBalance -= 32; // 0 based
}
else
{
//
// no balance slider we assume the balance doesn't change
//
LONG lDiv = (LONG)(max(adwVolume[0], adwVolume[1])
- VOLUME_MIN);
//
// if we're pegged, don't try to calculate the balance.
//
if (adwVolume[0] == 0 && adwVolume[1] == 0)
lBalance = 0;
else if (adwVolume[0] == 0)
lBalance = 32;
else if (adwVolume[1] == 0)
lBalance = -32;
else if (lDiv > 0)
{
lBalance = (32 * ((LONG)adwVolume[1]-(LONG)adwVolume[0]))
/ lDiv;
//
// we always lose precision doing this.
//
if (lBalance > 0) lBalance++;
if (lBalance < 0) lBalance--;
}
else
lBalance = 0;
}
//
// Recalc channels based on Balance vs. Volume
//
adwVolume[0] = dwVolume;
adwVolume[1] = dwVolume;
if (lBalance > 0)
adwVolume[0] -= (lBalance * (LONG)(adwVolume[1]-VOLUME_MIN))
/ 32;
else if (lBalance < 0)
adwVolume[1] -= (-lBalance * (LONG)(adwVolume[0]-VOLUME_MIN))
/ 32;
mxcd.cChannels = (pvcd->dwSupport & VCD_SUPPORTF_MONO)?1:2;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)adwVolume;
//
// Indicate to the callback that we're just setting volume
//
pmxul->acr[MIXUI_BALANCE].noset++;
mmr = mixerSetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
break;
}
case MIXUI_SWITCH:
{
LONG fChecked;
if (pmxuc->state != MIXUI_CONTROL_INITIALIZED)
break;
fChecked = SendMessage(pmxuc->hwnd, BM_GETCHECK, 0, 0);
//
// it's unlikely that there is a mixer and a mux and a mute
// representing the same line. It's most important that when a line
// is selected that the user gets a response. If there is a mute
// but no mux, then mute and mixer should be OFF and ON
// respectively and vice versa. If there is a mux and a mute the
// same is true.
// If there is a mux and a mixer... then the mux select should
// correspond.
//
if ( pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE
&& pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUTE )
{
mmr = Mixer_Mute((HMIXEROBJ)(pmxud->hmx),
pvcd, &mxcd, fChecked);
}
if (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MIXER
&& pvcd->dwVisible & VCD_VISIBLEF_MIXER_MIXER )
{
//
// get all other mixer settings, make sure this one is checked
//
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMixerID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = pvcd->cMixer;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = (LPVOID)pvcd->amcd_bMixer;
mmr = mixerGetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
pvcd->amcd_bMixer[pvcd->iMixer].fValue = fChecked;
mmr = mixerSetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
}
if (fChecked && pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE)
{
mmr = Mixer_Mute((HMIXEROBJ)(pmxud->hmx), pvcd, &mxcd, FALSE);
}
}
if (pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUX
&& pvcd->dwVisible & VCD_VISIBLEF_MIXER_MUX )
{
DWORD i;
//
// get all other mux settings, make sure this one is checked
// or unchecked and all others are not.
//
for (i = 0; i < pvcd->cMux; i++)
pvcd->amcd_bMux[i].fValue = FALSE;
pvcd->amcd_bMux[pvcd->iMux].fValue = TRUE;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pvcd->dwMuxID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = pvcd->cMux;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = (LPVOID)pvcd->amcd_bMux;
mmr = mixerSetControlDetails((HMIXEROBJ)(pmxud->hmx)
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
if (fChecked && pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE)
{
mmr = Mixer_Mute((HMIXEROBJ)(pmxud->hmx), pvcd, &mxcd, FALSE);
}
}
break;
}
default:
break;
}
}
/*
* Mixer_PollingUpdate
*
* Controls that need to be updated by a timer.
*
* */
void Mixer_PollingUpdate(
PMIXUIDIALOG pmxud)
{
DWORD i;
MMRESULT mmr;
MIXERLINE mxl;
//
// For all visible mixer lines, locate the control id's that need to be
// updated.
//
for (i = 0; i < pmxud->cmxul; i++)
{
PMIXUICTRL pmxuc = &pmxud->amxul[i].acr[MIXUI_VUMETER];
PVOLCTRLDESC pvcd = pmxud->amxul[i].pvcd;
if (pmxuc->state == MIXUI_CONTROL_UNINITIALIZED)
continue;
if (!(pvcd->dwSupport & VCD_SUPPORTF_MIXER_METER))
continue;
//
// Is the line active?
//
mxl.cbStruct = sizeof(MIXERLINE);
mxl.dwLineID = pvcd->dwLineID;
mmr = mixerGetLineInfo((HMIXEROBJ)(pmxud->hmx)
, &mxl
, MIXER_GETLINEINFOF_LINEID);
//
// Force non active or invalid lines to 0
//
if (mmr != MMSYSERR_NOERROR || !(mxl.fdwLine & MIXERLINE_LINEF_ACTIVE))
{
SendMessage(pmxuc->hwnd, VU_SETPOS, 0, 0L);
continue;
}
//
// Force a visible update
//
Mixer_GetControlFromID(pmxud, pvcd->dwMeterID);
}
}
/*
* Mixer_Init
*
* Control initialization
* */
BOOL Mixer_Init(
PMIXUIDIALOG pmxud)
{
MMRESULT mmr;
MIXERLINE mlDst;
DWORD iline;
TCHAR achFmt[256];
TCHAR achTitle[256];
mmr = mixerOpen((LPHMIXER)&pmxud->hmx
, pmxud->mxid
, (DWORD)pmxud->hwnd
, 0
, CALLBACK_WINDOW);
if (mmr != MMSYSERR_NOERROR)
return FALSE;
if (mixerMessage((HMIXER)(pmxud->mxid), DRV_QUERYDEVNODE, (DWORD)&pmxud->dwDevNode, 0L))
pmxud->dwDevNode = 0L;
LoadString(pmxud->hInstance, IDS_APPTITLE, achFmt, SIZEOF(achFmt));
mlDst.cbStruct = sizeof ( mlDst );
mlDst.dwDestination = pmxud->iDest;
mmr = mixerGetLineInfo((HMIXEROBJ)(pmxud->mxid)
, &mlDst
, MIXER_GETLINEINFOF_DESTINATION);
if (mmr == MMSYSERR_NOERROR)
{
lstrcpy(achTitle, mlDst.szName);
}
else
{
LoadString(pmxud->hInstance, IDS_APPBASE, achTitle, SIZEOF(achTitle));
}
SetWindowText(pmxud->hwnd, achTitle);
//
// since we cannot get a WM_PARENTNOTIFY, we need to run through
// all controls and make appropriate modifications.
//
for ( iline = 0 ; iline < pmxud->cmxul ; iline++ )
{
PMIXUILINE pmxul = &pmxud->amxul[iline];
PMIXUICTRL amxuc = pmxul->acr;
HWND ctrl;
ctrl = Volume_GetLineItem(pmxud->hwnd, iline, IDC_LINELABEL);
if (ctrl)
{
if (pmxud->dwStyle & MXUD_STYLEF_SMALL)
Static_SetText(ctrl, pmxul->pvcd->szShortName);
else
Static_SetText(ctrl, pmxul->pvcd->szName);
}
//
// Advanced escape
//
if (MXUD_ADVANCED(pmxud) &&
!(pmxud->dwStyle & MXUD_STYLEF_SMALL))
{
HWND hadv = Volume_GetLineItem(pmxud->hwnd, iline, IDC_ADVANCED);
ShowWindow(hadv,(pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_ADVANCED)?SW_SHOW:SW_HIDE);
EnableWindow(hadv,
(pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_ADVANCED)?TRUE:FALSE);
}
if (pmxul->pvcd->dwSupport & VCD_SUPPORTF_DISABLED)
continue;
//
// allow init of control structures
//
if (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_VOLUME)
{
amxuc[MIXUI_VOLUME].state = MIXUI_CONTROL_ENABLED;
if (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MONO)
{
amxuc[MIXUI_BALANCE].state = MIXUI_CONTROL_UNINITIALIZED;
}
else
amxuc[MIXUI_BALANCE].state = MIXUI_CONTROL_ENABLED;
}
if (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_METER)
amxuc[MIXUI_VUMETER].state = MIXUI_CONTROL_ENABLED;
if (pmxul->pvcd->dwSupport & VCD_SUPPORTF_MIXER_MUTE)
amxuc[MIXUI_SWITCH].state = MIXUI_CONTROL_ENABLED;
if ((pmxul->pvcd->dwSupport & ( VCD_SUPPORTF_MIXER_MIXER
| VCD_SUPPORTF_MIXER_MUX))
&& (pmxul->pvcd->dwVisible & ( VCD_VISIBLEF_MIXER_MIXER
| VCD_VISIBLEF_MIXER_MUX)))
{
//
// No longer make the mute visible
//
pmxul->pvcd->dwVisible &= ~VCD_VISIBLEF_MIXER_MUTE;
amxuc[MIXUI_SWITCH].state = MIXUI_CONTROL_ENABLED;
ctrl = Volume_GetLineItem(pmxud->hwnd, iline, IDC_SWITCH);
if (ctrl)
{
TCHAR ach[256];
if (LoadString(pmxud->hInstance, IDS_SELECT, ach, SIZEOF(ach)))
Button_SetText(ctrl, ach);
}
}
}
return TRUE;
}
/*
* Mixer_Shutdown
*
* Close handles, etc..
* */
void Mixer_Shutdown(
PMIXUIDIALOG pmxud)
{
if (pmxud->hmx)
{
mixerClose(pmxud->hmx);
pmxud->hmx = NULL;
}
Mixer_CleanupVolumeDescription(pmxud->avcd, pmxud->cvcd);
}
/* - - - - - - - - - */
typedef struct tagAdv {
PMIXUIDIALOG pmxud; // IN
DWORD dwLineID; // IN
HMIXER hmx; // IN
LPTSTR szName; // IN
DWORD dwSupport;
DWORD dwBassID;
DWORD dwTrebleID;
DWORD dwSwitch1ID;
DWORD dwSwitch2ID;
} ADVPARAM, *PADVPARAM;
#define GETPADVPARAM(x) (ADVPARAM *)GetWindowLong(x, DWL_USER)
#define SETPADVPARAM(x,y) SetWindowLong(x, DWL_USER, y)
#define ADV_HAS_BASS 0x00000001
#define ADV_HAS_TREBLE 0x00000002
#define ADV_HAS_SWITCH1 0x00000004
#define ADV_HAS_SWITCH2 0x00000008
void Mixer_Advanced_Update(
PADVPARAM pap,
HWND hwnd)
{
MIXERCONTROLDETAILS mxcd;
DWORD dwValue;
MMRESULT mmr;
if (pap->dwSupport & ADV_HAS_TREBLE)
{
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwTrebleID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwValue;
mmr = mixerGetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
dwValue = (255 * (dwValue - VOLUME_MIN))
/ (VOLUME_MAX - VOLUME_MIN);
SendMessage(GetDlgItem(hwnd, IDC_TREBLE), TBM_SETPOS, TRUE, dwValue);
}
}
if (pap->dwSupport & ADV_HAS_BASS)
{
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwBassID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwValue;
mmr = mixerGetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
dwValue = (255 * (dwValue - VOLUME_MIN))
/ (VOLUME_MAX - VOLUME_MIN);
SendMessage(GetDlgItem(hwnd, IDC_BASS), TBM_SETPOS, TRUE, dwValue);
}
}
if (pap->dwSupport & ADV_HAS_SWITCH1)
{
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwSwitch1ID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwValue;
mmr = mixerGetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
Button_SetCheck(GetDlgItem(hwnd,IDC_SWITCH1),dwValue);
}
}
if (pap->dwSupport & ADV_HAS_SWITCH2)
{
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwSwitch2ID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwValue;
mmr = mixerGetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == MMSYSERR_NOERROR)
{
Button_SetCheck(GetDlgItem(hwnd,IDC_SWITCH2),dwValue);
}
}
}
void Mixer_Advanced_OnMixmControlChange(
HWND hwnd,
HMIXER hmx,
DWORD dwControlID)
{
PADVPARAM pap = GETPADVPARAM(hwnd);
if (!pap)
return;
if ( ((pap->dwSupport & ADV_HAS_BASS)
&& dwControlID == pap->dwBassID)
|| ((pap->dwSupport & ADV_HAS_TREBLE)
&& dwControlID == pap->dwTrebleID)
|| ((pap->dwSupport & ADV_HAS_SWITCH1)
&& dwControlID == pap->dwSwitch1ID)
|| ((pap->dwSupport & ADV_HAS_SWITCH2)
&& dwControlID == pap->dwSwitch2ID) )
{
Mixer_Advanced_Update(pap,hwnd);
}
}
BOOL Mixer_Advanced_OnInitDialog(
HWND hwnd,
HWND hwndFocus,
LPARAM lParam)
{
PADVPARAM pap;
MIXERLINECONTROLS mxlc;
MIXERCONTROL *pmxc;
MIXERLINE ml;
MMRESULT mmr;
DWORD iCtrl, iSwitch1, iSwitch2;
TCHAR ach[MIXER_LONG_NAME_CHARS + 24];
TCHAR achFmt[256];
HWND hBass,hTreble,hSwitch1,hSwitch2;
SETPADVPARAM(hwnd, lParam);
pap = GETPADVPARAM(hwnd);
if (!pap)
EndDialog(hwnd, FALSE);
//
// clone the mixer handle to catch callbacks
//
mmr = mixerOpen((LPHMIXER)&pap->hmx
, (UINT)pap->pmxud->hmx
, (DWORD)hwnd
, 0
, CALLBACK_WINDOW | MIXER_OBJECTF_HMIXER );
if (mmr != MMSYSERR_NOERROR)
EndDialog(hwnd, FALSE);
//
// Get all controls.
//
ml.cbStruct = sizeof(ml);
ml.dwLineID = pap->dwLineID;
mmr = mixerGetLineInfo((HMIXEROBJ)pap->hmx
, &ml
, MIXER_GETLINEINFOF_LINEID);
if (mmr != MMSYSERR_NOERROR || ml.cControls == 0L)
EndDialog(hwnd, FALSE);
pmxc = (MIXERCONTROL *)GlobalAllocPtr(GHND,
sizeof(MIXERCONTROL) * ml.cControls);
if (!pmxc)
EndDialog(hwnd, FALSE);
mxlc.cbStruct = sizeof(mxlc);
mxlc.dwLineID = pap->dwLineID;
mxlc.cControls = ml.cControls;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = pmxc;
mmr = mixerGetLineControls((HMIXEROBJ)(pap->hmx)
, &mxlc
, MIXER_GETLINECONTROLSF_ALL);
if (mmr != MMSYSERR_NOERROR)
{
GlobalFreePtr(pmxc);
EndDialog(hwnd, FALSE);
}
pap->dwSupport = 0L;
for (iCtrl = 0; iCtrl < ml.cControls; iCtrl++)
{
switch (pmxc[iCtrl].dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_BASS:
if (!(pap->dwSupport & ADV_HAS_BASS))
{
pap->dwBassID = pmxc[iCtrl].dwControlID;
pap->dwSupport |= ADV_HAS_BASS;
}
break;
case MIXERCONTROL_CONTROLTYPE_TREBLE:
if (!(pap->dwSupport & ADV_HAS_TREBLE))
{
pap->dwTrebleID = pmxc[iCtrl].dwControlID;
pap->dwSupport |= ADV_HAS_TREBLE;
}
break;
case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
case MIXERCONTROL_CONTROLTYPE_MONO:
case MIXERCONTROL_CONTROLTYPE_STEREOENH:
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
if (!(pap->dwSupport & ADV_HAS_SWITCH1))
{
pap->dwSwitch1ID = pmxc[iCtrl].dwControlID;
pap->dwSupport |= ADV_HAS_SWITCH1;
iSwitch1 = iCtrl;
}
else if (!(pap->dwSupport & ADV_HAS_SWITCH2))
{
pap->dwSwitch2ID = pmxc[iCtrl].dwControlID;
pap->dwSupport |= ADV_HAS_SWITCH2;
iSwitch2 = iCtrl;
}
break;
}
}
//
//
//
hBass = GetDlgItem(hwnd, IDC_BASS);
hTreble = GetDlgItem(hwnd, IDC_TREBLE);
hSwitch1 = GetDlgItem(hwnd, IDC_SWITCH1);
hSwitch2 = GetDlgItem(hwnd, IDC_SWITCH2);
SendMessage(hBass, TBM_SETRANGE, 0, MAKELONG(0, 255));
SendMessage(hBass, TBM_SETTICFREQ, 43, 0 );
SendMessage(hTreble, TBM_SETRANGE, 0, MAKELONG(0, 255));
SendMessage(hTreble, TBM_SETTICFREQ, 43, 0 );
if (!(pap->dwSupport & ADV_HAS_BASS))
{
SendMessage(hBass, TBM_SETPOS, 64, 0 );
EnableWindow(GetDlgItem(hwnd, IDC_TXT_LOW1), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_TXT_HI1), FALSE);
}
EnableWindow(hBass, (pap->dwSupport & ADV_HAS_BASS));
if (!(pap->dwSupport & ADV_HAS_TREBLE))
{
SendMessage(hTreble, TBM_SETPOS, 64, 0 );
EnableWindow(GetDlgItem(hwnd, IDC_TXT_LOW2), FALSE);
EnableWindow(GetDlgItem(hwnd, IDC_TXT_HI2), FALSE);
}
EnableWindow(hTreble, (pap->dwSupport & ADV_HAS_TREBLE));
if (pap->dwSupport & ADV_HAS_SWITCH1)
{
LoadString(pap->pmxud->hInstance, IDS_ADV_SWITCH1, achFmt,
SIZEOF(achFmt));
wsprintf(ach, achFmt, pmxc[iSwitch1].szName);
SetWindowText(hSwitch1, ach);
ShowWindow(hSwitch1, SW_SHOW);
ShowWindow(GetDlgItem(hwnd, IDC_TXT_SWITCHES), SW_SHOW);
ShowWindow(GetDlgItem(hwnd, IDC_GRP_OTHER), SW_SHOW);
}
EnableWindow(hSwitch1, (pap->dwSupport & ADV_HAS_SWITCH1));
if (pap->dwSupport & ADV_HAS_SWITCH2)
{
LoadString(pap->pmxud->hInstance, IDS_ADV_SWITCH2, achFmt,
SIZEOF(achFmt));
wsprintf(ach, achFmt, pmxc[iSwitch2].szName);
SetWindowText(hSwitch2, ach);
ShowWindow(hSwitch2, SW_SHOW);
}
EnableWindow(hSwitch2, (pap->dwSupport & ADV_HAS_SWITCH2));
if (pap->dwSupport & (ADV_HAS_SWITCH1 | ADV_HAS_SWITCH2))
{
RECT rcGrp,rcGrp2,rcClose,rcWnd;
DWORD dwDY=0L;
POINT pos;
HWND hClose = GetDlgItem(hwnd, IDOK);
HWND hGrp2 = GetDlgItem(hwnd, IDC_GRP_OTHER);
GetWindowRect(GetDlgItem(hwnd, IDC_GRP_TONE), &rcGrp);
GetWindowRect(GetDlgItem(hwnd, IDC_GRP_OTHER), &rcGrp2);
GetWindowRect(hClose, &rcClose);
GetWindowRect(hwnd, &rcWnd);
if (pap->dwSupport & ADV_HAS_SWITCH2)
{
RECT rc1, rc2;
GetWindowRect(hSwitch1,&rc1);
GetWindowRect(hSwitch2,&rc2);
rcGrp2.bottom += rc2.bottom - rc1.bottom;
}
dwDY = rcGrp2.bottom - rcGrp.bottom;
//
// resize our main window
//
MoveWindow(hwnd, rcWnd.left
, rcWnd.top
, rcWnd.right - rcWnd.left
, (rcWnd.bottom - rcWnd.top) + dwDY
, FALSE);
//
// move the close button
//
pos.x = rcClose.left;
pos.y = rcClose.top;
ScreenToClient(hwnd,&pos);
MoveWindow(hClose, pos.x
, pos.y + dwDY
, rcClose.right - rcClose.left
, rcClose.bottom - rcClose.top
, FALSE);
//
// resize our group box if necessary
//
if (pap->dwSupport & ADV_HAS_SWITCH2)
{
pos.x = rcGrp2.left;
pos.y = rcGrp2.top;
ScreenToClient(hwnd,&pos);
MoveWindow(hGrp2, pos.x
, pos.y
, rcGrp2.right - rcGrp2.left
, rcGrp2.bottom - rcGrp2.top
, FALSE);
}
}
GlobalFreePtr(pmxc);
{
TCHAR achTitle[MIXER_LONG_NAME_CHARS+256];
LoadString(pap->pmxud->hInstance, IDS_ADV_TITLE, achFmt,
SIZEOF(achFmt));
wsprintf(achTitle, achFmt, pap->szName);
SetWindowText(hwnd, achTitle);
}
Mixer_Advanced_Update(pap, hwnd);
return TRUE;
}
void Mixer_Advanced_OnXScroll(
HWND hwnd,
HWND hwndCtl,
UINT code,
int pos)
{
PADVPARAM pap;
MIXERCONTROLDETAILS mxcd;
DWORD dwVol;
MMRESULT mmr;
pap = GETPADVPARAM(hwnd);
if (!pap)
return;
if (pap->dwSupport & ADV_HAS_TREBLE)
{
dwVol = SendMessage( GetDlgItem(hwnd, IDC_TREBLE)
, TBM_GETPOS
, 0
, 0 );
dwVol = VOLUME_MIN
+ ((VOLUME_MAX - VOLUME_MIN)*dwVol)/255;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwTrebleID ;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwVol;
mixerSetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
}
if (pap->dwSupport & ADV_HAS_BASS)
{
dwVol = SendMessage( GetDlgItem(hwnd, IDC_BASS)
, TBM_GETPOS
, 0
, 0 );
dwVol = VOLUME_MIN
+ ((VOLUME_MAX - VOLUME_MIN)*dwVol)/255;
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = pap->dwBassID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwVol;
mmr = mixerSetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
}
}
void Mixer_Advanced_OnSwitch(
HWND hwnd,
int id,
HWND hwndCtl)
{
PADVPARAM pap;
MIXERCONTROLDETAILS mxcd;
DWORD dwValue;
MMRESULT mmr;
pap = GETPADVPARAM(hwnd);
if (!pap)
return;
dwValue = Button_GetCheck(hwndCtl);
mxcd.cbStruct = sizeof(mxcd);
mxcd.dwControlID = (id == IDC_SWITCH1)?pap->dwSwitch1ID:pap->dwSwitch2ID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(DWORD);
mxcd.paDetails = (LPVOID)&dwValue;
mmr = mixerSetControlDetails((HMIXEROBJ)(pap->hmx)
, &mxcd
, MIXER_SETCONTROLDETAILSF_VALUE);
}
BOOL Mixer_Advanced_OnCommand(
HWND hwnd,
int id,
HWND hwndCtl,
UINT codeNotify)
{
switch (id)
{
case IDOK:
EndDialog(hwnd, TRUE);
break;
case IDCANCEL:
EndDialog(hwnd, FALSE);
break;
case IDC_SWITCH1:
Mixer_Advanced_OnSwitch(hwnd, id, hwndCtl);
break;
case IDC_SWITCH2:
Mixer_Advanced_OnSwitch(hwnd, id, hwndCtl);
break;
}
return FALSE;
}
BOOL CALLBACK Mixer_Advanced_Proc(
HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
switch (msg)
{
case WM_INITDIALOG:
HANDLE_WM_INITDIALOG(hwnd, wparam, lparam, Mixer_Advanced_OnInitDialog);
return TRUE;
case MM_MIXM_CONTROL_CHANGE:
HANDLE_MM_MIXM_CONTROL_CHANGE(hwnd
, wparam
, lparam
, Mixer_Advanced_OnMixmControlChange);
break;
case WM_CLOSE:
EndDialog(hwnd, FALSE);
break;
case WM_HSCROLL:
HANDLE_WM_XSCROLL(hwnd, wparam, lparam, Mixer_Advanced_OnXScroll);
break;
case WM_COMMAND:
HANDLE_WM_COMMAND(hwnd, wparam, lparam, Mixer_Advanced_OnCommand);
break;
case WM_DESTROY:
{
PADVPARAM pap = GETPADVPARAM(hwnd);
if (pap)
{
if (pap->hmx)
mixerClose(pap->hmx);
}
break;
}
default:
break;
}
return FALSE;
}
/*
* Advanced Features for specific mixer lines.
*/
void Mixer_Advanced(
PMIXUIDIALOG pmxud,
DWORD dwLineID,
LPTSTR szName)
{
ADVPARAM advp;
ZeroMemory(&advp, sizeof(ADVPARAM));
advp.pmxud = pmxud;
advp.dwLineID = dwLineID;
advp.szName = szName;
DialogBoxParam(pmxud->hInstance
, MAKEINTRESOURCE(IDD_ADVANCED)
, pmxud->hwnd
, Mixer_Advanced_Proc
, (DWORD)(LPVOID)&advp);
}