/* ------------------------------------------------------------------------------ | WAVES | | Author : Terry Leach | Revision: 8/1/02 Initial creation | Revision: 9/22/02 Rewritten to describe wave in terms of VECTORs. | Revision: 9/19/03 Support direct waveforms... those which are not calculated here | but at a higher application level. Purpose : Encapsulates data and functionality associated with a waveform. */ #include #include #include #include "GLOBALS.h" #include "WAVES2.hpp" #include "MEM.h" #include "ERROR.hpp" ERR g_Err; char g_Debug[ 256 ]; //--------- Global to all WAVEs uint WAVE::g_Width = 32; // All wave values are 32 bits wide int WAVE::g_Shifts = 8; // Values are 24 bits left justified in 32 bits long WAVE::g_Len = FAST_FFT_SZ; // Default size of all waveforms uint WAVE::g_Count = 0; // Instantiation count of wave objects // --------------------------------------------------------------------------- WAVE::WAVE() /* | Purpose: Default constructor for the WAVE object */ { wave(); Init( NULL ,m_Tones ,NULL ); } // --------------------------------------------------------------------------- WAVE::WAVE( uint unWaveLen ) /* | Purpose: WAVE constructor sets internal memory size */ { if( unWaveLen && !g_Count ) g_Len = unWaveLen; wave(); Init( NULL ,m_Tones ,NULL ); } // --------------------------------------------------------------------------- WAVE::WAVE( void *pvLink ,VECTOR &Tones ,uInt16 *pBins ) /* | Purpose: Constructs a complete waveform, placing the calculated waveform in the target memory location. INPUTS: pvLink Memory link to the target waveform. Tones Vector of _COMPLEX numbers representing the tones in the waveform pBins List of fast FFT bins containing component tones of the waveform, 0 terminated OUTPUTS: *pvLink Calculated waveform using waveform size points. NOTE: Note caller should use the WAVE_SIZE define to size target waveform memory before using this constructor. */ { wave(); Init( pvLink ,Tones ,pBins ); } // --------------------------------------------------------------------------- WAVE::WAVE( VECTOR &Tones ,uInt16 *pBins ) /* | Purpose: Calculates and stores the base waveform parameters. This requires allocation of storage space for COS and SIN. */ { wave(); Init( NULL ,Tones ,pBins ); } // --------------------------------------------------------------------------- WAVE::WAVE( void *pvLink ) /* | Purpose: Just allocates space for the base waveform components. */ { wave(); Init( pvLink ,m_Tones ,NULL ); } // --------------------------------------------------------------------------- WAVE::~WAVE() /* | Purpose: Destructor for the WAVE object */ { if( g_Count ) g_Count--; if( m_pWVcopy.pf ) delete [] m_pWVcopy.pf; if( m_pBins ) delete [] m_pBins; g_Err.Warn( "WAVE::~WAVE" ); } WAVE::WAVE( WAVE &refWAVE ) { copy( &refWAVE ); } WAVE::WAVE( WAVE *pWAVE ) { copy( pWAVE ); } // --------------------------------------------------------------------------- void WAVE::copy( WAVE *pWAVE ) /* | Purpose: Common copy constructor code */ { if( this == pWAVE ) return; wave(); Init( NULL ,pWAVE-> m_Tones ,pWAVE-> m_pBins ); // Initializer will allocate memory } // --------------------------------------------------------------------------- void WAVE::wave() /* | Purpose: Common construction */ { g_Count++; m_pBins = NULL; m_pWAVE.pv = NULL; m_pWVcopy.pv= NULL; } // --------------------------------------------------------------------------- WAVE &WAVE::operator += ( WAVE &rhsWV ) /* | Purpose: */ { if( rhsWV.m_pWAVE.pv ) if( m_pWAVE.pv ) for( int k = FAST_FFT_SZ; k--; ) m_pWAVE.pl[ k ] += rhsWV.m_pWAVE.pl[ k ]; else Init( NULL ,m_Tones + rhsWV.m_Tones ,rhsWV.m_pBins ); return *this; } // --------------------------------------------------------------------------- WAVE WAVE::operator + ( WAVE &rhsWV ) /* | Purpose: */ { WAVE waveTemp( this ); return WAVE( waveTemp += rhsWV ); } // --------------------------------------------------------------------------- WAVE &WAVE::operator -= ( WAVE &rhsWV ) /* | Purpose: */ { if( rhsWV.m_pWAVE.pv ) if( m_pWAVE.pv ) for( int k = FAST_FFT_SZ; k--; ) m_pWAVE.pl[ k ] -= rhsWV.m_pWAVE.pl[ k ]; else Init( NULL ,m_Tones - rhsWV.m_Tones ,rhsWV.m_pBins ); return *this; } // --------------------------------------------------------------------------- WAVE WAVE::operator - ( WAVE &rhsWV ) /* | Purpose: */ { WAVE waveTemp( this ); return WAVE( waveTemp -= rhsWV ); } // --------------------------------------------------------------------------- WAVE WAVE::operator - () /* | Purpose: */ { WAVE waveTemp; return WAVE( waveTemp -= *this ); } // --------------------------------------------------------------------------- WAVE &WAVE::operator = ( WAVE &rhsWV ) /* | Purpose: Assignment operator. Assigns right hand side into | left hand side (this). Contents of lhs is destroyed. */ { if( &rhsWV != this ) { if( rhsWV.m_pWAVE.pv ) if( m_pWAVE.pv ) for( int k = FAST_FFT_SZ; k--; ) m_pWAVE.pl[ k ] = rhsWV.m_pWAVE.pl[ k ]; else Init( NULL ,rhsWV.m_Tones ,rhsWV.m_pBins ); } return *this; } // --------------------------------------------------------------------------- void WAVE::Init( void *pvLink ,VECTOR &Tones ,uInt16 *pBins ) /* | Purpose: Performs common initialization to all contructors NOTE: See the full arguement constructor for description of arguements. */ { int OldBins = 0; int NewBins = 0; // ---------------- m_Tones = Tones; if( m_pBins ) for( OldBins = 0; m_pBins[ OldBins ]; OldBins++ ); if( pBins ) for( NewBins = 0; pBins[ NewBins ]; NewBins++ ); else NewBins = m_Tones.len(); if( OldBins < NewBins || !NewBins || !m_pBins ) { if( m_pBins ) delete [] m_pBins; m_pBins = (uInt16 *) new uInt16[ NewBins+1 ]; m_pBins[ NewBins ] = 0; } else m_pBins[ NewBins ] = 0; if( pBins ) for( ; NewBins--; m_pBins[ NewBins ] = pBins[ NewBins ] ); else for( ; NewBins--; m_pBins[ NewBins ] = 0 ); if( !m_pWAVE.pv ) { if( pvLink ) { if( m_pWVcopy.pv && (m_pWVcopy.pv != pvLink) ) { delete [] m_pWVcopy.pf; m_pWVcopy.pv = NULL; } m_pWAVE.pv = pvLink; } else { m_pWVcopy.pf= (float *) new float[ g_Len ]; m_pWAVE.pv = m_pWVcopy.pv; } } make(); } // --------------------------------------------------------------------------- void WAVE::make() /* | Purpose: Calculates a waveform and stores it in linked memory INPUTS: Member variables OUTPUTS: Contents of m_pCOS, m_pSIN */ { int k ,bin; double t ,*Omega ,*Lead; VECTOR Zero( m_Tones.len() ); double DACcorrect; // ------------------------------ // g_Err.Warn( "WAVE::Make Entry..." ); if( !m_pWAVE.pv ) return; // No memory linked to the waveform so bail if( !m_Tones.len() ) return; // No Tone vector so bail if( !m_pBins || !*m_pBins ) return; // No frequencies so bail Omega = (double *)new double[ m_Tones.len() ]; // Pre-calc this for efficiency in sin calc Lead = (double *)new double[ m_Tones.len() ]; // Space for correcting Layla phase lag for( bin = 0; m_pBins[ bin ]; bin++ ) { Omega[ bin ] = ((double) m_pBins[ bin ]) / (double) g_Len; Lead [ bin ] = CYCLESLOPE * m_pBins[bin]*4 + CYCLEINTERCEPT; // Phase lag correction... see latency.xls sprintf( g_Debug ,"WAVE::Make Omega[%d] = %g ,Lead = %g" ,bin ,Omega[bin] ,Lead[bin] ); g_Err.Warn( g_Debug ); } m_Tones.show(); // g_Err.Warn( "WAVE::Make Calculating waveform..." ); DACcorrect = pow( 10.0 ,0.5 / 20.0 ); for( k = FAST_FFT_SZ; k--; ) { t = (double) k; m_pWAVE.pf[ k ] = 0.0f; if( m_Tones != Zero ) { for( bin = 0; m_pBins[ bin ]; bin++ ) { m_pWAVE.pf[ k ] += (float) ( m_Tones[ bin ].Mag() * sin( _2PI*Omega[bin]*t + m_Tones[ bin ].Phase() - _2PI*Lead[bin] ) ); } m_pWAVE.pf[ k ] *= (float) FULL_SCALE; m_pWAVE.pf[ k ] *= (float) DACcorrect; m_pWAVE.pl[ k ] = ((long) m_pWAVE.pf[ k ]) << g_Shifts; } } delete [] Omega; delete [] Lead; // g_Err.Warn( "WAVE::Make Waveform calculated" ); } void WAVE::convert( WAVEPTR pWAVE ,long WaveLen ) { long Sample; // --------------- for(Sample = WaveLen; Sample--; pWAVE.pf[ Sample ] = ((float)(pWAVE.pl[ Sample ] >> g_Shifts)) / (float)FULL_SCALE ); } void WAVE::modify( VECTOR &Tones ,uInt16 *pBins ) { if( pBins && *pBins ) Init( NULL ,Tones ,pBins ); else Init( NULL ,Tones ,NULL ); } void WAVE::modify( float *pWave ) { if( !pWave ) return; // No new waveform supplied, bail for( uint unPt = g_Len; unPt--; ) // Copy new waveform into buffer m_pWAVE.pl[ unPt ] = ((long)(pWave[ unPt ] * (float)FULL_SCALE)) << g_Shifts; } void WAVE::show() { show( g_Len ); } // --------------------------------------------------------------------------- void WAVE::show( uint Amt ) /* | Purpose: Shows a portion of a waveform. INPUTS: Amt Amount of the waveform to show. */ { float fScale; long *pl; // --------------- if( !m_pWAVE.pv ) return; fScale = (float) FULL_SCALE; pl = m_pWAVE.pl; while( Amt-- ) { sprintf( g_Debug ,"%g" , (float)(*pl++ >> g_Shifts) / fScale ); g_Err.Warn( g_Debug ); } }