⛏️ index : haiku.git

// ****************************************************************************
//
//  	CLaylaDspCommObject.cpp
//
//		Implementation file for EchoGals generic driver Layla DSP
//		interface class.
//
// ----------------------------------------------------------------------------
//
// This file is part of Echo Digital Audio's generic driver library.
// Copyright Echo Digital Audio Corporation (c) 1998 - 2005
// All rights reserved
// www.echoaudio.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// ****************************************************************************

#include "CEchoGals.h"
#include "CLaylaDspCommObject.h"

#include "Layla20DSP.c"
#include "LaylaASIC.c"

//
// The ASIC files for Layla20 are always this size
//
#define LAYLA_ASIC_SIZE		32385


/****************************************************************************

	Construction and destruction

 ****************************************************************************/

//===========================================================================
//
// Constructor
//
//===========================================================================

CLaylaDspCommObject::CLaylaDspCommObject
(
	PDWORD		pdwRegBase,				// Virtual ptr to DSP registers
	PCOsSupport	pOsSupport
) : CDspCommObject( pdwRegBase, pOsSupport )
{
	strcpy( m_szCardName, "Layla" );
	m_pdwDspRegBase = pdwRegBase;		// Virtual addr DSP's register base

	m_wNumPipesOut = 12;
	m_wNumPipesIn = 10;
	m_wNumBussesOut = 12;
	m_wNumBussesIn = 10;
	m_wFirstDigitalBusOut = 10;
	m_wFirstDigitalBusIn = 8;

	m_fHasVmixer = FALSE;

	m_wNumMidiOut = 1;					// # MIDI out channels
	m_wNumMidiIn = 1;						// # MIDI in  channels

	m_bHasASIC = TRUE;

	m_pwDspCodeToLoad = pwLayla20DSP;
	
}	// CLaylaDspCommObject::CLaylaDspCommObject( DWORD dwPhysRegBase )


//===========================================================================
//
// Destructor
//
//===========================================================================

CLaylaDspCommObject::~CLaylaDspCommObject()
{
	ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::~CLaylaDspCommObject() is toast!\n" ) );
}	// CLaylaDspCommObject::~CLaylaDspCommObject()




/****************************************************************************

	Hardware setup and config

 ****************************************************************************/

//===========================================================================
//
// Layla20 has an ASIC in the external box
//
//===========================================================================

BOOL CLaylaDspCommObject::LoadASIC()
{
	if ( m_bASICLoaded == TRUE )
		return TRUE;

	if ( !CDspCommObject::LoadASIC( DSP_FNC_LOAD_LAYLA_ASIC,
											  pbLaylaASIC,
											  LAYLA_ASIC_SIZE ) )
		return FALSE;
	//
	// Check if ASIC is alive and well.
	//
	return( CheckAsicStatus() );
}	// BOOL CLaylaDspCommObject::LoadASIC()


//===========================================================================
//
// SetSampleRate
// 
// Set the sample rate for Layla
//
// Layla is simple; just send it the sampling rate (assuming that the clock
// mode is correct).
//
//===========================================================================

DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )
{
	//
	// Only set the clock for internal mode
	//	Do not return failure, simply treat it as a non-event.
	//
	if ( GetInputClock() != ECHO_CLOCK_INTERNAL )
	{
		ECHO_DEBUGPRINTF( ( "SetSampleRate: Cannot set sample rate because "
								  "Layla clock NOT set to CLK_CLOCKININTERNAL\n" ) );
		m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
		return GetSampleRate();
	}
	
	//
	// Sanity check - check the sample rate
	//
	if ( ( dwNewSampleRate < 8000 ) ||
		  ( dwNewSampleRate > 50000 ) )
	{
		ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate %ld out of range, "
								  "no change made\n",
								  dwNewSampleRate) );
		return 0xffffffff;
	}

	if ( !WaitForHandshake() )
		return 0xffffffff;

	m_pDspCommPage->dwSampleRate = SWAP( dwNewSampleRate );
	
	ClearHandshake();
	SendVector( DSP_VC_SET_LAYLA_SAMPLE_RATE );
	ECHO_DEBUGPRINTF( ( "SetSampleRate: Layla sample rate changed to %ld\n",
							  dwNewSampleRate ) );
	return( dwNewSampleRate );
}	// DWORD CLaylaDspCommObject::SetSampleRate( DWORD dwNewSampleRate )


