HMIXER CMicVolume::MixDevice(HMIXER current_mix, unsigned int mix_id) { HMIXER h_mixer; MIXERCAPS mixer_caps; if(mixerGetDevCaps(mix_id, &mixer_caps, sizeof(mixer_caps)) != MMSYSERR_NOERROR) return NULL; if(mixerOpen(&h_mixer, mix_id, DWORD(NULL), 0L, CALLBACK_WINDOW) != MMSYSERR_NOERROR) return NULL; if(current_mix != NULL){ if(mixerClose(current_mix) != MMSYSERR_NOERROR) { #ifdef _DEBUG MessageBox(NULL,"Mixer 장치가 사용중입니다.", "Mixer 열기실패", MB_ICONSTOP); #endif current_mix = NULL; } } //char szbuf[128]; //wsprintf(szbuf,"Mixer 장치명: %s", mixer_caps.szPname); //SetWindowText(g_hWnd, szbuf); //윈도우 타이틀바에 장치명 알림 return h_mixer; }
//################################################## //agenttype_mixer_menu_devices //################################################## void agenttype_mixer_menu_devices(Menu *menu, control *c, char *action, char *agentname, int format) { //Variables MIXERCAPS mixer_capabilities; HMIXER mixer_handle; //Count the devices UINT count_devices = mixerGetNumDevs(); if (count_devices < 1) { make_menuitem_nop(menu, "No audio devices present."); return; } //For every device... for (UINT device = 0; device < count_devices; device++) { //Open the mixer if (MMSYSERR_NOERROR == mixerOpen( &mixer_handle, device, 0, 0, 0) && MMSYSERR_NOERROR == mixerGetDevCaps(device, &mixer_capabilities, sizeof(MIXERCAPS))) { //Create a submenu for destination lines Menu *submenu; submenu = make_menu(mixer_capabilities.szPname, c); agenttype_mixer_menu_destlines(submenu, c, action, agentname, format, device, mixer_handle, mixer_capabilities); make_submenu_item(menu, mixer_capabilities.szPname, submenu); //Close the mixer mixerClose(mixer_handle); } } return; }
INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { MIXERCAPS mixerCaps; if (mixerGetDevCaps(mixerIndex, &mixerCaps, sizeof(MIXERCAPS)) == MMSYSERR_NOERROR) { strncpy(description->name, mixerCaps.szPname, PORT_STRING_LENGTH-1); description->name[PORT_STRING_LENGTH-1] = 0; sprintf(description->version, "%d.%d", (mixerCaps.vDriverVersion & 0xFF00) >> 8, mixerCaps.vDriverVersion & 0xFF); strncpy(description->description, "Port Mixer", PORT_STRING_LENGTH-1); return TRUE; }
BOOL SndMixerSelect(PSND_MIXER Mixer, UINT MixerId) { if (MixerId >= Mixer->MixersCount) { return FALSE; } SndMixerClose(Mixer); if (mixerOpen(&Mixer->hmx, MixerId, (DWORD_PTR)Mixer->hWndNotification, 0, CALLBACK_WINDOW | MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR || mixerOpen(&Mixer->hmx, MixerId, (DWORD_PTR)Mixer->hWndNotification, 0, CALLBACK_WINDOW) == MMSYSERR_NOERROR || mixerOpen(&Mixer->hmx, MixerId, 0, 0, 0) == MMSYSERR_NOERROR) { if (mixerGetDevCaps(MixerId, &Mixer->Caps, sizeof(Mixer->Caps)) == MMSYSERR_NOERROR) { BOOL Ret = FALSE; Mixer->MixerId = MixerId; ClearMixerCache(Mixer); Ret = SndMixerQueryDestinations(Mixer); if (!Ret) { ClearMixerCache(Mixer); } return Ret; } else { mixerClose(Mixer->hmx); } } Mixer->hmx = NULL; Mixer->MixerId = NO_MIXER_SELECTED; return FALSE; }
/** * A ridiculous amount of code to do something this simple. * But mixers are pretty abstract a subject, I guess... * (No, the API just sucks.) */ static int initMixer(void) { MIXERCAPS mixerCaps; int num = mixerGetNumDevs(); // Number of mixer devices. if(initMixerOk || CommandLine_Check("-nomixer")) return true; if(verbose) { // In verbose mode, print a lot of extra information. Con_Message("dsWinMM::initMixer: Number of mixer devices: %i", num); } // Open the mixer device. res = mixerOpen(&mixer, 0, 0, 0, MIXER_OBJECTF_MIXER); if(res != MMSYSERR_NOERROR) { if(verbose) Con_Message(" Error opening mixer: Error %i", res); return 0; } // Get the device caps. mixerGetDevCaps((UINT_PTR) mixer, &mixerCaps, sizeof(mixerCaps)); Con_Message("dsWinMM::initMixer: %s", mixerCaps.szPname); if(verbose) Con_Message(" Audio line destinations: %i", mixerCaps.cDestinations); // Init CD mixer. if(verbose) Con_Message("Init CD audio line:"); initMixerLine(&mixCD, MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC); if(verbose) Con_Message("Init synthesizer line:"); initMixerLine(&mixMidi, MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER); // We're successful. initMixerOk = true; // Get the original mixer volume settings (restored at shutdown). origVol = mixer3i(MIX_MIDI, MIX_GET, MIX_VOLUME); origCDVol = mixer3i(MIX_CDAUDIO, MIX_GET, MIX_VOLUME); return true; }
BOOL SndMixerEnumProducts(PSND_MIXER Mixer, PFNSNDMIXENUMPRODUCTS EnumProc, PVOID Context) { MIXERCAPS Caps; HMIXER hMixer; UINT i; BOOL Ret = TRUE; for (i = 0; i < Mixer->MixersCount; i++) { if (mixerOpen(&hMixer, i, 0, 0, 0) == MMSYSERR_NOERROR) { if (mixerGetDevCaps(i, &Caps, sizeof(Caps)) == MMSYSERR_NOERROR) { if (!EnumProc(Mixer, i, Caps.szPname, Context)) { mixerClose(hMixer); Ret = FALSE; break; } } else { DPRINT("Failed to get device capabilities for mixer id %d!\n", i); } mixerClose(hMixer); } } return Ret; }
PLUGIN_FUNCTION_ARG3(GetDeviceName,unsigned,index, char *,buffer, unsigned,bufsize) { if (buffer == NULL || bufsize < 4) return PluginLID_InvalidParameter; if (index >= 1) return PluginLID_NoMoreNames; UINT numDevs = mixerGetNumDevs(); for(UINT i = 0; i < numDevs; i++){ MIXERCAPS caps; mixerGetDevCaps(i, &caps, sizeof(caps)); if (strstr(caps.szPname, "USB Audio") != NULL) { strcpy(buffer, "HID"); return PluginLID_NoError; } } return PluginLID_NoMoreNames; }
//-------------------------------------------------------------------------------------- // Class: SoundResources // Method: _print_dst_lines // Description: This function prints in the screen the source lines present //-------------------------------------------------------------------------------------- void SoundResources::_print_dst_lines() { MIXERCAPS mixerCaps; mixerGetDevCaps(0,&mixerCaps, sizeof(mixerCaps)); for (int i = 0; i < mixerCaps.cDestinations; i++) { m_mixerLine.cbStruct = sizeof(MIXERLINE); m_mixerLine.dwSource = 0; m_mixerLine.dwDestination = i; if (!(m_err = mixerGetLineInfo((HMIXEROBJ)m_MixerHandle, &m_mixerLine, MIXER_GETLINEINFOF_DESTINATION))) { printf("\t#%lu: %s\n", i, m_mixerLine.szName); } m_numSrc = m_mixerLine.cConnections; _print_src_lines(); } }
/* If the PROP_DEVICE_NAME is set, find the mixer related to device; * otherwise we get the default input mixer. */ static gboolean gst_directsound_src_mixer_find (GstDirectSoundSrc * dsoundsrc, MIXERCAPS * mixer_caps) { MMRESULT mmres; guint i, num_mixers; num_mixers = mixerGetNumDevs (); for (i = 0; i < num_mixers; i++) { mmres = mixerOpen (&dsoundsrc->mixer, i, 0L, 0L, MIXER_OBJECTF_MIXER | MIXER_OBJECTF_WAVEIN); if (mmres != MMSYSERR_NOERROR) continue; mmres = mixerGetDevCaps (GPOINTER_TO_UINT (dsoundsrc->mixer), mixer_caps, sizeof (MIXERCAPS)); if (mmres != MMSYSERR_NOERROR) { mixerClose (dsoundsrc->mixer); continue; } /* Get default mixer */ if (dsoundsrc->device_name == NULL) { GST_DEBUG ("Got default input mixer: %s", mixer_caps->szPname); return TRUE; } if (g_strstr_len (dsoundsrc->device_name, -1, mixer_caps->szPname) != NULL) { GST_DEBUG ("Got requested input mixer: %s", mixer_caps->szPname); return TRUE; } /* Wrong mixer */ mixerClose (dsoundsrc->mixer); } GST_DEBUG ("Can't find input mixer"); return FALSE; }
BOOL CMicVolume::GetDevice() { MIXERCAPS mixer_caps; MIXERLINE mixer_line; if(mixerGetDevCaps((unsigned int)h_mix, &mixer_caps, sizeof(mixer_caps)) != MMSYSERR_NOERROR) { #ifdef _DEBUG MessageBox(NULL, "등록된 장치의 정보를 읽을 수 없습니다.", "시스템 정보 오류", MB_ICONSTOP); #endif mixer_caps.cDestinations = 0; return FALSE; } for(unsigned int i = 0; i < mixer_caps.cDestinations; i++){ mixer_line.cbStruct = sizeof(mixer_line); mixer_line.dwDestination = i; if(mixerGetLineInfo((HMIXEROBJ)h_mix, &mixer_line, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR) continue; if(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS == mixer_line.dwComponentType){ m_WavOut.nDeviceNum = (short)mixer_line.cConnections; m_WavOut.nIndex = (short)i; m_WavOut.nLineID = mixer_line.dwLineID; strcpy(m_WavOut.DeviceName, mixer_line.szName); //GetDeviceCtrl(&m_WavOut, &m_ctlSpeaker); } else if(MIXERLINE_COMPONENTTYPE_DST_WAVEIN == mixer_line.dwComponentType){ m_WavIn.nDeviceNum = (short)mixer_line.cConnections; m_WavIn.nIndex = (short)i; m_WavIn.nLineID = mixer_line.dwLineID; strcpy(m_WavIn.DeviceName, mixer_line.szName); } } GetMicDevice(); if(VolDevice(&m_MicIn) < 0) { return FALSE; } return TRUE; }
static void winsnd_detect(MSSndCardManager *m){ MMRESULT mr = NOERROR; unsigned int nInDevices = waveInGetNumDevs (); unsigned int item; char pcmdev[1024]; char mixdev[1024]; for (item = 0; item < nInDevices; item++) { WAVEINCAPS caps; mr = waveInGetDevCaps (item, &caps, sizeof (WAVEINCAPS)); if (mr == MMSYSERR_NOERROR) { MSSndCard *card; snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname); snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname); if (item == 0) { card=winsnd_card_new(pcmdev,mixdev, item-1); ms_snd_card_manager_add_card(m,card); } card=winsnd_card_new(pcmdev,mixdev, item); ms_snd_card_manager_add_card(m,card); } } #if 0 nInDevices = mixerGetNumDevs (); for (item = 0; item < nInDevices; item++) { MIXERCAPS caps; mr = mixerGetDevCaps (item, &caps, sizeof (MIXERCAPS)); if (mr == MMSYSERR_NOERROR) { snprintf(pcmdev,sizeof(pcmdev),"%s",caps.szPname); snprintf(mixdev,sizeof(mixdev),"%s",caps.szPname); } } #endif }
void CMicVolume::GetMicDevice() { MIXERCAPS mixer_caps; MIXERLINE mixer_line; mixerGetDevCaps((unsigned int)h_mix, &mixer_caps, sizeof(mixer_caps)); for(int i = 0; i < m_WavIn.nDeviceNum; i++){ mixer_line.cbStruct = sizeof(mixer_line); mixer_line.dwDestination = m_WavIn.nIndex; mixer_line.dwSource = i; if(mixerGetLineInfo((HMIXEROBJ)h_mix, &mixer_line, MIXER_GETLINEINFOF_SOURCE) != MMSYSERR_NOERROR) continue; if(mixer_line.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) { m_MicIn.nIndex = (short)i; m_MicIn.nLineID = mixer_line.dwLineID; GetDeviceCtrl(&m_MicIn); break; } } }
unsigned int iKX::get_winmm_device(int what,int subdevice) { UINT ret=0xffffffff; const char *device=get_winmm_name((what==KX_WINMM_MIXER)?KX_WINMM_WAVE:what); if(device==0) return ret; if(subdevice==0) { switch(what) { case KX_WINMM_MIXER: if(mixerGetNumDevs()) // else causes unsigned infinite loop for(UINT i=0;i<mixerGetNumDevs();i++) { MIXERCAPS caps; if(mixerGetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { if(strcmp(caps.szPname,device)==NULL) { ret=i; break; } } else break; } break; case KX_WINMM_WAVE: case KX_WINMM_WAVE23: case KX_WINMM_WAVE45: case KX_WINMM_WAVE67: case KX_WINMM_WAVEHQ: if(waveInGetNumDevs()) // else causes unsigned infinite loop for(UINT i=0;i<waveInGetNumDevs();i++) { WAVEINCAPS caps; if(waveInGetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { if(strcmp(caps.szPname,device)==NULL) { ret=i; break; } } else break; } break; case KX_WINMM_SYNTH: case KX_WINMM_SYNTH2: case KX_WINMM_UART: case KX_WINMM_UART2: case KX_WINMM_CTRL: if(midiInGetNumDevs()) // else causes unsigned infinite loop for(UINT i=0;i<midiInGetNumDevs();i++) { MIDIINCAPS caps; if(midiInGetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { if(strcmp(caps.szPname,device)==NULL) { ret=i; break; } } else break; } break; } } else { switch(what) { case KX_WINMM_MIXER: debug("kxapi: incorrect get_winmm call(mixer)\n"); break; case KX_WINMM_WAVE: case KX_WINMM_WAVE23: case KX_WINMM_WAVE45: case KX_WINMM_WAVE67: case KX_WINMM_WAVEHQ: if(waveOutGetNumDevs()) // else causes unsigned infinite loop for(UINT i=0;i<waveOutGetNumDevs();i++) { WAVEOUTCAPS caps; if(waveOutGetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { if(strcmp(caps.szPname,device)==NULL) { ret=i; break; } } else break; } break; case KX_WINMM_SYNTH: case KX_WINMM_SYNTH2: case KX_WINMM_UART: case KX_WINMM_UART2: case KX_WINMM_CTRL: if(midiOutGetNumDevs()) // else causes unsigned infinite loop for(UINT i=0;i<midiOutGetNumDevs();i++) { MIDIOUTCAPS caps; if(midiOutGetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { if(strcmp(caps.szPname,device)==NULL) { ret=i; break; } } else break; } break; } } return ret; }
int iKX::init_winmm() { // check for Vista and Windows7: OSVERSIONINFOEX ver; memset(&ver,0,sizeof(ver)); ver.dwOSVersionInfoSize=sizeof(ver); if(GetVersionEx((OSVERSIONINFO *)&ver)) // ok? { if(ver.dwPlatformId==VER_PLATFORM_WIN32_NT && ver.dwMajorVersion>=6) { debug("iKX(): init_winmm: mixers are not supported. Vista+ workaround\n"); return 0; } } int ret=-1; for(unsigned int i=0;i<mixerGetNumDevs();i++) { HMIXER mixer=0; int to_close=1; // open mixer if(mixerOpen(&mixer,i,0,0,MIXER_OBJECTF_MIXER)!=MMSYSERR_NOERROR) { debug("iKX(): mixerOpen failed [%x]\n",GetLastError()); continue; // next mixer } // get mixer caps MIXERCAPS mc; memset(&mc,0,sizeof(mc)); if(mixerGetDevCaps(i,&mc,sizeof(mc))!=MMSYSERR_NOERROR) { debug("iKX(): mixerGetDevCaps() failed [%x]\n",GetLastError()); mixerClose(mixer); continue; } // debug("iKX(): init_winmm: looking for '%s': '%s' [#%d out of %d]\n",wave_name,mc.szPname,i,mixerGetNumDevs()); if(strncmp(mc.szPname,wave_name,strlen(wave_name)-4)!=NULL) // yes, this should be 'wave_name', not 'mixer_name'; { mixerClose(mixer); continue; } if(strcmp(mc.szPname,wave_name)==0) { mixer_handler[0]=(uintptr_t)mixer; to_close=0; ret=0; } else if(strcmp(mc.szPname,wave23_name)==0) { mixer_handler[1]=(uintptr_t)mixer; to_close=0; ret=0; } else if(strcmp(mc.szPname,wave45_name)==0) { mixer_handler[2]=(uintptr_t)mixer; to_close=0; ret=0; } else if(strcmp(mc.szPname,wave67_name)==0) { mixer_handler[3]=(uintptr_t)mixer; to_close=0; ret=0; } else if(strcmp(mc.szPname,waveHQ_name)==0) { mixer_handler[4]=(uintptr_t)mixer; to_close=0; ret=0; } else { debug("kXAPI: WARNING: incorrect init_winmm() code: %s\n",mc.szPname); } if(to_close) mixerClose(mixer); // break; } if(ret==-1) { debug("iKX(): init_winmm: number of mixers: %d\n",mixerGetNumDevs()); } return ret; }
bool setVolume(DWORD volume) { HMIXER mixer; int mixerNum ;//总的混音器数量 bool is_find_mic; //获取当前系统总的混音器数量 mixerNum= mixerGetNumDevs(); is_find_mic = false; for(int i=0;i<mixerNum;i++) { if (mixerOpen(&mixer, i, 0, 0, 0) != MMSYSERR_NOERROR) { //这里修改麦克风音量是没有问题的,第一个你要找出那个混音器是麦克风啊 printf("mixer open failed ...\n"); MessageBoxW(NULL, L"Error: mixerOpen()", NULL, MB_ICONHAND); return false; } // Get the line info MIXERCAPS mixcaps; MIXERLINE mixerLine; mixerGetDevCaps(i, &mixcaps, sizeof(MIXERCAPS)); mixerLine.cbStruct = sizeof(MIXERLINE); mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; //用MIXERLINE_COMPONENTTYPE_DST_WAVEIN 作参数可得到所有录音的Connection mixerLine.dwSource = 0; mixerLine.dwDestination = 0; if (mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(mixer), &mixerLine, MIXER_GETLINEINFOF_SOURCE) != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Error: mixerGetLineInfo()", NULL, MB_ICONHAND); return false; } if(mixerLine.dwComponentType !=MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE ){ printf("i = %d ,this device is not microphone \n" ,i); mixerClose(mixer); continue; } is_find_mic = true; printf("mixerLine.dwComponentType = %xH ,MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = %xH \n" ,mixerLine.dwComponentType ,MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE); //下面的代码只有是耳麦的时候才去执行 // Get control for mixerline MIXERCONTROL mixerCtrl; MIXERLINECONTROLS mixerLineCtrl; mixerLineCtrl.cbStruct = sizeof(MIXERLINECONTROLS); mixerLineCtrl.dwLineID = mixerLine.dwLineID; mixerLineCtrl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mixerLineCtrl.cControls = 1; mixerLineCtrl.pamxctrl = &mixerCtrl; mixerLineCtrl.cbmxctrl = sizeof(MIXERCONTROL); mixerLineCtrl.cControls = 5; if (mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(mixer), &mixerLineCtrl, MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Error: mixerGetLineControls()", NULL, MB_ICONHAND); return false; } // Volume.. MIXERCONTROLDETAILS mixerCtrlDetails; MIXERCONTROLDETAILS_UNSIGNED mixerCtrlDetailsUnsigned; mixerCtrlDetailsUnsigned.dwValue = volume; //volume size mixerCtrlDetails.dwControlID = mixerCtrl.dwControlID; mixerCtrlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); mixerCtrlDetails.cMultipleItems = 0; mixerCtrlDetails.paDetails = &mixerCtrlDetailsUnsigned; mixerCtrlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); mixerCtrlDetails.cChannels = 1; if (mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(mixer), &mixerCtrlDetails, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) { MessageBoxW(NULL, L"Error: mixerSetControlDetails()", NULL, MB_ICONHAND); return false; } mixerClose(mixer); }//for loop return is_find_mic; }
VOID InitVolumeControls(HWND hwndDlg, PGLOBAL_DATA pGlobalData) { UINT NumMixers; MIXERCAPS mxc; TCHAR szNoDevices[256]; CheckDlgButton(hwndDlg, IDC_ICON_IN_TASKBAR, GetSystrayVolumeIconState() ? BST_CHECKED : BST_UNCHECKED); LoadString(hApplet, IDS_NO_DEVICES, szNoDevices, _countof(szNoDevices)); NumMixers = mixerGetNumDevs(); if (!NumMixers) { EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MUTE_CHECKBOX), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED_BTN), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_SPEAKER_VOL_BTN), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED2_BTN), FALSE); SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconNoHW); SetDlgItemText(hwndDlg, IDC_DEVICE_NAME, szNoDevices); return; } if (mixerOpen(&pGlobalData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR) { MessageBox(hwndDlg, _T("Cannot open mixer"), NULL, MB_OK); return; } ZeroMemory(&mxc, sizeof(MIXERCAPS)); if (mixerGetDevCaps(PtrToUint(pGlobalData->hMixer), &mxc, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR) { MessageBox(hwndDlg, _T("mixerGetDevCaps failed"), NULL, MB_OK); return; } GetMuteControl(pGlobalData); GetMuteState(pGlobalData); if (pGlobalData->muteVal) { SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0); SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted); } else { SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0); SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted); } GetVolumeControl(pGlobalData); GetVolumeValue(pGlobalData); SendDlgItemMessage(hwndDlg, IDC_DEVICE_NAME, WM_SETTEXT, 0, (LPARAM)mxc.szPname); SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(pGlobalData->volumeMinimum, pGlobalData->volumeMaximum/VOLUME_DIVIDER)); SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPAGESIZE, (WPARAM)FALSE, (LPARAM)1); SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETSEL, (WPARAM)FALSE, (LPARAM)MAKELONG(pGlobalData->volumeMinimum, pGlobalData->volumeValue/VOLUME_DIVIDER)); SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pGlobalData->volumeValue/VOLUME_DIVIDER); }
int SelectRecordingLine(unsigned int nMixerId, unsigned int nComponentID, char *user_mixer_line, unsigned int nLeftVolume, unsigned int nRightVolume) { // check windows version because this can't work on VIsta and Windows 7 OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(GetVersionEx(&osvi) == 0) return 1; // don't fail, just exit function // check if we have Vista or WIndows / if(osvi.dwMajorVersion > 5) return 1; unsigned int dwVolumeControlID = 0; unsigned int dwControlType = 0; unsigned int dwSelectControlID = 0; unsigned int dwMultipleItems = 0; unsigned int dwIndex = 0xFFFFFFFF; HMIXER hMixer = NULL; MIXERCAPS mxcaps; ::ZeroMemory(&mxcaps, sizeof(MIXERCAPS)); if(nComponentID >= WAVE_IN_NUM) return 0; // open mixer if(mixerOpen(&hMixer, (unsigned int) nMixerId, 0, 0, MIXER_OBJECTF_HWAVEIN) != MMSYSERR_NOERROR) return 0; if(mixerGetDevCaps((unsigned int) hMixer, &mxcaps, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR) { ::mixerClose(hMixer); return 0; } // get control we need if (hMixer == NULL) return 0; // get dwLineID MIXERLINE mxl; mxl.cbStruct = sizeof(MIXERLINE); mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; if (mixerGetLineInfo((HMIXEROBJ) hMixer, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR) { mixerClose(hMixer); return 0; } // get dwControlID MIXERCONTROL mxc; MIXERLINECONTROLS mxlc; dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER; mxlc.cbStruct = sizeof(MIXERLINECONTROLS); mxlc.dwLineID = mxl.dwLineID; mxlc.dwControlType = dwControlType; mxlc.cControls = 1; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = &mxc; if (mixerGetLineControls((HMIXEROBJ) hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) { // no mixer, try MUX dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; mxlc.cbStruct = sizeof(MIXERLINECONTROLS); mxlc.dwLineID = mxl.dwLineID; mxlc.dwControlType = dwControlType; mxlc.cControls = 1; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = &mxc; if (mixerGetLineControls((HMIXEROBJ) hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR) { mixerClose(hMixer); return 0; } } // store dwControlID, cMultipleItems dwSelectControlID = mxc.dwControlID; dwMultipleItems = mxc.cMultipleItems; if (dwMultipleItems == 0) { mixerClose(hMixer); return 0; } DWORD dwControlID = 0; DWORD dwLine = 0; // get the index of the specified Select control MIXERCONTROLDETAILS_LISTTEXT *pmxcdSelectText = new MIXERCONTROLDETAILS_LISTTEXT[dwMultipleItems]; DWORD dwi = 0; if (pmxcdSelectText != NULL) { MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = dwSelectControlID; mxcd.cChannels = 1; mxcd.cMultipleItems = dwMultipleItems; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT); mxcd.paDetails = pmxcdSelectText; if (mixerGetControlDetails((HMIXEROBJ) hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_LISTTEXT) == MMSYSERR_NOERROR) { for (dwi = 0; dwi < dwMultipleItems; dwi++) { // get the line information MIXERLINE mxl; mxl.cbStruct = sizeof(MIXERLINE); mxl.dwLineID = pmxcdSelectText[dwi].dwParam1; if (mixerGetLineInfo((HMIXEROBJ) hMixer, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID) == MMSYSERR_NOERROR && mxl.dwComponentType == g_wavein_id[nComponentID].id) { // check specified user name if(user_mixer_line) { if(strcmp(user_mixer_line, mxl.szShortName) != 0 && strcmp(user_mixer_line, mxl.szName) != 0) continue; } // found, dwi is the index. dwIndex = dwi; dwLine = pmxcdSelectText[dwIndex].dwParam1; break; } } if (dwi >= dwMultipleItems) { if(user_mixer_line) { // could not find it using line IDs, some mixer drivers have // different meaning for MIXERCONTROLDETAILS_LISTTEXT.dwParam1. // let's try comparing the item names. for (dwi = 0; dwi < dwMultipleItems; dwi++) { if (stricmp(pmxcdSelectText[dwi].szName, user_mixer_line) == 0) { // found, dwi is the index. dwIndex = dwi; dwLine = pmxcdSelectText[dwIndex].dwParam1; break; } } // error if (dwi >= dwMultipleItems) { mixerClose(hMixer); delete []pmxcdSelectText; return 0; } } } if (dwi >= dwMultipleItems) { // could not find it using line IDs, some mixer drivers have // different meaning for MIXERCONTROLDETAILS_LISTTEXT.dwParam1. // let's try comparing the item names. for (dwi = 0; dwi < dwMultipleItems; dwi++) { if (stricmp(pmxcdSelectText[dwi].szName, g_wavein_id[nComponentID].string_name1) == 0) { // found, dwi is the index. dwIndex = dwi; dwLine = pmxcdSelectText[dwIndex].dwParam1; break; } } } if (dwi >= dwMultipleItems) { // could not find it using line IDs, some mixer drivers have // different meaning for MIXERCONTROLDETAILS_LISTTEXT.dwParam1. // let's try comparing the item names. for (dwi = 0; dwi < dwMultipleItems; dwi++) { if (stricmp(pmxcdSelectText[dwi].szName, g_wavein_id[nComponentID].string_name2) == 0) { // found, dwi is the index. dwIndex = dwi; dwLine = pmxcdSelectText[dwIndex].dwParam1; break; } } } if (dwi >= dwMultipleItems) { // could not find it using line IDs, some mixer drivers have // different meaning for MIXERCONTROLDETAILS_LISTTEXT.dwParam1. // let's try comparing the item names. for (dwi = 0; dwi < dwMultipleItems; dwi++) { if (stricmp(pmxcdSelectText[dwi].szName, g_wavein_id[nComponentID].string_name3) == 0) { // found, dwi is the index. dwIndex = dwi; dwLine = pmxcdSelectText[dwIndex].dwParam1; break; } } } } delete []pmxcdSelectText; } // select component if (dwIndex >= dwMultipleItems) { mixerClose(hMixer); return 0; } // get the line information int ret = 0; // get all the values first MIXERCONTROLDETAILS_BOOLEAN *pmxcdSelectValue = new MIXERCONTROLDETAILS_BOOLEAN[dwMultipleItems]; if (pmxcdSelectValue != NULL) { // select control MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = dwSelectControlID; mxcd.cChannels = 1; mxcd.cMultipleItems = dwMultipleItems; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); mxcd.paDetails = pmxcdSelectValue; if (mixerGetControlDetails((HMIXEROBJ) hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR) { // MUX restricts the line selection to one source line at a time. if (dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) ZeroMemory(pmxcdSelectValue, dwMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN)); // set the value pmxcdSelectValue[dwIndex].fValue = 1; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = dwSelectControlID; mxcd.cChannels = 1; mxcd.cMultipleItems = dwMultipleItems; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); mxcd.paDetails = pmxcdSelectValue; if (mixerSetControlDetails((HMIXEROBJ) hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) == MMSYSERR_NOERROR) { ret = 1; } } delete []pmxcdSelectValue; } // set volume, if volume is larger than 100 skip volume change if(nLeftVolume <= 100 && nRightVolume <= 100) { mxl.cbStruct = sizeof(MIXERLINE); mxl.dwLineID = dwLine; if (mixerGetLineInfo((HMIXEROBJ) hMixer, &mxl, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID) == MMSYSERR_NOERROR) { mxlc.cbStruct = sizeof(MIXERLINECONTROLS); mxlc.dwLineID = dwLine; mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = &mxc; if (mixerGetLineControls((HMIXEROBJ) hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR) { if(nLeftVolume > 100) nLeftVolume = 100; if(nRightVolume > 100) nRightVolume = 100; MIXERCONTROLDETAILS_UNSIGNED mxcdVolume[2] = { mxc.Bounds.dwMaximum * nLeftVolume / 100, mxc.Bounds.dwMaximum * nRightVolume / 100}; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mxcd.dwControlID = mxc.dwControlID; mxcd.cChannels = mxl.cChannels; mxcd.cMultipleItems = 0; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); mxcd.paDetails = mxcdVolume; if (mixerSetControlDetails((HMIXEROBJ) hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR) { // error, can't set volume } } else { // error can't set volume } } } mixerClose(hMixer); return ret; }
BOOL CALLBACK MixerPlus_OptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static PMIXERPLUS_INFO pinfo = NULL; UINT i; MIXERCAPS mxcaps; switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: pinfo->dwMixerID = (DWORD) SendDlgItemMessage(hDlg, IDC_DEVICE, CB_GETCURSEL, 0, 0); if(IsDlgButtonChecked(hDlg, IDC_MODE_PLAYBACK) == BST_CHECKED) pinfo->mode = MIXERPLUS_MODE_PLAYBACK; else pinfo->mode = MIXERPLUS_MODE_RECORDING; EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } break; case WM_INITDIALOG: pinfo = (PMIXERPLUS_INFO) lParam; for(i = 0; i < mixerGetNumDevs(); i++) if(!MMERROR(mixerGetDevCaps(i, &mxcaps, sizeof(mxcaps)))) { SendDlgItemMessage(hDlg, IDC_DEVICE, CB_ADDSTRING, 0, (LPARAM) mxcaps.szPname); } SendDlgItemMessage(hDlg, IDC_DEVICE, CB_SETCURSEL, pinfo->dwMixerID, 0); if(pinfo->mode == MIXERPLUS_MODE_PLAYBACK) CheckDlgButton(hDlg, IDC_MODE_PLAYBACK, BST_CHECKED); else CheckDlgButton(hDlg, IDC_MODE_RECORDING, BST_CHECKED); return TRUE; } return FALSE; }
// // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_CREATE: { RECT rc; GetWindowRect(hWnd, &rc); hwndList = CreateWindow(TEXT("listbox"), NULL, WS_CHILD | WS_VISIBLE, 0, 0, rc.right-rc.left, rc.bottom-rc.top, hWnd, (HMENU)1, hInst, NULL); break; } case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: { //DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); SendMessage(hwndList, LB_RESETCONTENT, 0, 0); int numDevs = mixerGetNumDevs(); if (numDevs == 0) { MessageBox(hWnd, TEXT("No audio mixer devices found."), NULL, MB_OK); break; } #define MSG_LEN 1024 TCHAR msg[MSG_LEN+1]; TCHAR lpszComponent[MSG_LEN]; UINT nDevId = 0, uDest, uConnect, uConnections; MIXERCAPS mxcaps; MMRESULT rc; HMIXER hmx = NULL; for (int i=0; i<numDevs; i++) { mixerGetDevCaps(i, &mxcaps, sizeof(MIXERCAPS)); wsprintf(msg, TEXT("Device name: %s\t#Destinations: %ld"), mxcaps.szPname, mxcaps.cDestinations); SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)msg); rc = mixerOpen(&hmx, i, (DWORD_PTR)hWnd, NULL, CALLBACK_WINDOW | MIXER_OBJECTF_MIXER); if (rc != MMSYSERR_NOERROR) { MessageBox(hWnd, TEXT("Error opening mixer deivce"), NULL, MB_OK); mixerClose(hmx); continue; } lstrcpy(msg, TEXT("Type\tComponent\tName\tLine ID\tFlags\tCtls\tConnections")); SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)msg); MIXERLINE mxl; for (uDest = 0; uDest < mxcaps.cDestinations; uDest++) { mxl.cbStruct = sizeof(mxl); mxl.dwDestination = uDest; rc = mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_DESTINATION); if (rc != MMSYSERR_NOERROR) { wsprintf(msg, TEXT("mixerGetLineInfo(dst=%u) failed. rc=%u!"), uDest, rc); MessageBox(hWnd, msg, NULL, MB_OK); continue; } GetComponentType(&mxl, lpszComponent); wsprintf(msg, TEXT("%s\t%-25s\t%-25s\t%.08lXh\t%.08lXh\t%lu\t%lu"), (MIXERLINE_LINEF_ACTIVE & mxl.fdwLine) ? TEXT("Dest Active") : TEXT("Dest Inactive"), lpszComponent, mxl.szName, mxl.dwLineID, mxl.fdwLine, mxl.cControls, mxl.cConnections); SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)msg); uConnections = mxl.cConnections; for (uConnect = 0; uConnect < uConnections; uConnect++) { mxl.cbStruct = sizeof(mxl); mxl.dwDestination = uDest; mxl.dwSource = uConnect; rc = mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_SOURCE); if (rc != MMSYSERR_NOERROR) { wsprintf(msg, TEXT("mixerGetLineInfo(src=%u) failed. rc=%u!"), uConnect, rc); MessageBox(hWnd, msg, NULL, MB_OK); continue; } GetComponentType(&mxl, lpszComponent); wsprintf(msg, TEXT("%s\t%-25s\t%-25s\t%.08lXh\t%.08lXh\t%lu\t%lu"), (MIXERLINE_LINEF_ACTIVE & mxl.fdwLine) ? TEXT("Src Active") : TEXT("Src Inactive"), lpszComponent, mxl.szName, mxl.dwLineID, mxl.fdwLine, mxl.cControls, mxl.cConnections); SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)msg); } SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)TEXT("")); } } break; } case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
void Mixer::getPortsInfo() { MIXERCAPS mc; mixerGetDevCaps((UINT)hMixer, &mc, sizeof mc); MIXERLINE mlt; unsigned i; for (i = 0; i < mc.cDestinations; ++i) { memset(&mlt, 0, sizeof mlt); mlt.cbStruct = sizeof mlt; mlt.dwDestination = i; if (mixerGetLineInfo((HMIXEROBJ)hMixer, &mlt, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR) continue; if (mlt.dwLineID == dwRecLineID) break; // this is the destination we're interested in } ports = new AudioInputPort[mlt.cConnections]; numPorts = mlt.cConnections; for (i = 0; i < numPorts; ++i) { MIXERLINE mlc; memcpy(&mlc, &mlt, sizeof mlc); mlc.dwSource = i; mixerGetLineInfo((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINEINFOF_SOURCE/*|MIXER_OBJECTF_HMIXER*/); ports[i].tag = mlc.dwLineID; ports[i].dwComponentType = mlc.dwComponentType; #ifdef UNICODE wcstombs(ports[i].name, mlc.szName, MIXER_LONG_NAME_CHARS); #else strncpy(ports[i].name, mlc.szName, MIXER_LONG_NAME_CHARS); #endif } // Make the microphone the first port in the list: for (i = 1; i < numPorts; ++i) { #ifdef OLD_MICROPHONE_TESTING_CODE if (_strnicmp("mic", ports[i].name, 3) == 0 || _strnicmp("mik", ports[i].name, 3) == 0) { #else if (ports[i].dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) { #endif AudioInputPort tmp = ports[0]; ports[0] = ports[i]; ports[i] = tmp; } } } Boolean Mixer::enableInputPort(unsigned portIndex, char const*& errReason, MMRESULT& errCode) { errReason = NULL; // unless there's an error AudioInputPort& port = ports[portIndex]; MIXERCONTROL mc; mc.cMultipleItems = 1; // in case it doesn't get set below MIXERLINECONTROLS mlc; #if 0 // the following doesn't seem to be needed, and can fail: mlc.cbStruct = sizeof mlc; mlc.pamxctrl = &mc; mlc.cbmxctrl = sizeof (MIXERCONTROL); mlc.dwLineID = port.tag; mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { errReason = "mixerGetLineControls()"; return False; } #endif MIXERLINE ml; memset(&ml, 0, sizeof (MIXERLINE)); ml.cbStruct = sizeof (MIXERLINE); ml.dwLineID = port.tag; if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID)) != MMSYSERR_NOERROR) { errReason = "mixerGetLineInfo()1"; return False; } #ifdef UNICODE wchar_t portname[MIXER_LONG_NAME_CHARS+1]; wcsncpy(portname, ml.szName, MIXER_LONG_NAME_CHARS); #else char portname[MIXER_LONG_NAME_CHARS+1]; strncpy(portname, ml.szName, MIXER_LONG_NAME_CHARS); #endif memset(&ml, 0, sizeof (MIXERLINE)); ml.cbStruct = sizeof (MIXERLINE); ml.dwLineID = dwRecLineID; if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { errReason = "mixerGetLineInfo()2"; return False; } // Get Mixer/MUX control information (need control id to set and get control details) mlc.cbStruct = sizeof mlc; mlc.dwLineID = ml.dwLineID; mlc.cControls = 1; mc.cbStruct = sizeof mc; // Needed???##### mc.dwControlID = 0xDEADBEEF; // For testing ##### mlc.pamxctrl = &mc; mlc.cbmxctrl = sizeof mc; mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; // Single Select if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER; // Multiple Select mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/); } unsigned matchLine = 0; if (mc.cMultipleItems > 1) { // Before getting control, we need to know which line to grab. // We figure this out by listing the lines, and comparing names: MIXERCONTROLDETAILS mcd; mcd.cbStruct = sizeof mcd; mcd.cChannels = ml.cChannels; mcd.cMultipleItems = mc.cMultipleItems; MIXERCONTROLDETAILS_LISTTEXT* mcdlText = new MIXERCONTROLDETAILS_LISTTEXT[mc.cMultipleItems]; mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_LISTTEXT); mcd.paDetails = mcdlText; if (mc.dwControlID != 0xDEADBEEF) { // we know the control id for real mcd.dwControlID = mc.dwControlID; if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { delete[] mcdlText; errReason = "mixerGetControlDetails()1"; return False; } } else { // Hack: We couldn't find a MUX or MIXER control, so try to guess the control id: for (mc.dwControlID = 0; mc.dwControlID < 32; ++mc.dwControlID) { mcd.dwControlID = mc.dwControlID; if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT/*|MIXER_OBJECTF_HMIXER*/)) == MMSYSERR_NOERROR) break; } if (mc.dwControlID == 32) { // unable to guess mux/mixer control id delete[] mcdlText; errReason = "mixerGetControlDetails()2"; return False; } } #ifdef UNICODE for (unsigned i = 0; i < mcd.cMultipleItems; ++i) { if (wcscmp(mcdlText[i].szName, portname) == 0) { matchLine = i; break; } } #else for (unsigned i = 0; i < mcd.cMultipleItems; ++i) { if (strcmp(mcdlText[i].szName, portname) == 0) { matchLine = i; break; } } #endif delete[] mcdlText; } // Now get control itself: MIXERCONTROLDETAILS mcd; mcd.cbStruct = sizeof mcd; mcd.dwControlID = mc.dwControlID; mcd.cChannels = ml.cChannels; mcd.cMultipleItems = mc.cMultipleItems; MIXERCONTROLDETAILS_BOOLEAN* mcdbState = new MIXERCONTROLDETAILS_BOOLEAN[mc.cMultipleItems]; mcd.paDetails = mcdbState; mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_BOOLEAN); if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_VALUE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { delete[] mcdbState; errReason = "mixerGetControlDetails()3"; return False; } for (unsigned j = 0; j < mcd.cMultipleItems; ++j) { mcdbState[j].fValue = (j == matchLine); } if ((errCode = mixerSetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_OBJECTF_HMIXER)) != MMSYSERR_NOERROR) { delete[] mcdbState; errReason = "mixerSetControlDetails()"; return False; } delete[] mcdbState; return True; }
LRESULT CALLBACK MixerPlus_MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HMIXER hMixer = NULL; static DWORD dwLines = 0; // Must always count plinfo correctly static PMIXERPLUS_INFO pinfo = NULL; static PMIXERPLUS_LINE_INFO plinfo = NULL; // Array static HWND hCFader = NULL; static DWORD dwControlFlags = 0; static MIXERLINE mxlineDest; static MIXERPLUS_CONTROL_FEED feed; UINT i, j; RECT rcCtrl, rcCFader, rcWnd; SCROLLINFO si; MIXERCAPS mxcaps; MIXERLINE mxlineSrc; MIXERLINECONTROLS mxlctls; MIXERCONTROL mxctl; MIXERCONTROLDETAILS mxcdtls; TCHAR szTitle[MIXERPLUS_MAX_TITLE]; switch(uMsg) { case MM_MIXM_LINE_CHANGE: for(i = 0; i < dwLines; i++) if(((DWORD) lParam) == plinfo[i].dwLineID) { SendMessage(plinfo[i].hCtrl, uMsg, wParam, lParam); return 0; } break; case MM_MIXM_CONTROL_CHANGE: for(i = 0; i < dwLines; i++) { /* Check if child contains control for which this message is intended */ if(((plinfo[i].dwControlFlags & MIXERPLUS_LINE_CONTROL_VOLUME) && ((DWORD) lParam) == plinfo[i].volume.dwID) || ((plinfo[i].dwControlFlags & MIXERPLUS_LINE_CONTROL_MUTE) && ((DWORD) lParam) == plinfo[i].mute.dwID)) { SendMessage(plinfo[i].hCtrl, uMsg, wParam, lParam); return 0; } } if((dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) && (((DWORD) lParam) == feed.dwID)) { mxlctls.cbStruct = sizeof(mxlctls); mxlctls.cbmxctrl = sizeof(mxctl); mxlctls.dwControlID = feed.dwID; mxlctls.pamxctrl = &mxctl; if(MMERROR(mixerGetLineControls((HMIXEROBJ) hMixer, &mxlctls, MIXER_GETLINECONTROLSF_ONEBYID))) { return 0; } if(feed.dwSources != mxctl.cMultipleItems) { /* Reallocate */ HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_lt); HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_b); feed.pmxcdtls_lt = (LPMIXERCONTROLDETAILS_LISTTEXT) HeapAlloc(pinfo->hHeap, 0, mxctl.cMultipleItems * sizeof(MIXERCONTROLDETAILS_LISTTEXT)); feed.pmxcdtls_b = (LPMIXERCONTROLDETAILS_BOOLEAN) HeapAlloc(pinfo->hHeap, 0, mxctl.cMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN)); if(!feed.pmxcdtls_lt || !feed.pmxcdtls_b) { dwControlFlags &= ~MIXERPLUS_LINE_CONTROL_FEED; MixerPlus_ErrorBox(hWnd, TEXT("Cannot allocate memory. Check available memory.")); DestroyWindow(hWnd); return 0; } feed.dwSources = mxctl.cMultipleItems; } mxcdtls.cbStruct = sizeof(mxcdtls); mxcdtls.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT); mxcdtls.dwControlID = feed.dwID; mxcdtls.cMultipleItems = feed.dwSources; mxcdtls.cChannels = 1; mxcdtls.paDetails = feed.pmxcdtls_lt; if(MMERROR(mixerGetControlDetails((HMIXEROBJ) hMixer, &mxcdtls, MIXER_GETCONTROLDETAILSF_LISTTEXT))) { return 0; } mxcdtls.cbStruct = sizeof(mxcdtls); mxcdtls.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); mxcdtls.dwControlID = feed.dwID; mxcdtls.cMultipleItems = feed.dwSources; mxcdtls.cChannels = 1; mxcdtls.paDetails = feed.pmxcdtls_b; if(MMERROR(mixerGetControlDetails((HMIXEROBJ) hMixer, &mxcdtls, MIXER_GETCONTROLDETAILSF_VALUE))) { return 0; } for(i = 0; i < dwLines; i++) for(j = 0; j < feed.dwSources; j++) if(plinfo[i].dwLineID == feed.pmxcdtls_lt[j].dwParam1) CheckDlgButton(plinfo[i].hCtrl, IDB_POWER, feed.pmxcdtls_b[j].fValue ? BST_CHECKED : BST_UNCHECKED); } break; case WM_HSCROLL: /* Get scroll position */ si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hWnd, SB_HORZ, &si); /* Adjust */ switch(LOWORD(wParam)) { case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; case SB_LINELEFT: case SB_PAGELEFT: si.nPos--; break; case SB_LINERIGHT: case SB_PAGERIGHT: si.nPos++; break; case SB_LEFT: si.nPos = si.nMin; break; case SB_RIGHT: si.nPos = si.nMax; break; } SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); /* Allow for adjustments by Windows */ si.cbSize = sizeof(si); si.fMask = SIF_POS; GetScrollInfo(hWnd, SB_HORZ, &si); /* Move child windows */ for(i = 0; i < dwLines; i++) { GetWindowRect(plinfo[i].hCtrl, &rcCtrl); MoveWindow(plinfo[i].hCtrl, (i - si.nPos) * (rcCtrl.right - rcCtrl.left), 0, (rcCtrl.right - rcCtrl.left), (rcCtrl.bottom - rcCtrl.top), TRUE); } return TRUE; case WM_COMMAND: /* Passed from crossfader */ if(LOWORD(wParam) == IDB_FADE && HIWORD(wParam) == BN_CLICKED) { /* Get indices */ i = (DWORD) SendDlgItemMessage(hCFader, IDC_SOURCE, CB_GETCURSEL, 0, 0); j = (DWORD) SendDlgItemMessage(hCFader, IDC_TARGET, CB_GETCURSEL, 0, 0); /* Do nothing if source is target */ if(i == j) return TRUE; /* Start faders */ SendMessage(plinfo[i].hCtrl, WM_COMMAND, MAKEWPARAM(IDB_FADEOUT, BN_CLICKED), (LPARAM) GetDlgItem(plinfo[i].hCtrl, IDB_FADEOUT)); SendMessage(plinfo[j].hCtrl, WM_COMMAND, MAKEWPARAM(IDB_FADEIN, BN_CLICKED), (LPARAM) GetDlgItem(plinfo[j].hCtrl, IDB_FADEIN)); return TRUE; } /* Passed from feed button */ else if((dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) && LOWORD(wParam) == IDB_POWER && HIWORD(wParam) == BN_CLICKED) { mxcdtls.cbStruct = sizeof(mxcdtls); mxcdtls.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); mxcdtls.dwControlID = feed.dwID; mxcdtls.cMultipleItems = feed.dwSources; mxcdtls.cChannels = 1; mxcdtls.paDetails = feed.pmxcdtls_b; for(i = 0; i < dwLines; i++) if(((HWND) lParam) == GetDlgItem(plinfo[i].hCtrl, IDB_POWER)) { for(j = 0; j < feed.dwSources; j++) if(plinfo[i].dwLineID == feed.pmxcdtls_lt[j].dwParam1) { ZeroMemory(feed.pmxcdtls_b, feed.dwSources * sizeof(MIXERCONTROLDETAILS_BOOLEAN)); feed.pmxcdtls_b[j].fValue = !(IsDlgButtonChecked(plinfo[i].hCtrl, IDB_POWER) == BST_CHECKED); mixerSetControlDetails((HMIXEROBJ) hMixer, &mxcdtls, MIXER_SETCONTROLDETAILSF_VALUE); return TRUE; } break; } return TRUE; } switch(LOWORD(wParam)) { case ID_FILE_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0); return 0; case ID_TOOLS_OPTIONS: /* Show options dialog box */ if(DialogBoxParam(pinfo->hInstance, MAKEINTRESOURCE(IDD_OPTIONS), hWnd, (DLGPROC) MixerPlus_OptionsDlgProc, (LPARAM) pinfo) != IDOK) { return TRUE; } /* Destroy everything */ for(i = 0; i < dwLines; i++) DestroyWindow(plinfo[i].hCtrl); if(hCFader) { DestroyWindow(hCFader); hCFader = NULL; } if(dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) { dwControlFlags &= ~MIXERPLUS_LINE_CONTROL_FEED; HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_lt); HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_b); } if(plinfo) { HeapFree(pinfo->hHeap, 0, plinfo); plinfo = NULL; dwLines = 0; } if(hMixer) { mixerClose(hMixer); hMixer = NULL; } /* Recreate */ SendMessage(hWnd, WM_CREATE, 0, 0); // Do not need to set this since pinfo not NULL return 0; case ID_HELP_ABOUT: MessageBox(hWnd, TEXT("Mixer Plus v0.2\n\nWritten by John Peloquin"), TEXT("Mixer Plus"), MB_ICONINFORMATION); return 0; } break; case WM_CREATE: /* NOTE: This message is also simulated when the user changes options */ /* Get init info if we do not aleady have it */ if(!pinfo) pinfo = (PMIXERPLUS_INFO)(((LPCREATESTRUCT) lParam)->lpCreateParams); /* Open mixer device */ if(MMERROR(mixerOpen(&hMixer, pinfo->dwMixerID, (DWORD_PTR) hWnd, 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW))) { MixerPlus_ErrorBox(hWnd, TEXT("Cannot open mixer device.")); return 0; } if(!MMERROR(mixerGetDevCaps((UINT) hMixer, &mxcaps, sizeof(mxcaps)))) { if(SUCCEEDED(StringCchPrintf(szTitle, LENGTHOF(szTitle), TEXT("Mixer Plus [%s - %s]"), mxcaps.szPname, (pinfo->mode == MIXERPLUS_MODE_PLAYBACK) ? TEXT("Playback") : TEXT("Recording")))) { SetWindowText(hWnd, szTitle); } } /* Get mixer destination line info */ mxlineDest.cbStruct = sizeof(mxlineDest); mxlineDest.dwComponentType = (pinfo->mode == MIXERPLUS_MODE_PLAYBACK) ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN; if(MMERROR(mixerGetLineInfo((HMIXEROBJ) hMixer, &mxlineDest, MIXER_GETLINEINFOF_COMPONENTTYPE))) { mixerClose(hMixer); MixerPlus_ErrorBox(hWnd, TEXT("Cannot open mixer destination line.")); return 0; } /* The output destination line also has volume and other controls, so we wish to treat it like a source line. We do not do this for the recording destination line */ dwLines = mxlineDest.cConnections + ((pinfo->mode == MIXERPLUS_MODE_PLAYBACK) ? 1 : 0); /* Allocate info block memory for destination line and its associated source lines */ if(!(plinfo = HeapAlloc(pinfo->hHeap, HEAP_ZERO_MEMORY, // This is necessary! dwLines * sizeof(MIXERPLUS_LINE_INFO)))) { mixerClose(hMixer); MixerPlus_ErrorBox(hWnd, TEXT("Cannot allocate memory. Check available memory.")); return -1; } /* Create crossfader */ if(dwLines > 0) { hCFader = CreateDialog(pinfo->hInstance, MAKEINTRESOURCE(IDD_CROSSFADER), hWnd, (DLGPROC) MixerPlus_CFaderDlgProc); } if(pinfo->mode == MIXERPLUS_MODE_PLAYBACK) { /* Put output destination line info at beginning of array */ i = 0; plinfo[i].mode = pinfo->mode; plinfo[i].hHeap = pinfo->hHeap; plinfo[i].hMixer = hMixer; plinfo[i].dwLineID = mxlineDest.dwLineID; plinfo[i].dwChannels = mxlineDest.cChannels; StringCchCopy(plinfo[i].szName, LENGTHOF(plinfo[i].szName), mxlineDest.szName); /* Add to crossfader lists */ SendDlgItemMessage(hCFader, IDC_SOURCE, CB_ADDSTRING, 0, (LPARAM) plinfo[i].szName); SendDlgItemMessage(hCFader, IDC_TARGET, CB_ADDSTRING, 0, (LPARAM) plinfo[i].szName); /* Create its child window */ if(plinfo[i].hCtrl = CreateDialogParam(pinfo->hInstance, MAKEINTRESOURCE(IDD_MIXERCTRL), hWnd, (DLGPROC) MixerPlus_CtrlDlgProc, (LPARAM) &plinfo[i])) { ShowWindow(plinfo[i].hCtrl, SW_SHOW); } } /* Get ahold of selection control for recording destination line */ else { mxlctls.cbStruct = sizeof(mxlctls); mxlctls.cbmxctrl = sizeof(mxctl); mxlctls.dwLineID = mxlineDest.dwLineID; mxlctls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; mxlctls.pamxctrl = &mxctl; if(!MMERROR(mixerGetLineControls((HMIXEROBJ) hMixer, &mxlctls, MIXER_GETLINECONTROLSF_ONEBYTYPE))) { feed.pmxcdtls_lt = (LPMIXERCONTROLDETAILS_LISTTEXT) HeapAlloc(pinfo->hHeap, 0, mxctl.cMultipleItems * sizeof(MIXERCONTROLDETAILS_LISTTEXT)); feed.pmxcdtls_b = (LPMIXERCONTROLDETAILS_BOOLEAN) HeapAlloc(pinfo->hHeap, 0, mxctl.cMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN)); if(!feed.pmxcdtls_lt || !feed.pmxcdtls_b) { mixerClose(hMixer); MixerPlus_ErrorBox(hWnd, TEXT("Cannot allocate memory. Check available memory.")); return -1; } dwControlFlags |= MIXERPLUS_LINE_CONTROL_FEED; feed.dwID = mxctl.dwControlID; feed.dwSources = mxctl.cMultipleItems; } } /* Get source line info and create child windows */ for(i = 0; i < mxlineDest.cConnections; i++) { j = (pinfo->mode == MIXERPLUS_MODE_PLAYBACK) ? i + 1 : i; mxlineSrc.cbStruct = sizeof(mxlineSrc); mxlineSrc.dwDestination = mxlineDest.dwDestination; mxlineSrc.dwSource = i; mixerGetLineInfo((HMIXEROBJ) hMixer, &mxlineSrc, MIXER_GETLINEINFOF_SOURCE); plinfo[j].mode = pinfo->mode; plinfo[j].hHeap = pinfo->hHeap; plinfo[j].hMixer = hMixer; plinfo[j].dwLineID = mxlineSrc.dwLineID; plinfo[j].dwChannels = mxlineSrc.cChannels; StringCchCopy(plinfo[j].szName, LENGTHOF(plinfo[j].szName), mxlineSrc.szName); /* Add to crossfader lists */ SendDlgItemMessage(hCFader, IDC_SOURCE, CB_ADDSTRING, 0, (LPARAM) plinfo[j].szName); SendDlgItemMessage(hCFader, IDC_TARGET, CB_ADDSTRING, 0, (LPARAM) plinfo[j].szName); if(plinfo[j].hCtrl = CreateDialogParam(pinfo->hInstance, MAKEINTRESOURCE(IDD_MIXERCTRL), hWnd, (DLGPROC) MixerPlus_CtrlDlgProc, (LPARAM) &plinfo[j])) { if(dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) { SetDlgItemText(plinfo[j].hCtrl, IDB_POWER, TEXT("Feed")); EnableWindow(GetDlgItem(plinfo[j].hCtrl, IDB_POWER), TRUE); } GetWindowRect(plinfo[j].hCtrl, &rcCtrl); MoveWindow(plinfo[j].hCtrl, j * (rcCtrl.right - rcCtrl.left), 0, rcCtrl.right - rcCtrl.left, rcCtrl.bottom - rcCtrl.top, FALSE); ShowWindow(plinfo[j].hCtrl, SW_SHOW); } } /* Adjust window */ if(dwLines > 0 && hCFader) { /* Simulate feed control update if necessary */ if(dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) SendMessage(hWnd, MM_MIXM_CONTROL_CHANGE, (WPARAM) hMixer, (LPARAM) feed.dwID); /* Initialize crossfader */ SendDlgItemMessage(hCFader, IDC_SOURCE, CB_SETCURSEL, 0, 0); SendDlgItemMessage(hCFader, IDC_TARGET, CB_SETCURSEL, 0, 0); GetWindowRect(hCFader, &rcCFader); MoveWindow(hCFader, 0, rcCtrl.bottom - rcCtrl.top, rcCFader.right - rcCFader.left, rcCFader.bottom - rcCFader.top, FALSE); ShowWindow(hCFader, SW_SHOW); /* Resize main window */ rcWnd.left = 0; rcWnd.top = 0; rcWnd.right = MIXERPLUS_LINES_PER_VIEW * (rcCtrl.right - rcCtrl.left); rcWnd.bottom = (rcCtrl.bottom - rcCtrl.top) + (rcCFader.bottom - rcCFader.top); AdjustWindowRect(&rcWnd, WS_CAPTION, TRUE); rcWnd.bottom += GetSystemMetrics(SM_CYHSCROLL); SetWindowPos(hWnd, HWND_TOP, 0, 0, rcWnd.right - rcWnd.left, rcWnd.bottom - rcWnd.top, SWP_NOMOVE); /* Set scroll range and position */ si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = max(0, dwLines - MIXERPLUS_LINES_PER_VIEW); si.nPos = 0; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } return 0; case WM_DESTROY: if(dwControlFlags & MIXERPLUS_LINE_CONTROL_FEED) { HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_lt); HeapFree(pinfo->hHeap, 0, feed.pmxcdtls_b); } /* BUG FIX: intermittent access violation on exit. Do not free plinfo here, as the child windows reference it during their WM_DESTROY processing, occurs after this (see MSDN). This is not a huge leak, as the heap is destroyed immediately after the message loop. */ /* if(plinfo) HeapFree(pinfo->hHeap, 0, plinfo); */ if(hMixer) mixerClose(hMixer); /* Kill message loop */ PostQuitMessage(0); return 0; } /* Pass message to default handler */ return DefWindowProc(hWnd, uMsg, wParam, lParam); }