www.pudn.com > SMV_Code.rar > check.c


/*=========================================================================*/ 
/* Each of the companies; Ericsson, Lucent, Mindspeed, Motorola, Nokia,    */ 
/* Nortel Networks, and Qualcomm (hereinafter referred to individually as  */ 
/* “Source” or collectively as “Sources”) do hereby state:                 */ 
/*                                                                         */ 
/* To the extent to which the Source(s) may legally and freely do so,      */ 
/* the Source(s), upon submission of a Contribution, grant(s) a free,      */ 
/* irrevocable, non-exclusive, license to the Third Generation Partnership */ 
/* Project 2 (3GPP2) and its Organizational Partners: ARIB, CCSA, TIA,     */ 
/* TTA, and TTC, under the Source’s copyright or copyright license rights  */ 
/* in the Contribution, to, in whole or in part, copy, make derivative     */ 
/* works, perform, display and distribute the Contribution and derivative  */ 
/* works thereof consistent with 3GPP2’s and each Organizational Partner’s */ 
/* policies and procedures, with the right to (i) sublicense the foregoing */ 
/* rights consistent with 3GPP2’s and each Organizational Partner’s        */ 
/* policies and procedures and (ii) copyright and sell, if applicable) in  */ 
/* 3GPP2's name or each Organizational Partner’s name any 3GPP2 or         */ 
/* transposed Publication even though this Publication may contain the     */ 
/* Contribution or a derivative work thereof.  The Contribution shall      */ 
/* disclose any known limitations on the Source’s rights to license as     */ 
/* herein provided.                                                        */ 
/*                                                                         */ 
/* When a Contribution is submitted by the Source(s) to assist the         */ 
/* formulating groups of 3GPP2 or any of its Organizational Partners,      */ 
/* it is proposed to the Committee as a basis for discussion and is not    */ 
/* to be construed as a binding proposal on the Source(s).  The Source(s)  */ 
/* specifically reserve(s) the right to amend or modify the material       */ 
/* contained in the Contribution. Nothing contained in the Contribution    */ 
/* shall, except as herein expressly provided, be construed as conferring  */ 
/* by implication, estoppel or otherwise, any license or right under       */ 
/* (i) any existing or later issuing patent, whether or not the use of     */ 
/* information in the document necessarily employs an invention of any     */ 
/* existing or later issued patent, (ii) any copyright, (iii) any          */ 
/* trademark, or (iv) any other intellectual property right.               */ 
/*                                                                         */ 
/* With respect to the Software necessary for the practice of any or all   */ 
/* Normative portions of the Selectable Mode Vocoder (SMV) as it exists on */ 
/* the date of submittal of this form, should the SMV be approved as a     */ 
/* Specification or Report by 3GPP2, or as a transposed Standard by any of */ 
/* the 3GPP2’s Organizational Partners, the Source(s) state(s) that a      */ 
/* worldwide license to reproduce, use and distribute the Software, the    */ 
/* license rights to which are held by the Source(s), will be made         */ 
/* available to applicants under terms and conditions that are reasonable  */ 
/* and non-discriminatory, which may include monetary compensation,        */ 
/* and only to the extent necessary for the practice of any or all of the  */ 
/* Normative portions of the SMV or the field of use of practice of the    */ 
/* SMV Specification, Report, or Standard.  The statement contained above  */ 
/* is irrevocable and shall be binding upon the Source(s).  In the event   */ 
/* the rights of the Source(s) in and to copyright or copyright license    */ 
/* rights subject to such commitment are assigned or transferred,          */ 
/* the Source(s) shall notify the assignee or transferee of the existence  */ 
/* of such commitments.                                                    */ 
/*=========================================================================*/ 
/*                                                                   */ 
/*-------------------------------------------------------------------*/ 
/*===================================================================*/ 
 
/*===========================================================================*/ 
/*         ..Includes.                                                       */ 
/*---------------------------------------------------------------------------*/ 
#include  
#include "basic_op.h" 
#include "dtmf.h" 
#include "goertzel.h" 
#include "tables.h" 
 
/*===========================================================================*/ 
/*         ..Defines.                                                        */ 
/*---------------------------------------------------------------------------*/ 
 
/*===========================================================================*/ 
/*         ..Globals.                                                        */ 
/*---------------------------------------------------------------------------*/ 
void  terminate_checks(DTMF_DETECTOR*); 
  
