1 // **************************************************************************** 2 // 3 // CLayla24DspCommObject.cpp 4 // 5 // Implementation file for EchoGals generic driver Layla24 DSP 6 // interface class. 7 // 8 // ---------------------------------------------------------------------------- 9 // 10 // This file is part of Echo Digital Audio's generic driver library. 11 // Copyright Echo Digital Audio Corporation (c) 1998 - 2005 12 // All rights reserved 13 // www.echoaudio.com 14 // 15 // This library is free software; you can redistribute it and/or 16 // modify it under the terms of the GNU Lesser General Public 17 // License as published by the Free Software Foundation; either 18 // version 2.1 of the License, or (at your option) any later version. 19 // 20 // This library is distributed in the hope that it will be useful, 21 // but WITHOUT ANY WARRANTY; without even the implied warranty of 22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 // Lesser General Public License for more details. 24 // 25 // You should have received a copy of the GNU Lesser General Public 26 // License along with this library; if not, write to the Free Software 27 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 // 29 // **************************************************************************** 30 31 #include "CEchoGals.h" 32 #include "CLayla24DspCommObject.h" 33 34 #include LAYLA24_DSP_FILENAME 35 #include "Layla24_1ASIC.c" 36 #include "Layla24_2A_ASIC.c" 37 #include LAYLA24_2ASIC_FILENAME 38 39 // 40 // The ASIC files for Layla24 are always this size 41 // 42 #define LAYLA24_ASIC_SIZE 31146 43 44 45 /**************************************************************************** 46 47 Construction and destruction 48 49 ****************************************************************************/ 50 51 //=========================================================================== 52 // 53 // Constructor 54 // 55 //=========================================================================== 56 57 CLayla24DspCommObject::CLayla24DspCommObject 58 ( 59 PDWORD pdwRegBase, // Virtual ptr to DSP registers 60 PCOsSupport pOsSupport 61 ) : CGMLDspCommObject( pdwRegBase, pOsSupport ) 62 { 63 64 strcpy( m_szCardName, LAYLA24_CARD_NAME); 65 66 m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base 67 68 m_wNumPipesOut = 16; 69 m_wNumPipesIn = 16; 70 m_wNumBussesOut = 16; 71 m_wNumBussesIn = 16; 72 m_wFirstDigitalBusOut = 8; 73 m_wFirstDigitalBusIn = 8; 74 75 m_fHasVmixer = LAYLA24_HAS_VMIXER; 76 77 m_wNumMidiOut = 1; // # MIDI out channels 78 m_wNumMidiIn = 1; // # MIDI in channels 79 m_bHasASIC = TRUE; 80 81 m_pwDspCodeToLoad = LAYLA24_DSP_CODE; 82 83 m_byDigitalMode = DIGITAL_MODE_SPDIF_RCA; 84 m_bProfessionalSpdif = FALSE; 85 m_wMtcState = MIDI_IN_STATE_NORMAL; 86 87 m_dwSampleRate = 48000; 88 89 } // CLayla24DspCommObject::CLayla24DspCommObject( DWORD dwPhysRegBase ) 90 91 92 //=========================================================================== 93 // 94 // Destructor 95 // 96 //=========================================================================== 97 98 CLayla24DspCommObject::~CLayla24DspCommObject() 99 { 100 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::~CLayla24DspCommObject() " 101 "is toast!\n" ) ); 102 } // CLayla24DspCommObject::~CLayla24DspCommObject() 103 104 105 106 107 /**************************************************************************** 108 109 Hardware setup and config 110 111 ****************************************************************************/ 112 113 //=========================================================================== 114 // 115 // Layla24 has an ASIC on the PCI card and another ASIC in the external box; 116 // both need to be loaded. 117 // 118 //=========================================================================== 119 120 BOOL CLayla24DspCommObject::LoadASIC() 121 { 122 DWORD dwControlReg; 123 124 if ( m_bASICLoaded == TRUE ) 125 return TRUE; 126 127 ECHO_DEBUGPRINTF(("CLayla24DspCommObject::LoadASIC\n")); 128 129 // 130 // Give the DSP a few milliseconds to settle down 131 // 132 m_pOsSupport->OsSnooze( 10000 ); 133 134 // 135 // Load the ASIC for the PCI card 136 // 137 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, 138 pbLayla24_1ASIC, 139 sizeof( pbLayla24_1ASIC ) ) ) 140 return FALSE; 141 142 m_pbyAsic = pbLayla24_2S_ASIC; 143 144 // 145 // Now give the new ASIC a little time to set up 146 // 147 m_pOsSupport->OsSnooze( 10000 ); 148 149 // 150 // Do the external one 151 // 152 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, 153 pbLayla24_2S_ASIC, 154 sizeof( pbLayla24_2S_ASIC ) ) ) 155 return FALSE; 156 157 // 158 // Now give the external ASIC a little time to set up 159 // 160 m_pOsSupport->OsSnooze( 10000 ); 161 162 // 163 // See if it worked 164 // 165 CheckAsicStatus(); 166 167 // 168 // Set up the control register if the load succeeded - 169 // 170 // 48 kHz, internal clock, S/PDIF RCA mode 171 // 172 if ( m_bASICLoaded ) 173 { 174 dwControlReg = GML_CONVERTER_ENABLE | GML_48KHZ; 175 WriteControlReg( dwControlReg, TRUE ); 176 177 m_dwSampleRate = 48000; 178 } 179 180 ECHO_DEBUGPRINTF(("\tFinished\n")); 181 182 return m_bASICLoaded; 183 } // BOOL CLayla24DspCommObject::LoadASIC() 184 185 186 187 //=========================================================================== 188 // 189 // SetSampleRate 190 // 191 // Set the sample rate for Layla24 192 // 193 // Layla24 is simple; just send it the sampling rate (assuming that the clock 194 // mode is correct). 195 // 196 //=========================================================================== 197 198 DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 199 { 200 DWORD dwControlReg, dwNewClock, dwBaseRate; 201 BOOL bSetFreqReg = FALSE; 202 203 // 204 // Only set the clock for internal mode. If the clock is not set to 205 // internal, try and re-set the input clock; this more transparently 206 // handles switching between single and double-speed mode 207 // 208 if ( GetInputClock() != ECHO_CLOCK_INTERNAL ) 209 { 210 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetSampleRate: Cannot set sample rate - " 211 "clock not set to CLK_CLOCKININTERNAL\n" ) ); 212 213 // 214 // Save the rate anyhow 215 // 216 m_dwSampleRate = SWAP( dwNewSampleRate ); 217 218 // 219 // Set the input clock to the current value 220 // 221 SetInputClock( m_wInputClock ); 222 223 return dwNewSampleRate; 224 } 225 226 // 227 // Get the control register & clear the appropriate bits 228 // 229 dwControlReg = GetControlRegister(); 230 dwControlReg &= GML_CLOCK_CLEAR_MASK; 231 dwControlReg &= GML_SPDIF_RATE_CLEAR_MASK; 232 233 // 234 // Set the sample rate 235 // 236 bSetFreqReg = FALSE; 237 238 switch ( dwNewSampleRate ) 239 { 240 case 96000 : 241 dwNewClock = GML_96KHZ; 242 break; 243 244 case 88200 : 245 dwNewClock = GML_88KHZ; 246 break; 247 248 case 48000 : 249 dwNewClock = GML_48KHZ | GML_SPDIF_SAMPLE_RATE1; 250 break; 251 252 case 44100 : 253 dwNewClock = GML_44KHZ; 254 255 // 256 // Professional mode 257 // 258 if ( dwControlReg & GML_SPDIF_PRO_MODE ) 259 { 260 dwNewClock |= GML_SPDIF_SAMPLE_RATE0; 261 } 262 break; 263 264 case 32000 : 265 dwNewClock = GML_32KHZ | 266 GML_SPDIF_SAMPLE_RATE0 | 267 GML_SPDIF_SAMPLE_RATE1; 268 break; 269 270 case 22050 : 271 dwNewClock = GML_22KHZ; 272 break; 273 274 case 16000 : 275 dwNewClock = GML_16KHZ; 276 break; 277 278 case 11025 : 279 dwNewClock = GML_11KHZ; 280 break; 281 282 case 8000 : 283 dwNewClock = GML_8KHZ; 284 break; 285 286 default : 287 // 288 // Set flag to write the frequency register 289 // 290 bSetFreqReg = TRUE; 291 292 // 293 // Set for continuous mode 294 // 295 dwNewClock = LAYLA24_CONTINUOUS_CLOCK; 296 } 297 298 dwControlReg |= dwNewClock; 299 300 // 301 // If this is a non-standard rate, then the driver 302 // needs to use Layla24's special "continuous frequency" mode 303 // 304 if ( bSetFreqReg ) 305 { 306 if ( dwNewSampleRate > 50000 ) 307 { 308 dwBaseRate = dwNewSampleRate >> 1; 309 dwControlReg |= GML_DOUBLE_SPEED_MODE; 310 } 311 else 312 { 313 dwBaseRate = dwNewSampleRate; 314 } 315 316 if ( dwBaseRate < 25000 ) 317 dwBaseRate = 25000; 318 319 if ( !WaitForHandshake() ) 320 return 0xffffffff; 321 322 m_pDspCommPage->dwSampleRate = 323 SWAP( LAYLA24_MAGIC_NUMBER / dwBaseRate - 2 ); 324 325 ClearHandshake(); 326 SendVector( DSP_VC_SET_LAYLA24_FREQUENCY_REG ); 327 } 328 329 // 330 // Tell the DSP about it 331 // 332 if ( ECHOSTATUS_OK == WriteControlReg( dwControlReg ) ) 333 { 334 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); 335 336 ECHO_DEBUGPRINTF( ("CLayla24DspCommObject::SetSampleRate: %ld " 337 "clock %lx\n", dwNewSampleRate, dwControlReg) ); 338 } 339 340 m_dwSampleRate = dwNewSampleRate; 341 342 return dwNewSampleRate; 343 344 } // DWORD CLayla24DspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 345 346 347 //=========================================================================== 348 // 349 // SetDigitalMode 350 // 351 //=========================================================================== 352 353 ECHOSTATUS CLayla24DspCommObject::SetDigitalMode 354 ( 355 BYTE byNewMode 356 ) 357 { 358 BOOL AsicOk; 359 360 // 361 // Change the ASIC 362 // 363 switch ( byNewMode ) 364 { 365 case DIGITAL_MODE_SPDIF_RCA : 366 case DIGITAL_MODE_SPDIF_OPTICAL : 367 // 368 // If the currently loaded ASIC is the S/PDIF ASIC, switch 369 // to the ADAT ASIC 370 // 371 AsicOk = SwitchAsic( pbLayla24_2S_ASIC, sizeof( pbLayla24_2S_ASIC ) ); 372 break; 373 374 case DIGITAL_MODE_ADAT : 375 // 376 // If the currently loaded ASIC is the S/PDIF ASIC, switch 377 // to the ADAT ASIC 378 // 379 AsicOk = SwitchAsic( pbLayla24_2A_ASIC, sizeof( pbLayla24_2A_ASIC ) ); 380 break; 381 382 default : 383 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED; 384 } 385 386 if (FALSE == AsicOk) 387 return ECHOSTATUS_ASIC_NOT_LOADED; 388 389 // 390 // Call the base class to tweak the input clock if necessary 391 // 392 return CGMLDspCommObject::SetDigitalMode(byNewMode); 393 394 } // ECHOSTATUS CLaya24DspCommObject::SetDigitalMode 395 396 397 //=========================================================================== 398 // 399 // Depending on what digital mode you want, Layla24 needs different ASICs 400 // loaded. This function checks the ASIC needed for the new mode and sees 401 // if it matches the one already loaded. 402 // 403 //=========================================================================== 404 405 BOOL CLayla24DspCommObject::SwitchAsic 406 ( 407 BYTE * pbyAsicNeeded, 408 DWORD dwAsicSize 409 ) 410 { 411 BOOL rval; 412 413 // 414 // Check to see if this is already loaded 415 // 416 rval = TRUE; 417 if ( pbyAsicNeeded != m_pbyAsic ) 418 { 419 BYTE byMonitors[ MONITOR_ARRAY_SIZE ]; 420 memmove( byMonitors, m_pDspCommPage->byMonitors, MONITOR_ARRAY_SIZE ); 421 memset( m_pDspCommPage->byMonitors, 422 GENERIC_TO_DSP(ECHOGAIN_MUTED), 423 MONITOR_ARRAY_SIZE ); 424 425 // 426 // Load the desired ASIC 427 // 428 rval = CDspCommObject::LoadASIC(DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, 429 pbyAsicNeeded, 430 dwAsicSize ); 431 if (FALSE != rval) 432 { 433 m_pbyAsic = pbyAsicNeeded; 434 } 435 memmove( m_pDspCommPage->byMonitors, byMonitors, MONITOR_ARRAY_SIZE ); 436 } 437 438 return rval; 439 440 } // BOOL CLayla24DspCommObject::SwitchAsic( DWORD dwMask96 ) 441 442 443 //=========================================================================== 444 // 445 // SetInputClock 446 // 447 //=========================================================================== 448 449 ECHOSTATUS CLayla24DspCommObject::SetInputClock(WORD wClock) 450 { 451 BOOL bSetRate; 452 BOOL bWriteControlReg; 453 DWORD dwControlReg, dwSampleRate; 454 455 ECHO_DEBUGPRINTF( ( "CLayla24DspCommObject::SetInputClock:\n" ) ); 456 457 dwControlReg = GetControlRegister(); 458 459 // 460 // Mask off the clock select bits 461 // 462 dwControlReg &= GML_CLOCK_CLEAR_MASK; 463 dwSampleRate = GetSampleRate(); 464 465 bSetRate = FALSE; 466 bWriteControlReg = TRUE; 467 468 // 469 // Pick the new clock 470 // 471 switch ( wClock ) 472 { 473 case ECHO_CLOCK_INTERNAL : 474 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) ); 475 476 // If the sample rate is out of range for some reason, set it 477 // to a reasonable value. mattg 478 if ( ( GetSampleRate() < 8000 ) || 479 ( GetSampleRate() > 100000 ) ) 480 { 481 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); 482 m_dwSampleRate = 48000; 483 } 484 485 bSetRate = TRUE; 486 bWriteControlReg = FALSE; 487 break; 488 489 case ECHO_CLOCK_SPDIF: 490 if ( DIGITAL_MODE_ADAT == GetDigitalMode() ) 491 { 492 return ECHOSTATUS_CLOCK_NOT_AVAILABLE; 493 } 494 495 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) ); 496 497 dwControlReg |= GML_SPDIF_CLOCK; 498 499 /* 500 Since Layla24 doesn't support 96 kHz S/PDIF, this can be ignored 501 if ( GML_CLOCK_DETECT_BIT_SPDIF96 & GetInputClockDetect() ) 502 { 503 dwControlReg |= GML_DOUBLE_SPEED_MODE; 504 } 505 else 506 { 507 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 508 } 509 */ 510 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 511 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to SPDIF\n" ) ); 512 break; 513 514 case ECHO_CLOCK_WORD: 515 dwControlReg |= GML_WORD_CLOCK; 516 517 if ( GML_CLOCK_DETECT_BIT_WORD96 & GetInputClockDetect() ) 518 { 519 dwControlReg |= GML_DOUBLE_SPEED_MODE; 520 } 521 else 522 { 523 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 524 } 525 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to WORD\n" ) ); 526 break; 527 528 529 case ECHO_CLOCK_ADAT : 530 if ( DIGITAL_MODE_ADAT != GetDigitalMode() ) 531 { 532 return ECHOSTATUS_CLOCK_NOT_AVAILABLE; 533 } 534 535 dwControlReg |= GML_ADAT_CLOCK; 536 dwControlReg &= ~GML_DOUBLE_SPEED_MODE; 537 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to ADAT\n" ) ); 538 break; 539 540 default : 541 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock)); 542 ECHO_DEBUGBREAK(); 543 return ECHOSTATUS_CLOCK_NOT_SUPPORTED; 544 545 } // switch (wClock) 546 547 // 548 // Winner! Save the new input clock. 549 // 550 m_wInputClock = wClock; 551 552 // 553 // Do things according to the flags 554 // 555 if ( bWriteControlReg ) 556 { 557 WriteControlReg( dwControlReg, TRUE ); 558 } 559 560 // 561 // If the user just switched to internal clock, 562 // set the sample rate 563 // 564 if ( bSetRate ) 565 SetSampleRate( m_dwSampleRate ); 566 567 return ECHOSTATUS_OK; 568 569 } // ECHOSTATUS CLayla24DspCommObject::SetInputClock() 570 571 572 // **** Layla24DspCommObject.cpp **** 573