//===========================================================================
//
// Send new input clock setting to DSP
//
//===========================================================================

ECHOSTATUS CLaylaDspCommObject::SetInputClock(WORD wClock)
{
	BOOL			bSetRate;
	WORD			wNewClock;

	ECHO_DEBUGPRINTF( ( "CLaylaDspCommObject::SetInputClock:\n" ) );

	bSetRate = FALSE;
	
	switch ( wClock )
	{
		case ECHO_CLOCK_INTERNAL : 
			ECHO_DEBUGPRINTF( ( "\tSet Layla24 clock to INTERNAL\n" ) );

			// If the sample rate is out of range for some reason, set it
			// to a reasonable value.  mattg
			if ( ( GetSampleRate() < 8000 ) ||
			     ( GetSampleRate() > 50000 ) )
			{
				m_pDspCommPage->dwSampleRate = SWAP( (DWORD) 48000 );
			}

			bSetRate = TRUE;
			wNewClock = LAYLA20_CLOCK_INTERNAL;
			break;

		case ECHO_CLOCK_SPDIF:
			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SPDIF\n" ) );
			
			wNewClock = LAYLA20_CLOCK_SPDIF;
			break;

		case ECHO_CLOCK_WORD: 
			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to WORD\n" ) );
			
			wNewClock = LAYLA20_CLOCK_WORD;
			
			break;

		case ECHO_CLOCK_SUPER: 
			ECHO_DEBUGPRINTF( ( "\tSet Layla20 clock to SUPER\n" ) );
			
			wNewClock = LAYLA20_CLOCK_SUPER;
			
			break;

		default :
			ECHO_DEBUGPRINTF(("Input clock 0x%x not supported for Layla24\n",wClock));
			ECHO_DEBUGBREAK();
				return ECHOSTATUS_CLOCK_NOT_SUPPORTED;

	}		// switch (wClock)

	//
	// Winner! Save the new input clock.
	//
	m_wInputClock = wClock;

	//
	// Send the new clock to the DSP
	//
	m_pDspCommPage->wInputClock = SWAP(wNewClock);
	ClearHandshake();
	SendVector( DSP_VC_UPDATE_CLOCKS );
	
	if ( bSetRate )
		SetSampleRate();
		
	return ECHOSTATUS_OK;
}		// ECHOSTATUS CLaylaDspCommObject::SetInputClock()


//===========================================================================
//
// Set new output clock
//
//===========================================================================

ECHOSTATUS CLaylaDspCommObject::SetOutputClock(WORD wClock)
{
	WORD wLaylaOutClock;

	if (FALSE == m_bASICLoaded)
		return ECHOSTATUS_ASIC_NOT_LOADED;
		
	if (!WaitForHandshake())
		return ECHOSTATUS_DSP_DEAD;

	ECHO_DEBUGPRINTF( ("CDspCommObject::SetOutputClock:\n") );
		
	//
	// Translate generic driver clock constants to values for Layla20 firmware
	//
	switch (wClock)
	{
		case ECHO_CLOCK_SUPER :
			wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_SUPER;
			break;
	
		case ECHO_CLOCK_WORD :
			wLaylaOutClock = LAYLA20_OUTPUT_CLOCK_WORD;
			break;
													  		
		default :
			return ECHOSTATUS_INVALID_PARAM;
	}

	m_pDspCommPage->wOutputClock = SWAP(wLaylaOutClock);
	m_wOutputClock = wClock;
	
	ClearHandshake();
	ECHOSTATUS Status = SendVector(DSP_VC_UPDATE_CLOCKS);
	
	return Status;
}	// ECHOSTATUS CLaylaDspCommObject::SetOutputClock


//===========================================================================
//
// Input bus gain - iGain is in units of .5 dB
//
//===========================================================================

