1 // ****************************************************************************
3 // CLaylaDspCommObject.cpp
5 // Implementation file for EchoGals generic driver Layla DSP
8 // ----------------------------------------------------------------------------
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
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.
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.
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
29 // ****************************************************************************
31 #include "CEchoGals.h"
32 #include "CLaylaDspCommObject.h"
34 #include "Layla20DSP.c"
35 #include "LaylaASIC.c"
38 // The ASIC files for Layla20 are always this size
40 #define LAYLA_ASIC_SIZE 32385
43 /****************************************************************************
45 Construction and destruction
47 ****************************************************************************/
49 //===========================================================================
53 //===========================================================================
55 CLaylaDspCommObject::CLaylaDspCommObject
57 PDWORD pdwRegBase
, // Virtual ptr to DSP registers
58 PCOsSupport pOsSupport
59 ) : CDspCommObject( pdwRegBase
, pOsSupport
)
61 strcpy( m_szCardName
, "Layla" );
62 m_pdwDspRegBase
= pdwRegBase
; // Virtual addr DSP's register base
68 m_wFirstDigitalBusOut
= 10;
69 m_wFirstDigitalBusIn
= 8;
73 m_wNumMidiOut
= 1; // # MIDI out channels
74 m_wNumMidiIn
= 1; // # MIDI in channels
78 m_pwDspCodeToLoad
= pwLayla20DSP
;
80 } // CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase )
83 //===========================================================================
87 //===========================================================================
89 CLaylaDspCommObject::~CLaylaDspCommObject()
91 ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) );
92 } // CLaylaDspCommObject::~CLaylaDspCommObject()
97 /****************************************************************************
99 Hardware setup and config
101 ****************************************************************************/
103 //===========================================================================
105 // Layla20 has an ASIC in the external box
107 //===========================================================================
109 BOOL
CLaylaDspCommObject::LoadASIC()
111 if ( m_bASICLoaded
== TRUE
)
114 if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC
,
119 // Check if ASIC is alive and well.
121 return( CheckAsicStatus() );
122 } // BOOL CLaylaDspCommObject::LoadASIC()
125 //===========================================================================
129 // Set the sample rate for Layla
131 // Layla is simple; just send it the sampling rate (assuming that the clock
134 //===========================================================================
136 DWORD
CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate
)
139 // Only set the clock for internal mode
140 // Do not return failure, simply treat it as a non-event.
142 if ( GetInputClock() != ECHO_CLOCK_INTERNAL
)
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();
151 // Sanity check - check the sample rate
153 if ( ( dwNewSampleRate
< 8000 ) ||
154 ( dwNewSampleRate
> 50000 ) )
156 ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %ld out of range, "
162 if ( !WaitForHandshake() )
165 m_pDspCommPage
->dwSampleRate
= SWAP( dwNewSampleRate
);
168 SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE
);
169 ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %ld\n",
171 return( dwNewSampleRate
);
172 } // DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
175 //===========================================================================
177 // Send new input clock setting to DSP
179 //===========================================================================
181 ECHOSTATUS
CLaylaDspCommObject::SetInputClock(WORD wClock
)
186 ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) );
192 case ECHO_CLOCK_INTERNAL
:
193 ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) );
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 ) )
200 m_pDspCommPage
->dwSampleRate
= SWAP( (DWORD
) 48000 );
204 wNewClock
= LAYLA20_CLOCK_INTERNAL
;
207 case ECHO_CLOCK_SPDIF
:
208 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) );
210 wNewClock
= LAYLA20_CLOCK_SPDIF
;
213 case ECHO_CLOCK_WORD
:
214 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) );
216 wNewClock
= LAYLA20_CLOCK_WORD
;
220 case ECHO_CLOCK_SUPER
:
221 ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) );
223 wNewClock
= LAYLA20_CLOCK_SUPER
;
228 ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock
));
230 return ECHOSTATUS_CLOCK_NOT_SUPPORTED
;
235 // Winner! Save the new input clock.
237 m_wInputClock
= wClock
;
240 // Send the new clock to the DSP
242 m_pDspCommPage
->wInputClock
= SWAP(wNewClock
);
244 SendVector( DSP_VC_UPDATE_CLOCKS
);
249 return ECHOSTATUS_OK
;
250 } // ECHOSTATUS CLaylaDspCommObject::SetInputClock()
253 //===========================================================================
255 // Set new output clock
257 //===========================================================================
259 ECHOSTATUS
CLaylaDspCommObject::SetOutputClock(WORD wClock
)
263 if (FALSE
== m_bASICLoaded
)
264 return ECHOSTATUS_ASIC_NOT_LOADED
;
266 if (!WaitForHandshake())
267 return ECHOSTATUS_DSP_DEAD
;
269 ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") );
272 // Translate generic driver clock constants to values for Layla20 firmware
276 case ECHO_CLOCK_SUPER
:
277 wLaylaOutClock
= LAYLA20_OUTPUT_CLOCK_SUPER
;
280 case ECHO_CLOCK_WORD
:
281 wLaylaOutClock
= LAYLA20_OUTPUT_CLOCK_WORD
;
285 return ECHOSTATUS_INVALID_PARAM
;
288 m_pDspCommPage
->wOutputClock
= SWAP(wLaylaOutClock
);
289 m_wOutputClock
= wClock
;
292 ECHOSTATUS Status
= SendVector(DSP_VC_UPDATE_CLOCKS
);
295 } // ECHOSTATUS CLaylaDspCommObject::SetOutputClock
298 //===========================================================================
300 // Input bus gain - iGain is in units of .5 dB
302 //===========================================================================
304 ECHOSTATUS
CLaylaDspCommObject::SetBusInGain( WORD wBusIn
, INT32 iGain
)
306 ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetBusInGain\n"));
308 if (wBusIn
>= LAYLA20_INPUT_TRIMS
)
309 return ECHOSTATUS_INVALID_CHANNEL
;
312 // Store the gain for later use
314 m_byInputTrims
[wBusIn
] = (BYTE
) iGain
;
317 // Adjust the input gain depending on the nominal level switch
320 GetNominalLevel( wBusIn
+ m_wNumBussesOut
, &byMinus10
);
325 // This channel is in +4 mode; subtract 12 dB from the input gain
326 // (note that iGain is in units of .5 dB)
331 return CDspCommObject::SetBusInGain(wBusIn
,iGain
);
336 ECHOSTATUS
CLaylaDspCommObject::GetBusInGain( WORD wBusIn
, INT32
&iGain
)
338 if (wBusIn
>= LAYLA20_INPUT_TRIMS
)
339 return ECHOSTATUS_INVALID_CHANNEL
;
341 iGain
= (INT32
) m_byInputTrims
[wBusIn
];
343 return ECHOSTATUS_OK
;
347 //===========================================================================
349 // Set the nominal level for an input or output bus
351 // Set bState to TRUE for -10, FALSE for +4
353 // Layla20 sets the input nominal level by adjusting the
356 //===========================================================================
358 ECHOSTATUS
CLaylaDspCommObject::SetNominalLevel
364 ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetNominalLevel\n"));
366 if (wBus
< m_wNumBussesOut
)
369 // This is an output bus; call the base class routine to service it
371 return CDspCommObject::SetNominalLevel(wBus
,bState
);
375 // Check the bus number
377 ECHO_DEBUGPRINTF(("\tChecking the bus number\n"));
378 if (wBus
< (m_wNumBussesOut
+ LAYLA20_INPUT_TRIMS
))
380 ECHO_DEBUGPRINTF(("\twBus %d m_pDspCommPage %p\n",wBus
,m_pDspCommPage
));
382 // Set the nominal bit in the comm page
385 m_pDspCommPage
->cmdNominalLevel
.SetIndexInMask( wBus
);
387 m_pDspCommPage
->cmdNominalLevel
.ClearIndexInMask( wBus
);
390 // Set the input trim, using the current gain
392 ECHO_DEBUGPRINTF(("\tCalling SetBusInGain\n"));
394 wBus
= wBus
- m_wNumBussesOut
;
395 return SetBusInGain( wBus
, (INT32
) m_byInputTrims
[wBus
]);
398 ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid "
401 return ECHOSTATUS_INVALID_CHANNEL
;
403 } // ECHOSTATUS CLaylaDspCommObject::SetNominalLevel
406 //===========================================================================
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.
413 //===========================================================================
415 BOOL
CLaylaDspCommObject::CheckAsicStatus()
421 dwNumTests
= NUM_ASIC_ATTEMPTS
;
425 bLoaded
= CDspCommObject::CheckAsicStatus();
426 if (FALSE
!= bLoaded
)
429 if (NUM_ASIC_WINS
== dwNumWins
)
431 m_bASICLoaded
= TRUE
;
436 m_bASICLoaded
= FALSE
;
438 } while (dwNumTests
!= 0);
440 return m_bASICLoaded
;
442 } // BOOL CLaylaDspCommObject::CheckAsicStatus()
445 // **** LaylaDspCommObject.cpp ****