| /* |
| * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| |
| #define USE_ERROR |
| //#define USE_TRACE |
| |
| #ifndef WIN32_EXTRA_LEAN |
| #define WIN32_EXTRA_LEAN |
| #endif |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif |
| |
| #include <windows.h> |
| #include <mmsystem.h> |
| #include "Ports.h" |
| |
| #if USE_PORTS == TRUE |
| |
| typedef struct tag_PortControlID PortControlID; |
| |
| typedef struct tag_PortInfo { |
| // Windows API stuff |
| HMIXER handle; |
| INT32 mixerIndex; |
| int dstLineCount; // how many MIXERLINE structs in dstMixerLine |
| MIXERLINE* dstLines; |
| int srcLineCount; // how many MIXERLINE structs in srcMixerLine |
| MIXERLINE* srcLines; // contains all the Source Lines of dstLines |
| // Java Sound mapping |
| int targetPortCount; // one port per dstLine (playback) |
| int sourcePortCount; // only WAVEIN; one port maps to one srcLine |
| LPMIXERLINE* ports; // points into dstLines and dstLines. Starts with Target Ports (Playback) |
| int maxControlCount; // upper bound of number of controls |
| int usedControlIDs; // number of items already filled in controlIDs |
| PortControlID* controlIDs; // the control IDs themselves |
| int usedMuxData; |
| MIXERCONTROLDETAILS_BOOLEAN* muxData; |
| } PortInfo; |
| |
| #define PORT_CONTROL_TYPE_BOOLEAN 1 |
| #define PORT_CONTROL_TYPE_SIGNED 2 |
| #define PORT_CONTROL_TYPE_UNSIGNED 3 |
| //#define PORT_CONTROL_TYPE_UNSIGNED_DB 4 |
| #define PORT_CONTROL_TYPE_FAKE_VOLUME 5 |
| #define PORT_CONTROL_TYPE_FAKE_BALANCE 6 |
| #define PORT_CONTROL_TYPE_MUX 5 |
| #define PORT_CONTROL_TYPE_MIXER 6 |
| |
| typedef struct tag_PortControlID { |
| PortInfo* portInfo; |
| INT32 controlType; // one of PORT_CONTROL_TYPE_XX |
| INT32 min; |
| INT32 max; |
| MIXERCONTROLDETAILS details; |
| union { |
| MIXERCONTROLDETAILS_BOOLEAN boolValue; |
| MIXERCONTROLDETAILS_SIGNED signedValue; |
| MIXERCONTROLDETAILS_UNSIGNED unsignedValue[2]; |
| INT32 muxIndex; |
| }; |
| } PortControlID; |
| |
| |
| int getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls); |
| |
| INT32 PORT_GetPortMixerCount() { |
| return (INT32) mixerGetNumDevs(); |
| } |
| |
| #ifdef USE_TRACE |
| |
| char* getLineFlags(DWORD flags) { |
| static char ret[100]; |
| ret[0]=0; |
| if (flags & MIXERLINE_LINEF_ACTIVE) { |
| strcat(ret, "ACTIVE "); |
| flags ^= MIXERLINE_LINEF_ACTIVE; |
| } |
| if (flags & MIXERLINE_LINEF_DISCONNECTED) { |
| strcat(ret, "DISCONNECTED "); |
| flags ^= MIXERLINE_LINEF_DISCONNECTED; |
| } |
| if (flags & MIXERLINE_LINEF_SOURCE) { |
| strcat(ret, "SOURCE "); |
| flags ^= MIXERLINE_LINEF_SOURCE; |
| } |
| if (flags!=0) { |
| UINT_PTR r = (UINT_PTR) ret; |
| r += strlen(ret); |
| sprintf((char*) r, "%d", flags); |
| } |
| return ret; |
| } |
| |
| char* getComponentType(int componentType) { |
| switch (componentType) { |
| case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return "DST_HEADPHONES"; |
| case MIXERLINE_COMPONENTTYPE_DST_LINE: return "DST_LINE"; |
| case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return "DST_SPEAKERS"; |
| case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return "DST_DIGITAL"; |
| case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return "DST_MONITOR"; |
| case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return "DST_TELEPHONE"; |
| case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return "DST_UNDEFINED"; |
| case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return "DST_VOICEIN"; |
| case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return "DST_WAVEIN"; |
| |
| case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return "SRC_COMPACTDISC"; |
| case MIXERLINE_COMPONENTTYPE_SRC_LINE: return "SRC_LINE"; |
| case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return "SRC_MICROPHONE"; |
| case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return "SRC_ANALOG"; |
| case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return "SRC_AUXILIARY"; |
| case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return "SRC_DIGITAL"; |
| case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return "SRC_PCSPEAKER"; |
| case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return "SRC_SYNTHESIZER"; |
| case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return "SRC_TELEPHONE"; |
| case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return "SRC_UNDEFINED"; |
| case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return "SRC_WAVEOUT"; |
| } |
| return ""; |
| } |
| |
| void printMixerLine(MIXERLINE* mixerLine) { |
| TRACE2("MIXERLINE destination=%d, source=%d, ", mixerLine->dwDestination, mixerLine->dwSource); |
| TRACE3("channels=%d, connections=%d, controls=%d, ", mixerLine->cChannels, mixerLine->cConnections, mixerLine->cControls); |
| TRACE3("\"%s\", fdwLine=%s, componentType=%s\n", mixerLine->szName, getLineFlags(mixerLine->fdwLine), getComponentType(mixerLine->dwComponentType)); |
| } |
| |
| char* getControlClass(int controlType) { |
| switch (controlType & MIXERCONTROL_CT_CLASS_MASK) { |
| case MIXERCONTROL_CT_CLASS_CUSTOM : return "CLASS_CUSTOM"; |
| case MIXERCONTROL_CT_CLASS_FADER : return "CLASS_FADER "; |
| case MIXERCONTROL_CT_CLASS_LIST : return "CLASS_LIST "; |
| case MIXERCONTROL_CT_CLASS_METER : return "CLASS_METER "; |
| case MIXERCONTROL_CT_CLASS_NUMBER : return "CLASS_NUMBER"; |
| case MIXERCONTROL_CT_CLASS_SLIDER : return "CLASS_SLIDER"; |
| case MIXERCONTROL_CT_CLASS_SWITCH : return "CLASS_SWITCH"; |
| case MIXERCONTROL_CT_CLASS_TIME : return "CLASS_TIME "; |
| } |
| return "unknown class"; |
| } |
| |
| char* getControlType(int controlType) { |
| switch (controlType) { |
| case MIXERCONTROL_CONTROLTYPE_CUSTOM : return "CUSTOM "; |
| case MIXERCONTROL_CONTROLTYPE_BASS : return "BASS "; |
| case MIXERCONTROL_CONTROLTYPE_EQUALIZER : return "EQUALIZER "; |
| case MIXERCONTROL_CONTROLTYPE_FADER : return "FADER "; |
| case MIXERCONTROL_CONTROLTYPE_TREBLE : return "TREBLE "; |
| case MIXERCONTROL_CONTROLTYPE_VOLUME : return "VOLUME "; |
| case MIXERCONTROL_CONTROLTYPE_MIXER : return "MIXER "; |
| case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT : return "MULTIPLESELECT "; |
| case MIXERCONTROL_CONTROLTYPE_MUX : return "MUX "; |
| case MIXERCONTROL_CONTROLTYPE_SINGLESELECT : return "SINGLESELECT "; |
| case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER : return "BOOLEANMETER "; |
| case MIXERCONTROL_CONTROLTYPE_PEAKMETER : return "PEAKMETER "; |
| case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER : return "SIGNEDMETER "; |
| case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER : return "UNSIGNEDMETER "; |
| case MIXERCONTROL_CONTROLTYPE_DECIBELS : return "DECIBELS "; |
| case MIXERCONTROL_CONTROLTYPE_PERCENT : return "PERCENT "; |
| case MIXERCONTROL_CONTROLTYPE_SIGNED : return "SIGNED "; |
| case MIXERCONTROL_CONTROLTYPE_UNSIGNED : return "UNSIGNED "; |
| case MIXERCONTROL_CONTROLTYPE_PAN : return "PAN "; |
| case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN : return "QSOUNDPAN "; |
| case MIXERCONTROL_CONTROLTYPE_SLIDER : return "SLIDER "; |
| case MIXERCONTROL_CONTROLTYPE_BOOLEAN : return "BOOLEAN "; |
| case MIXERCONTROL_CONTROLTYPE_BUTTON : return "BUTTON "; |
| case MIXERCONTROL_CONTROLTYPE_LOUDNESS : return "LOUDNESS "; |
| case MIXERCONTROL_CONTROLTYPE_MONO : return "MONO "; |
| case MIXERCONTROL_CONTROLTYPE_MUTE : return "MUTE "; |
| case MIXERCONTROL_CONTROLTYPE_ONOFF : return "ONOFF "; |
| case MIXERCONTROL_CONTROLTYPE_STEREOENH : return "STEREOENH "; |
| case MIXERCONTROL_CONTROLTYPE_MICROTIME : return "MICROTIME "; |
| case MIXERCONTROL_CONTROLTYPE_MILLITIME : return "MILLITIME "; |
| } |
| return "unknown"; |
| } |
| |
| char* getControlState(DWORD controlState) { |
| static char ret[100]; |
| ret[0]=0; |
| if (controlState & MIXERCONTROL_CONTROLF_DISABLED) { |
| strcat(ret, "DISABLED "); |
| controlState ^= MIXERCONTROL_CONTROLF_DISABLED; |
| } |
| if (controlState & MIXERCONTROL_CONTROLF_MULTIPLE) { |
| strcat(ret, "MULTIPLE "); |
| controlState ^= MIXERCONTROL_CONTROLF_MULTIPLE; |
| } |
| if (controlState & MIXERCONTROL_CONTROLF_UNIFORM) { |
| strcat(ret, "UNIFORM "); |
| controlState ^= MIXERCONTROL_CONTROLF_UNIFORM; |
| } |
| if (controlState!=0) { |
| UINT_PTR r = (UINT_PTR) ret; |
| r += strlen(ret); |
| sprintf((char*) r, "%d", controlState); |
| } |
| return ret; |
| } |
| |
| void printControl(MIXERCONTROL* control) { |
| TRACE3(" %s: dwControlType=%s/%s, ", control->szName, getControlClass(control->dwControlType), getControlType(control->dwControlType)); |
| TRACE3("multpleItems=%d, state=%d, %s\n", control->cMultipleItems, control->fdwControl, getControlState(control->fdwControl)); |
| } |
| |
| void printMixerLineControls(HMIXER handle, MIXERLINE* mixerLine) { |
| MIXERLINECONTROLS controls; |
| DWORD i; |
| TRACE1(" Controls for %s:\n", mixerLine->szName); |
| if (getControlInfo(handle, mixerLine, &controls)) { |
| for (i = 0; i < controls.cControls; i++) { |
| printControl(&controls.pamxctrl[i]); |
| } |
| if (controls.pamxctrl) { |
| free(controls.pamxctrl); |
| controls.pamxctrl = NULL; |
| } |
| } |
| } |
| |
| void printInfo(PortInfo* info) { |
| TRACE5(" PortInfo %p: handle=%p, mixerIndex=%d, dstLineCount=%d, dstLines=%p, ", info, (void*) info->handle, info->mixerIndex, info->dstLineCount, info->dstLines); |
| TRACE5("srcLineCount=%d, srcLines=%p, targetPortCount=%d, sourcePortCount=%d, ports=%p, ", info->srcLineCount, info->srcLines, info->targetPortCount, info->sourcePortCount, info->ports); |
| TRACE3("maxControlCount=%d, usedControlIDs=%d, controlIDs=%p \n", info->maxControlCount, info->usedControlIDs, info->controlIDs); |
| TRACE2("usedMuxData=%d, muxData=%p, controlIDs=%p \n", info->usedMuxData, info->muxData); |
| } |
| |
| #endif // USE_TRACE |
| |
| // internal utility functions |
| |
| int getMixerLineByDestination(HMIXER handle, DWORD dstIndex, MIXERLINE* mixerLine) { |
| mixerLine->cbStruct = sizeof(MIXERLINE); |
| mixerLine->dwDestination = dstIndex; |
| if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine, |
| MIXER_GETLINEINFOF_DESTINATION | MIXER_OBJECTF_HMIXER |
| ) == MMSYSERR_NOERROR) { |
| return TRUE; |
| } |
| mixerLine->cControls = 0; |
| mixerLine->cConnections = 0; |
| return FALSE; |
| } |
| |
| int getMixerLineByType(HMIXER handle, DWORD linetype, MIXERLINE* mixerLine) { |
| mixerLine->cbStruct = sizeof(MIXERLINE); |
| mixerLine->dwComponentType = linetype; |
| if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine, |
| MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_HMIXER |
| ) == MMSYSERR_NOERROR) { |
| return TRUE; |
| } |
| mixerLine->cControls = 0; |
| mixerLine->cConnections = 0; |
| return FALSE; |
| } |
| |
| int getMixerLineBySource(HMIXER handle, DWORD dstIndex, DWORD srcIndex, MIXERLINE* mixerLine) { |
| mixerLine->cbStruct = sizeof(MIXERLINE); |
| mixerLine->dwDestination = dstIndex; |
| mixerLine->dwSource = srcIndex; |
| if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine, |
| MIXER_GETLINEINFOF_SOURCE | MIXER_OBJECTF_HMIXER |
| ) == MMSYSERR_NOERROR) { |
| return TRUE; |
| } |
| mixerLine->cControls = 0; |
| mixerLine->cConnections = 0; |
| return FALSE; |
| } |
| |
| int getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) { |
| int ret = FALSE; |
| |
| //TRACE2(">getControlInfo for line %s with %d controls\n", line->szName, line->cControls); |
| controls->pamxctrl = NULL; |
| if (line->cControls > 0) { |
| // line points to the requested line. |
| // Reserve memory for the control infos |
| controls->cbStruct = sizeof(MIXERLINECONTROLS); |
| controls->dwLineID = line->dwLineID; |
| controls->cControls = line->cControls; |
| controls->cbmxctrl = sizeof(MIXERCONTROL); |
| controls->pamxctrl = (MIXERCONTROL*) malloc(sizeof(MIXERCONTROL) * line->cControls); |
| if (controls->pamxctrl) { |
| //TRACE0(" calling mixerGetLineControls\n"); |
| ret = mixerGetLineControls((HMIXEROBJ) handle, controls, |
| MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR; |
| } |
| } |
| if (!ret) { |
| if (controls->pamxctrl) { |
| free(controls->pamxctrl); |
| controls->pamxctrl = NULL; |
| } |
| } |
| //TRACE0("<getControlInfo \n"); |
| return ret; |
| } |
| |
| // returns TRUE if there are more than MIXER/MUX controls in this line |
| // if controls is non-NULL, it will be filled with the info |
| int lineHasControls(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) { |
| MIXERLINECONTROLS localControls; |
| int ret = FALSE; |
| UINT i; |
| |
| localControls.pamxctrl = NULL; |
| if (controls == NULL) { |
| controls = &localControls; |
| } |
| if (getControlInfo(handle, line, controls)) { |
| for (i = 0; !ret && (i < controls->cControls); i++) { |
| switch (controls->pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) { |
| case MIXERCONTROL_CT_CLASS_FADER : // fall through |
| case MIXERCONTROL_CT_CLASS_SLIDER : // fall through |
| case MIXERCONTROL_CT_CLASS_SWITCH : ret = TRUE; |
| } |
| } |
| } |
| if (localControls.pamxctrl) { |
| free(localControls.pamxctrl); |
| localControls.pamxctrl = NULL; |
| } |
| return ret; |
| } |
| |
| |
| ///// implemented functions of Ports.h |
| |
| 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; |
| } |
| return FALSE; |
| } |
| |
| int getDestinationCount(HMIXER handle) { |
| int ret = 0; |
| MIXERCAPS mixerCaps; |
| |
| if (mixerGetDevCaps((UINT_PTR) handle, &mixerCaps, sizeof(MIXERCAPS)) == MMSYSERR_NOERROR) { |
| ret = mixerCaps.cDestinations; |
| } |
| return ret; |
| } |
| |
| void* PORT_Open(INT32 mixerIndex) { |
| PortInfo* info = NULL; |
| MMRESULT mmres; |
| HMIXER handle; |
| MIXERLINE* waveInLine; |
| int success = FALSE; |
| int src, dst, srcIndex, waveInHasControls; |
| int dstCount; |
| |
| TRACE0("PORT_Open\n"); |
| mmres = mixerOpen((LPHMIXER) &handle, mixerIndex, 0, 0, MIXER_OBJECTF_MIXER); |
| if (mmres != MMSYSERR_NOERROR) { |
| return NULL; |
| } |
| |
| info = (PortInfo*) malloc(sizeof(PortInfo)); |
| if (info != NULL) { |
| success = TRUE; |
| memset(info, 0, sizeof(PortInfo)); |
| info->handle = handle; |
| info->mixerIndex = mixerIndex; |
| waveInLine = NULL; |
| waveInHasControls = FALSE; |
| // number of destinations |
| dstCount = getDestinationCount(handle); |
| if (dstCount) { |
| info->dstLines = (MIXERLINE*) malloc(dstCount * sizeof(MIXERLINE)); |
| success = (info->dstLines != NULL); |
| } |
| if (success && info->dstLines) { |
| // go through all destinations and fill the structures in PortInfo |
| for (dst = 0; dst < dstCount; dst++) { |
| if (getMixerLineByDestination(handle, dst, &info->dstLines[info->dstLineCount])) { |
| info->srcLineCount += info->dstLines[info->dstLineCount].cConnections; |
| if (info->dstLines[info->dstLineCount].dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN && !waveInLine) { |
| waveInLine = &info->dstLines[info->dstLineCount]; |
| info->sourcePortCount = waveInLine->cConnections; |
| if (lineHasControls(handle, waveInLine, NULL)) { |
| // add a single port for all the controls that do not show in the MUX/MIXER controls |
| info->sourcePortCount++; |
| waveInHasControls = TRUE; |
| } |
| } else { |
| info->targetPortCount++; |
| } |
| info->dstLineCount++; |
| } |
| } |
| } |
| if (info->srcLineCount) { |
| info->srcLines = (MIXERLINE*) malloc(info->srcLineCount * sizeof(MIXERLINE)); |
| success = (info->srcLines != NULL); |
| } |
| if (success && info->srcLines) { |
| // go through all destinations and fill the source line structures in PortInfo |
| srcIndex = 0; |
| for (dst = 0; dst < info->dstLineCount; dst++) { |
| // remember the srcIndex for mapping the srcLines to this destination line |
| info->dstLines[dst].dwUser = srcIndex; |
| for (src = 0; src < (int) info->dstLines[dst].cConnections; src++) { |
| getMixerLineBySource(handle, dst, src, &info->srcLines[srcIndex++]); |
| } |
| } |
| } |
| // now create the mapping to Java Sound |
| if ((info->targetPortCount + info->sourcePortCount) > 0) { |
| info->ports = (LPMIXERLINE*) malloc((info->targetPortCount + info->sourcePortCount) * sizeof(LPMIXERLINE)); |
| success = (info->ports != NULL); |
| } |
| if (success && info->ports) { |
| // first add the target MIXERLINEs to the array |
| srcIndex = 0; |
| for (dst = 0; dst < info->dstLineCount; dst++) { |
| if (waveInLine != &info->dstLines[dst]) { |
| info->ports[srcIndex++] = &info->dstLines[dst]; |
| } |
| } |
| if (srcIndex != info->targetPortCount) { |
| ERROR2("srcIndex=%d is NOT targetPortCount=%d !\n", srcIndex, info->targetPortCount); |
| } |
| //srcIndex = info->targetPortCount; // should be automatic! |
| if (waveInLine) { |
| // if the recording destination line has controls, add the line |
| if (waveInHasControls) { |
| info->ports[srcIndex++] = waveInLine; |
| } |
| for (src = 0; src < (int) waveInLine->cConnections; src++) { |
| info->ports[srcIndex++] = &info->srcLines[src + waveInLine->dwUser]; |
| } |
| } |
| if (srcIndex != (info->targetPortCount + info->sourcePortCount)) { |
| ERROR2("srcIndex=%d is NOT PortCount=%d !\n", srcIndex, (info->targetPortCount + info->sourcePortCount)); |
| } |
| } |
| } |
| if (!success) { |
| if (handle != NULL) { |
| mixerClose(handle); |
| } |
| PORT_Close((void*) info); |
| info = NULL; |
| } |
| return info; |
| } |
| |
| void PORT_Close(void* id) { |
| TRACE0("PORT_Close\n"); |
| if (id != NULL) { |
| PortInfo* info = (PortInfo*) id; |
| if (info->handle) { |
| mixerClose(info->handle); |
| info->handle = NULL; |
| } |
| if (info->dstLines) { |
| free(info->dstLines); |
| info->dstLines = NULL; |
| } |
| if (info->srcLines) { |
| free(info->srcLines); |
| info->srcLines=NULL; |
| } |
| if (info->ports) { |
| free(info->ports); |
| info->ports = NULL; |
| } |
| if (info->controlIDs) { |
| free(info->controlIDs); |
| info->controlIDs = NULL; |
| } |
| if (info->muxData) { |
| free(info->muxData); |
| info->muxData = NULL; |
| } |
| free(info); |
| } |
| } |
| |
| INT32 PORT_GetPortCount(void* id) { |
| int ret = 0; |
| PortInfo* info = (PortInfo*) id; |
| if (info != NULL) { |
| ret = info->targetPortCount + info->sourcePortCount; |
| } |
| return ret; |
| } |
| |
| int componentType2type(DWORD componentType) { |
| int ret = 0; |
| if (componentType >= MIXERLINE_COMPONENTTYPE_DST_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_DST_LAST) { |
| ret = PORT_DST_UNKNOWN; |
| } |
| else if (componentType >= MIXERLINE_COMPONENTTYPE_SRC_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_SRC_LAST) { |
| ret = PORT_SRC_UNKNOWN; |
| } |
| // handle special cases |
| switch (componentType) { |
| case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: ret = PORT_DST_HEADPHONE; break; |
| case MIXERLINE_COMPONENTTYPE_DST_LINE: ret = PORT_DST_LINE_OUT; break; |
| case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: ret = PORT_DST_SPEAKER; break; |
| case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: ret = PORT_SRC_COMPACT_DISC; break; |
| case MIXERLINE_COMPONENTTYPE_SRC_LINE: ret = PORT_SRC_LINE_IN; break; |
| case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: ret = PORT_SRC_MICROPHONE; break; |
| } |
| return ret; |
| } |
| |
| INT32 PORT_GetPortType(void* id, INT32 portIndex) { |
| MIXERLINE* line; |
| PortInfo* info = (PortInfo*) id; |
| if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { |
| line = info->ports[portIndex]; |
| if (line) { |
| return componentType2type(line->dwComponentType); |
| } |
| } |
| return 0; |
| } |
| |
| INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { |
| MIXERLINE* line; |
| PortInfo* info = (PortInfo*) id; |
| |
| if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { |
| line = info->ports[portIndex]; |
| if (line) { |
| strncpy(name, line->szName, len-1); |
| name[len-1] = 0; |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| int getControlCount(HMIXER handle, MIXERLINE* line, INT32* muxCount) { |
| MIXERLINECONTROLS controls; |
| int ret = 0; |
| UINT i; |
| |
| controls.pamxctrl = NULL; |
| if (getControlInfo(handle, line, &controls)) { |
| for (i = 0; i < controls.cControls; i++) { |
| switch (controls.pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) { |
| case MIXERCONTROL_CT_CLASS_FADER : // fall through |
| case MIXERCONTROL_CT_CLASS_SLIDER : // fall through |
| case MIXERCONTROL_CT_CLASS_SWITCH : // fall through |
| case MIXERCONTROL_CT_CLASS_LIST : ret++; break; |
| } |
| if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER) |
| || (controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)) { |
| ret += controls.pamxctrl[i].cMultipleItems; |
| if (muxCount) { |
| (*muxCount) += controls.pamxctrl[i].cMultipleItems; |
| } |
| } |
| else if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) |
| && (line->cChannels == 2)) { |
| ret++; // for FAKE volume/balance pairs |
| } |
| } |
| } |
| if (controls.pamxctrl) { |
| free(controls.pamxctrl); |
| controls.pamxctrl = NULL; |
| } |
| return ret; |
| } |
| |
| MIXERLINE* findDestLine(PortInfo* info, DWORD dwDestination) { |
| int i; |
| TRACE0(">findDestLine\n"); |
| for (i = 0; i < info->dstLineCount; i++) { |
| if (info->dstLines[i].dwDestination == dwDestination) { |
| TRACE0("<findDestLine\n"); |
| return &(info->dstLines[i]); |
| } |
| } |
| TRACE0("<findDestLine NULL\n"); |
| return NULL; |
| } |
| |
| void createMuxControl(PortInfo* info, PortControlCreator* creator, MIXERLINE* dstLine, DWORD srcLineID, void** controlObjects, int* controlCount) { |
| MIXERLINECONTROLS controlInfos; |
| MIXERCONTROLDETAILS* details; |
| MIXERCONTROLDETAILS_LISTTEXT* listTextDetails = NULL; |
| UINT listTextDetailCount = 0; |
| PortControlID* controlID; |
| UINT i, c; |
| int m; |
| |
| TRACE0(">createMuxControl\n"); |
| // go through all controls of dstline |
| controlInfos.pamxctrl = NULL; |
| if (getControlInfo(info->handle, dstLine, &controlInfos)) { |
| for (i = 0; i < controlInfos.cControls; i++) { |
| if (((controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER) |
| || (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)) |
| && (controlInfos.pamxctrl[i].cMultipleItems > 0)) { |
| if (info->usedControlIDs >= info->maxControlCount) { |
| ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount); |
| break; |
| } |
| // get the details for this mux control |
| controlID = &(info->controlIDs[info->usedControlIDs]); |
| controlID->portInfo = info; |
| if (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER) { |
| controlID->controlType = PORT_CONTROL_TYPE_MIXER; |
| } else { |
| controlID->controlType = PORT_CONTROL_TYPE_MUX; |
| } |
| details = &(controlID->details); |
| details->cbStruct = sizeof(MIXERCONTROLDETAILS); |
| details->dwControlID = controlInfos.pamxctrl[i].dwControlID; |
| details->cChannels = 1; |
| details->cMultipleItems = controlInfos.pamxctrl[i].cMultipleItems; |
| details->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT); |
| if (!listTextDetails || (listTextDetailCount < (details->cMultipleItems * details->cChannels))) { |
| // need to allocate new listTextDetails |
| if (listTextDetails) { |
| free(listTextDetails); |
| listTextDetails = NULL; |
| } |
| listTextDetailCount = details->cMultipleItems * details->cChannels; |
| listTextDetails = (MIXERCONTROLDETAILS_LISTTEXT*) malloc(listTextDetailCount * sizeof(MIXERCONTROLDETAILS_LISTTEXT)); |
| if (!listTextDetails) { |
| ERROR0("createMuxControl: unable to allocate listTextDetails!\n"); |
| if (controlInfos.pamxctrl) { |
| free(controlInfos.pamxctrl); |
| controlInfos.pamxctrl = NULL; |
| } |
| TRACE0("<createMuxControl ERROR\n"); |
| return; |
| } |
| } |
| details->paDetails = listTextDetails; |
| if (mixerGetControlDetails((HMIXEROBJ) info->handle, details, MIXER_GETCONTROLDETAILSF_LISTTEXT | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { |
| ERROR0("createMuxControl: unable to get control details!\n"); |
| continue; |
| } |
| // prevent freeing this data |
| details->paDetails = NULL; |
| // go through all mux items. If the line matches, then add a BOOLEAN select control |
| for (c = 0; c < details->cMultipleItems; c++) { |
| if (listTextDetails[c].dwParam1 == srcLineID) { |
| // we have found the line in the MUX lines. |
| controlID->muxIndex = c; |
| details->cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); |
| // now look if any other controlID was already part of this MUX line |
| for (m = 0; m < info->usedControlIDs; m++) { |
| if (info->controlIDs[m].details.dwControlID == details->dwControlID) { |
| // reuse the MUX Data |
| TRACE2("Reusing paDetails=%p of controlID[%d]\n", info->controlIDs[m].details.paDetails, m); |
| details->paDetails = info->controlIDs[m].details.paDetails; |
| break; |
| } |
| } |
| if (!details->paDetails) { |
| // first time this MUX control is used, allocate some of the muxData |
| details->paDetails = &(info->muxData[info->usedMuxData]); |
| TRACE2("Setting paDetails=%p to muxData[%d] \n", details->paDetails, info->usedMuxData); |
| info->usedMuxData += details->cMultipleItems; |
| } |
| // finally this line can be added |
| controlObjects[*controlCount] = (creator->newBooleanControl)(creator, controlID, CONTROL_TYPE_SELECT); |
| (*controlCount)++; |
| info->usedControlIDs++; |
| break; |
| } |
| } |
| } |
| } |
| } |
| if (listTextDetails) { |
| free(listTextDetails); |
| listTextDetails = NULL; |
| } |
| if (controlInfos.pamxctrl) { |
| free(controlInfos.pamxctrl); |
| controlInfos.pamxctrl = NULL; |
| } |
| TRACE0("<createMuxControl\n"); |
| } |
| |
| void createPortControl(PortInfo* info, PortControlCreator* creator, MIXERCONTROL* mixerControl, |
| INT32 type, void** controlObjects, int* controlCount) { |
| PortControlID* controlID; |
| void* newControl = NULL; |
| char* typeName = mixerControl->szName; |
| float min; |
| TRACE0(">createPortControl\n"); |
| |
| // fill the ControlID structure and add this control |
| if (info->usedControlIDs >= info->maxControlCount) { |
| ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount); |
| return; |
| } |
| controlID = &(info->controlIDs[info->usedControlIDs]); |
| controlID->portInfo = info; |
| controlID->controlType = type; |
| controlID->details.cbStruct = sizeof(MIXERCONTROLDETAILS); |
| controlID->details.dwControlID = mixerControl->dwControlID; |
| controlID->details.cChannels = 1; // uniform |
| controlID->details.cMultipleItems = 0; |
| switch (type) { |
| case PORT_CONTROL_TYPE_BOOLEAN: |
| TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n"); |
| controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); |
| controlID->details.paDetails = &(controlID->boolValue); |
| if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) { |
| typeName = CONTROL_TYPE_MUTE; |
| } |
| newControl = (creator->newBooleanControl)(creator, controlID, typeName); |
| break; |
| case PORT_CONTROL_TYPE_SIGNED: |
| TRACE0(" PORT_CONTROL_TYPE_SIGNED\n"); |
| controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED); |
| controlID->details.paDetails = &(controlID->signedValue); |
| controlID->min = (INT32) mixerControl->Bounds.lMinimum; |
| controlID->max = (INT32) mixerControl->Bounds.lMaximum; |
| if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_PAN) { |
| typeName = CONTROL_TYPE_PAN; |
| } |
| newControl = (creator->newFloatControl)(creator, controlID, typeName, |
| -1.0f, 1.0f, 2.0f / (controlID->max - controlID->min + 1), ""); |
| break; |
| case PORT_CONTROL_TYPE_FAKE_VOLUME: // fall through |
| case PORT_CONTROL_TYPE_FAKE_BALANCE: // fall through |
| case PORT_CONTROL_TYPE_UNSIGNED: |
| TRACE0(" PORT_CONTROL_TYPE_UNSIGNED\n"); |
| controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); |
| controlID->details.paDetails = &(controlID->unsignedValue[0]); |
| controlID->min = (INT32) mixerControl->Bounds.dwMinimum; |
| controlID->max = (INT32) mixerControl->Bounds.dwMaximum; |
| min = 0.0f; |
| if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME) |
| || (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) { |
| typeName = CONTROL_TYPE_VOLUME; |
| } |
| if (type == PORT_CONTROL_TYPE_FAKE_BALANCE) { |
| typeName = CONTROL_TYPE_BALANCE; |
| min = -1.0f; |
| } |
| if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME) |
| || (type == PORT_CONTROL_TYPE_FAKE_BALANCE)) { |
| controlID->details.cChannels = 2; |
| } |
| TRACE0(" ....PORT_CONTROL_TYPE_UNSIGNED\n"); |
| newControl = (creator->newFloatControl)(creator, controlID, typeName, |
| min, 1.0f, 1.0f / (controlID->max - controlID->min + 1), ""); |
| break; |
| default: |
| ERROR1("createPortControl: unknown type %d !", type); |
| break; |
| } |
| if (newControl) { |
| controlObjects[*controlCount] = newControl; |
| (*controlCount)++; |
| info->usedControlIDs++; |
| } |
| TRACE0("<createPortControl\n"); |
| } |
| |
| void createLineControls(PortInfo* info, PortControlCreator* creator, MIXERLINE* line, void** controlObjects, int* controlCount) { |
| MIXERLINECONTROLS controlInfos; |
| MIXERCONTROL* mixerControl; |
| UINT i; |
| INT32 type; |
| |
| TRACE1(">createLineControls for line %s\n", line->szName); |
| // go through all controls of line |
| controlInfos.pamxctrl = NULL; |
| if (getControlInfo(info->handle, line, &controlInfos)) { |
| for (i = 0; i < controlInfos.cControls; i++) { |
| TRACE1(" %d\n", i); |
| mixerControl = &(controlInfos.pamxctrl[i]); |
| type = 0; |
| switch (mixerControl->dwControlType) { |
| case MIXERCONTROL_CONTROLTYPE_BOOLEAN : // fall through |
| case MIXERCONTROL_CONTROLTYPE_BUTTON : // fall through |
| case MIXERCONTROL_CONTROLTYPE_LOUDNESS : // fall through |
| case MIXERCONTROL_CONTROLTYPE_MONO : // fall through |
| case MIXERCONTROL_CONTROLTYPE_MUTE : // fall through |
| case MIXERCONTROL_CONTROLTYPE_ONOFF : // fall through |
| case MIXERCONTROL_CONTROLTYPE_STEREOENH: type = PORT_CONTROL_TYPE_BOOLEAN; break; |
| |
| case MIXERCONTROL_CONTROLTYPE_PAN : // fall through |
| case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN: // fall through |
| case MIXERCONTROL_CONTROLTYPE_SLIDER : type = PORT_CONTROL_TYPE_SIGNED; break; |
| |
| case MIXERCONTROL_CONTROLTYPE_BASS : // fall through |
| //case MIXERCONTROL_CONTROLTYPE_EQUALIZER: // fall through |
| case MIXERCONTROL_CONTROLTYPE_FADER : // fall through |
| case MIXERCONTROL_CONTROLTYPE_TREBLE : type = PORT_CONTROL_TYPE_UNSIGNED; break; |
| case MIXERCONTROL_CONTROLTYPE_VOLUME : |
| type = PORT_CONTROL_TYPE_UNSIGNED; |
| if (line->cChannels == 2 && ((mixerControl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) == 0)) { |
| type = PORT_CONTROL_TYPE_FAKE_VOLUME; |
| } |
| break; |
| } |
| if (type != 0) { |
| createPortControl(info, creator, mixerControl, type, controlObjects, controlCount); |
| // create fake balance for fake volume |
| if (type == PORT_CONTROL_TYPE_FAKE_VOLUME) { |
| createPortControl(info, creator, mixerControl, PORT_CONTROL_TYPE_FAKE_BALANCE, controlObjects, controlCount); |
| } |
| } |
| } |
| } |
| if (controlInfos.pamxctrl) { |
| free(controlInfos.pamxctrl); |
| controlInfos.pamxctrl = NULL; |
| } |
| TRACE0("<createLineControls\n"); |
| } |
| |
| void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) { |
| void* compControl; |
| |
| TRACE1(">addCompoundControl %d controls\n", *controlCount); |
| if (*controlCount) { |
| // create compound control and add it to the vector |
| compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount); |
| if (compControl) { |
| TRACE1(" addCompoundControl: calling addControl %p\n", compControl); |
| (creator->addControl)(creator, compControl); |
| } |
| *controlCount = 0; |
| } |
| TRACE0("<addCompoundControl\n"); |
| } |
| |
| void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) { |
| int i = 0; |
| |
| TRACE0(">addAllControl\n"); |
| // go through all controls and add them to the vector |
| for (i = 0; i < *controlCount; i++) { |
| (creator->addControl)(creator, controlObjects[i]); |
| } |
| *controlCount = 0; |
| TRACE0("<addAllControl\n"); |
| } |
| |
| |
| |
| void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { |
| MIXERLINE* line; |
| PortInfo* info = (PortInfo*) id; |
| int portCount = PORT_GetPortCount(id); |
| void** controls = NULL; |
| int controlCount; |
| UINT i; |
| |
| TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", id, portIndex, info->controlIDs, info->maxControlCount); |
| if ((portIndex >= 0) && (portIndex < portCount)) { |
| line = info->ports[portIndex]; |
| if (line) { |
| // if the memory isn't reserved for the control structures, allocate it |
| if (!info->controlIDs) { |
| int i, maxCount = 0, muxCount = 0; |
| TRACE0("getControl: allocate mem\n"); |
| // get a maximum number of controls |
| // first for all destination lines |
| for (i = 0; i < info->dstLineCount; i++) { |
| MIXERLINE* thisLine = &(info->dstLines[i]); |
| maxCount += getControlCount(info->handle, thisLine, &muxCount); |
| } |
| // then all source lines |
| for (i = 0; i < info->srcLineCount; i++) { |
| MIXERLINE* thisLine = &(info->srcLines[i]); |
| maxCount += getControlCount(info->handle, thisLine, &muxCount); |
| } |
| info->maxControlCount = maxCount; |
| if (maxCount > 0) { |
| info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount); |
| } else { |
| // no ports: nothing to do ! |
| return; |
| } |
| TRACE2("Creating muxData for %d elements and %d controlIDs.\n", muxCount, maxCount); |
| if (muxCount > 0) { |
| info->muxData = (MIXERCONTROLDETAILS_BOOLEAN*) malloc(sizeof(MIXERCONTROLDETAILS_BOOLEAN) * muxCount); |
| } |
| if (!info->controlIDs || (muxCount && !info->muxData)) { |
| ERROR3("PORT_GetControls: info->controlIDs=%p, muxCount=%d, info->muxData=%p !!\n", info->controlIDs, muxCount, info->muxData); |
| return; |
| } |
| } |
| if (info->maxControlCount == 0) { |
| return; |
| } |
| controls = (void*) malloc(info->maxControlCount * sizeof(void*)); |
| if (!controls) { |
| ERROR0("PORT_GetControls: couldn't allocate controls!\n"); |
| return; |
| } |
| |
| // add controls of this line |
| controlCount = 0; |
| // if this line is part of MUX, add the respective BOOLEANCONTROL as a control |
| if ((line->fdwLine & MIXERLINE_LINEF_SOURCE) == MIXERLINE_LINEF_SOURCE) { |
| MIXERLINE* dstLine = findDestLine(info, line->dwDestination); |
| TRACE0("Port_getControls: this is a source line\n"); |
| if (dstLine) { |
| // selection controls (implemented as Mute control) |
| createMuxControl(info, creator, dstLine, line->dwLineID, controls, &controlCount); |
| } |
| // then add all controls in one compound control |
| createLineControls(info, creator, line, controls, &controlCount); |
| addCompoundControl(info, creator, line->szName, controls, &controlCount); |
| } else { |
| TRACE0("getControl: this is a dest line\n"); |
| // if this is a destination line, add its controls |
| createLineControls(info, creator, line, controls, &controlCount); |
| addAllControls(info, creator, controls, &controlCount); |
| // then add all controls of its source lines as one compound control |
| for (i = 0; i < line->cConnections; i++) { |
| // then add all controls |
| MIXERLINE* srcLine = &(info->srcLines[line->dwUser + i]); |
| TRACE1("PORT_getControls: add source line %d\n", i); |
| createLineControls(info, creator, srcLine, controls, &controlCount); |
| addCompoundControl(info, creator, srcLine->szName, controls, &controlCount); |
| } |
| } |
| } |
| } |
| if (controls) { |
| free(controls); |
| } |
| TRACE0("< PORT_getControls\n"); |
| } |
| |
| int getControlValue(PortControlID* controlID) { |
| if (mixerGetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details), |
| MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { |
| ERROR0("getControlValue: unable to get control details!\n"); |
| //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels); |
| //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| int setControlValue(PortControlID* controlID) { |
| if (mixerSetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details), |
| MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) { |
| ERROR0("setControlValue: unable to set control details!\n"); |
| //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels); |
| //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| INT32 PORT_GetIntValue(void* controlIDV) { |
| PortControlID* controlID = (PortControlID*) controlIDV; |
| MIXERCONTROLDETAILS_BOOLEAN* bools; |
| int ret = 0; |
| if (getControlValue(controlID)) { |
| switch (controlID->controlType) { |
| case PORT_CONTROL_TYPE_MUX: // fall through |
| case PORT_CONTROL_TYPE_MIXER: |
| bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails; |
| ret = (bools[controlID->muxIndex].fValue)?TRUE:FALSE; |
| break; |
| case PORT_CONTROL_TYPE_BOOLEAN: |
| ret = (controlID->boolValue.fValue)?TRUE:FALSE; |
| break; |
| default: ERROR1("PORT_GetIntValue: wrong controlType=%d !\n", controlID->controlType); |
| } |
| } |
| return ret; |
| } |
| |
| void PORT_SetIntValue(void* controlIDV, INT32 value) { |
| PortControlID* controlID = (PortControlID*) controlIDV; |
| MIXERCONTROLDETAILS_BOOLEAN* bools; |
| UINT i; |
| |
| switch (controlID->controlType) { |
| case PORT_CONTROL_TYPE_MUX: |
| if (!value) { |
| // cannot unselect a MUX line |
| return; |
| } |
| if (!getControlValue(controlID)) { |
| return; |
| } |
| bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails; |
| for (i = 0; i < controlID->details.cMultipleItems; i++) { |
| bools[i].fValue = (i == (UINT) controlID->muxIndex)?TRUE:FALSE; |
| } |
| break; |
| case PORT_CONTROL_TYPE_MIXER: |
| if (!getControlValue(controlID)) { |
| return; |
| } |
| bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails; |
| bools[controlID->muxIndex].fValue = (value?TRUE:FALSE); |
| break; |
| case PORT_CONTROL_TYPE_BOOLEAN: |
| controlID->boolValue.fValue = (value?TRUE:FALSE); |
| break; |
| default: |
| ERROR1("PORT_SetIntValue: wrong controlType=%d !\n", controlID->controlType); |
| return; |
| } |
| setControlValue(controlID); |
| } |
| |
| float getFakeBalance(PortControlID* controlID) { |
| float volL, volR; |
| float range = (float) (controlID->max - controlID->min); |
| // pan is the ratio of left and right |
| volL = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range); |
| volR = (((float) (controlID->unsignedValue[1].dwValue - controlID->min)) / range); |
| if (volL > volR) { |
| return -1.0f + (volR / volL); |
| } |
| else if (volR > volL) { |
| return 1.0f - (volL / volR); |
| } |
| return 0.0f; |
| } |
| |
| float getFakeVolume(PortControlID* controlID) { |
| // volume is the greater value of both |
| UINT vol = controlID->unsignedValue[0].dwValue; |
| if (controlID->unsignedValue[1].dwValue > vol) { |
| vol = controlID->unsignedValue[1].dwValue; |
| } |
| return (((float) (vol - controlID->min)) / (controlID->max - controlID->min)); |
| } |
| |
| /* |
| * sets the unsigned values for left and right volume according to |
| * the given volume (0...1) and balance (-1..0..+1) |
| */ |
| void setFakeVolume(PortControlID* controlID, float vol, float bal) { |
| vol = vol * (controlID->max - controlID->min); |
| if (bal < 0.0f) { |
| controlID->unsignedValue[0].dwValue = (UINT) (vol + 0.5f) + controlID->min; |
| controlID->unsignedValue[1].dwValue = (UINT) ((vol * (bal + 1.0f)) + 0.5f) + controlID->min; |
| } else { |
| controlID->unsignedValue[1].dwValue = (UINT) (vol + 0.5f) + controlID->min; |
| controlID->unsignedValue[0].dwValue = (UINT) ((vol * (1.0f - bal)) + 0.5f) + controlID->min; |
| } |
| } |
| |
| float PORT_GetFloatValue(void* controlIDV) { |
| PortControlID* controlID = (PortControlID*) controlIDV; |
| float ret = 0.0f; |
| float range = (float) (controlID->max - controlID->min); |
| if (getControlValue(controlID)) { |
| switch (controlID->controlType) { |
| case PORT_CONTROL_TYPE_SIGNED: |
| ret = ((float) controlID->signedValue.lValue) / controlID->max; |
| break; |
| case PORT_CONTROL_TYPE_UNSIGNED: |
| ret = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range); |
| break; |
| case PORT_CONTROL_TYPE_FAKE_VOLUME: |
| ret = getFakeVolume(controlID); |
| break; |
| case PORT_CONTROL_TYPE_FAKE_BALANCE: |
| ret = getFakeBalance(controlID); |
| break; |
| default: ERROR1("PORT_GetFloatValue: wrong controlType=%d !\n", controlID->controlType); |
| } |
| } |
| return ret; |
| } |
| |
| void PORT_SetFloatValue(void* controlIDV, float value) { |
| PortControlID* controlID = (PortControlID*) controlIDV; |
| float range = (float) (controlID->max - controlID->min); |
| switch (controlID->controlType) { |
| case PORT_CONTROL_TYPE_SIGNED: |
| controlID->signedValue.lValue = (INT32) ((value * controlID->max) + 0.5f); |
| break; |
| case PORT_CONTROL_TYPE_UNSIGNED: |
| controlID->unsignedValue[0].dwValue = (INT32) ((value * range) + 0.5f) + controlID->min; |
| break; |
| case PORT_CONTROL_TYPE_FAKE_VOLUME: |
| if (!getControlValue(controlID)) { |
| return; |
| } |
| setFakeVolume(controlID, value, getFakeBalance(controlID)); |
| break; |
| case PORT_CONTROL_TYPE_FAKE_BALANCE: |
| if (!getControlValue(controlID)) { |
| return; |
| } |
| setFakeVolume(controlID, getFakeVolume(controlID), value); |
| break; |
| default: |
| ERROR1("PORT_SetFloatValue: wrong controlType=%d !\n", controlID->controlType); |
| return; |
| } |
| setControlValue(controlID); |
| } |
| |
| #endif // USE_PORTS |