#include “windows.h”
#include “mmsystem.h”
#pragma comment(lib, “winmm.lib”)
enum Volume_type
{
EM_MAIN_VOLUME,
EM_WAVEOUT_VOLUME,
};
typedef struct VolumeControl
{
char m_name[64];
uint32_t m_controlnum;
uint32_t m_controlid;
HWND m_hwnd;
uint32_t m_min;
uint32_t m_max;
HMIXER m_hMixer;
int m_volume_left;
int m_volume_right;
int m_volume_step;
void (*SetValue)(int32_t vl ,int32_t vr);
int32_t (*GetValue)(int32_t *vl,int32_t*vr);
int32_t (*GetMin)();
int32_t (*GetMax)();
void (*Close)();
void (*Create)(struct VolumeControl *vc,HWND hwnd,
int32_t type1,int32_t type2,int32_t type3);
}VolumeControl;
void wxPlayer_create_volume(VolumeControl *vc,HWND hwnd,enum Volume_type volume_type)
{
MIXERCAPS m_mxcaps;
MIXERLINE mxl;
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
int i=0;
long type=0;
if(volume_type==EM_MAIN_VOLUME)
type=-1;
else if(volume_type==EM_WAVEOUT_VOLUME)
type=MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
memset(vc,0,sizeof(VolumeControl));
vc->m_hwnd=hwnd;
vc->m_hMixer = NULL;
ZeroMemory(&m_mxcaps, sizeof(MIXERCAPS));
if (mixerGetNumDevs() != 0)
{
if (mixerOpen(&vc->m_hMixer,0,(DWORD)vc->m_hwnd,NULL,
MIXER_OBJECTF_MIXER | CALLBACK_WINDOW)
!= MMSYSERR_NOERROR)
return ;
if (mixerGetDevCaps((UINT)vc->m_hMixer, &m_mxcaps, sizeof(MIXERCAPS))
!= MMSYSERR_NOERROR)
return ;
}
if (vc->m_hMixer == NULL)
return ;
mxl.cbStruct = sizeof(MIXERLINE);
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
if (mixerGetLineInfo((HMIXEROBJ)vc->m_hMixer,&mxl,
MIXER_OBJECTF_HMIXER |MIXER_GETLINEINFOF_COMPONENTTYPE)
!= MMSYSERR_NOERROR)
return ;
if(type!=-1)
{
int32_t num=mxl.cConnections;
int32_t temp_type=mxl.dwDestination;
for( i=0;i {
mxl.cbStruct = sizeof(mxl);
mxl.dwDestination = temp_type;
mxl.dwSource = i;
if(mixerGetLineInfo((HMIXEROBJ)vc->m_hMixer, &mxl,
MIXER_GETLINEINFOF_SOURCE|MIXER_OBJECTF_HMIXER)!= MMSYSERR_NOERROR)
{
continue;
}
if(mxl.dwComponentType==type)
break;
if(i==num)
{
return;
}
}
}
vc->m_controlnum=mxl.cChannels;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = mxl.dwLineID;
mxlc.dwControlType =MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls =1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
if (mixerGetLineControls((HMIXEROBJ)vc->m_hMixer,&mxlc,
MIXER_OBJECTF_HMIXER |MIXER_GETLINECONTROLSF_ONEBYTYPE )
!= MMSYSERR_NOERROR)
return;
strcpy(vc->m_name,mxc.szName);;
vc->m_controlid = mxc.dwControlID;
vc->m_min= mxc.Bounds.lMinimum;
vc->m_max= mxc.Bounds.lMaximum;
vc->m_volume_step=(vc->m_max-vc->m_min)/20;
wxPlayer_getvalue_volume(vc,&vc->m_volume_left,&vc->m_volume_right);
}
void wxPlayer_close_volume(VolumeControl *vc)
{
if (vc->m_hMixer != NULL)
{
mixerClose(vc->m_hMixer);
vc->m_hMixer = NULL;
}
}
int32_t wxPlayer_getmax_volume(VolumeControl *vc)
{
return vc->m_max;
}
int32_t wxPlayer_getmin_volume(VolumeControl *vc)
{
return vc->m_min;
}
int32_t wxPlayer_getvalue_volume(VolumeControl *vc,int32_t *vl,int32_t *vr)
{
MIXERCONTROLDETAILS_SIGNED mxcdVolume[2];
MIXERCONTROLDETAILS mxcd;
if (vc->m_hMixer == NULL)
return -1;
*vl=-1;
*vr=-1;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = vc->m_controlid;
mxcd.cChannels = vc->m_controlnum;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
mxcd.paDetails = mxcdVolume;
if (mixerGetControlDetails((HMIXEROBJ)vc->m_hMixer,
&mxcd,
MIXER_OBJECTF_HMIXER |
MIXER_GETCONTROLDETAILSF_VALUE)
!= MMSYSERR_NOERROR)
return -1;
*vl=mxcdVolume[0].lValue;
if(vc->m_controlnum==2)
*vr=mxcdVolume[1].lValue;
return 1;
}
void wxPlayer_setvalue_volume(VolumeControl *vc,int32_t vl,int32_t vr)
{
MIXERCONTROLDETAILS_SIGNED mxcdVolume[2] = {vl,vr};
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = vc->m_controlid;
mxcd.cChannels = vc->m_controlnum;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
mxcd.paDetails = &mxcdVolume;
if (mixerSetControlDetails((HMIXEROBJ)vc->m_hMixer,
&mxcd,
MIXER_OBJECTF_HMIXER |
MIXER_SETCONTROLDETAILSF_VALUE)
!= MMSYSERR_NOERROR)
return ;
}
void wxPlayer_add_volume(VolumeControl *vc)
{
wxPlayer_getvalue_volume(vc,&vc->m_volume_left,&vc->m_volume_right);
if(vc->m_volume_left>=0&&vc->m_volume_left<=vc->m_max-vc->m_volume_step)
vc->m_volume_left+=vc->m_volume_step;
else if(vc->m_volume_left>0)
vc->m_volume_left=vc->m_max;
else
vc->m_volume_left=0;
if(vc->m_volume_right>=0&&vc->m_volume_right<=vc->m_max-vc->m_volume_step)
vc->m_volume_right+=vc->m_volume_step;
else if(vc->m_volume_right>0)
vc->m_volume_right=vc->m_max;
else
vc->m_volume_right=0;
wxPlayer_setvalue_volume(vc,vc->m_volume_left,vc->m_volume_right);
}
void wxPlayer_down_volume(VolumeControl *vc)
{
wxPlayer_getvalue_volume(vc,&vc->m_volume_left,&vc->m_volume_right);
if(vc->m_volume_left>=0&&vc->m_volume_left>=vc->m_min+vc->m_volume_step)
vc->m_volume_left-=vc->m_volume_step;
else
vc->m_volume_left=vc->m_min;
if(vc->m_volume_right>=vc->m_min+vc->m_volume_step)
vc->m_volume_right-=vc->m_volume_step;
else
vc->m_volume_right=vc->m_min;
wxPlayer_setvalue_volume(vc,vc->m_volume_left,vc->m_volume_right);
}
/*some demo code*/
//handle for volume control
VolumeControl g_MainVolume;
VolumeControl g_WaveoutVolume;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//……………..
switch (message)
{
case WM_CREATE:
wxPlayer_create_volume(&g_MainVolume,hWnd,EM_MAIN_VOLUME);
wxPlayer_create_volume(&g_WaveoutVolume,hWnd,EM_WAVEOUT_VOLUME);
break;
//………………..
case WM_KEYDOWN:
{
static int volume_left=0,volume_right=0;
int key=(int)wParam;
switch(key)
{
case VK_UP:
wxPlayer_add_volume(&g_MainVolume);
break;
case VK_DOWN:
wxPlayer_down_volume(&g_MainVolume);
break;
case VK_HOME:
wxPlayer_add_volume(&g_WaveoutVolume);
break;
case VK_END:
wxPlayer_down_volume(&g_WaveoutVolume);
default:
break;
}
}
break;
case WM_DESTROY:
wxPlayer_close_volume(&g_MainVolume);
wxPlayer_close_volume(&g_WaveoutVolume);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}