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

Last change on this file since 8498 was 8498, checked in by sandervl, 23 years ago

bugfix

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