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

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

Implemented mixerSetControlDetails + mixer updates/fixes

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