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
CLaylaDspCommObject(PDWORD pdwRegBase,PCOsSupport pOsSupport)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
~CLaylaDspCommObject()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
LoadASIC()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
SetSampleRate(DWORD dwNewSampleRate)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
SetInputClock(WORD wClock)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
SetOutputClock(WORD wClock)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
SetBusInGain(WORD wBusIn,INT32 iGain)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
GetBusInGain(WORD wBusIn,INT32 & iGain)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
SetNominalLevel(WORD wBus,BOOL bState)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
CheckAsicStatus()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