ECHOSTATUS CLaylaDspCommObject::SetBusInGain( WORD wBusIn, INT32 iGain)
{
	ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetBusInGain\n"));
	
	if (wBusIn >= LAYLA20_INPUT_TRIMS)
		return ECHOSTATUS_INVALID_CHANNEL;

	//
	// Store the gain for later use
	//
	m_byInputTrims[wBusIn] = (BYTE) iGain;

	//
	// Adjust the input gain depending on the nominal level switch
	//
	BYTE byMinus10;
	GetNominalLevel( wBusIn + m_wNumBussesOut, &byMinus10);
	
	if (0 == byMinus10)
	{
		//
		// This channel is in +4 mode; subtract 12 dB from the input gain
		// (note that iGain is in units of .5 dB)
		//
		iGain -= 12 << 1;
	}
	
	return CDspCommObject::SetBusInGain(wBusIn,iGain);

}	


ECHOSTATUS CLaylaDspCommObject::GetBusInGain( WORD wBusIn, INT32 &iGain)
{
	if (wBusIn >= LAYLA20_INPUT_TRIMS)
		return ECHOSTATUS_INVALID_CHANNEL;
	
	iGain = (INT32) m_byInputTrims[wBusIn];	
	
	return ECHOSTATUS_OK;
}	


//===========================================================================
//
// Set the nominal level for an input or output bus
//
//	Set bState to TRUE for -10, FALSE for +4 
//
// Layla20 sets the input nominal level by adjusting the 
// input trim
//
//===========================================================================

ECHOSTATUS CLaylaDspCommObject::SetNominalLevel
(
	WORD	wBus,
	BOOL	bState
)
{
	ECHO_DEBUGPRINTF(("CLaylaDspCommObject::SetNominalLevel\n"));

	if (wBus < m_wNumBussesOut)
	{
		//
		//	This is an output bus; call the base class routine to service it
		//
		return CDspCommObject::SetNominalLevel(wBus,bState);
	}

	//
	// Check the bus number
	//
	ECHO_DEBUGPRINTF(("\tChecking the bus number\n"));
	if (wBus < (m_wNumBussesOut + LAYLA20_INPUT_TRIMS))
	{
		ECHO_DEBUGPRINTF(("\twBus %d  m_pDspCommPage %p\n",wBus,m_pDspCommPage));
		//
		// Set the nominal bit in the comm page
		//		
		if ( bState )
			m_pDspCommPage->cmdNominalLevel.SetIndexInMask( wBus );
		else
			m_pDspCommPage->cmdNominalLevel.ClearIndexInMask( wBus );
		
		//
		// Set the input trim, using the current gain
		//	
		ECHO_DEBUGPRINTF(("\tCalling SetBusInGain\n"));
		
		wBus = wBus - m_wNumBussesOut;
		return SetBusInGain(	wBus, (INT32) m_byInputTrims[wBus]);
	}

	ECHO_DEBUGPRINTF( ("CLaylaDspCommObject::SetNominalOutLineLevel Invalid "
							 "index %d\n",
							 wBus ) );
	return ECHOSTATUS_INVALID_CHANNEL;

}	// ECHOSTATUS CLaylaDspCommObject::SetNominalLevel


//===========================================================================
//
// ASIC status check
//
// This test sometimes fails for Layla20; for Layla20, the loop runs 5 times
// and succeeds if it wins on three of the loops.
//
//===========================================================================

BOOL CLaylaDspCommObject::CheckAsicStatus()
{
	DWORD dwNumTests;
	DWORD dwNumWins;
	BOOL bLoaded;

	dwNumTests = NUM_ASIC_ATTEMPTS;
	dwNumWins = 0;
	do
	{
		bLoaded = CDspCommObject::CheckAsicStatus();
		if (FALSE != bLoaded)
		{
			dwNumWins++;
			if (NUM_ASIC_WINS == dwNumWins)
			{
				m_bASICLoaded = TRUE;
				break;
			}
		}
	
		m_bASICLoaded = FALSE;
		dwNumTests--;
	} while (dwNumTests != 0);

	return m_bASICLoaded;

}	// BOOL CLaylaDspCommObject::CheckAsicStatus()


// **** LaylaDspCommObject.cpp ****