1 // **************************************************************************** 2 // 3 // CLaylaDspCommObject.cpp 4 // 5 // Implementation file for EchoGals generic driver Layla 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 "CLaylaDspCommObject.h" 33 34 #include "Layla20DSP.c" 35 #include "LaylaASIC.c" 36 37 // 38 // The ASIC files for Layla20 are always this size 39 // 40 #define LAYLA_ASIC_SIZE 32385 41 42 43 /**************************************************************************** 44 45 Construction and destruction 46 47 ****************************************************************************/ 48 49 //=========================================================================== 50 // 51 // Constructor 52 // 53 //=========================================================================== 54 55 CLaylaDspCommObject::CLaylaDspCommObject 56 ( 57 PDWORD pdwRegBase, // Virtual ptr to DSP registers 58 PCOsSupport pOsSupport 59 ) : CDspCommObject( pdwRegBase, pOsSupport ) 60 { 61 strcpy( m_szCardName, "Layla" ); 62 m_pdwDspRegBase = pdwRegBase; // Virtual addr DSP's register base 63 64 m_wNumPipesOut = 12; 65 m_wNumPipesIn = 10; 66 m_wNumBussesOut = 12; 67 m_wNumBussesIn = 10; 68 m_wFirstDigitalBusOut = 10; 69 m_wFirstDigitalBusIn = 8; 70 71 m_fHasVmixer = FALSE; 72 73 m_wNumMidiOut = 1; // # MIDI out channels 74 m_wNumMidiIn = 1; // # MIDI in channels 75 76 m_bHasASIC = TRUE; 77 78 m_pwDspCodeToLoad = pwLayla20DSP; 79 80 } // CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase ) 81 82 83 //=========================================================================== 84 // 85 // Destructor 86 // 87 //=========================================================================== 88 89 CLaylaDspCommObject::~CLaylaDspCommObject() 90 { 91 ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) ); 92 } // CLaylaDspCommObject::~CLaylaDspCommObject() 93 94 95 96 97 /**************************************************************************** 98 99 Hardware setup and config 100 101 ****************************************************************************/ 102 103 //=========================================================================== 104 // 105 // Layla20 has an ASIC in the external box 106 // 107 //=========================================================================== 108 109 BOOL CLaylaDspCommObject::LoadASIC() 110 { 111 if ( m_bASICLoaded == TRUE ) 112 return TRUE; 113 114 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC, 115 pbLaylaASIC, 116 LAYLA_ASIC_SIZE ) ) 117 return FALSE; 118 // 119 // Check if ASIC is alive and well. 120 // 121 return( CheckAsicStatus() ); 122 } // BOOL CLaylaDspCommObject::LoadASIC() 123 124 125 //=========================================================================== 126 // 127 // SetSampleRate 128 // 129 // Set the sample rate for Layla 130 // 131 // Layla is simple; just send it the sampling rate (assuming that the clock 132 // mode is correct). 133 // 134 //=========================================================================== 135 136 DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 137 { 138 // 139 // Only set the clock for internal mode 140 // Do not return failure, simply treat it as a non-event. 141 // 142 if ( GetInputClock() != ECHO_CLOCK_INTERNAL ) 143 { 144 ECHO_DEBUGPRINTF( ( "SetSampleRate: Cannot set sample rate because " 145 "Layla clock NOT set to CLK_CLOCKININTERNAL\n" ) ); 146 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); 147 return GetSampleRate(); 148 } 149 150 // 151 // Sanity check - check the sample rate 152 // 153 if ( ( dwNewSampleRate < 8000 ) || 154 ( dwNewSampleRate > 50000 ) ) 155 { 156 ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %ld out of range, " 157 "no change made\n", 158 dwNewSampleRate) ); 159 return 0xffffffff; 160 } 161 162 if ( !WaitForHandshake() ) 163 return 0xffffffff; 164 165 m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate ); 166 167 ClearHandshake(); 168 SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE ); 169 ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %ld\n", 170 dwNewSampleRate ) ); 171 return( dwNewSampleRate ); 172 } // DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate ) 173 174 175 //=========================================================================== 176 // 177 // Send new input clock setting to DSP 178 // 179 //=========================================================================== 180 181 ECHOSTATUS CLaylaDspCommObject::SetInputClock(WORD wClock) 182 { 183 BOOL bSetRate; 184 WORD wNewClock; 185 186 ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) ); 187 188 bSetRate = FALSE; 189 190 switch ( wClock ) 191 { 192 case ECHO_CLOCK_INTERNAL : 193 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) ); 194 195 // If the sample rate is out of range for some reason, set it 196 // to a reasonable value. mattg 197 if ( ( GetSampleRate() < 8000 ) || 198 ( GetSampleRate() > 50000 ) ) 199 { 200 m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 ); 201 } 202 203 bSetRate = TRUE; 204 wNewClock = LAYLA20_CLOCK_INTERNAL; 205 break; 206 207 case ECHO_CLOCK_SPDIF: 208 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) ); 209 210 wNewClock = LAYLA20_CLOCK_SPDIF; 211 break; 212 213 case ECHO_CLOCK_WORD: 214 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) ); 215 216 wNewClock = LAYLA20_CLOCK_WORD; 217 218 break; 219 220 case ECHO_CLOCK_SUPER: 221 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) ); 222 223 wNewClock = LAYLA20_CLOCK_SUPER; 224 225 break; 226 227 default : 228 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock)); 229 ECHO_DEBUGBREAK(); 230 return ECHOSTATUS_CLOCK_NOT_SUPPORTED; 231 232 } // switch (wClock) 233 234 // 235 // Winner! Save the new input clock. 236 // 237 m_wInputClock = wClock; 238 239 // 240 // Send the new clock to the DSP 241 // 242 m_pDspCommPage->wInputClock = SWAP(wNewClock); 243 ClearHandshake(); 244 SendVector( DSP_VC_UPDATE_CLOCKS ); 245 246 if ( bSetRate ) 247 SetSampleRate(); 248 249 return ECHOSTATUS_OK; 250 } // ECHOSTATUS CLaylaDspCommObject::SetInputClock() 251 252 253 //=========================================================================== 254 // 255 // Set new output clock 256 // 257 //=========================================================================== 258 259 ECHOSTATUS CLaylaDspCommObject::SetOutputClock(WORD wClock) 260 { 261 WORD wLaylaOutClock; 262 263 if (FALSE == m_bASICLoaded) 264 return ECHOSTATUS_ASIC_NOT_LOADED; 265 266 if (!WaitForHandshake()) 267 return ECHOSTATUS_DSP_DEAD; 268 269 ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") ); 270 271 // 272 // Translate generic driver clock constants to values for Layla20 firmware 273 // 274 switch (wClock) 275 { 276 case ECHO_CLOCK_SUPER : 277 wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_SUPER; 278 break; 279 280 case ECHO_CLOCK_WORD : 281 wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_WORD; 282 break; 283 284 default : 285 return ECHOSTATUS_INVALID_PARAM; 286 } 287 288 m_pDspCommPage->wOutputClock = SWAP(wLaylaOutClock); 289 m_wOutputClock = wClock; 290 291 ClearHandshake(); 292 ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS); 293 294 return Status; 295 } // ECHOSTATUS CLaylaDspCommObject::SetOutputClock 296 297 298 //=========================================================================== 299 // 300 // Input bus gain - iGain is in units of .5 dB 301 // 302 //=========================================================================== 303 304 ECHOSTATUS CLaylaDspCommObject::SetBusInGain( WORD wBusIn, INT32 iGain) 305 { 306 ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetBusInGain\n")); 307 308 if (wBusIn >= LAYLA20_INPUT_TRIMS) 309 return ECHOSTATUS_INVALID_CHANNEL; 310 311 // 312 // Store the gain for later use 313 // 314 m_byInputTrims[wBusIn] = (BYTE) iGain; 315 316 // 317 // Adjust the input gain depending on the nominal level switch 318 // 319 BYTE byMinus10; 320 GetNominalLevel( wBusIn + m_wNumBussesOut, &byMinus10); 321 322 if (0 == byMinus10) 323 { 324 // 325 // This channel is in +4 mode; subtract 12 dB from the input gain 326 // (note that iGain is in units of .5 dB) 327 // 328 iGain -= 12 << 1; 329 } 330 331 return CDspCommObject::SetBusInGain(wBusIn,iGain); 332 333 } 334 335 336 ECHOSTATUS CLaylaDspCommObject::GetBusInGain( WORD wBusIn, INT32 &iGain) 337 { 338 if (wBusIn >= LAYLA20_INPUT_TRIMS) 339 return ECHOSTATUS_INVALID_CHANNEL; 340 341 iGain = (INT32) m_byInputTrims[wBusIn]; 342 343 return ECHOSTATUS_OK; 344 } 345 346 347 //=========================================================================== 348 // 349 // Set the nominal level for an input or output bus 350 // 351 // Set bState to TRUE for -10, FALSE for +4 352 // 353 // Layla20 sets the input nominal level by adjusting the 354 // input trim 355 // 356 //=========================================================================== 357 358 ECHOSTATUS CLaylaDspCommObject::SetNominalLevel 359 ( 360 WORD wBus, 361 BOOL bState 362 ) 363 { 364 ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetNominalLevel\n")); 365 366 if (wBus < m_wNumBussesOut) 367 { 368 // 369 // This is an output bus; call the base class routine to service it 370 // 371 return CDspCommObject::SetNominalLevel(wBus,bState); 372 } 373 374 // 375 // Check the bus number 376 // 377 ECHO_DEBUGPRINTF(("\tChecking the bus number\n")); 378 if (wBus < (m_wNumBussesOut + LAYLA20_INPUT_TRIMS)) 379 { 380 ECHO_DEBUGPRINTF(("\twBus %d m_pDspCommPage %p\n",wBus,m_pDspCommPage)); 381 // 382 // Set the nominal bit in the comm page 383 // 384 if ( bState ) 385 m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus ); 386 else 387 m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus ); 388 389 // 390 // Set the input trim, using the current gain 391 // 392 ECHO_DEBUGPRINTF(("\tCalling SetBusInGain\n")); 393 394 wBus = wBus - m_wNumBussesOut; 395 return SetBusInGain( wBus, (INT32) m_byInputTrims[wBus]); 396 } 397 398 ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid " 399 "index %d\n", 400 wBus ) ); 401 return ECHOSTATUS_INVALID_CHANNEL; 402 403 } // ECHOSTATUS CLaylaDspCommObject::SetNominalLevel 404 405 406 //=========================================================================== 407 // 408 // ASIC status check 409 // 410 // This test sometimes fails for Layla20; for Layla20, the loop runs 5 times 411 // and succeeds if it wins on three of the loops. 412 // 413 //=========================================================================== 414 415 BOOL CLaylaDspCommObject::CheckAsicStatus() 416 { 417 DWORD dwNumTests; 418 DWORD dwNumWins; 419 BOOL bLoaded; 420 421 dwNumTests = NUM_ASIC_ATTEMPTS; 422 dwNumWins = 0; 423 do 424 { 425 bLoaded = CDspCommObject::CheckAsicStatus(); 426 if (FALSE != bLoaded) 427 { 428 dwNumWins++; 429 if (NUM_ASIC_WINS == dwNumWins) 430 { 431 m_bASICLoaded = TRUE; 432 break; 433 } 434 } 435 436 m_bASICLoaded = FALSE; 437 dwNumTests--; 438 } while (dwNumTests != 0); 439 440 return m_bASICLoaded; 441 442 } // BOOL CLaylaDspCommObject::CheckAsicStatus() 443 444 445 // **** LaylaDspCommObject.cpp **** 446