1 // **************************************************************************** 2 // 3 // CLayla24DspCommObject.cpp 4 // 5 // Implementation file for EchoGals generic driver Layla24 DSP 6 // interface class. 7 // 8 // Copyright Echo Digital Audio Corporation (c) 1998 - 2002 9 // All rights reserved 10 // www.echoaudio.com 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a 13 // copy of this software and associated documentation files (the 14 // "Software"), to deal with the Software without restriction, including 15 // without limitation the rights to use, copy, modify, merge, publish, 16 // distribute, sublicense, and/or sell copies of the Software, and to 17 // permit persons to whom the Software is furnished to do so, subject to 18 // the following conditions: 19 // 20 // - Redistributions of source code must retain the above copyright 21 // notice, this list of conditions and the following disclaimers. 22 // 23 // - Redistributions in binary form must reproduce the above copyright 24 // notice, this list of conditions and the following disclaimers in the 25 // documentation and/or other materials provided with the distribution. 26 // 27 // - Neither the name of Echo Digital Audio, nor the names of its 28 // contributors may be used to endorse or promote products derived from 29 // this Software without specific prior written permission. 30 // 31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 34 // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR 35 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 36 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 37 // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 38 // 39 // **************************************************************************** 40 41 #include "CEchoGals.h" 42 #include "CLayla24DspCommObject.h" 43 44 #include "Layla24DSP.c" // regular DSP code 45 46 #include "Layla24_1ASIC.c" 47 #include "Layla24_2A_ASIC.c" 48 #include "Layla24_2S_ASIC.c" 49 50 // 51 // The ASIC files for Layla24 are always this size 52 // 53 #define LAYLA24_ASIC_SIZE 31146 54 55 56 /**************************************************************************** 57 58 Construction and destruction 59 60 ****************************************************************************/ 61 62 //=========================================================================== 63 // 64 // Constructor 65 // 66 //=========================================================================== 67 68 CLayla24DspCommObject::CLayla24DspCommObject 69 ( 70 PDWORD pdwRegBase, // Virtual ptr to DSP registers 71 PCOsSupport pOsSupport 72 ) : CGMLDspCommObject( pdwRegBase, pOsSupport ) 73 { 74 75 strcpy( m_szCardName, "Layla24" ); 76 m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base 77 78 m_wNumPipesOut = 16; 79 m_wNumPipesIn = 16; 80 m_wNumBussesOut = 16; 81 m_wNumBussesIn = 16; 82 m_wFirstDigitalBusOut = 8; 83 m_wFirstDigitalBusIn = 8; 84 m_fHasVmixer = FALSE; 85 86 m_wNumMidiOut = 1; // # MIDI out channels 87 m_wNumMidiIn = 1; // # MIDI in channels 88 m_bHasASIC = TRUE; 89 90 m_pwDspCodeToLoad = pwLayla24DSP; 91 92 m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA; 93 m_bProfessionalSpdif = FALSE; 94 m_wMtcState = MTC_STATE_NORMAL; 95 96 } // CLayla24DspCommObject::CLayla24DspCommObject( DWORD dwPhysRegBase ) 97 98 99 //=========================================================================== 100 // 101 // Destructor 102 // 103 //=========================================================================== 104 105 CLayla24DspCommObject::~CLayla24DspCommObject() 106 { 107 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::~CLayla24DspCommObject() " 108 "is toast!\n" ) ); 109 } // CLayla24DspCommObject::~CLayla24DspCommObject() 110 111 112 113 114 /**************************************************************************** 115 116 Hardware setup and config 117 118 ****************************************************************************/ 119 120 //=========================================================================== 121 // 122 // Layla24 has an ASIC on the PCI card and another ASIC in the external box; 123 // both need to be loaded. 124 // 125 //=========================================================================== 126 127 BOOL CLayla24DspCommObject::LoadASIC() 128 { 129 DWORD dwControlReg; 130 131 if ( m_bASICLoaded == TRUE ) 132 return TRUE; 133 134 ECHO_DEBUGPRINTF(("CLayla24DspCommObject::LoadASIC\n")); 135 136 // 137 // Give the DSP a few milliseconds to settle down 138 // 139 m_pOsSupport->OsSnooze( 10000 ); 140 141 // 142 // Load the ASIC for the PCI card 143 // 144 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, 145 pbLayla24_1ASIC, 146 sizeof( pbLayla24_1ASIC ) ) ) 147 return FALSE; 148 149 m_pbyAsic = pbLayla24_2S_ASIC; 150 151 // 152 // Now give the new ASIC a little time to set up 153 // 154 m_pOsSupport->OsSnooze( 10000 ); 155 156 // 157 // Do the external one 158 // 159 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, 160 pbLayla24_2S_ASIC, 161 sizeof( pbLayla24_2S_ASIC ) ) ) 162 return FALSE; 163 164 // 165 // Now give the external ASIC a little time to set up 166 // 167 m_pOsSupport->OsSnooze( 10000 ); 168 169 // 170 // See if it worked 171 // 172 CheckAsicStatus(); 173 174 // 175 // Set up the control register if the load succeeded - 176 // 177 // 48 kHz, internal clock, S/PDIF RCA mode 178 // 179 if ( m_bASICLoaded ) 180 { 181 dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ; 182 WriteControlReg( dwControlReg ); 183 } 184 185 ECHO_DEBUGPRINTF(("\tFinished\n")); 186 187 return m_bASICLoaded; 188 } // BOOL CLayla24DspCommObject::LoadASIC() 189 190 191 192 //=========================================================================== 193 // 194 // SetSampleRate 195 // 196 // Set the sample rate for Layla24 197 // 198 // Layla24 is simple; just send it the sampling rate (assuming that the clock 199 // mode is correct). 200 // 201 //=========================================================================== 202 203 DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 204 { 205 DWORD dwControlReg, dwNewClock, dwBaseRate; 206 BOOL bSetFreqReg = FALSE; 207 208 // 209 // Only set the clock for internal mode. If the clock is not set to 210 // internal, try and re-set the input clock; this more transparently 211 // handles switching between single and double-speed mode 212 // 213 if ( GetInputClock() != ECHO_CLOCK_INTERNAL ) 214 { 215 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetSampleRate: Cannot set sample rate - " 216 "clock not set to CLK_CLOCKININTERNAL\n" ) ); 217 218 // 219 // Save the rate anyhow 220 // 221 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); 222 223 // 224 // Set the input clock to the current value 225 // 226 SetInputClock( m_wInputClock ); 227 228 return GetSampleRate(); 229 } 230 231 // 232 // Get the control register & clear the appropriate bits 233 // 234 dwControlReg = GetControlRegister(); 235 dwControlReg &= GML_CLOCK_CLEAR_MASK; 236 dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK; 237 238 // 239 // Set the sample rate 240 // 241 bSetFreqReg = FALSE; 242 243 switch ( dwNewSampleRate ) 244 { 245 case 96000 : 246 dwNewClock = GML_96KHZ; 247 break; 248 249 case 88200 : 250 dwNewClock = GML_88KHZ; 251 break; 252 253 case 48000 : 254 dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1; 255 break; 256 257 case 44100 : 258 dwNewClock = GML_44KHZ; 259 260 // 261 // Professional mode 262 // 263 if ( dwControlReg & GML_SPDIF_PRO_MODE ) 264 { 265 dwNewClock |= GML_SPDIF_SAMPLE_RATE0; 266 } 267 break; 268 269 case 32000 : 270 dwNewClock = GML_32KHZ | 271 GML_SPDIF_SAMPLE_RATE0 | 272 GML_SPDIF_SAMPLE_RATE1; 273 break; 274 275 case 22050 : 276 dwNewClock = GML_22KHZ; 277 break; 278 279 case 16000 : 280 dwNewClock = GML_16KHZ; 281 break; 282 283 case 11025 : 284 dwNewClock = GML_11KHZ; 285 break; 286 287 case 8000 : 288 dwNewClock = GML_8KHZ; 289 break; 290 291 default : 292 // 293 // Set flag to write the frequency register 294 // 295 bSetFreqReg = TRUE; 296 297 // 298 // Set for continuous mode 299 // 300 dwNewClock = LAYLA24_CONTINUOUS_CLOCK; 301 } 302 303 dwControlReg |= dwNewClock; 304 305 // 306 // If this is a non-standard rate, then the driver 307 // needs to use Layla24's special "continuous frequency" mode 308 // 309 if ( bSetFreqReg ) 310 { 311 if ( dwNewSampleRate > 50000 ) 312 { 313 dwBaseRate = dwNewSampleRate >> 1; 314 dwControlReg |= GML_DOUBLE_SPEED_MODE; 315 } 316 else 317 { 318 dwBaseRate = dwNewSampleRate; 319 } 320 321 if ( dwBaseRate < 25000 ) 322 dwBaseRate = 25000; 323 324 if ( !WaitForHandshake() ) 325 return 0xffffffff; 326 327 m_pDspCommPage->dwSampleRate = 328 SWAP( LAYLA24_MAGIC_NUMBER / dwBaseRate - 2 ); 329 330 ClearHandshake(); 331 SendVector( DSP_VC_SET_LAYLA24_FREQUENCY_REG ); 332 } 333 334 // 335 // Tell the DSP about it 336 // 337 if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg ) ) 338 { 339 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); 340 341 ECHO_DEBUGPRINTF( ("CLayla24DspCommObject::SetSampleRate: %ld " 342 "clock %ld\n", dwNewSampleRate, dwControlReg) ); 343 } 344 345 return GetSampleRate(); 346 347 } // DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 348 349 350 //=========================================================================== 351 // 352 // SetDigitalMode 353 // 354 //=========================================================================== 355 356 ECHOSTATUS CLayla24DspCommObject::SetDigitalMode 357 ( 358 BYTE byNewMode 359 ) 360 { 361 DWORD dwControlReg; 362 363 dwControlReg = GetControlRegister(); 364 // 365 // Clear the current digital mode 366 // 367 dwControlReg &= GML_DIGITAL_MODE_CLEAR_MASK; 368 369 // 370 // Tweak the control reg 371 // 372 switch ( byNewMode ) 373 { 374 default : 375 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED; 376 377 case DIGITAL_MODE_SPDIF_OPTICAL : 378 379 dwControlReg |= GML_SPDIF_OPTICAL_MODE; 380 381 // fall through 382 383 case DIGITAL_MODE_SPDIF_RCA : 384 // 385 // If the input clock is set to ADAT, set the 386 // input clock to internal and the sample rate to 48 KHz 387 // 388 if ( ECHO_CLOCK_ADAT == GetInputClock() ) 389 { 390 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); 391 SetInputClock( ECHO_CLOCK_INTERNAL ); 392 } 393 // 394 // If the currently loaded ASIC is the S/PDIF ASIC, switch 395 // to the ADAT ASIC 396 // 397 if ( !SwitchAsic( pbLayla24_2S_ASIC, sizeof( pbLayla24_2S_ASIC ) ) ) 398 SetInputClock( ECHO_CLOCK_INTERNAL ); 399 400 break; 401 402 case DIGITAL_MODE_ADAT : 403 // 404 // If the input clock is set to S/PDIF, set the 405 // input clock to internal and the sample rate to 48 KHz 406 // 407 if ( ECHO_CLOCK_SPDIF == GetInputClock() ) 408 { 409 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); 410 SetInputClock( ECHO_CLOCK_INTERNAL ); 411 } 412 // 413 // If the currently loaded ASIC is the S/PDIF ASIC, switch 414 // to the ADAT ASIC 415 // 416 if ( !SwitchAsic( pbLayla24_2A_ASIC, sizeof( pbLayla24_2A_ASIC ) ) ) 417 return( ECHOSTATUS_ASIC_NOT_LOADED ); 418 419 dwControlReg |= GML_ADAT_MODE; 420 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 421 break; 422 } 423 424 // 425 // Write the control reg 426 // 427 WriteControlReg( dwControlReg ); 428 429 m_byDigitalMode = byNewMode; 430 431 ECHO_DEBUGPRINTF( ("CLayla24DspCommObject::SetDigitalMode to %ld\n", 432 (DWORD) m_byDigitalMode) ); 433 434 return ECHOSTATUS_OK; 435 436 } // ECHOSTATUS CLaya24DspCommObject::SetDigitalMode 437 438 439 //=========================================================================== 440 // 441 // Depending on what digital mode you want, Layla24 needs different ASICs 442 // loaded. This function checks the ASIC needed for the new mode and sees 443 // if it matches the one already loaded. 444 // 445 //=========================================================================== 446 447 BOOL CLayla24DspCommObject::SwitchAsic 448 ( 449 BYTE * pbyAsicNeeded, 450 DWORD dwAsicSize 451 ) 452 { 453 // 454 // Check to see if this is already loaded 455 // 456 if ( pbyAsicNeeded != m_pbyAsic ) 457 { 458 BYTE byMonitors[ MONITOR_ARRAY_SIZE ]; 459 memmove( byMonitors, m_pDspCommPage->byMonitors, MONITOR_ARRAY_SIZE ); 460 memset( m_pDspCommPage->byMonitors, 461 GENERIC_TO_DSP(ECHOGAIN_MUTED), 462 MONITOR_ARRAY_SIZE ); 463 464 // 465 // Load the desired ASIC 466 // 467 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, 468 pbyAsicNeeded, 469 dwAsicSize ) ) 470 { 471 memmove( m_pDspCommPage->byMonitors, byMonitors, MONITOR_ARRAY_SIZE ); 472 return FALSE; 473 } 474 m_pbyAsic = pbyAsicNeeded; 475 memmove( m_pDspCommPage->byMonitors, byMonitors, MONITOR_ARRAY_SIZE ); 476 } 477 478 return TRUE; 479 480 } // BOOL CLayla24DspCommObject::SwitchAsic( DWORD dwMask96 ) 481 482 483 //=========================================================================== 484 // 485 // SetInputClock 486 // 487 //=========================================================================== 488 489 ECHOSTATUS CLayla24DspCommObject::SetInputClock(WORD wClock) 490 { 491 BOOL bSetRate; 492 BOOL bWriteControlReg; 493 DWORD dwControlReg, dwSampleRate; 494 495 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetInputClock:\n" ) ); 496 497 dwControlReg = GetControlRegister(); 498 499 // 500 // Mask off the clock select bits 501 // 502 dwControlReg &= GML_CLOCK_CLEAR_MASK; 503 dwSampleRate = GetSampleRate(); 504 505 bSetRate = FALSE; 506 bWriteControlReg = TRUE; 507 508 // 509 // Pick the new clock 510 // 511 switch ( wClock ) 512 { 513 case ECHO_CLOCK_INTERNAL : 514 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) ); 515 516 // If the sample rate is out of range for some reason, set it 517 // to a reasonable value. mattg 518 if ( ( GetSampleRate() < 8000 ) || 519 ( GetSampleRate() > 100000 ) ) 520 { 521 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); 522 } 523 524 bSetRate = TRUE; 525 bWriteControlReg = FALSE; 526 break; 527 528 case ECHO_CLOCK_SPDIF: 529 if ( DIGITAL_MODE_ADAT == GetDigitalMode() ) 530 { 531 return ECHOSTATUS_CLOCK_NOT_AVAILABLE; 532 } 533 534 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) ); 535 536 dwControlReg |= GML_SPDIF_CLOCK; 537 538 /* 539 Since Layla24 doesn't support 96 kHz S/PDIF, this can be ignored 540 if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() ) 541 { 542 dwControlReg |= GML_DOUBLE_SPEED_MODE; 543 } 544 else 545 { 546 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 547 } 548 */ 549 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 550 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) ); 551 break; 552 553 case ECHO_CLOCK_WORD: 554 dwControlReg |= GML_WORD_CLOCK; 555 556 if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() ) 557 { 558 dwControlReg |= GML_DOUBLE_SPEED_MODE; 559 } 560 else 561 { 562 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 563 } 564 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to WORD\n" ) ); 565 break; 566 567 568 case ECHO_CLOCK_ADAT : 569 if ( DIGITAL_MODE_ADAT != GetDigitalMode() ) 570 { 571 return ECHOSTATUS_CLOCK_NOT_AVAILABLE; 572 } 573 574 dwControlReg |= GML_ADAT_CLOCK; 575 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 576 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to ADAT\n" ) ); 577 break; 578 579 default : 580 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock)); 581 ECHO_DEBUGBREAK(); 582 return ECHOSTATUS_CLOCK_NOT_SUPPORTED; 583 584 } // switch (wClock) 585 586 // 587 // Winner! Save the new input clock. 588 // 589 m_wInputClock = wClock; 590 591 // 592 // Do things according to the flags 593 // 594 if ( bWriteControlReg ) 595 { 596 WriteControlReg( dwControlReg ); 597 } 598 599 // 600 // If the user just switched to internal clock, 601 // set the sample rate 602 // 603 if ( bSetRate ) 604 SetSampleRate(); 605 606 return ECHOSTATUS_OK; 607 608 } // ECHOSTATUS CLayla24DspCommObject::SetInputClock() 609 610 611 612 //=========================================================================== 613 // 614 // Detect MIDI output activity 615 // 616 //=========================================================================== 617 618 BOOL CLayla24DspCommObject::IsMidiOutActive() 619 { 620 ULONGLONG ullCurTime; 621 622 m_pOsSupport->OsGetSystemTime( &ullCurTime ); 623 return( ( ( ullCurTime - m_ullMidiOutTime ) > MIDI_ACTIVITY_TIMEOUT_USEC ) ? FALSE : TRUE ); 624 625 } // BOOL CLayla24DspCommObject::IsMidiOutActive() 626 627 // **** Layla24DspCommObject.cpp **** 628