source: trunk/src/winmm/mixer.cpp@ 21570

Last change on this file since 21570 was 21570, checked in by dmik, 15 years ago

winmm: Accept handles returned by mixerOpen() as IDs in mixerGetDevCaps() (according to MSDN). We actually accept any ID ATM since we provide only one mixer device but that shoud be fine for now.

File size: 75.2 KB
Line 
1/* $Id: mixer.cpp,v 1.26 2002-07-12 08:12:29 sandervl Exp $ */
2
3/*
4 * Mixer functions
5 *
6 * Copyright 2002 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * TODO: Mixer notification
9 *
10 * NOTE: Not really flexible (capabilities, > 1 audio card)
11 *
12 * Some portions borrowed from Wine (X11): (dll\winmm\mmsystem.c)
13 * (mixerGetLineControlsW/mixerGetControlDetailsW)
14 * Copyright 1993 Martin Ayotte
15 * Eric POUECH
16 *
17 * Project Odin Software License can be found in LICENSE.TXT
18 *
19 */
20
21/****************************************************************************
22 * Includes *
23 ****************************************************************************/
24
25#define NONAMELESSUNION
26#define NONAMELESSSTRUCT
27
28#include <os2win.h>
29#include <string.h>
30#include <dbglog.h>
31#include <mmsystem.h>
32#include <winnls.h>
33
34#include "waveoutdart.h"
35#include "winmm.h"
36#include "initwinmm.h"
37#include "mixer.h"
38#include "mixeros2.h"
39
40#define DBG_LOCALLOG DBG_mixer
41#include "dbglocal.h"
42
43static MIXERCONTROLA *mixerAddControl(DWORD dwControl, MIXLINE *pSrcLine);
44static MIXLINE *mixerAddSource(MIXLINE *pDestLine, DWORD dwSource);
45static MIXLINE *mixerAddDestination(DWORD dwDest);
46
47//array of destination mixer lines
48static MIXLINE mixerDest[MAX_MIXER_DESTINATIONS] = {0};
49//array of source mixer lines
50static MIXLINE mixerSource[MAX_MIXER_SOURCES] = {0};
51//array of all mixer lines
52static MIXLINE *pmixerLines[MAX_MIXER_LINES] = {NULL};
53//array of all mixer controls
54static MIXCONTROL mixerControls[MAX_MIXER_CONTROLS] = {0};
55
56static int nrDestinations = 0;
57static int nrSources = 0;
58static int nrControls = 0;
59static int nrLines = 0;
60
61/******************************************************************************/
62/******************************************************************************/
63MMRESULT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
64{
65 DWORD lineID, controlType;
66 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
67
68 if((fdwDetails & 0xF0000000)== MIXER_OBJECTF_HMIXER) {
69 if(!pMixInfo) {
70 return MMSYSERR_INVALHANDLE;
71 }
72 }
73 else
74 if((fdwDetails & 0xF0000000) == MIXER_OBJECTF_MIXER) {
75 if(!HIWORD(hmxobj) && hmxobj > 0) {
76 return MMSYSERR_NODRIVER;
77 }
78 }
79
80 if(lpmcd == NULL || lpmcd->cbStruct != sizeof(MIXERCONTROLDETAILS)) {
81 dprintf(("ERROR: invalid pointer or structure size %d (%d)", (lpmcd) ? lpmcd->cbStruct : 0, sizeof(MIXERCONTROLDETAILS)));
82 return MMSYSERR_INVALPARAM;
83 }
84 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
85 case MIXER_GETCONTROLDETAILSF_VALUE:
86 dprintf(("MIXER_GETCONTROLDETAILSF_VALUE %d (internal id %d)", lpmcd->dwControlID, mixerControls[lpmcd->dwControlID].id));
87 if(lpmcd->dwControlID >= nrControls) {
88 dprintf(("invalid control %d", lpmcd->dwControlID));
89 return MIXERR_INVALCONTROL;
90 }
91 if(lpmcd->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED)) {
92 dprintf(("not enough room in buffer (%d)", lpmcd->cbDetails));
93 return MMSYSERR_INVALPARAM;
94 }
95 switch(mixerControls[lpmcd->dwControlID].ctrl.dwControlType) {
96 case MIXERCONTROL_CONTROLTYPE_MUX:
97 {
98 MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)lpmcd->paDetails;
99 DWORD dwRecSrc;
100
101 dprintf(("MIXERCONTROL_CONTROLTYPE_MUX"));
102 if(lpmcd->cChannels != 1) {//only accepts 1 in win2k
103 dprintf(("invalid number of channels %d", lpmcd->cChannels));
104 return MMSYSERR_INVALPARAM;
105 }
106 //this is also checked in win2k
107 if(lpmcd->u.cMultipleItems != mixerControls[lpmcd->dwControlID].ctrl.cMultipleItems) {
108 dprintf(("invalid cMultipleItems %d", lpmcd->u.cMultipleItems));
109 return MMSYSERR_INVALPARAM;
110 }
111
112 if(mixerControls[lpmcd->dwControlID].id != MIX_CTRL_MUX_IN_W_SRC) {
113 dprintf(("oh, oh. not wavein mux"));
114 DebugInt3();
115 return MMSYSERR_INVALPARAM;
116 }
117
118 if(OSLibMixGetRecSource(&dwRecSrc) == FALSE) {
119 dprintf(("OSLibMixGetRecSource failed!!"));
120 return MIXERR_INVALCONTROL;
121 }
122 //clear the array
123 memset(pDetails, 0, sizeof(MIXERCONTROLDETAILS_BOOLEAN)*lpmcd->u.cMultipleItems);
124 //mark recording source
125 for(int i=0;i<nrDestinations;i++) {
126 if(mixerDest[i].id == MIXER_DEST_WAVEIN) {
127 for(int j=0;j<mixerDest[i].cConnections;j++) {
128 dprintf(("wavein source %s %d (id %d)", pmixerLines[mixerDest[i].Connections[j]]->line.szName, pmixerLines[mixerDest[i].Connections[j]]->id, mixerDest[i].Connections[j]));
129 if(pmixerLines[mixerDest[i].Connections[j]]->id == dwRecSrc) {
130 pDetails[j].fValue = 1;
131 return MMSYSERR_NOERROR;
132 }
133 }
134 }
135 }
136 dprintf(("recording source %d not found!!", dwRecSrc));
137 break;
138 }
139
140 case MIXERCONTROL_CONTROLTYPE_VOLUME: //unsigned
141 {
142 MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)lpmcd->paDetails;
143 DWORD dwVolLeft, dwVolRight;
144
145 dprintf(("MIXERCONTROL_CONTROLTYPE_VOLUME"));
146 if(OSLibMixGetVolume(mixerControls[lpmcd->dwControlID].id, &dwVolLeft, &dwVolRight) == FALSE) {
147 dprintf(("OSLibMixGetVolume failed!!"));
148 return MIXERR_INVALCONTROL;
149 }
150 pDetails->dwValue = dwVolLeft;
151 dprintf(("%s Left volume %d", mixerControls[lpmcd->dwControlID].ctrl.szName, dwVolLeft));
152 if(lpmcd->cChannels == 2) {
153 dprintf(("%s Right volume %d", mixerControls[lpmcd->dwControlID].ctrl.szName, dwVolRight));
154 pDetails += 1;
155 pDetails->dwValue = dwVolRight;
156 }
157 //todo > 2 channels
158 return MMSYSERR_NOERROR;
159 }
160
161 case MIXERCONTROL_CONTROLTYPE_MUTE: //assuming boolean
162 {
163 MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)lpmcd->paDetails;
164 BOOL fMute;
165
166 dprintf(("MIXERCONTROL_CONTROLTYPE_MUTE"));
167 if(OSLibMixGetMute(mixerControls[lpmcd->dwControlID].id, &fMute) == FALSE) {
168 dprintf(("OSLibMixGetVolume failed!!"));
169 return MIXERR_INVALCONTROL;
170 }
171 pDetails->fValue = fMute;
172 dprintf(("%s Left mute %d", mixerControls[lpmcd->dwControlID].ctrl.szName, fMute));
173 if(lpmcd->cChannels == 2) {
174 dprintf(("%s Right mute %d", mixerControls[lpmcd->dwControlID].ctrl.szName, fMute));
175 pDetails += 1;
176 pDetails->fValue = fMute;
177 }
178 //todo > 2 channels (usually only 1 channel is requested though)
179 return MMSYSERR_NOERROR;
180 }
181
182 case MIXERCONTROL_CONTROLTYPE_FADER:
183 {
184 MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)lpmcd->paDetails;
185 DWORD dwLevelL;
186
187 dprintf(("MIXERCONTROL_CONTROLTYPE_FADER"));
188
189 if(OSLibMixGetVolume(mixerControls[lpmcd->dwControlID].id, &dwLevelL, NULL) == FALSE) {
190 dprintf(("OSLibMixGetVolume failed!!"));
191 return MIXERR_INVALCONTROL;
192 }
193 pDetails->dwValue = dwLevelL;
194#ifdef DEBUG
195 if(mixerControls[lpmcd->dwControlID].id == MIX_CTRL_OUT_L_3DCENTER) {
196 dprintf(("3D center %d", dwLevelL));
197 }
198 else dprintf(("3D depth %d", dwLevelL));
199#endif
200 if(lpmcd->cChannels == 2) {
201 pDetails += 1;
202 pDetails->dwValue = dwLevelL;
203 }
204 //todo > 2 channels (??)
205 return MMSYSERR_NOERROR;
206 }
207
208 case MIXERCONTROL_CONTROLTYPE_BASS:
209 case MIXERCONTROL_CONTROLTYPE_TREBLE:
210 {
211 MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)lpmcd->paDetails;
212 DWORD dwLevelL;
213
214#ifdef DEBUG
215 switch(fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
216 case MIXERCONTROL_CONTROLTYPE_TREBLE:
217 dprintf(("MIXERCONTROL_CONTROLTYPE_TREBLE"));
218 break;
219 case MIXERCONTROL_CONTROLTYPE_BASS:
220 dprintf(("MIXERCONTROL_CONTROLTYPE_BASS"));
221 break;
222 }
223#endif
224
225 if(OSLibMixGetVolume(mixerControls[lpmcd->dwControlID].id, &dwLevelL, NULL) == FALSE) {
226 dprintf(("OSLibMixGetVolume failed!!"));
227 return MIXERR_INVALCONTROL;
228 }
229 pDetails->dwValue = dwLevelL;
230 dprintf(("%s %d", mixerControls[lpmcd->dwControlID].ctrl.szName, dwLevelL));
231 if(lpmcd->cChannels == 2) {
232 pDetails += 1;
233 pDetails->dwValue = dwLevelL;
234 }
235 return MMSYSERR_NOERROR;
236 }
237
238#ifdef DEBUG
239 case MIXERCONTROL_CONTROLTYPE_MIXER:
240 dprintf(("MIXERCONTROL_CONTROLTYPE_MIXER"));
241 break;
242 case MIXERCONTROL_CONTROLTYPE_CUSTOM:
243 dprintf(("MIXERCONTROL_CONTROLTYPE_CUSTOM"));
244 break;
245 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER:
246 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEANMETER"));
247 break;
248 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER:
249 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNEDMETER"));
250 break;
251 case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
252 dprintf(("MIXERCONTROL_CONTROLTYPE_PEAKMETER"));
253 break;
254 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER:
255 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER"));
256 break;
257 case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
258 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEAN"));
259 break;
260 case MIXERCONTROL_CONTROLTYPE_ONOFF:
261 dprintf(("MIXERCONTROL_CONTROLTYPE_ONOFF"));
262 break;
263 case MIXERCONTROL_CONTROLTYPE_MONO:
264 dprintf(("MIXERCONTROL_CONTROLTYPE_MONO"));
265 break;
266 case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
267 dprintf(("MIXERCONTROL_CONTROLTYPE_LOUDNESS"));
268 break;
269 case MIXERCONTROL_CONTROLTYPE_STEREOENH:
270 dprintf(("MIXERCONTROL_CONTROLTYPE_STEREOENH"));
271 break;
272 case MIXERCONTROL_CONTROLTYPE_BUTTON:
273 dprintf(("MIXERCONTROL_CONTROLTYPE_BUTTON"));
274 break;
275 case MIXERCONTROL_CONTROLTYPE_DECIBELS:
276 dprintf(("MIXERCONTROL_CONTROLTYPE_DECIBELS"));
277 break;
278 case MIXERCONTROL_CONTROLTYPE_SIGNED:
279 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNED"));
280 break;
281 case MIXERCONTROL_CONTROLTYPE_UNSIGNED:
282 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNED"));
283 break;
284 case MIXERCONTROL_CONTROLTYPE_PERCENT:
285 dprintf(("MIXERCONTROL_CONTROLTYPE_PERCENT"));
286 break;
287 case MIXERCONTROL_CONTROLTYPE_SLIDER:
288 dprintf(("MIXERCONTROL_CONTROLTYPE_SLIDER"));
289 break;
290 case MIXERCONTROL_CONTROLTYPE_PAN:
291 dprintf(("MIXERCONTROL_CONTROLTYPE_PAN"));
292 break;
293 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN:
294 dprintf(("MIXERCONTROL_CONTROLTYPE_QSOUNDPAN"));
295 break;
296 case MIXERCONTROL_CONTROLTYPE_EQUALIZER:
297 dprintf(("MIXERCONTROL_CONTROLTYPE_EQUALIZER"));
298 break;
299 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
300 dprintf(("MIXERCONTROL_CONTROLTYPE_SINGLESELECT"));
301 break;
302 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
303 dprintf(("MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT"));
304 break;
305 case MIXERCONTROL_CONTROLTYPE_MICROTIME:
306 dprintf(("MIXERCONTROL_CONTROLTYPE_MICROTIME"));
307 break;
308 case MIXERCONTROL_CONTROLTYPE_MILLITIME:
309 dprintf(("MIXERCONTROL_CONTROLTYPE_MILLITIME"));
310 break;
311#endif
312 default:
313 DebugInt3();
314 return MIXERR_INVALCONTROL;
315 }
316 return MIXERR_INVALCONTROL;
317
318 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
319 dprintf(("MIXER_GETCONTROLDETAILSF_LISTTEXT %d", lpmcd->dwControlID));
320 if(lpmcd->dwControlID >= nrControls) {
321 dprintf(("invalid control %d", lpmcd->dwControlID));
322 return MIXERR_INVALCONTROL;
323 }
324 switch(mixerControls[lpmcd->dwControlID].ctrl.dwControlType) {
325 case MIXERCONTROL_CONTROLTYPE_MUX:
326 {
327 MIXERCONTROLDETAILS_LISTTEXTA *pDetails = (MIXERCONTROLDETAILS_LISTTEXTA *)lpmcd->paDetails;
328 if(lpmcd->cChannels != 1) {//only accepts 1 in win2k
329 dprintf(("invalid number of channels %d", lpmcd->cChannels));
330 return MMSYSERR_INVALPARAM;
331 }
332 //this is also checked in win2k
333 if(lpmcd->u.cMultipleItems != mixerControls[lpmcd->dwControlID].ctrl.cMultipleItems) {
334 dprintf(("invalid cMultipleItems %d", lpmcd->u.cMultipleItems));
335 return MMSYSERR_INVALPARAM;
336 }
337 //fails otherwise in win2k
338 if(lpmcd->cbDetails != sizeof(MIXERCONTROLDETAILS_LISTTEXTA)) {
339 dprintf(("invalid buffer size %d; should be %d", lpmcd->cbDetails, sizeof(MIXERCONTROLDETAILS_LISTTEXTA)));
340 return MMSYSERR_INVALPARAM;
341 }
342 if(mixerControls[lpmcd->dwControlID].id != MIX_CTRL_MUX_IN_W_SRC) {
343 dprintf(("oh, oh. not wavein mux"));
344 DebugInt3();
345 return MMSYSERR_INVALPARAM;
346 }
347 //clear the array
348 memset(pDetails, 0, sizeof(MIXERCONTROLDETAILS_LISTTEXTA)*lpmcd->u.cMultipleItems);
349 //set mux source details
350 for(int i=0;i<nrDestinations;i++) {
351 if(mixerDest[i].id == MIXER_DEST_WAVEIN) {
352 for(int j=0;j<mixerDest[i].cConnections;j++) {
353 dprintf(("wavein source %s %d (%s)", pmixerLines[mixerDest[i].Connections[j]]->line.szName, pmixerLines[mixerDest[i].Connections[j]]->id, pmixerLines[mixerDest[i].Connections[j]]->line.szName));
354 pDetails->dwParam1 = pmixerLines[mixerDest[i].Connections[j]]->line.dwLineID;
355 pDetails->dwParam2 = 0;
356 strncpy(pDetails->szName, pmixerLines[mixerDest[i].Connections[j]]->line.szName, sizeof(pDetails->szName));
357 pDetails++;
358 }
359 return MMSYSERR_NOERROR;
360 }
361 }
362 DebugInt3();
363 return MMSYSERR_INVALPARAM;
364 }
365 case MIXERCONTROL_CONTROLTYPE_EQUALIZER:
366 case MIXERCONTROL_CONTROLTYPE_MIXER:
367 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
368 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
369 dprintf(("Only implemented for mux controls"));
370 return MIXERR_INVALCONTROL;
371
372 default:
373 dprintf(("Only implemented for multiple item controls"));
374 return MIXERR_INVALCONTROL;
375 }
376
377 default:
378 dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
379 break;
380 }
381 return MMSYSERR_NOERROR;
382}
383/******************************************************************************/
384/******************************************************************************/
385MMRESULT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
386{
387 DWORD ret = MMSYSERR_NOTENABLED;
388
389 if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd))
390 return MMSYSERR_INVALPARAM;
391
392 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
393 case MIXER_GETCONTROLDETAILSF_VALUE:
394 /* can safely use W structure as it is, no string inside */
395 ret = mixerGetControlDetailsA(hmxobj, lpmcd, fdwDetails);
396 break;
397
398 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
399 {
400 MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW = (MIXERCONTROLDETAILS_LISTTEXTW *)lpmcd->paDetails;
401 MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA;
402 int size = max(1, lpmcd->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
403 int i;
404
405 if (lpmcd->u.cMultipleItems != 0) {
406 size *= lpmcd->u.cMultipleItems;
407 }
408 pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)HeapAlloc(GetProcessHeap(), 0, size);
409 lpmcd->paDetails = pDetailsA;
410 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
411 /* set up lpmcd->paDetails */
412 ret = mixerGetControlDetailsA(hmxobj, lpmcd, fdwDetails);
413 /* copy from lpmcd->paDetails back to paDetailsW; */
414 if(ret == MMSYSERR_NOERROR) {
415 for(i=0;i<lpmcd->u.cMultipleItems*lpmcd->cChannels;i++) {
416 pDetailsW->dwParam1 = pDetailsA->dwParam1;
417 pDetailsW->dwParam2 = pDetailsA->dwParam2;
418 MultiByteToWideChar( CP_ACP, 0, pDetailsA->szName, -1,
419 pDetailsW->szName,
420 sizeof(pDetailsW->szName)/sizeof(WCHAR) );
421 pDetailsA++;
422 pDetailsW++;
423 }
424 pDetailsA -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
425 pDetailsW -= lpmcd->u.cMultipleItems*lpmcd->cChannels;
426 }
427 HeapFree(GetProcessHeap(), 0, pDetailsA);
428 lpmcd->paDetails = pDetailsW;
429 lpmcd->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
430 break;
431 }
432 default:
433 dprintf(("Unsupported fdwDetails=0x%08lx\n", fdwDetails));
434 break;
435 }
436
437 return ret;
438}
439/******************************************************************************/
440/******************************************************************************/
441MMRESULT WINAPI mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
442{
443 DWORD ret = MMSYSERR_NOTSUPPORTED;
444 DWORD lineID, controlType;
445 int val;
446 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
447
448 if((fdwDetails & 0xF0000000) == MIXER_OBJECTF_HMIXER) {
449 if(!pMixInfo) {
450 return MMSYSERR_INVALHANDLE;
451 }
452 }
453 else
454 if((fdwDetails & 0xF0000000) == MIXER_OBJECTF_MIXER) {
455 if(!HIWORD(hmxobj) && hmxobj > 0) {
456 return MMSYSERR_NODRIVER;
457 }
458 }
459 if(lpmcd == NULL || lpmcd->cbStruct != sizeof(MIXERCONTROLDETAILS)) {
460 dprintf(("ERROR: invalid pointer or structure size %x %d", lpmcd, lpmcd->cbStruct));
461 return MMSYSERR_INVALPARAM;
462 }
463
464 switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
465 case MIXER_GETCONTROLDETAILSF_VALUE:
466 dprintf(("MIXER_GETCONTROLDETAILSF_VALUE %d (internal id %d)", lpmcd->dwControlID, mixerControls[lpmcd->dwControlID].id));
467 if(lpmcd->dwControlID >= nrControls) {
468 dprintf(("invalid control %d", lpmcd->dwControlID));
469 return MIXERR_INVALCONTROL;
470 }
471 if(lpmcd->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED)) {
472 dprintf(("not enough room in buffer (%d)", lpmcd->cbDetails));
473 return MMSYSERR_INVALPARAM;
474 }
475 switch(mixerControls[lpmcd->dwControlID].ctrl.dwControlType) {
476 case MIXERCONTROL_CONTROLTYPE_MUX:
477 {
478 MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)lpmcd->paDetails;
479 DWORD dwRecSrc;
480
481 dprintf(("MIXERCONTROL_CONTROLTYPE_MUX"));
482 if(lpmcd->cChannels != 1) {//only accepts 1 in win2k
483 dprintf(("invalid number of channels %d", lpmcd->cChannels));
484 return MMSYSERR_INVALPARAM;
485 }
486 //this is also checked in win2k
487 if(lpmcd->u.cMultipleItems != mixerControls[lpmcd->dwControlID].ctrl.cMultipleItems) {
488 dprintf(("invalid cMultipleItems %d", lpmcd->u.cMultipleItems));
489 return MMSYSERR_INVALPARAM;
490 }
491
492 if(mixerControls[lpmcd->dwControlID].id != MIX_CTRL_MUX_IN_W_SRC) {
493 dprintf(("oh, oh. not wavein mux"));
494 DebugInt3();
495 return MMSYSERR_INVALPARAM;
496 }
497 //select recording source
498 for(int i=0;i<nrDestinations;i++) {
499 if(mixerDest[i].id == MIXER_DEST_WAVEIN)
500 {
501 for(int j=0;j<mixerDest[i].cConnections;j++) {
502 dprintf(("wavein source %s %d (id %d)", pmixerLines[mixerDest[i].Connections[j]]->line.szName, pmixerLines[mixerDest[i].Connections[j]]->id, mixerDest[i].Connections[j]));
503 if(pDetails[j].fValue)
504 {
505 if(OSLibMixSetRecSource(pmixerLines[mixerDest[i].Connections[j]]->id) == FALSE) {
506 dprintf(("OSLibMixGetRecSource failed!!"));
507 return MIXERR_INVALCONTROL;
508 }
509 goto success;
510 }
511 }
512 }
513 }
514 dprintf(("recording source %d not found!!", dwRecSrc));
515 break;
516 }
517
518 case MIXERCONTROL_CONTROLTYPE_VOLUME: //unsigned
519 {
520 MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)lpmcd->paDetails;
521 DWORD dwVolumeL, dwVolumeR;
522
523 dprintf(("MIXERCONTROL_CONTROLTYPE_VOLUME"));
524 dwVolumeL = pDetails->dwValue;
525
526 dprintf(("%s Left volume %d", mixerControls[lpmcd->dwControlID].ctrl.szName, pDetails->dwValue));
527 if(lpmcd->cChannels == 2) {
528 pDetails += 1;
529 dprintf(("%s Right volume %d", mixerControls[lpmcd->dwControlID].ctrl.szName, pDetails->dwValue));
530 dwVolumeR = pDetails->dwValue;
531 }
532 else dwVolumeR = dwVolumeL;
533 //todo > 2 channels
534
535 if(OSLibMixSetVolume(mixerControls[lpmcd->dwControlID].id, dwVolumeL, dwVolumeR) == FALSE) {
536 return MMSYSERR_INVALPARAM;
537 }
538 mixerControls[lpmcd->dwControlID].val[0].dwValue = dwVolumeL;
539 mixerControls[lpmcd->dwControlID].val[1].dwValue = dwVolumeR;
540 goto success;
541 }
542
543 case MIXERCONTROL_CONTROLTYPE_MUTE: //assuming boolean
544 {
545 MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)lpmcd->paDetails;
546 BOOL fMute;
547
548 dprintf(("MIXERCONTROL_CONTROLTYPE_MUTE"));
549 dprintf(("%s Left mute %d", mixerControls[lpmcd->dwControlID].ctrl.szName, pDetails->fValue));
550 fMute = pDetails->fValue;
551 if(lpmcd->cChannels == 2) {
552 pDetails += 1;
553 dprintf(("%s Right mute %d", mixerControls[lpmcd->dwControlID].ctrl.szName, pDetails->fValue));
554 }
555 //todo > 2 channels (usually only 1 channel is requested though)
556
557 if(OSLibMixSetMute(mixerControls[lpmcd->dwControlID].id, fMute) == FALSE) {
558 return MMSYSERR_INVALPARAM;
559 }
560 mixerControls[lpmcd->dwControlID].val[0].dwValue = fMute;
561 goto success;
562 }
563
564 case MIXERCONTROL_CONTROLTYPE_BASS:
565 case MIXERCONTROL_CONTROLTYPE_TREBLE:
566 case MIXERCONTROL_CONTROLTYPE_FADER:
567 {
568 MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)lpmcd->paDetails;
569 DWORD dwLevel;
570
571#ifdef DEBUG
572 switch(fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
573 case MIXERCONTROL_CONTROLTYPE_TREBLE:
574 dprintf(("MIXERCONTROL_CONTROLTYPE_TREBLE"));
575 break;
576 case MIXERCONTROL_CONTROLTYPE_BASS:
577 dprintf(("MIXERCONTROL_CONTROLTYPE_BASS"));
578 break;
579 case MIXERCONTROL_CONTROLTYPE_FADER:
580 dprintf(("MIXERCONTROL_CONTROLTYPE_FADER"));
581 break;
582 }
583#endif
584 dprintf(("%s %d", mixerControls[lpmcd->dwControlID].ctrl.szName, pDetails->dwValue));
585 dwLevel = pDetails->dwValue;
586 if(OSLibMixSetVolume(mixerControls[lpmcd->dwControlID].id, dwLevel, dwLevel) == FALSE) {
587 return MMSYSERR_INVALPARAM;
588 }
589 mixerControls[lpmcd->dwControlID].val[0].dwValue = dwLevel;
590 goto success;
591 }
592
593#ifdef DEBUG
594 case MIXERCONTROL_CONTROLTYPE_MIXER:
595 dprintf(("MIXERCONTROL_CONTROLTYPE_MIXER"));
596 break;
597 case MIXERCONTROL_CONTROLTYPE_CUSTOM:
598 dprintf(("MIXERCONTROL_CONTROLTYPE_CUSTOM"));
599 break;
600 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER:
601 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEANMETER"));
602 break;
603 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER:
604 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNEDMETER"));
605 break;
606 case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
607 dprintf(("MIXERCONTROL_CONTROLTYPE_PEAKMETER"));
608 break;
609 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER:
610 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER"));
611 break;
612 case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
613 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEAN"));
614 break;
615 case MIXERCONTROL_CONTROLTYPE_ONOFF:
616 dprintf(("MIXERCONTROL_CONTROLTYPE_ONOFF"));
617 break;
618 case MIXERCONTROL_CONTROLTYPE_MONO:
619 dprintf(("MIXERCONTROL_CONTROLTYPE_MONO"));
620 break;
621 case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
622 dprintf(("MIXERCONTROL_CONTROLTYPE_LOUDNESS"));
623 break;
624 case MIXERCONTROL_CONTROLTYPE_STEREOENH:
625 dprintf(("MIXERCONTROL_CONTROLTYPE_STEREOENH"));
626 break;
627 case MIXERCONTROL_CONTROLTYPE_BUTTON:
628 dprintf(("MIXERCONTROL_CONTROLTYPE_BUTTON"));
629 break;
630 case MIXERCONTROL_CONTROLTYPE_DECIBELS:
631 dprintf(("MIXERCONTROL_CONTROLTYPE_DECIBELS"));
632 break;
633 case MIXERCONTROL_CONTROLTYPE_SIGNED:
634 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNED"));
635 break;
636 case MIXERCONTROL_CONTROLTYPE_UNSIGNED:
637 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNED"));
638 break;
639 case MIXERCONTROL_CONTROLTYPE_PERCENT:
640 dprintf(("MIXERCONTROL_CONTROLTYPE_PERCENT"));
641 break;
642 case MIXERCONTROL_CONTROLTYPE_SLIDER:
643 dprintf(("MIXERCONTROL_CONTROLTYPE_SLIDER"));
644 break;
645 case MIXERCONTROL_CONTROLTYPE_PAN:
646 dprintf(("MIXERCONTROL_CONTROLTYPE_PAN"));
647 break;
648 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN:
649 dprintf(("MIXERCONTROL_CONTROLTYPE_QSOUNDPAN"));
650 break;
651 case MIXERCONTROL_CONTROLTYPE_EQUALIZER:
652 dprintf(("MIXERCONTROL_CONTROLTYPE_EQUALIZER"));
653 break;
654 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
655 dprintf(("MIXERCONTROL_CONTROLTYPE_SINGLESELECT"));
656 break;
657 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
658 dprintf(("MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT"));
659 break;
660 case MIXERCONTROL_CONTROLTYPE_MICROTIME:
661 dprintf(("MIXERCONTROL_CONTROLTYPE_MICROTIME"));
662 break;
663 case MIXERCONTROL_CONTROLTYPE_MILLITIME:
664 dprintf(("MIXERCONTROL_CONTROLTYPE_MILLITIME"));
665 break;
666#endif
667 default:
668 DebugInt3();
669 return MIXERR_INVALCONTROL;
670 }
671 return MIXERR_INVALCONTROL;
672 case MIXER_GETCONTROLDETAILSF_LISTTEXT:
673 dprintf(("MIXER_GETCONTROLDETAILSF_LISTTEXT"));
674 break;
675 default:
676 dprintf(("Unknown flag (%08lx)\n", fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK));
677 break;
678 }
679 return MMSYSERR_NOTSUPPORTED;
680
681success:
682 if(pMixInfo->dwFlags & CALLBACK_WINDOW && pMixInfo->dwCallback) {
683 dprintf(("Notify window %x of control change", pMixInfo->dwCallback));
684 PostMessageA((HWND)pMixInfo->dwCallback, MM_MIXM_CONTROL_CHANGE, (WPARAM)hmxobj, (LPARAM)lpmcd->dwControlID);
685 }
686 return MMSYSERR_NOERROR;
687}
688/******************************************************************************/
689/******************************************************************************/
690MMRESULT WINAPI mixerGetLineControlsA(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSA lpMlc, DWORD fdwControls)
691{
692 DWORD dwRet = MMSYSERR_NOERROR;
693 DWORD lineID, controlType;
694 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
695
696 if((fdwControls & 0xF0000000) == MIXER_OBJECTF_HMIXER) {
697 if(!pMixInfo) {
698 return MMSYSERR_INVALHANDLE;
699 }
700 }
701 else
702 if((fdwControls & 0xF0000000) == MIXER_OBJECTF_MIXER) {
703 if(!HIWORD(hmxobj) && hmxobj > 0) {
704 return MMSYSERR_NODRIVER;
705 }
706 }
707
708 if (lpMlc == NULL) return MMSYSERR_INVALPARAM;
709
710 if (lpMlc->cbStruct < sizeof(*lpMlc) || lpMlc->cbmxctrl < sizeof(MIXERCONTROLA))
711 return MMSYSERR_INVALPARAM;
712
713 switch(fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)
714 {
715 case MIXER_GETLINECONTROLSF_ALL:
716 {
717 MIXERLINEA *pLine;
718 MIXERCONTROLA *pCtrl;
719
720 dprintf(("MIXER_GETLINECONTROLSF_ALL for line %d", lpMlc->dwLineID));
721 if(lpMlc->dwLineID >= nrLines) {
722 dprintf(("ERROR: Invalid line %d", lpMlc->dwLineID));
723 return MIXERR_INVALLINE;
724 }
725 pLine = &pmixerLines[lpMlc->dwLineID]->line;
726 if(lpMlc->cControls != pLine->cControls) {
727 dprintf(("ERROR: invalid nr of controls %d or structure size %d (%d) (ptr %x)", lpMlc->cControls, lpMlc->cbmxctrl, pLine->cControls*sizeof(MIXERCONTROLA), lpMlc->pamxctrl));
728 return MMSYSERR_INVALPARAM;
729 }
730 for(int i=0;i<lpMlc->cControls;i++) {
731 pCtrl = lpMlc->pamxctrl+i;
732 memcpy(pCtrl, &mixerControls[pmixerLines[lpMlc->dwLineID]->Controls[i]].ctrl, sizeof(MIXERCONTROLA));
733 dprintf(("found control %s (%s) control id %d", pCtrl->szName, pCtrl->szShortName, pCtrl->dwControlID));
734 }
735 break;
736 }
737
738 case MIXER_GETLINECONTROLSF_ONEBYID:
739 {
740 dprintf(("MIXER_GETLINECONTROLSF_ONEBYID %x", lpMlc->u.dwControlID));
741 if(lpMlc->cControls != 1 || lpMlc->cbmxctrl != sizeof(MIXERCONTROLA)) {
742 dprintf(("invalid parameters"));
743 return MMSYSERR_INVALPARAM;
744 }
745 if(lpMlc->u.dwControlID >= nrControls) {
746 dprintf(("invalid control"));
747 return MIXERR_INVALCONTROL;
748 }
749 //find line associated with this control
750 lpMlc->dwLineID = -1;
751 for(int i=0;i<nrLines;i++) {
752 for(int j=0;j<pmixerLines[i]->cControls;j++) {
753 if(pmixerLines[i]->Controls[j] == lpMlc->u.dwControlID) {
754 lpMlc->dwLineID = i;
755 break;
756 }
757 else
758 if(pmixerLines[i]->Controls[j] == -1) {
759 break;
760 }
761 }
762 if(lpMlc->dwLineID != -1) {
763 break;
764 }
765 }
766 if(i == MAX_MIXER_LINES) {
767 dprintf(("Associated line for control %d NOT FOUND", lpMlc->u.dwControlID));
768 return MIXERR_INVALCONTROL;
769 }
770 memcpy(lpMlc->pamxctrl, &mixerControls[lpMlc->u.dwControlID].ctrl, sizeof(MIXERCONTROLA));
771
772 dprintf(("found control %s (%s) associated line %d", lpMlc->pamxctrl->szName, lpMlc->pamxctrl->szShortName, lpMlc->dwLineID));
773 break;
774 }
775
776 case MIXER_GETLINECONTROLSF_ONEBYTYPE:
777 {
778 dprintf(("MIXER_GETLINECONTROLSF_ONEBYTYPE %x %d", lpMlc->u.dwControlType, lpMlc->dwLineID));
779 if(lpMlc->dwLineID >= nrLines) {
780 dprintf(("ERROR: Invalid line %d", lpMlc->dwLineID));
781 return MIXERR_INVALLINE;
782 }
783#ifdef DEBUG
784 switch (lpMlc->u.dwControlType) {
785 case MIXERCONTROL_CONTROLTYPE_CUSTOM:
786 dprintf(("MIXERCONTROL_CONTROLTYPE_CUSTOM"));
787 break;
788 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER:
789 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEANMETER"));
790 break;
791 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER:
792 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNEDMETER"));
793 break;
794 case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
795 dprintf(("MIXERCONTROL_CONTROLTYPE_PEAKMETER"));
796 break;
797 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER:
798 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER"));
799 break;
800 case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
801 dprintf(("MIXERCONTROL_CONTROLTYPE_BOOLEAN"));
802 break;
803 case MIXERCONTROL_CONTROLTYPE_ONOFF:
804 dprintf(("MIXERCONTROL_CONTROLTYPE_ONOFF"));
805 break;
806 case MIXERCONTROL_CONTROLTYPE_MUTE:
807 dprintf(("MIXERCONTROL_CONTROLTYPE_MUTE"));
808 break;
809 case MIXERCONTROL_CONTROLTYPE_MONO:
810 dprintf(("MIXERCONTROL_CONTROLTYPE_MONO"));
811 break;
812 case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
813 dprintf(("MIXERCONTROL_CONTROLTYPE_LOUDNESS"));
814 break;
815 case MIXERCONTROL_CONTROLTYPE_STEREOENH:
816 dprintf(("MIXERCONTROL_CONTROLTYPE_STEREOENH"));
817 break;
818 case MIXERCONTROL_CONTROLTYPE_BUTTON:
819 dprintf(("MIXERCONTROL_CONTROLTYPE_BUTTON"));
820 break;
821 case MIXERCONTROL_CONTROLTYPE_DECIBELS:
822 dprintf(("MIXERCONTROL_CONTROLTYPE_DECIBELS"));
823 break;
824 case MIXERCONTROL_CONTROLTYPE_SIGNED:
825 dprintf(("MIXERCONTROL_CONTROLTYPE_SIGNED"));
826 break;
827 case MIXERCONTROL_CONTROLTYPE_UNSIGNED:
828 dprintf(("MIXERCONTROL_CONTROLTYPE_UNSIGNED"));
829 break;
830 case MIXERCONTROL_CONTROLTYPE_PERCENT:
831 dprintf(("MIXERCONTROL_CONTROLTYPE_PERCENT"));
832 break;
833 case MIXERCONTROL_CONTROLTYPE_SLIDER:
834 dprintf(("MIXERCONTROL_CONTROLTYPE_SLIDER"));
835 break;
836 case MIXERCONTROL_CONTROLTYPE_PAN:
837 dprintf(("MIXERCONTROL_CONTROLTYPE_PAN"));
838 break;
839 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN:
840 dprintf(("MIXERCONTROL_CONTROLTYPE_QSOUNDPAN"));
841 break;
842 case MIXERCONTROL_CONTROLTYPE_FADER:
843 dprintf(("MIXERCONTROL_CONTROLTYPE_FADER"));
844 break;
845 case MIXERCONTROL_CONTROLTYPE_VOLUME:
846 dprintf(("MIXERCONTROL_CONTROLTYPE_VOLUME"));
847 break;
848 case MIXERCONTROL_CONTROLTYPE_BASS:
849 dprintf(("MIXERCONTROL_CONTROLTYPE_BASS"));
850 break;
851 case MIXERCONTROL_CONTROLTYPE_TREBLE:
852 dprintf(("MIXERCONTROL_CONTROLTYPE_TREBLE"));
853 break;
854 case MIXERCONTROL_CONTROLTYPE_EQUALIZER:
855 dprintf(("MIXERCONTROL_CONTROLTYPE_EQUALIZER"));
856 break;
857 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
858 dprintf(("MIXERCONTROL_CONTROLTYPE_SINGLESELECT"));
859 break;
860 case MIXERCONTROL_CONTROLTYPE_MUX:
861 dprintf(("MIXERCONTROL_CONTROLTYPE_MUX"));
862 break;
863 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
864 dprintf(("MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT"));
865 break;
866 case MIXERCONTROL_CONTROLTYPE_MIXER:
867 dprintf(("MIXERCONTROL_CONTROLTYPE_MIXER"));
868 break;
869 case MIXERCONTROL_CONTROLTYPE_MICROTIME:
870 dprintf(("MIXERCONTROL_CONTROLTYPE_MICROTIME"));
871 break;
872 case MIXERCONTROL_CONTROLTYPE_MILLITIME:
873 dprintf(("MIXERCONTROL_CONTROLTYPE_MILLITIME"));
874 break;
875 default:
876 return MMSYSERR_INVALPARAM;
877 }
878#endif
879 int idx;
880
881 for(int i=0;i<pmixerLines[lpMlc->dwLineID]->cControls;i++) {
882 idx = pmixerLines[lpMlc->dwLineID]->Controls[i];
883 if(mixerControls[idx].ctrl.dwControlType == lpMlc->u.dwControlType) {
884 memcpy(lpMlc->pamxctrl, &mixerControls[idx].ctrl, sizeof(MIXERCONTROLA));
885 dprintf(("found control %s (%s) control id %d", lpMlc->pamxctrl->szName, lpMlc->pamxctrl->szShortName, lpMlc->pamxctrl->dwControlID));
886 return MMSYSERR_NOERROR;
887 }
888
889 }
890 return MIXERR_INVALLINE; //returned by win2k when type not found
891 }
892 default:
893 dprintf(("Unknown flag %08lx\n", fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK));
894 dwRet = MMSYSERR_INVALPARAM;
895 break;
896 }
897
898 return dwRet;
899}
900/******************************************************************************/
901/******************************************************************************/
902MMRESULT WINAPI mixerGetLineControlsW(HMIXEROBJ hmxobj, LPMIXERLINECONTROLSW lpmlcW, DWORD fdwControls)
903{
904 MIXERLINECONTROLSA mlcA;
905 DWORD ret;
906 int i;
907
908 if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW) || lpmlcW->cbmxctrl != sizeof(MIXERCONTROLW))
909 return MMSYSERR_INVALPARAM;
910
911 mlcA.cbStruct = sizeof(mlcA);
912 mlcA.dwLineID = lpmlcW->dwLineID;
913 mlcA.u.dwControlID = lpmlcW->u.dwControlID;
914 mlcA.u.dwControlType = lpmlcW->u.dwControlType;
915 mlcA.cControls = lpmlcW->cControls;
916 mlcA.cbmxctrl = sizeof(MIXERCONTROLA);
917 mlcA.pamxctrl = (MIXERCONTROLA *)HeapAlloc(GetProcessHeap(), 0, mlcA.cControls * mlcA.cbmxctrl);
918
919 ret = mixerGetLineControlsA(hmxobj, &mlcA, fdwControls);
920
921 if (ret == MMSYSERR_NOERROR) {
922 lpmlcW->dwLineID = mlcA.dwLineID;
923 lpmlcW->u.dwControlID = mlcA.u.dwControlID;
924 lpmlcW->u.dwControlType = mlcA.u.dwControlType;
925 lpmlcW->cControls = mlcA.cControls;
926
927 for (i = 0; i < mlcA.cControls; i++) {
928 lpmlcW->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLW);
929 lpmlcW->pamxctrl[i].dwControlID = mlcA.pamxctrl[i].dwControlID;
930 lpmlcW->pamxctrl[i].dwControlType = mlcA.pamxctrl[i].dwControlType;
931 lpmlcW->pamxctrl[i].fdwControl = mlcA.pamxctrl[i].fdwControl;
932 lpmlcW->pamxctrl[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems;
933 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szShortName, -1,
934 lpmlcW->pamxctrl[i].szShortName,
935 sizeof(lpmlcW->pamxctrl[i].szShortName)/sizeof(WCHAR) );
936 MultiByteToWideChar( CP_ACP, 0, mlcA.pamxctrl[i].szName, -1,
937 lpmlcW->pamxctrl[i].szName,
938 sizeof(lpmlcW->pamxctrl[i].szName)/sizeof(WCHAR) );
939 /* sizeof(lpmlcW->pamxctrl[i].Bounds) ==
940 * sizeof(mlcA.pamxctrl[i].Bounds) */
941 memcpy(&lpmlcW->pamxctrl[i].Bounds, &mlcA.pamxctrl[i].Bounds,
942 sizeof(mlcA.pamxctrl[i].Bounds));
943 /* sizeof(lpmlcW->pamxctrl[i].Metrics) ==
944 * sizeof(mlcA.pamxctrl[i].Metrics) */
945 memcpy(&lpmlcW->pamxctrl[i].Metrics, &mlcA.pamxctrl[i].Metrics,
946 sizeof(mlcA.pamxctrl[i].Metrics));
947 }
948 }
949
950 HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl);
951 return ret;
952}
953/******************************************************************************/
954/******************************************************************************/
955MMRESULT WINAPI mixerGetLineInfoA(HMIXEROBJ hmxobj, LPMIXERLINEA lpMl, DWORD fdwInfo)
956{
957 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
958
959 if((fdwInfo & 0xF0000000) == MIXER_OBJECTF_HMIXER) {
960 if(!pMixInfo) {
961 return MMSYSERR_INVALHANDLE;
962 }
963 }
964 else
965 if((fdwInfo & 0xF0000000) == MIXER_OBJECTF_MIXER) {
966 if(!HIWORD(hmxobj) && hmxobj > 0) {
967 return MMSYSERR_NODRIVER;
968 }
969 }
970
971 if (lpMl == NULL || lpMl->cbStruct != sizeof(*lpMl)) {
972 dprintf(("ERROR: mixerGetLineInfoA: invalid paramter!!"));
973 return MMSYSERR_INVALPARAM;
974 }
975
976 switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK)
977 {
978 case MIXER_GETLINEINFOF_DESTINATION:
979 dprintf(("MIXER_GETLINEINFOF_DESTINATION %d", lpMl->dwDestination));
980 if(lpMl->dwDestination >= nrDestinations) {
981 dprintf(("ERROR: Invalid destination %d", lpMl->dwDestination));
982 return MMSYSERR_INVALPARAM;
983 }
984 memcpy(lpMl, &mixerDest[lpMl->dwDestination].line, sizeof(MIXERLINEA));
985 dprintf(("found line %s (%s) id %d connections %d controls %d", lpMl->szName, lpMl->szShortName, lpMl->dwLineID, lpMl->cConnections, lpMl->cControls));
986 break;
987
988 case MIXER_GETLINEINFOF_LINEID:
989 dprintf(("MIXER_GETLINEINFOF_LINEID %d", lpMl->dwLineID));
990 if(lpMl->dwLineID >= nrLines) {
991 dprintf(("ERROR: Invalid line %d", lpMl->dwLineID));
992 return MIXERR_INVALLINE;
993 }
994 memcpy(lpMl, &pmixerLines[lpMl->dwLineID]->line, sizeof(MIXERLINEA));
995 dprintf(("found line %s (%s) connections %d controls %d", lpMl->szName, lpMl->szShortName, lpMl->cConnections, lpMl->cControls));
996 break;
997
998 case MIXER_GETLINEINFOF_SOURCE:
999 dprintf(("MIXER_GETLINEINFOF_SOURCE %d %d", lpMl->dwDestination, lpMl->dwSource));
1000 if(lpMl->dwDestination >= nrDestinations) {
1001 dprintf(("ERROR: Invalid destination %d", lpMl->dwDestination));
1002 return MIXERR_INVALLINE;
1003 }
1004 if(lpMl->dwSource >= MIXER_SRC_MAX) {
1005 dprintf(("ERROR: Invalid source %d", lpMl->dwSource));
1006 return MIXERR_INVALLINE;
1007 }
1008 if(mixerDest[lpMl->dwDestination].Connections[lpMl->dwSource] == -1) {
1009 dprintf(("ERROR: Invalid destination/source combo (%d,%d)", lpMl->dwDestination, lpMl->dwSource));
1010 return MIXERR_INVALLINE;
1011 }
1012 memcpy(lpMl, &pmixerLines[mixerDest[lpMl->dwDestination].Connections[lpMl->dwSource]]->line, sizeof(MIXERLINEA));
1013 dprintf(("found line %s (%s) id %d connections %d controls %d", lpMl->szName, lpMl->szShortName, lpMl->dwLineID, lpMl->cConnections, lpMl->cControls));
1014 break;
1015
1016 case MIXER_GETLINEINFOF_COMPONENTTYPE:
1017 {
1018 dprintf(("MIXER_GETLINEINFOF_COMPONENTTYPE"));
1019#ifdef DEBUG
1020 switch (lpMl->dwComponentType)
1021 {
1022 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED:
1023 dprintf(("MIXERLINE_COMPONENTTYPE_DST_UNDEFINED"));
1024 break;
1025 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL:
1026 dprintf(("MIXERLINE_COMPONENTTYPE_DST_DIGITAL"));
1027 break;
1028 case MIXERLINE_COMPONENTTYPE_DST_LINE:
1029 dprintf(("MIXERLINE_COMPONENTTYPE_DST_LINE"));
1030 break;
1031 case MIXERLINE_COMPONENTTYPE_DST_MONITOR:
1032 dprintf(("MIXERLINE_COMPONENTTYPE_DST_MONITOR"));
1033 break;
1034 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
1035 dprintf(("MIXERLINE_COMPONENTTYPE_DST_SPEAKERS"));
1036 break;
1037 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES:
1038 dprintf(("MIXERLINE_COMPONENTTYPE_DST_HEADPHONES"));
1039 break;
1040 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE:
1041 dprintf(("MIXERLINE_COMPONENTTYPE_DST_TELEPHONE"));
1042 break;
1043 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
1044 dprintf(("MIXERLINE_COMPONENTTYPE_DST_WAVEIN"));
1045 break;
1046 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN:
1047 dprintf(("MIXERLINE_COMPONENTTYPE_DST_VOICEIN"));
1048 break;
1049 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED:
1050 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED"));
1051 break;
1052 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL:
1053 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_DIGITAL"));
1054 break;
1055 case MIXERLINE_COMPONENTTYPE_SRC_LINE:
1056 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_LINE"));
1057 break;
1058 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
1059 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE"));
1060 break;
1061 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
1062 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER"));
1063 break;
1064 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
1065 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC"));
1066 break;
1067 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE:
1068 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE"));
1069 break;
1070 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER:
1071 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER"));
1072 break;
1073 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
1074 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT"));
1075 break;
1076 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY:
1077 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY"));
1078 break;
1079 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG:
1080 dprintf(("MIXERLINE_COMPONENTTYPE_SRC_ANALOG"));
1081 break;
1082 default:
1083 dprintf(("Unhandled component type (%08lx)\n", lpMl->dwComponentType));
1084 return MMSYSERR_INVALPARAM;
1085 }
1086#endif
1087 //search all lines (src & dest) for one with specified type
1088 for(int i=0;i<nrLines;i++) {
1089 if(pmixerLines[i]->line.dwComponentType == lpMl->dwComponentType) {
1090 break;
1091 }
1092 }
1093 if(i == nrLines) {
1094 dprintf(("Component type %d not found!!", lpMl->dwComponentType));
1095 return MIXERR_INVALLINE;
1096 }
1097 memcpy(lpMl, &pmixerLines[i]->line, sizeof(MIXERLINEA));
1098 dprintf(("found line %s (%s) id %d connections %d controls %d", lpMl->szName, lpMl->szShortName, lpMl->dwLineID, lpMl->cConnections, lpMl->cControls));
1099 break;
1100 }
1101 case MIXER_GETLINEINFOF_TARGETTYPE:
1102 {
1103 dprintf(("MIXER_GETLINEINFOF_TARGETTYPE %x", lpMl->Target.dwType));
1104#ifdef DEBUG
1105 switch(lpMl->Target.dwType) {
1106 case MIXERLINE_TARGETTYPE_UNDEFINED:
1107 dprintf(("MIXERLINE_TARGETTYPE_UNDEFINED"));
1108 break;
1109 case MIXERLINE_TARGETTYPE_WAVEOUT:
1110 dprintf(("MIXERLINE_TARGETTYPE_WAVEOUT"));
1111 break;
1112 case MIXERLINE_TARGETTYPE_WAVEIN:
1113 dprintf(("MIXERLINE_TARGETTYPE_WAVEIN"));
1114 break;
1115 case MIXERLINE_TARGETTYPE_MIDIOUT:
1116 dprintf(("MIXERLINE_TARGETTYPE_MIDIOUT"));
1117 break;
1118 case MIXERLINE_TARGETTYPE_MIDIIN:
1119 dprintf(("MIXERLINE_TARGETTYPE_MIDIIN"));
1120 break;
1121 case MIXERLINE_TARGETTYPE_AUX:
1122 dprintf(("MIXERLINE_TARGETTYPE_AUX"));
1123 break;
1124 default:
1125 dprintf(("Unhandled target type (%08lx)\n", lpMl->Target.dwType));
1126 return MMSYSERR_INVALPARAM;
1127 }
1128#endif
1129 //search all lines (src & dest) for one with specified type
1130 //TODO: Should we compare mid, pid & pddname too? (must be initialized according to MSDN)
1131 // (see below; unicode version doesn't copy pddname; change if these checks are required)
1132 for(int i=0;i<nrLines;i++) {
1133 if(pmixerLines[i]->line.Target.dwType == lpMl->Target.dwType) {
1134 break;
1135 }
1136 }
1137 if(i == nrLines) {
1138 dprintf(("Component type %d not found!!", lpMl->Target.dwType));
1139 return MIXERR_INVALLINE;
1140 }
1141 memcpy(lpMl, &pmixerLines[i]->line, sizeof(MIXERLINEA));
1142 dprintf(("found line %s (%s) id %d connections %d controls %d", lpMl->szName, lpMl->szShortName, lpMl->dwLineID, lpMl->cConnections, lpMl->cControls));
1143 break;
1144 }
1145 default:
1146 dprintf(("Unknown flag (%08lx)\n", fdwInfo & MIXER_GETLINEINFOF_QUERYMASK));
1147 return MMSYSERR_INVALPARAM;
1148 break;
1149 }
1150 return MMSYSERR_NOERROR;
1151}
1152/******************************************************************************/
1153/******************************************************************************/
1154MMRESULT WINAPI mixerGetLineInfoW(HMIXEROBJ hmxobj, LPMIXERLINEW pmxl, DWORD fdwInfo)
1155{
1156 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
1157 MIXERLINEA line;
1158 MMRESULT result;
1159
1160 line.cbStruct = sizeof(MIXERLINEA);
1161 line.cChannels = pmxl->cChannels;
1162 line.cConnections = pmxl->cConnections;
1163 line.cControls = pmxl->cControls;
1164 line.dwComponentType = pmxl->dwComponentType;
1165 line.dwDestination = pmxl->dwDestination;
1166 line.dwLineID = pmxl->dwLineID;
1167 line.dwSource = pmxl->dwSource;
1168 line.dwUser = pmxl->dwUser;
1169 line.fdwLine = pmxl->fdwLine;
1170 line.szName[0] = 0;
1171 line.szShortName[0] = 0;
1172 line.Target.dwDeviceID = pmxl->Target.dwDeviceID;
1173 line.Target.dwType = pmxl->Target.dwType;
1174 line.Target.vDriverVersion = pmxl->Target.vDriverVersion;
1175 line.Target.wMid = pmxl->Target.wMid;
1176 line.Target.wPid = pmxl->Target.wPid;
1177 //TODO: need to copy this?? (MIXER_GETLINEINFOF_TARGETTYPE)
1178 line.Target.szPname[0] = 0;
1179
1180 result = mixerGetLineInfoA(hmxobj, &line, fdwInfo);
1181 if(result != MMSYSERR_NOERROR) {
1182 return result;
1183 }
1184 pmxl->cbStruct = sizeof(MIXERLINEA);
1185 pmxl->cChannels = line.cChannels;
1186 pmxl->cConnections = line.cConnections;
1187 pmxl->cControls = line.cControls;
1188 pmxl->dwComponentType = line.dwComponentType;
1189 pmxl->dwDestination = line.dwDestination;
1190 pmxl->dwLineID = line.dwLineID;
1191 pmxl->dwSource = line.dwSource;
1192 pmxl->dwUser = line.dwUser;
1193 pmxl->fdwLine = line.fdwLine;
1194 MultiByteToWideChar(CP_ACP, 0, line.szName, -1, pmxl->szName, sizeof(line.szName));
1195 MultiByteToWideChar(CP_ACP, 0, line.szShortName, -1, pmxl->szShortName, sizeof(line.szShortName));
1196 pmxl->Target.dwDeviceID = line.Target.dwDeviceID;
1197 pmxl->Target.dwType = line.Target.dwType;
1198 pmxl->Target.vDriverVersion = line.Target.vDriverVersion;
1199 pmxl->Target.wMid = line.Target.wMid;
1200 pmxl->Target.wPid = line.Target.wPid;
1201 pmxl->Target.szPname[0] = 0;
1202 MultiByteToWideChar(CP_ACP, 0, line.Target.szPname, -1, pmxl->Target.szPname, sizeof(line.Target.szPname));
1203 return MMSYSERR_NOERROR;
1204}
1205/******************************************************************************/
1206/******************************************************************************/
1207MMRESULT WINAPI mixerMessage(HMIXER hmx, UINT uMsg, DWORD dwParam1, DWORD dwParam2)
1208{
1209 dprintf(("WINMM:mixerMessage - NOT IMPLEMENTED" ));
1210 return MMSYSERR_NOTSUPPORTED;
1211}
1212/******************************************************************************/
1213/******************************************************************************/
1214UINT WINAPI mixerGetNumDevs()
1215{
1216 if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
1217 return 0;
1218 }
1219 return 1;
1220}
1221/******************************************************************************/
1222/******************************************************************************/
1223MMRESULT WINAPI mixerGetDevCapsA(UINT uMxId, LPMIXERCAPSA pmxcaps, UINT cbmxcaps)
1224{
1225 if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
1226 return MMSYSERR_BADDEVICEID;
1227 }
1228
1229 // According to MSDN, uMxId may be a handle returned by mixerOpen() so we
1230 // must accept this situation. Note that since we don't actually track
1231 // the created handles and that we provide only one mixer anyway
1232 // (see mixerGetNumDevs()), we have to accept any uMxId value here...
1233#if 0
1234 if(uMxId > 0) {
1235 return MMSYSERR_BADDEVICEID;
1236 }
1237#endif
1238
1239 //According to MSDN, nothing is copied when cbmxcaps is zero
1240 if(cbmxcaps >= sizeof(MIXERCAPSA)) {
1241 pmxcaps->wMid = WINMM_MIXER_CAPS_WMID; /* manufacturer ID */
1242 pmxcaps->wPid = WINMM_MIXER_CAPS_WPID; /* product ID */
1243 pmxcaps->vDriverVersion = WINMM_MIXER_CAPS_VERSION; /* version of the driver */
1244 strncpy( pmxcaps->szPname, WINMM_MIXERSTRING_A, sizeof(pmxcaps->szPname)); /* product name */
1245
1246 pmxcaps->fdwSupport = 0; //no mixer flags exist
1247 pmxcaps->cDestinations = nrDestinations;
1248 dprintf(("mixerGetDevCapsA: cDestinations %d", pmxcaps->cDestinations));
1249 }
1250
1251 return MMSYSERR_NOERROR;
1252}
1253/******************************************************************************/
1254/******************************************************************************/
1255MMRESULT WINAPI mixerGetDevCapsW(UINT uMxId, LPMIXERCAPSW pmxcaps, UINT cbmxcaps)
1256{
1257 if(fMMPMAvailable == FALSE || DartWaveOut::getNumDevices() == 0) {
1258 return MMSYSERR_BADDEVICEID;
1259 }
1260
1261 // According to MSDN, uMxId may be a handle returned by mixerOpen() so we
1262 // must accept this situation. Note that since we don't actually track
1263 // the created handles and that we provide only one mixer anyway
1264 // (see mixerGetNumDevs()), we have to accept any uMxId value here...
1265#if 0
1266 if(uMxId > 0) {
1267 return MMSYSERR_BADDEVICEID;
1268 }
1269#endif
1270
1271 //According to MSDN, nothing is copied when cbmxcaps is zero
1272 if(cbmxcaps >= sizeof(MIXERCAPSW)) {
1273 pmxcaps->wMid = WINMM_MIXER_CAPS_WMID; /* manufacturer ID */
1274 pmxcaps->wPid = WINMM_MIXER_CAPS_WPID; /* product ID */
1275 pmxcaps->vDriverVersion = WINMM_MIXER_CAPS_VERSION; /* version of the driver */
1276 lstrcpyW( pmxcaps->szPname, WINMM_MIXERSTRING_W ); /* product name */
1277
1278 pmxcaps->fdwSupport = 0; //no mixer flags exist
1279 pmxcaps->cDestinations = nrDestinations;
1280 dprintf(("mixerGetDevCapsW: cDestinations %d", pmxcaps->cDestinations));
1281 }
1282
1283 return MMSYSERR_NOERROR;
1284}
1285/******************************************************************************/
1286/******************************************************************************/
1287MMRESULT WINAPI mixerGetID(HMIXEROBJ hmxobj, UINT * puMxId, DWORD fdwId)
1288{
1289 switch(fdwId) {
1290 case MIXER_OBJECTF_MIXER:
1291 {
1292 DEVICE_STRUCT *pMixInfo = (DEVICE_STRUCT *)hmxobj;
1293 if(!pMixInfo) {
1294 if(puMxId) {
1295 *puMxId = -1;
1296 }
1297 return MMSYSERR_INVALHANDLE;
1298 }
1299 if(puMxId) {
1300 *puMxId = pMixInfo->uDeviceID;
1301 }
1302 break;
1303 }
1304
1305 case MIXER_OBJECTF_HMIXER:
1306 case MIXER_OBJECTF_WAVEOUT:
1307 case MIXER_OBJECTF_HWAVEOUT:
1308 case MIXER_OBJECTF_WAVEIN:
1309 case MIXER_OBJECTF_HWAVEIN:
1310 case MIXER_OBJECTF_MIDIOUT:
1311 case MIXER_OBJECTF_HMIDIOUT:
1312 case MIXER_OBJECTF_MIDIIN:
1313 case MIXER_OBJECTF_HMIDIIN:
1314 case MIXER_OBJECTF_AUX:
1315 //TODO: assume default mixer
1316 if(puMxId) {
1317 *puMxId = 0;
1318 }
1319 break;
1320 default:
1321 if(puMxId) {
1322 *puMxId = -1;
1323 }
1324 return MMSYSERR_INVALPARAM;
1325 }
1326 return MMSYSERR_NOERROR;
1327}
1328/******************************************************************************/
1329/******************************************************************************/
1330MMRESULT WINAPI mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD dwCallback, DWORD dwInstance,
1331 DWORD fdwOpen)
1332{
1333 DEVICE_STRUCT *pMixInfo;
1334
1335 if (mixerGetNumDevs() <= uMxId) {
1336 if(phmx) *phmx = 0;
1337 return MMSYSERR_NODRIVER;
1338 }
1339
1340 pMixInfo = (DEVICE_STRUCT *)malloc(sizeof(DEVICE_STRUCT));
1341 if(pMixInfo == NULL) {
1342 return MMSYSERR_NODRIVER;
1343 }
1344 pMixInfo->dwCallback = dwCallback;
1345 pMixInfo->dwDriverInstance = dwInstance;
1346 pMixInfo->dwFlags = fdwOpen;
1347 pMixInfo->uDeviceID = uMxId;
1348 pMixInfo->type = WINMM_MIXER;
1349 if(phmx)
1350 *phmx = (HMIXER)pMixInfo;
1351
1352 return MMSYSERR_NOERROR;
1353}
1354/******************************************************************************/
1355/******************************************************************************/
1356MMRESULT WINAPI mixerClose(HMIXER hmx)
1357{
1358 if(hmx) {
1359 free((void *)hmx);
1360 }
1361 return MMSYSERR_NOERROR;
1362}
1363/******************************************************************************/
1364/******************************************************************************/
1365BOOL mixerInit()
1366{
1367 MIXLINE *pDestLine;
1368 MIXERCONTROLA *pWaveInMux;
1369
1370 if(!fMMPMAvailable) return TRUE;
1371
1372 memset(mixerDest, 0, sizeof(mixerDest));
1373 for(int i=0;i<MIXER_DEST_MAX;i++) {
1374 memset(mixerDest[i].Connections, -1, sizeof(mixerDest[i].Connections));
1375 memset(mixerDest[i].Controls, -1, sizeof(mixerDest[i].Controls));
1376 }
1377 memset(mixerSource, 0, sizeof(mixerSource));
1378 for(i=0;i<MIXER_SRC_MAX;i++) {
1379 memset(mixerSource[i].Connections, -1, sizeof(mixerSource[i].Connections));
1380 memset(mixerSource[i].Controls, -1, sizeof(mixerSource[i].Controls));
1381 mixerSource[i].id = -1;
1382 }
1383 if(OSLibMixerOpen() == FALSE) {
1384 //Line out destination
1385 pDestLine = mixerAddDestination(MIXER_DEST_LINEOUT);
1386 mixerAddControl(MIX_CTRL_VOL_OUT_LINE, pDestLine);
1387 mixerAddControl(MIX_CTRL_MUTE_OUT_LINE, pDestLine);
1388
1389 //WaveIn destination
1390 pDestLine = mixerAddDestination(MIXER_DEST_WAVEIN);
1391 pWaveInMux = mixerAddControl(MIX_CTRL_MUX_IN_W_SRC, pDestLine);
1392 mixerAddControl(MIX_CTRL_VOL_IN_W_MIC, pDestLine);
1393 mixerAddControl(MIX_CTRL_VOL_IN_W_LINE, pDestLine);
1394 pWaveInMux->cMultipleItems = pDestLine->line.cConnections;
1395 return TRUE;
1396 }
1397
1398 //Line out destination
1399 pDestLine = mixerAddDestination(MIXER_DEST_LINEOUT);
1400
1401 mixerAddControl(MIX_CTRL_VOL_OUT_LINE, pDestLine);
1402 mixerAddControl(MIX_CTRL_MUTE_OUT_LINE, pDestLine);
1403
1404 if(OSLibMixIsControlPresent(MIX_CTRL_OUT_L_3DCENTER)) {
1405 mixerAddControl(MIX_CTRL_OUT_L_3DCENTER, pDestLine);
1406 }
1407 if(OSLibMixIsControlPresent(MIX_CTRL_OUT_L_3DDEPTH)) {
1408 mixerAddControl(MIX_CTRL_OUT_L_3DDEPTH, pDestLine);
1409 }
1410 if(OSLibMixIsControlPresent(MIX_CTRL_OUT_L_TREBLE)) {
1411 mixerAddControl(MIX_CTRL_OUT_L_TREBLE, pDestLine);
1412 }
1413 if(OSLibMixIsControlPresent(MIX_CTRL_OUT_L_BASS)) {
1414 mixerAddControl(MIX_CTRL_OUT_L_BASS, pDestLine);
1415 }
1416
1417 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_PCM)) {
1418 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_PCM);
1419 mixerAddControl(MIX_CTRL_VOL_IN_L_PCM, pLine);
1420 mixerAddControl(MIX_CTRL_MUTE_IN_L_PCM, pLine);
1421 }
1422 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_WAVETABLE)) {
1423 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_WAVETABLE);
1424 mixerAddControl(MIX_CTRL_VOL_IN_L_WAVETABLE, pLine);
1425 mixerAddControl(MIX_CTRL_MUTE_IN_L_WAVETABLE, pLine);
1426 }
1427 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_MIDI)) {
1428 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_MIDI);
1429 mixerAddControl(MIX_CTRL_VOL_IN_L_MIDI, pLine);
1430 mixerAddControl(MIX_CTRL_MUTE_IN_L_MIDI, pLine);
1431 }
1432 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_MIC)) {
1433 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_MIC);
1434 mixerAddControl(MIX_CTRL_VOL_IN_L_MIC, pLine);
1435 mixerAddControl(MIX_CTRL_MUTE_IN_L_MIC, pLine);
1436 if(OSLibMixIsControlPresent(MIX_CTRL_BOOST_IN_L_MIC)) {
1437 mixerAddControl(MIX_CTRL_BOOST_IN_L_MIC, pLine);
1438 }
1439 }
1440 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_LINE)) {
1441 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_LINE);
1442 mixerAddControl(MIX_CTRL_VOL_IN_L_LINE, pLine);
1443 mixerAddControl(MIX_CTRL_MUTE_IN_L_LINE, pLine);
1444 }
1445 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_CD)) {
1446 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_CD);
1447 mixerAddControl(MIX_CTRL_VOL_IN_L_CD, pLine);
1448 mixerAddControl(MIX_CTRL_MUTE_IN_L_CD, pLine);
1449 }
1450 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_AUX)) {
1451 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_AUX);
1452 mixerAddControl(MIX_CTRL_VOL_IN_L_AUX, pLine);
1453 mixerAddControl(MIX_CTRL_MUTE_IN_L_AUX, pLine);
1454 }
1455 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_SPDIF)) {
1456 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_SPDIF);
1457 mixerAddControl(MIX_CTRL_VOL_IN_L_SPDIF, pLine);
1458 mixerAddControl(MIX_CTRL_MUTE_IN_L_SPDIF, pLine);
1459 }
1460 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_MONO)) {
1461 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_MONOIN);
1462 mixerAddControl(MIX_CTRL_VOL_IN_L_MONO, pLine);
1463 mixerAddControl(MIX_CTRL_MUTE_IN_L_MONO, pLine);
1464 }
1465 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_PHONE)) {
1466 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_PHONE);
1467 mixerAddControl(MIX_CTRL_VOL_IN_L_PHONE, pLine);
1468 mixerAddControl(MIX_CTRL_MUTE_IN_L_PHONE, pLine);
1469 }
1470 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_IN_L_VIDEO)) {
1471 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_L_VIDEO);
1472 mixerAddControl(MIX_CTRL_VOL_IN_L_VIDEO, pLine);
1473 mixerAddControl(MIX_CTRL_MUTE_IN_L_VIDEO, pLine);
1474 }
1475
1476 //Wave In Destination
1477 if(OSLibMixIsControlPresent(MIX_CTRL_MUX_IN_W_SRC)) {
1478 pDestLine = mixerAddDestination(MIXER_DEST_WAVEIN);
1479 pWaveInMux = mixerAddControl(MIX_CTRL_MUX_IN_W_SRC, pDestLine);
1480
1481 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_MIC)) {
1482 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_MIC);
1483 mixerAddControl(MIX_CTRL_VOL_IN_W_MIC, pLine);
1484 }
1485 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_LINE)) {
1486 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_LINE);
1487 mixerAddControl(MIX_CTRL_VOL_IN_W_LINE, pLine);
1488 }
1489 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_CD)) {
1490 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_CD);
1491 mixerAddControl(MIX_CTRL_VOL_IN_W_CD, pLine);
1492 }
1493 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_AUX)) {
1494 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_AUX);
1495 mixerAddControl(MIX_CTRL_VOL_IN_W_AUX, pLine);
1496 }
1497 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_PCM)) {
1498 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_PCM);
1499 mixerAddControl(MIX_CTRL_VOL_IN_W_PCM, pLine);
1500 }
1501 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_WAVETABLE)) {
1502 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_WAVETABLE);
1503 mixerAddControl(MIX_CTRL_VOL_IN_W_WAVETABLE, pLine);
1504 }
1505 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_MIDI)) {
1506 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_MIDI);
1507 mixerAddControl(MIX_CTRL_VOL_IN_W_MIDI, pLine);
1508 }
1509 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_MONOIN)) {
1510 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_MONOIN);
1511 mixerAddControl(MIX_CTRL_VOL_IN_W_MONO, pLine);
1512 }
1513 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_PHONE)) {
1514 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_PHONE);
1515 mixerAddControl(MIX_CTRL_VOL_IN_W_PHONE, pLine);
1516 }
1517 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_SPDIF)) {
1518 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_SPDIF);
1519 mixerAddControl(MIX_CTRL_VOL_IN_W_SPDIF, pLine);
1520 }
1521 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_VIDEO)) {
1522 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_VIDEO);
1523 mixerAddControl(MIX_CTRL_VOL_IN_W_VIDEO, pLine);
1524 }
1525 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_STEREOMIX)) {
1526 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_STEREOMIX);
1527 mixerAddControl(MIX_CTRL_VOL_IN_W_STEREOMIX, pLine);
1528 }
1529 if(OSLibMixIsRecSourcePresent(MIXER_SRC_IN_W_MONOMIX)) {
1530 MIXLINE *pLine = mixerAddSource(pDestLine, MIXER_SRC_IN_W_MONOMIX);
1531 mixerAddControl(MIX_CTRL_VOL_IN_W_MONOMIX, pLine);
1532 }
1533 pWaveInMux->cMultipleItems = pDestLine->line.cConnections;
1534 pWaveInMux->Bounds.s.lMinimum = 0;
1535 pWaveInMux->Bounds.s.lMaximum = pDestLine->line.cConnections;
1536 pWaveInMux->Metrics.cSteps = pDestLine->line.cConnections;
1537 }
1538
1539 //SPDIF destination
1540 if(OSLibMixIsControlPresent(MIX_CTRL_VOL_OUT_SPDIF)) {
1541 pDestLine = mixerAddDestination(MIXER_DEST_SPDIFOUT);
1542 mixerAddControl(MIX_CTRL_VOL_OUT_SPDIF, pDestLine);
1543 mixerAddControl(MIX_CTRL_MUTE_OUT_SPDIF, pDestLine);
1544 }
1545
1546 return TRUE;
1547}
1548/******************************************************************************/
1549/******************************************************************************/
1550void mixerExit()
1551{
1552 if(fMMPMAvailable == FALSE) return;
1553
1554 OSLibMixerClose();
1555}
1556/******************************************************************************/
1557/******************************************************************************/
1558static MIXLINE *mixerAddSource(MIXLINE *pDestLine, DWORD dwSource)
1559{
1560 MIXLINE *pSource = &mixerSource[nrSources];
1561 MIXERLINEA *pline = &pSource->line;
1562
1563 if(nrSources >= MAX_MIXER_SOURCES) {
1564 dprintf(("ERROR: mixerAddSource: out of room!!!"));
1565 DebugInt3();
1566 return NULL;
1567 }
1568
1569 memset(pline, 0, sizeof(MIXERLINEA));
1570
1571 pline->cbStruct = sizeof(MIXERLINEA);
1572 pline->cConnections = 0;
1573 pline->cControls = 0;
1574 pline->dwDestination = 0;
1575 pline->fdwLine = MIXERLINE_LINEF_SOURCE;
1576 pline->Target.dwDeviceID = 0;
1577 pline->Target.wMid = WINMM_MIXER_CAPS_WMID;
1578 pline->Target.vDriverVersion = WINMM_MIXER_CAPS_VERSION;
1579 pline->dwSource = nrSources;
1580 OSLibMixGetLineCaps(dwSource, &pline->cChannels);
1581 nrSources++;
1582
1583 switch(dwSource) {
1584 case MIXER_SRC_IN_L_MONOIN:
1585 case MIXER_SRC_IN_W_MONOIN:
1586 case MIXER_SRC_IN_L_PHONE:
1587 case MIXER_SRC_IN_W_PHONE:
1588 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
1589 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1590 break;
1591
1592 case MIXER_SRC_IN_L_MIC:
1593 case MIXER_SRC_IN_W_MIC:
1594 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
1595 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1596 break;
1597
1598 case MIXER_SRC_IN_L_LINE:
1599 case MIXER_SRC_IN_W_LINE:
1600 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
1601 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1602 break;
1603
1604 case MIXER_SRC_IN_L_CD:
1605 case MIXER_SRC_IN_W_CD:
1606 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
1607 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1608 break;
1609
1610 case MIXER_SRC_IN_L_SPDIF:
1611 case MIXER_SRC_IN_W_SPDIF:
1612 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
1613 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1614 break;
1615
1616 case MIXER_SRC_IN_L_VIDEO:
1617 case MIXER_SRC_IN_W_VIDEO:
1618 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
1619 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1620 break;
1621
1622 case MIXER_SRC_IN_L_AUX:
1623 case MIXER_SRC_IN_W_AUX:
1624 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY;
1625 pline->Target.dwType = MIXERLINE_TARGETTYPE_AUX;
1626 break;
1627
1628 case MIXER_SRC_IN_L_PCM:
1629 case MIXER_SRC_IN_W_PCM:
1630 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
1631 pline->Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
1632 break;
1633
1634 case MIXER_SRC_IN_L_WAVETABLE:
1635 case MIXER_SRC_IN_W_WAVETABLE:
1636 case MIXER_SRC_IN_L_MIDI:
1637 case MIXER_SRC_IN_W_MIDI:
1638 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
1639 pline->Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT;
1640 break;
1641
1642 default:
1643 DebugInt3();
1644 return NULL;
1645 }
1646 strncpy(pline->szShortName, szSourceName[dwSource][0], sizeof(pline->szShortName));
1647 strncpy(pline->szName, szSourceName[dwSource][1], sizeof(pline->szName));
1648 strncpy(pline->Target.szPname, WINMM_MIXERSTRING_A, sizeof(pline->Target.szPname));
1649
1650 //add to array of mixer line pointers
1651 pline->dwLineID = nrLines;
1652 pmixerLines[nrLines] = pSource;
1653 nrLines++;
1654
1655 //store line id in source to line mapping array
1656 pSource->id = dwSource;
1657
1658 //increase nr of inputs at destination line
1659 pDestLine->line.cConnections++;
1660 pDestLine->Connections[pDestLine->cConnections] = pline->dwLineID;
1661 pDestLine->cConnections++;
1662
1663 dprintf(("Adding Source %s (%s) with destination %s (%d -> %d)", pline->szName, pline->szShortName, pDestLine->line.szName, dwSource, pline->dwLineID));
1664
1665 return pSource;
1666}
1667/******************************************************************************/
1668/******************************************************************************/
1669static MIXLINE *mixerAddDestination(DWORD dwDest)
1670{
1671 MIXLINE *pDest = &mixerDest[nrDestinations];
1672 MIXERLINEA *pline = &pDest->line;
1673
1674 if(nrDestinations >= MAX_MIXER_DESTINATIONS) {
1675 dprintf(("ERROR: mixerAddDestination: out of room!!!"));
1676 DebugInt3();
1677 return NULL;
1678 }
1679 memset(pline, 0, sizeof(MIXERLINEA));
1680 pline->cbStruct = sizeof(MIXERLINEA);
1681 pline->cConnections = 0;
1682 pline->cControls = 0;
1683 pline->dwSource = (DWORD)-1;
1684 pline->dwDestination = nrDestinations;
1685
1686 switch(dwDest) {
1687 case MIXER_DEST_LINEOUT:
1688 pline->cChannels = 2;
1689 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
1690 pline->fdwLine = MIXERLINE_LINEF_ACTIVE;
1691 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1692 break;
1693
1694 case MIXER_DEST_SPDIFOUT:
1695 pline->cChannels = 2;
1696 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_DIGITAL;
1697 pline->fdwLine = MIXERLINE_LINEF_ACTIVE;
1698 pline->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1699 break;
1700
1701 case MIXER_DEST_WAVEIN:
1702 pline->cChannels = 2;
1703 pline->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
1704 pline->fdwLine = MIXERLINE_LINEF_ACTIVE;
1705 pline->Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
1706 break;
1707
1708 default:
1709 DebugInt3();
1710 return NULL;
1711 }
1712 strncpy(pline->szShortName, szDestName[dwDest][0], sizeof(pline->szShortName));
1713 strncpy(pline->szName, szDestName[dwDest][1], sizeof(pline->szName));
1714 strncpy(pline->Target.szPname, WINMM_MIXERSTRING_A, sizeof(pline->Target.szPname));
1715 pline->Target.dwDeviceID = 0;
1716 pline->Target.wMid = WINMM_MIXER_CAPS_WMID;
1717 pline->Target.wPid = WINMM_MIXER_CAPS_WPID;
1718 pline->Target.vDriverVersion = WINMM_MIXER_CAPS_VERSION;
1719
1720 dprintf(("Adding destination %s (%s) connections %d controls %d", pline->szName, pline->szShortName, pline->cConnections, pline->cControls));
1721 nrDestinations++;
1722
1723 pline->dwLineID = nrLines;
1724 pmixerLines[nrLines] = pDest;
1725 nrLines++;
1726
1727 //save internal id
1728 pDest->id = dwDest;
1729 return pDest;
1730}
1731/******************************************************************************/
1732/******************************************************************************/
1733static MIXERCONTROLA * mixerAddControl(DWORD dwControl, MIXLINE *pSrcLine)
1734{
1735 MIXCONTROL *pmixctrl = &mixerControls[nrControls];
1736 MIXERCONTROLA *pctrl = &pmixctrl->ctrl;
1737
1738 if(nrControls >= MAX_MIXER_CONTROLS) {
1739 dprintf(("ERROR: mixerAddControl: out of room!!!"));
1740 DebugInt3();
1741 return NULL;
1742 }
1743
1744 memset(pctrl, 0, sizeof(MIXERCONTROLA));
1745 pctrl->cbStruct = sizeof(MIXERCONTROLA);
1746 pctrl->cMultipleItems = 0;
1747 pctrl->dwControlID = nrControls;
1748 pctrl->fdwControl = 0;
1749 switch(dwControl) {
1750 case MIX_CTRL_MUX_IN_W_SRC:
1751 pctrl->fdwControl = MIXERCONTROL_CONTROLF_MULTIPLE | MIXERCONTROL_CONTROLF_UNIFORM;
1752 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
1753 pctrl->Bounds.s.lMinimum = 0;
1754 pctrl->Bounds.s.lMaximum = 1;
1755 pctrl->Metrics.cSteps = 1;
1756 pctrl->cMultipleItems = 0; //to be filled in later (see caller)
1757 break;
1758
1759 case MIX_CTRL_VOL_OUT_LINE:
1760 case MIX_CTRL_VOL_IN_L_MONO:
1761 case MIX_CTRL_VOL_IN_L_PHONE:
1762 case MIX_CTRL_VOL_IN_L_MIC:
1763 case MIX_CTRL_VOL_IN_L_LINE:
1764 case MIX_CTRL_VOL_IN_L_CD:
1765 case MIX_CTRL_VOL_IN_L_SPDIF:
1766 case MIX_CTRL_VOL_IN_L_VIDEO:
1767 case MIX_CTRL_VOL_IN_L_AUX:
1768 case MIX_CTRL_VOL_IN_L_PCM:
1769 case MIX_CTRL_VOL_IN_L_WAVETABLE:
1770 case MIX_CTRL_VOL_IN_L_MIDI:
1771 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
1772 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1773 break;
1774
1775 case MIX_CTRL_VOL_IN_W_MONO:
1776 case MIX_CTRL_VOL_IN_W_PHONE:
1777 case MIX_CTRL_VOL_IN_W_MIC:
1778 case MIX_CTRL_VOL_IN_W_LINE:
1779 case MIX_CTRL_VOL_IN_W_CD:
1780 case MIX_CTRL_VOL_IN_W_SPDIF:
1781 case MIX_CTRL_VOL_IN_W_VIDEO:
1782 case MIX_CTRL_VOL_IN_W_AUX:
1783 case MIX_CTRL_VOL_IN_W_PCM:
1784 case MIX_CTRL_VOL_IN_W_WAVETABLE:
1785 case MIX_CTRL_VOL_IN_W_MIDI:
1786 case MIX_CTRL_VOL_IN_W_STEREOMIX:
1787 case MIX_CTRL_VOL_IN_W_MONOMIX:
1788 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
1789 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1790 break;
1791
1792 case MIX_CTRL_MUTE_OUT_LINE:
1793 case MIX_CTRL_MUTE_IN_L_MONO:
1794 case MIX_CTRL_MUTE_IN_L_PHONE:
1795 case MIX_CTRL_MUTE_IN_L_MIC:
1796 case MIX_CTRL_MUTE_IN_L_LINE:
1797 case MIX_CTRL_MUTE_IN_L_CD:
1798 case MIX_CTRL_MUTE_IN_L_SPDIF:
1799 case MIX_CTRL_MUTE_IN_L_VIDEO:
1800 case MIX_CTRL_MUTE_IN_L_AUX:
1801 case MIX_CTRL_MUTE_IN_L_PCM:
1802 pctrl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
1803 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
1804 pctrl->Bounds.s.lMinimum = 0;
1805 pctrl->Bounds.s.lMaximum = 1;
1806 pctrl->Metrics.cSteps = 0;
1807 break;
1808
1809 case MIX_CTRL_VOL_OUT_SPDIF:
1810 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
1811 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1812 break;
1813
1814 case MIX_CTRL_MUTE_OUT_SPDIF:
1815 pctrl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
1816 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
1817 pctrl->Bounds.s.lMinimum = 0;
1818 pctrl->Bounds.s.lMaximum = 1;
1819 pctrl->Metrics.cSteps = 0;
1820 break;
1821
1822 case MIX_CTRL_BOOST_IN_L_MIC:
1823 pctrl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
1824 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_ONOFF;
1825 pctrl->Bounds.s.lMinimum = 0;
1826 pctrl->Bounds.s.lMaximum = 1;
1827 pctrl->Metrics.cSteps = 0;
1828 break;
1829
1830 case MIX_CTRL_OUT_L_3DDEPTH:
1831 pctrl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
1832 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_FADER;
1833 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1834 break;
1835
1836 case MIX_CTRL_OUT_L_3DCENTER:
1837 pctrl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
1838 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_FADER;
1839 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1840 break;
1841
1842 case MIX_CTRL_OUT_L_TREBLE:
1843 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_TREBLE;
1844 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1845 break;
1846
1847 case MIX_CTRL_OUT_L_BASS:
1848 pctrl->dwControlType = MIXERCONTROL_CONTROLTYPE_BASS;
1849 OSLibMixGetCtrlCaps(dwControl, &pctrl->Bounds.s.lMinimum, &pctrl->Bounds.s.lMaximum, &pctrl->Metrics.cSteps);
1850 break;
1851
1852 default:
1853 DebugInt3();
1854 return FALSE;
1855 }
1856
1857 //add control to list of controls associated with source line
1858 pSrcLine->Controls[pSrcLine->cControls] = pctrl->dwControlID;
1859 pSrcLine->line.cControls++;
1860 pSrcLine->cControls++;
1861
1862 strncpy(pctrl->szShortName, szCtrlName[dwControl][0], sizeof(pctrl->szShortName));
1863 strncpy(pctrl->szName, szCtrlName[dwControl][1], sizeof(pctrl->szName));
1864
1865 //save internal id
1866 pmixctrl->id = dwControl;
1867 nrControls++;
1868 dprintf(("Adding control %s (%s)", pctrl->szName, pctrl->szShortName));
1869 return pctrl;
1870}
1871/******************************************************************************/
1872/******************************************************************************/
1873
Note: See TracBrowser for help on using the repository browser.