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
55CLaylaDspCommObject::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
89CLaylaDspCommObject::~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
109BOOL 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
136DWORD 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
181ECHOSTATUS 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
259ECHOSTATUS 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
304ECHOSTATUS 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
336ECHOSTATUS 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
358ECHOSTATUS 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
415BOOL 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