/*===========================================================================*/ 
/*         ..Determine if DTMF is present.                                   */ 
/*---------------------------------------------------------------------------*/ 
void  check ( 
    DTMF_DETECTOR* D,    /* (i) - pointer to detector structure */ 
    short*         data  /* (i) - input data buffer */ 
) 
{ 
    /* ..(local) variables..*/ 
    register int k; 
    short dtmf_mem[16]; /* local scratch array */ 
    short *dP; 
    short *vkP; 
    short *eP; 
    short *coefP; 
    short *rmaxP;  /* points to max. row energy */ 
    short *cmaxP;  /* points to max. col. energy */ 
    short rmax_index; 
    short cmax_index; 
    Acc   accA; 
    Acc   accB; 
 
    /*..execute..*/ 
 
    /* DetectStat flag can be set to 1 only if */ 
    /* all conditions for a valid digit are met. */ 
    D->DtmfDetectStat = 0; 
 
 
 
    /* Find maximum row energy */ 
    eP = D->DtmfEnergy; 
    rmaxP = eP; 
    rmax_index = 0; 
    eP++; 
    for (k=1; k<4; k++) 
    { 
        if (*eP > *rmaxP)  
        { 
            rmaxP = eP; 
            rmax_index = k; 
        } 
        eP++; 
    } 
 
    /* Find maximum column energy */ 
    eP = &D->DtmfEnergy[4]; 
    cmaxP = eP; 
    cmax_index = 4; 
    eP++; 
    for (k=1; k<4; k++) 
    { 
        if (*eP > *cmaxP)  
        { 
            cmaxP = eP; 
            cmax_index = k+4; 
        } 
        eP++; 
    } 
 
    /* Pause test */ 
    if ( Max(*rmaxP,*cmaxP) < THR_PAU) 
    { 
        D->DtmfPauseLatch += 1; 
        if (D->DtmfPauseLatch >= 16384)  D->DtmfPauseLatch = 16384; 
 
        terminate_checks(D); 
        return; 
    } 
 
    /* Signal strength check: compare sum of rowmax and colmax to threshold */ 
    if ( (*rmaxP + *cmaxP) <= thr_sig2[rmax_index]) 
    { 
        terminate_checks(D); 
        return; 
    } 
 
    /* Twist Check */ 
    if (*rmaxP <= *cmaxP)  /* standard twist */ 
    { 
     /*   if ( (A_set_hi(*rmaxP)) <= (A_mul_ss(THR_STDTWI,*cmaxP)) )*/ 
		 if ( ( (*rmaxP)<<16) <= (L_mult(THR_STDTWI,*cmaxP)) ) 
        { 
            terminate_checks(D); 
            return; 
        } 
    } else   /* reverse twist */ 
    { 
        if ( ( (*cmaxP)<<16) <= (L_mult(THR_REVTWI,*rmaxP)) ) 
        { 
            terminate_checks(D); 
            return; 
        } 
    } 
 
    /* Copy goertzel energies to local array */ 
    for (k=0; k<8; k++) 
    { 
        dtmf_mem[k] = D->DtmfEnergy[k]; 
    } 
 
    /* Set highest row and col energies in local mem to -1 */ 
    /* in order to compute second highest row and col energies. */ 
    dtmf_mem[rmax_index] = -1; 
    dtmf_mem[cmax_index] = -1; 
 
    /* Compare max row energy to second highest row energy */ 
    eP = dtmf_mem; 
    accB =  (-1)<<16;    /* hold second highest row energy in accB */ 
    for (k=0; k<4; k++) 
    { 
       accA =  (*eP)<<16; 
       accB = Max(accB,accA);  
       eP++; 
    } 
 
    if ( accB >= L_mult(thr_rowrel[rmax_index],*rmaxP) ) 
    { 
        terminate_checks(D); 
        return; 
    } 
 
    /* Compare max col energy to second highest col energy */ 
    accB =  (-1)<<16;    /* hold second highest col energy in accB */ 
    for (k=0; k<4; k++) 
    { 
       accA = (*eP)<<16; 
       accB = Max(accB,accA);  
       eP++; 
    } 
 
    if ( accB >=L_mult(THR_COLREL,*cmaxP) ) 
    { 
        terminate_checks(D); 
        return; 
    } 
 
    /* 2nd Harmonic check for row */ 
    coefP = &COEF2nd[rmax_index]; 
    dP = data;                /* dP points to input data */ 
    dtmf_mem[0] = 0;          /* init goertzel filter memory to 0 */ 
    dtmf_mem[1] = 0; 
    vkP = &dtmf_mem[1];       /* vkP points filter memory for row's 2nd harmonic */ 
    eP = &D->DtmfEnergy[8];   /* pointer to row's 2nd harmonic in energy template */ 
 
    /* Goertzel filtering and energy computation */ 
    accB = goertzel2(dP,vkP,coefP,eP,0); 
 
    /* Check threshold conditions for row's 2nd harmonic */ 
    if (accB >= L_mult(THR_ROW2nd,*rmaxP))  
    { 
        terminate_checks(D); 
        return; 
    } 
 
    /* 2nd Harmonic check for column */ 
    coefP = &COEF2nd[cmax_index]; 
    dP = data;                /* dP points to input data */ 
    dtmf_mem[0] = 0;          /* init goertzel filter memory to 0 */ 
    dtmf_mem[1] = 0; 
    vkP = &dtmf_mem[1];       /* vkP points filter memory for col's 2nd harmonic */ 
    eP = &D->DtmfEnergy[9];   /* pointer to column's 2nd harmonic in energy template */ 
 
    /* Goertzel filtering and energy computation */ 
    accB = goertzel2(dP,vkP,coefP,eP,0); 
 
    /* Check threshold conditions for column's 2nd harmonic */ 
    if (accB >= L_mult(THR_COL2nd,*cmaxP))  
    { 
        terminate_checks(D); 
        return; 
    } 
 
    /* If code reaches this point, all validity tests have passed (except 3.5% test).*/ 
    k = (((rmax_index)&0x3)<<2) | ((cmax_index-4)&0x3); 
    D->DtmfDigit = dtmf_lookup_table[k]; 
 
    /* Cannot change DtmfDuration from 0 to 1 unless a pause had been */ 
    /* detected 3 previous  and the last digit was considered not valid */ 
    if ( (D->DtmfDigitLast == (short) 0x8000) && (D->DtmfPauseLatch >= 3) ) 
 
    { 
        D->DtmfDuration = 1; 
        D->DtmfDigitLast = D->DtmfDigit; 
        D->DtmfDigit = 0xffff; 
        return; 
    } 
 
    /* Current digit must = last digit to increment duration counter */ 
    if ( (D->DtmfDuration > 0) && (D->DtmfDigit == D->DtmfDigitLast) ) 
    { 
        D->DtmfDuration += 1; 
    } 
    else 
    { 
        /* if (D->DtmfDuration == 0) || (D->DtmfDigit != D->DtmfDigitLast) */ 
        D->DtmfDuration = 0; 
        D->DtmfPauseLatch = 0;  /* must now wait for a pause */ 
    } 
 
    /* Check for 3.5% error in lowest and highest row  freq using 160 pt Goertzel */ 
    if ( (D->DtmfDuration == THR_DURATION) && ((rmax_index==0)||(rmax_index==3)) ) 
    { 
        coefP = &COEF1st[rmax_index]; 
        dP = data;                    /* dP points to input data */ 
        if (rmax_index==0) 
            vkP = &D->DtmfSaveMemLast1[1]; /* vkP points to saved filter memory for 1st freq row's max */ 
        if (rmax_index==3) 
            vkP = &D->DtmfSaveMemLast4[1]; /* vkP points to saved filter memory for 4th freq row's max */ 
 
        eP = &D->DtmfEnergy[10];  /* pointer to rowmax 160 pt energy template */ 
 
        /* Goertzel filtering and energy computation */ 
        accB = goertzel2(dP,vkP,coefP,eP,1); 
 
        /* Check threshold conditions for row's160 pt Goertzel */ 
        accA = L_mult(THR_ROW160,*rmaxP); 
        if   ((accB-accA) <= 0)  /* accB still holds *eP */ 
        { 
            terminate_checks(D); 
            return; 
        } 
    } 
 
    D->DtmfDigitLast = D->DtmfDigit; 
    if (D->DtmfDuration >= THR_DURATION) 
    { 
        D->DtmfPauseLatch = 0; 
        D->DtmfDetectStat = 1;  /* valid DTMF signal present */ 
    } else { 
        D->DtmfDigit=0xffff; 
    } 
 
    /* Exit */ 
    return; 
} 
 
void  terminate_checks ( 
    DTMF_DETECTOR* D  /* (i) - pointer to current channel detector structure */ 
) 
{ 
    D->DtmfDigitLast = (short) 0x8000;  
    D->DtmfDuration = 0; 
    D->DtmfDigit = 0xffff; 
}