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