xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CMonitorCtrl.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 // ****************************************************************************
2 //
3 //		CMonitorCtrl.cpp
4 //
5 //		Class to control monitors
6 //
7 // ----------------------------------------------------------------------------
8 //
9 // This file is part of Echo Digital Audio's generic driver library.
10 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005
11 // All rights reserved
12 // www.echoaudio.com
13 //
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2.1 of the License, or (at your option) any later version.
18 //
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 // Lesser General Public License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27 //
28 // ****************************************************************************
29 
30 #include "CEchoGals.h"
31 #include "CMonitorCtrl.h"
32 
33 //*****************************************************************************
34 //
35 // Destructor (this class uses the default constructor)
36 //
37 //*****************************************************************************
38 
39 CMonitorCtrl::~CMonitorCtrl()
40 {
41 	Cleanup();
42 }
43 
44 
45 //*****************************************************************************
46 //
47 // Init
48 //
49 //*****************************************************************************
50 
51 ECHOSTATUS CMonitorCtrl::Init(CEchoGals *pEG)
52 {
53 	DWORD	dwBytes;
54 	DWORD	dwArraySize;
55 
56 	m_Gains = NULL;
57 	m_Mutes = NULL;
58 	m_Pans = NULL;
59 	m_PanDbs = NULL;
60 
61 	//
62 	// Cache stuff
63 	//
64 	m_pEG = pEG;
65 	m_wNumBussesIn = pEG->GetNumBussesIn();
66 	m_wNumBussesOut = pEG->GetNumBussesOut();
67 
68 	//
69 	// Indigo has no inputs; attempting to allocate 0 bytes
70 	// causes a BSOD on Windows ME.
71 	//
72 	if ((0 == m_wNumBussesIn) || (0 == m_wNumBussesOut))
73 	{
74 		ECHO_DEBUGPRINTF(("CMonitorCtrl::Init - this card has no inputs!\n"));
75 		return ECHOSTATUS_OK;
76 	}
77 
78 	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 	//
80 	// Allocate the arrays
81 	//
82 	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
83 
84 	dwArraySize = m_wNumBussesIn * (m_wNumBussesOut >> 1);
85 
86 	dwBytes = sizeof(INT8) * dwArraySize;
87 	OsAllocateNonPaged(dwBytes,(void **) &m_Gains);
88 	if (NULL == m_Gains)
89 	{
90 		Cleanup();
91 		return ECHOSTATUS_NO_MEM;
92 	}
93 
94 	dwBytes = sizeof(WORD) * dwArraySize;
95 	OsAllocateNonPaged(dwBytes,(void **) &m_Pans);
96 	if (NULL == m_Pans)
97 	{
98 		Cleanup();
99 		return ECHOSTATUS_NO_MEM;
100 	}
101 
102 	dwBytes = sizeof(BYTE) * dwArraySize;
103 	OsAllocateNonPaged(dwBytes,(void **) &m_Mutes);
104 	if (NULL == m_Mutes)
105 	{
106 		Cleanup();
107 		return ECHOSTATUS_NO_MEM;
108 	}
109 
110 	dwBytes = sizeof(PAN_DB) * dwArraySize;
111 	OsAllocateNonPaged(dwBytes,(void **) &m_PanDbs );
112 	if (NULL == m_PanDbs)
113 	{
114 		Cleanup();
115 		return ECHOSTATUS_NO_MEM;
116 	}
117 
118 	//==============================================================
119 	//
120 	// Init the arrays
121 	//
122 	//==============================================================
123 
124 	WORD wBusIn,wBusOut,wIndex;
125 
126 	for (wBusIn = 0; wBusIn < m_wNumBussesIn; wBusIn++)
127 		for (wBusOut = 0; wBusOut < m_wNumBussesOut; wBusOut += 2)
128 		{
129 			wIndex = GetIndex(wBusIn,wBusOut);
130 
131 			//
132 			// Pan hard left for even inputs, hard right for odd
133 			//
134 			if (0 == (wBusIn & 1))
135 			{
136 				m_Pans[wIndex] = 0;
137 				m_PanDbs[wIndex].iLeft = 0;
138 				m_PanDbs[wIndex].iRight = (INT8) GENERIC_TO_DSP( ECHOGAIN_MUTED );
139 			}
140 			else
141 			{
142 				m_Pans[wIndex] = MAX_MIXER_PAN;
143 				m_PanDbs[wIndex].iLeft = (INT8) GENERIC_TO_DSP( ECHOGAIN_MUTED );
144 				m_PanDbs[wIndex].iRight = 0;
145 			}
146 
147 			//
148 			// Mute unless this is not a digital input
149 			// and the input is going to the same-numbered output
150 			//
151 			if ( (wBusIn  < m_pEG->GetFirstDigitalBusIn()) &&
152 				  ( (wBusIn & 0xfffe) == wBusOut ) )
153 			{
154 				m_Mutes[wIndex] = FALSE;
155 			}
156 			else
157 			{
158 				m_Mutes[wIndex] = TRUE;
159 			}
160 
161 			//
162 			// Put stuff in the comm page
163 			//
164 			SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,FALSE);
165 		}
166 
167 	//
168 	// Now actually update the DSP
169 	//
170 	m_pEG->GetDspCommObject()->UpdateAudioOutLineLevel();
171 
172 
173 	return ECHOSTATUS_OK;
174 
175 }	// Init
176 
177 
178 //*****************************************************************************
179 //
180 // Cleanup - free allocated memory
181 //
182 //*****************************************************************************
183 
184 void CMonitorCtrl::Cleanup()
185 {
186 	if (m_Gains)
187 		OsFreeNonPaged(m_Gains);
188 
189 	if (m_Mutes)
190 		OsFreeNonPaged(m_Mutes);
191 
192 	if (m_Pans)
193 		OsFreeNonPaged(m_Pans);
194 
195 	if (m_PanDbs)
196 		OsFreeNonPaged(m_PanDbs);
197 
198 }	// Cleanup
199 
200 
201 //*****************************************************************************
202 //
203 // Set and get gain
204 //
205 //*****************************************************************************
206 
207 ECHOSTATUS CMonitorCtrl::SetGain
208 (
209 	WORD 	wBusIn,
210 	WORD 	wBusOut,
211 	INT32 iGain,
212 	BOOL 	fImmediate
213 )
214 {
215 	ECHOSTATUS Status;
216 
217 	if (NULL == m_pEG)
218 		return ECHOSTATUS_DSP_DEAD;
219 
220 	if (	(NULL == m_Gains) ||
221 			(NULL == m_PanDbs) )
222 		return ECHOSTATUS_NO_MEM;
223 
224 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
225 	{
226 		ECHO_DEBUGPRINTF(("CMonitorCtrl::SetGain - out of range   in %d out %d\n",
227 								wBusIn,wBusOut));
228 		return ECHOSTATUS_INVALID_PARAM;
229 	}
230 
231 	//
232 	// Round down to the nearest even bus
233 	//
234 	wBusOut &= 0xfffe;
235 
236 	//
237 	// Figure out the index into the array
238 	//
239 	WORD wIndex = GetIndex(wBusIn,wBusOut);
240 
241 	if (ECHOGAIN_UPDATE == iGain)
242 	{
243 		iGain = DSP_TO_GENERIC( m_Gains[ wIndex ] );
244 	}
245 	else
246 	{
247 		if (iGain > ECHOGAIN_MAXOUT)
248 			iGain = ECHOGAIN_MAXOUT;
249 		else if (iGain < ECHOGAIN_MUTED)
250 			iGain = ECHOGAIN_MUTED;
251 
252 		m_Gains[ wIndex ] = (INT8) GENERIC_TO_DSP( iGain );
253 
254 		//
255 		// Gain has changed; store the notify
256 		//
257 		m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_LEVEL,wBusIn,wBusOut);
258 	}
259 
260 	//
261 	// Use the gain that was passed in, the pan setting,
262 	// and the mute to calculate the left and right gains
263 	//
264 	INT32 iLeft = iGain + DSP_TO_GENERIC( m_PanDbs[wIndex].iLeft );
265 	INT32 iRight = iGain + DSP_TO_GENERIC( m_PanDbs[wIndex].iRight );
266 
267 	//
268 	// Adjust left and right by the output bus gain
269 	//
270 	iLeft += m_pEG->m_BusOutLineLevels[wBusOut].GetGain();
271 	iRight += m_pEG->m_BusOutLineLevels[wBusOut + 1].GetGain();
272 
273 	//
274 	// Either mute or clamp
275 	//
276 	if (TRUE == m_Mutes[wIndex])
277 	{
278 		iLeft = ECHOGAIN_MUTED;
279 		iRight = ECHOGAIN_MUTED;
280 	}
281 	else
282 	{
283 		if ( m_pEG->m_BusOutLineLevels[wBusOut].IsMuteOn() )
284 		{
285 			iLeft = ECHOGAIN_MUTED;
286 		}
287 		else
288 		{
289 			//
290 			// Clamp left
291 			//
292 			if (iLeft > ECHOGAIN_MAXOUT)
293 				iLeft = ECHOGAIN_MAXOUT;
294 			else if (iLeft < ECHOGAIN_MUTED)
295 				iLeft = ECHOGAIN_MUTED;
296 		}
297 
298 		if ( m_pEG->m_BusOutLineLevels[wBusOut + 1].IsMuteOn() )
299 		{
300 			iRight = ECHOGAIN_MUTED;
301 		}
302 		else
303 		{
304 			//
305 			// Clamp right
306 			//
307 			if (iRight > ECHOGAIN_MAXOUT)
308 				iRight = ECHOGAIN_MAXOUT;
309 			else if (iRight < ECHOGAIN_MUTED)
310 				iRight = ECHOGAIN_MUTED;
311 
312 		}
313 	}
314 
315 
316 	//
317 	// Set the left channel
318 	//
319 	if ( (NULL == m_pEG) ||
320 			(NULL == m_pEG->GetDspCommObject() ) )
321 		return ECHOSTATUS_DSP_DEAD;
322 
323 
324 	Status = m_pEG->
325 					GetDspCommObject()->
326 						SetAudioMonitor( 	wBusOut,
327 												wBusIn,
328 												iLeft,
329 												FALSE);
330 
331 	//
332 	//	Set the right channel
333 	//
334 	if (ECHOSTATUS_OK == Status)
335 	{
336 		Status = m_pEG->
337 						GetDspCommObject()->
338 							SetAudioMonitor( 	wBusOut + 1,
339 													wBusIn,
340 													iRight,
341 													fImmediate);
342 	}
343 
344 	return Status;
345 }
346 
347 
348 ECHOSTATUS CMonitorCtrl::GetGain(WORD wBusIn, WORD wBusOut, INT32 &iGain)
349 {
350 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
351 
352 	if (NULL == m_Gains)
353 		return ECHOSTATUS_NO_MEM;
354 
355 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
356 	{
357 		ECHO_DEBUGPRINTF(("CMonitorCtrl::GetGain - out of range in %d out %d\n",
358 								wBusIn,wBusOut));
359 		return ECHOSTATUS_INVALID_PARAM;
360 	}
361 
362 	iGain = DSP_TO_GENERIC( m_Gains[wIndex] );
363 
364 	return ECHOSTATUS_OK;
365 }
366 
367 
368 //*****************************************************************************
369 //
370 // Set and get mute
371 //
372 //*****************************************************************************
373 
374 ECHOSTATUS CMonitorCtrl::SetMute
375 (
376 	WORD wBusIn,
377 	WORD wBusOut,
378 	BOOL bMute,
379 	BOOL fImmediate
380 )
381 {
382 	if (NULL == m_Mutes)
383 		return ECHOSTATUS_NO_MEM;
384 
385 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
386 	{
387 		ECHO_DEBUGPRINTF(("CMonitorCtrl::SetMute - out of range   in %d out %d\n",
388 								wBusIn,wBusOut));
389 		return ECHOSTATUS_INVALID_PARAM;
390 	}
391 
392 	wBusOut &= 0xfffe;
393 
394 	WORD wIndex = GetIndex(wBusIn,wBusOut);
395 
396 	//
397 	// Store the mute
398 	//
399  	m_Mutes[ wIndex ] = (BYTE) bMute;
400 
401 	//
402 	// Store the notify
403 	//
404 	m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_MUTE,wBusIn,wBusOut);
405 
406 
407 	//
408 	// Call the SetGain function to do all the heavy lifting
409 	// Use the ECHOGAIN_UPDATE value to tell the function to
410 	// recalculate the gain setting using the currently stored value.
411 	//
412 	return SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,fImmediate);
413 }
414 
415 
416 ECHOSTATUS CMonitorCtrl::GetMute(WORD wBusIn, WORD wBusOut, BOOL &bMute)
417 {
418 	wBusOut &= 0xfffe;
419 
420 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
421 	{
422 		ECHO_DEBUGPRINTF(("CMonitorCtrl::GetMute - out of range   in %d out %d\n",
423 								wBusIn,wBusOut));
424 		return ECHOSTATUS_INVALID_PARAM;
425 	}
426 
427 
428 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
429 
430 	if (NULL == m_Mutes)
431 		return ECHOSTATUS_NO_MEM;
432 
433 	bMute = (BOOL) m_Mutes[ wIndex ];
434 
435 	return ECHOSTATUS_OK;
436 }
437 
438 
439 //*****************************************************************************
440 //
441 // Set and get pan
442 //
443 //*****************************************************************************
444 
445 ECHOSTATUS CMonitorCtrl::SetPan(WORD wBusIn, WORD wBusOut, INT32 iPan)
446 {
447 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
448 	{
449 		ECHO_DEBUGPRINTF(("CMonitorCtrl::SetPan - out of range   in %d out %d\n",
450 								wBusIn,wBusOut));
451 		return ECHOSTATUS_INVALID_PARAM;
452 	}
453 
454 	wBusOut &= 0xfffe;
455 
456 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
457 
458 	if (NULL == m_Pans)
459 		return ECHOSTATUS_NO_MEM;
460 
461 	//
462 	// Clamp it and stash it
463 	//
464 	if (iPan < 0)
465 		iPan = 0;
466 	else if (iPan > MAX_MIXER_PAN)
467 		iPan = MAX_MIXER_PAN;
468 
469 	m_Pans[wIndex] = (WORD) iPan;
470 
471 	//
472 	//	Convert this pan setting into left and right dB values
473 	//
474 	m_PanDbs[wIndex].iLeft = (INT8) GENERIC_TO_DSP( PanToDb(MAX_MIXER_PAN - iPan) );
475 	m_PanDbs[wIndex].iRight = (INT8) GENERIC_TO_DSP( PanToDb(iPan) );
476 
477 	//
478 	// Store the notify
479 	//
480 	m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_PAN,wBusIn,wBusOut);
481 
482 	//
483 	// Once again SetGain does all the hard work
484 	//
485 	return SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE);
486 }
487 
488 
489 ECHOSTATUS CMonitorCtrl::GetPan(WORD wBusIn, WORD wBusOut, INT32 &iPan)
490 {
491 	if (	(wBusIn >= m_wNumBussesIn) || (wBusOut >= m_wNumBussesOut) )
492 	{
493 		ECHO_DEBUGPRINTF(("CMonitorCtrl::GetPan - out of range   in %d out %d\n",
494 								wBusIn,wBusOut));
495 		return ECHOSTATUS_INVALID_PARAM;
496 	}
497 
498 
499 	wBusOut &= 0xfffe;
500 
501 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
502 
503 	if (NULL == m_Pans)
504 		return ECHOSTATUS_NO_MEM;
505 
506 	iPan = m_Pans[ wIndex ];
507 
508 	return ECHOSTATUS_OK;
509 }
510