xref: /haiku/src/add-ons/kernel/drivers/audio/echo/generic/CMonitorCtrl.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
1 // ****************************************************************************
2 //
3 //		CMonitorCtrl.cpp
4 //
5 //		Class to control monitors
6 //
7 //		Copyright Echo Digital Audio Corporation (c) 1998 - 2002
8 //		All rights reserved
9 //		www.echoaudio.com
10 //
11 //		Permission is hereby granted, free of charge, to any person obtaining a
12 //		copy of this software and associated documentation files (the
13 //		"Software"), to deal with the Software without restriction, including
14 //		without limitation the rights to use, copy, modify, merge, publish,
15 //		distribute, sublicense, and/or sell copies of the Software, and to
16 //		permit persons to whom the Software is furnished to do so, subject to
17 //		the following conditions:
18 //
19 //		- Redistributions of source code must retain the above copyright
20 //		notice, this list of conditions and the following disclaimers.
21 //
22 //		- Redistributions in binary form must reproduce the above copyright
23 //		notice, this list of conditions and the following disclaimers in the
24 //		documentation and/or other materials provided with the distribution.
25 //
26 //		- Neither the name of Echo Digital Audio, nor the names of its
27 //		contributors may be used to endorse or promote products derived from
28 //		this Software without specific prior written permission.
29 //
30 //		THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 //		EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 //		MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33 //		IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34 //		ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35 //		TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36 //		SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
37 //
38 // ****************************************************************************
39 
40 #include "CEchoGals.h"
41 #include "CMonitorCtrl.h"
42 
43 //*****************************************************************************
44 //
45 // Init
46 //
47 //*****************************************************************************
48 
49 ECHOSTATUS CMonitorCtrl::Init(CEchoGals *pEG)
50 {
51 	DWORD	dwBytes;
52 	DWORD	dwArraySize;
53 
54 	m_Gains = NULL;
55 	m_Mutes = NULL;
56 	m_Pans = NULL;
57 	m_PanDbs = NULL;
58 
59 	//
60 	// Cache stuff
61 	//
62 	m_pEG = pEG;
63 	m_wNumBussesIn = pEG->GetNumBussesIn();
64 	m_wNumBussesOut = pEG->GetNumBussesOut();
65 
66 	//
67 	// Indigo has no inputs; attempting to allocate 0 bytes
68 	// causes a BSOD on Windows ME.
69 	//
70 	if ((0 == m_wNumBussesIn) || (0 == m_wNumBussesOut))
71 	{
72 		ECHO_DEBUGPRINTF(("CMonitorCtrl::Init - this card has no inputs!\n"));
73 		return ECHOSTATUS_OK;
74 	}
75 
76 	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77 	//
78 	// Allocate the arrays
79 	//
80 	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81 
82 	dwArraySize = m_wNumBussesIn * (m_wNumBussesOut >> 1);
83 
84 	dwBytes = sizeof(INT8) * dwArraySize;
85 	OsAllocateNonPaged(dwBytes,(void **) &m_Gains);
86 	if (NULL == m_Gains)
87 	{
88 		Cleanup();
89 		return ECHOSTATUS_NO_MEM;
90 	}
91 
92 	dwBytes = sizeof(WORD) * dwArraySize;
93 	OsAllocateNonPaged(dwBytes,(void **) &m_Pans);
94 	if (NULL == m_Pans)
95 	{
96 		Cleanup();
97 		return ECHOSTATUS_NO_MEM;
98 	}
99 
100 	dwBytes = sizeof(BYTE) * dwArraySize;
101 	OsAllocateNonPaged(dwBytes,(void **) &m_Mutes);
102 	if (NULL == m_Mutes)
103 	{
104 		Cleanup();
105 		return ECHOSTATUS_NO_MEM;
106 	}
107 
108 	dwBytes = sizeof(PAN_DB) * dwArraySize;
109 	OsAllocateNonPaged(dwBytes,(void **) &m_PanDbs );
110 	if (NULL == m_PanDbs)
111 	{
112 		Cleanup();
113 		return ECHOSTATUS_NO_MEM;
114 	}
115 
116 	//==============================================================
117 	//
118 	// Init the arrays
119 	//
120 	//==============================================================
121 
122 	WORD wBusIn,wBusOut,wIndex;
123 
124 	for (wBusIn = 0; wBusIn < m_wNumBussesIn; wBusIn++)
125 		for (wBusOut = 0; wBusOut < m_wNumBussesOut; wBusOut += 2)
126 		{
127 			wIndex = GetIndex(wBusIn,wBusOut);
128 
129 			//
130 			// Pan hard left for even inputs, hard right for odd
131 			//
132 			if (0 == (wBusIn & 1))
133 			{
134 				m_Pans[wIndex] = 0;
135 				m_PanDbs[wIndex].iLeft = 0;
136 				m_PanDbs[wIndex].iRight = GENERIC_TO_DSP( ECHOGAIN_MUTED );
137 			}
138 			else
139 			{
140 				m_Pans[wIndex] = MAX_MIXER_PAN;
141 				m_PanDbs[wIndex].iLeft = GENERIC_TO_DSP( ECHOGAIN_MUTED );
142 				m_PanDbs[wIndex].iRight = 0;
143 			}
144 
145 			//
146 			// Mute unless this is not a digital input
147 			// and the input is going to the same-numbered output
148 			//
149 			if ( (wBusIn  < m_pEG->GetFirstDigitalBusIn()) &&
150 				  ( (wBusIn & 0xfffe) == wBusOut ) )
151 			{
152 				m_Mutes[wIndex] = FALSE;
153 			}
154 			else
155 			{
156 				m_Mutes[wIndex] = TRUE;
157 			}
158 
159 			//
160 			// Put stuff in the comm page
161 			//
162 			SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,FALSE);
163 
164 		}
165 
166 	//
167 	// Now actually update the DSP
168 	//
169 	m_pEG->GetDspCommObject()->UpdateAudioOutLineLevel();
170 
171 
172 	return ECHOSTATUS_OK;
173 
174 }	// Init
175 
176 
177 //*****************************************************************************
178 //
179 // Cleanup - free allocated memory
180 //
181 //*****************************************************************************
182 
183 void CMonitorCtrl::Cleanup()
184 {
185 	if (m_Gains)
186 		OsFreeNonPaged(m_Gains);
187 
188 	if (m_Mutes)
189 		OsFreeNonPaged(m_Mutes);
190 
191 	if (m_Pans)
192 		OsFreeNonPaged(m_Pans);
193 
194 	if (m_PanDbs)
195 		OsFreeNonPaged(m_PanDbs);
196 
197 }	// Cleanup
198 
199 
200 //*****************************************************************************
201 //
202 // Set and get gain
203 //
204 //*****************************************************************************
205 
206 ECHOSTATUS CMonitorCtrl::SetGain
207 (
208 	WORD 	wBusIn,
209 	WORD 	wBusOut,
210 	INT32 	iGain,
211 	BOOL 	fImmediate
212 )
213 {
214 	ECHOSTATUS Status;
215 
216 	if (NULL == m_pEG)
217 		return ECHOSTATUS_DSP_DEAD;
218 
219 	if (	(NULL == m_Gains) ||
220 			(NULL == m_PanDbs) )
221 		return ECHOSTATUS_NO_MEM;
222 
223 	WORD wIndex = GetIndex(wBusIn,wBusOut);
224 
225 	if (ECHOGAIN_UPDATE == iGain)
226 	{
227 		iGain = DSP_TO_GENERIC( m_Gains[ wIndex ] );
228 	}
229 	else
230 	{
231 		if (iGain > ECHOGAIN_MAXOUT)
232 			iGain = ECHOGAIN_MAXOUT;
233 		else if (iGain < ECHOGAIN_MUTED)
234 			iGain = ECHOGAIN_MUTED;
235 
236 		m_Gains[ wIndex ] = GENERIC_TO_DSP( iGain );
237 
238 		//
239 		// Gain has changed; store the notify
240 		//
241 		m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_LEVEL,wBusIn,wBusOut);
242 	}
243 
244 	//
245 	// Use the gain that was passed in, the pan setting,
246 	// and the mute to calculate the left and right gains
247 	//
248 	INT32 iLeft = iGain + DSP_TO_GENERIC( m_PanDbs[wIndex].iLeft );
249 	INT32 iRight = iGain + DSP_TO_GENERIC( m_PanDbs[wIndex].iRight );
250 
251 	//
252 	// Adjust left and right by the output bus gain
253 	//
254 	iLeft += m_pEG->m_BusOutLineLevels[wBusOut].GetGain();
255 	iRight += m_pEG->m_BusOutLineLevels[wBusOut + 1].GetGain();
256 
257 	//
258 	// Either mute or clamp
259 	//
260 	if (TRUE == m_Mutes[wIndex])
261 	{
262 		iLeft = ECHOGAIN_MUTED;
263 		iRight = ECHOGAIN_MUTED;
264 	}
265 	else
266 	{
267 		if ( m_pEG->m_BusOutLineLevels[wBusOut].IsMuteOn() )
268 		{
269 			iLeft = ECHOGAIN_MUTED;
270 		}
271 		else
272 		{
273 			//
274 			// Clamp left
275 			//
276 			if (iLeft > ECHOGAIN_MAXOUT)
277 				iLeft = ECHOGAIN_MAXOUT;
278 			else if (iLeft < ECHOGAIN_MUTED)
279 				iLeft = ECHOGAIN_MUTED;
280 		}
281 
282 		if ( m_pEG->m_BusOutLineLevels[wBusOut + 1].IsMuteOn() )
283 		{
284 			iRight = ECHOGAIN_MUTED;
285 		}
286 		else
287 		{
288 			//
289 			// Clamp right
290 			//
291 			if (iRight > ECHOGAIN_MAXOUT)
292 				iRight = ECHOGAIN_MAXOUT;
293 			else if (iRight < ECHOGAIN_MUTED)
294 				iRight = ECHOGAIN_MUTED;
295 
296 		}
297 	}
298 
299 
300 	//
301 	// Set the left channel
302 	//
303 	if ( (NULL == m_pEG) ||
304 			(NULL == m_pEG->GetDspCommObject() ) )
305 		return ECHOSTATUS_DSP_DEAD;
306 
307 
308 	Status = m_pEG->
309 					GetDspCommObject()->
310 						SetAudioMonitor( 	wBusOut,
311 												wBusIn,
312 												iLeft,
313 												FALSE);
314 
315 	//
316 	//	Set the right channel
317 	//
318 	if (ECHOSTATUS_OK == Status)
319 	{
320 		Status = m_pEG->
321 						GetDspCommObject()->
322 							SetAudioMonitor( 	wBusOut + 1,
323 													wBusIn,
324 													iRight,
325 													fImmediate);
326 	}
327 
328 	return Status;
329 }
330 
331 
332 ECHOSTATUS CMonitorCtrl::GetGain(WORD wBusIn, WORD wBusOut, INT32 &iGain)
333 {
334 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
335 
336 	if (NULL == m_Gains)
337 		return ECHOSTATUS_NO_MEM;
338 
339 	iGain = DSP_TO_GENERIC( m_Gains[wIndex] );
340 
341 	return ECHOSTATUS_OK;
342 }
343 
344 
345 //*****************************************************************************
346 //
347 // Set and get mute
348 //
349 //*****************************************************************************
350 
351 ECHOSTATUS CMonitorCtrl::SetMute
352 (
353 	WORD wBusIn,
354 	WORD wBusOut,
355 	BOOL bMute,
356 	BOOL fImmediate
357 )
358 {
359 	if (NULL == m_Mutes)
360 		return ECHOSTATUS_NO_MEM;
361 
362 	WORD wIndex = GetIndex(wBusIn,wBusOut);
363 
364 	//
365 	// Store the mute
366 	//
367  	m_Mutes[ wIndex ] = (BYTE) bMute;
368 
369 	//
370 	// Store the notify
371 	//
372 	m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_MUTE,wBusIn,wBusOut);
373 
374 
375 	//
376 	// Call the SetGain function to do all the heavy lifting
377 	// Use the ECHOGAIN_UPDATE value to tell the function to
378 	// recalculate the gain setting using the currently stored value.
379 	//
380 	return SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,fImmediate);
381 }
382 
383 
384 ECHOSTATUS CMonitorCtrl::GetMute(WORD wBusIn, WORD wBusOut, BOOL &bMute)
385 {
386 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
387 
388 	if (NULL == m_Mutes)
389 		return ECHOSTATUS_NO_MEM;
390 
391 	bMute = (BOOL) m_Mutes[ wIndex ];
392 
393 	return ECHOSTATUS_OK;
394 }
395 
396 
397 //*****************************************************************************
398 //
399 // Set and get pan
400 //
401 //*****************************************************************************
402 
403 ECHOSTATUS CMonitorCtrl::SetPan(WORD wBusIn, WORD wBusOut, INT32 iPan)
404 {
405 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
406 
407 	if (NULL == m_Pans)
408 		return ECHOSTATUS_NO_MEM;
409 
410 	//
411 	// Clamp it and stash it
412 	//
413 	if (iPan < 0)
414 		iPan = 0;
415 	else if (iPan > MAX_MIXER_PAN)
416 		iPan = MAX_MIXER_PAN;
417 
418 	m_Pans[wIndex] = (WORD) iPan;
419 
420 	//
421 	//	Convert this pan setting INTo left and right dB values
422 	//
423 	m_PanDbs[wIndex].iLeft = GENERIC_TO_DSP( PanToDb(MAX_MIXER_PAN - iPan) );
424 	m_PanDbs[wIndex].iRight = GENERIC_TO_DSP( PanToDb(iPan) );
425 
426 	//
427 	// Store the notify
428 	//
429 	m_pEG->MixerControlChanged(ECHO_MONITOR,MXN_PAN,wBusIn,wBusOut);
430 
431 	//
432 	// Once again SetGain does all the hard work
433 	//
434 	return SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE);
435 }
436 
437 
438 ECHOSTATUS CMonitorCtrl::GetPan(WORD wBusIn, WORD wBusOut, INT32 &iPan)
439 {
440 	WORD	wIndex = GetIndex(wBusIn,wBusOut);
441 
442 	if (NULL == m_Pans)
443 		return ECHOSTATUS_NO_MEM;
444 
445 	iPan = m_Pans[ wIndex ];
446 
447 	return ECHOSTATUS_OK;
448 }
449