Example #1
0
SPAN_DECLARE(int) ademco_contactid_sender_fillin(ademco_contactid_sender_state_t *s, int samples)
{
    /* Restart any Goertzel and energy gathering operation we might be in the middle of. */
    goertzel_reset(&s->tone_1400);
    goertzel_reset(&s->tone_2300);
#if defined(SPANDSP_USE_FIXED_POINT)
    s->energy = 0;
#else
    s->energy = 0.0f;
#endif
    s->current_sample = 0;
    /* Don't update the hit detection. Pretend it never happened. */
    /* TODO: Surely we can be cleverer than this. */
    return 0;
}
Example #2
0
SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples)
{
    int i;

    /* Restart any Goertzel and energy gathering operation we might be in the middle of. */
    for (i = 0;  i < 4;  i++)
    {
        goertzel_reset(&s->row_out[i]);
        goertzel_reset(&s->col_out[i]);
    }
#if defined(SPANDSP_USE_FIXED_POINT)
    s->energy = 0;
#else
    s->energy = 0.0f;
#endif
    s->current_sample = 0;
    /* Don't update the hit detection. Pretend it never happened. */
    /* TODO: Surely we can be cleverer than this. */
    return 0;
}
Example #3
0
int r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples)
{
    float energy[6];
    float famp;
    float v1;
    int i;
    int j;
    int sample;
    int best;
    int second_best;
    int hit;
    int hit_char;
    int limit;

    hit = 0;
    hit_char = 0;
    for (sample = 0;  sample < samples;  sample = limit)
    {
        if ((samples - sample) >= (s->samples - s->current_sample))
            limit = sample + (s->samples - s->current_sample);
        else
            limit = samples;
        for (j = sample;  j < limit;  j++)
        {
            famp = amp[j];
    
            /* With GCC 2.95, the following unrolled code seems to take about 35%
               (rough estimate) as long as a neat little 0-5 loop */
            v1 = s->out[0].v2;
            s->out[0].v2 = s->out[0].v3;
            s->out[0].v3 = s->out[0].fac*s->out[0].v2 - v1 + famp;
    
            v1 = s->out[1].v2;
            s->out[1].v2 = s->out[1].v3;
            s->out[1].v3 = s->out[1].fac*s->out[1].v2 - v1 + famp;
    
            v1 = s->out[2].v2;
            s->out[2].v2 = s->out[2].v3;
            s->out[2].v3 = s->out[2].fac*s->out[2].v2 - v1 + famp;
    
            v1 = s->out[3].v2;
            s->out[3].v2 = s->out[3].v3;
            s->out[3].v3 = s->out[3].fac*s->out[3].v2 - v1 + famp;
    
            v1 = s->out[4].v2;
            s->out[4].v2 = s->out[4].v3;
            s->out[4].v3 = s->out[4].fac*s->out[4].v2 - v1 + famp;
    
            v1 = s->out[5].v2;
            s->out[5].v2 = s->out[5].v3;
            s->out[5].v3 = s->out[5].fac*s->out[5].v2 - v1 + famp;
        }
        s->current_sample += (limit - sample);
        if (s->current_sample < s->samples)
            continue;

        /* We are at the end of an MF detection block */
        /* Find the two highest energies */
        energy[0] = goertzel_result(&s->out[0]);
        energy[1] = goertzel_result(&s->out[1]);
        if (energy[0] > energy[1])
        {
            best = 0;
            second_best = 1;
        }
        else
        {
            best = 1;
            second_best = 0;
        }
        
        for (i = 2;  i < 6;  i++)
        {
            energy[i] = goertzel_result(&s->out[i]);
            if (energy[i] >= energy[best])
            {
                second_best = best;
                best = i;
            }
            else if (energy[i] >= energy[second_best])
            {
                second_best = i;
            }
        }
        /* Basic signal level and twist tests */
        hit = FALSE;
        if (energy[best] >= R2_MF_THRESHOLD
            &&
            energy[second_best] >= R2_MF_THRESHOLD
            &&
            energy[best] < energy[second_best]*R2_MF_TWIST
            &&
            energy[best]*R2_MF_TWIST > energy[second_best])
        {
            /* Relative peak test */
            hit = TRUE;
            for (i = 0;  i < 6;  i++)
            {
                if (i != best  &&  i != second_best)
                {
                    if (energy[i]*R2_MF_RELATIVE_PEAK >= energy[second_best])
                    {
                        /* The best two are not clearly the best */
                        hit = FALSE;
                        break;
                    }
                }
            }
        }
        if (hit)
        {
            /* Get the values into ascending order */
            if (second_best < best)
            {
                i = best;
                best = second_best;
                second_best = i;
            }
            best = best*5 + second_best - 1;
            hit_char = r2_mf_positions[best];
        }
        else
        {
            hit_char = 0;
        }

        /* Reinitialise the detector for the next block */
        if (s->fwd)
        {
            for (i = 0;  i < 6;  i++)
                goertzel_reset(&s->out[i]);
        }
        else
        {
            for (i = 0;  i < 6;  i++)
                goertzel_reset(&s->out[i]);
        }
        s->current_sample = 0;
    }
    return hit_char;
}
Example #4
0
int bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples)
{
    float energy[6];
    float famp;
    float v1;
    int i;
    int j;
    int sample;
    int best;
    int second_best;
    int limit;
    uint8_t hit;

    hit = 0;
    for (sample = 0;  sample < samples;  sample = limit)
    {
        if ((samples - sample) >= (120 - s->current_sample))
            limit = sample + (120 - s->current_sample);
        else
            limit = samples;
        for (j = sample;  j < limit;  j++)
        {
            famp = amp[j];
    
            /* With GCC 2.95, the following unrolled code seems to take about 35%
               (rough estimate) as long as a neat little 0-5 loop */
            v1 = s->out[0].v2;
            s->out[0].v2 = s->out[0].v3;
            s->out[0].v3 = s->out[0].fac*s->out[0].v2 - v1 + famp;
    
            v1 = s->out[1].v2;
            s->out[1].v2 = s->out[1].v3;
            s->out[1].v3 = s->out[1].fac*s->out[1].v2 - v1 + famp;
    
            v1 = s->out[2].v2;
            s->out[2].v2 = s->out[2].v3;
            s->out[2].v3 = s->out[2].fac*s->out[2].v2 - v1 + famp;
    
            v1 = s->out[3].v2;
            s->out[3].v2 = s->out[3].v3;
            s->out[3].v3 = s->out[3].fac*s->out[3].v2 - v1 + famp;
    
            v1 = s->out[4].v2;
            s->out[4].v2 = s->out[4].v3;
            s->out[4].v3 = s->out[4].fac*s->out[4].v2 - v1 + famp;
    
            v1 = s->out[5].v2;
            s->out[5].v2 = s->out[5].v3;
            s->out[5].v3 = s->out[5].fac*s->out[5].v2 - v1 + famp;
        }
        s->current_sample += (limit - sample);
        if (s->current_sample < 120)
            continue;

        /* We are at the end of an MF detection block */
        /* Find the two highest energies. The spec says to look for
           two tones and two tones only. Taking this literally -ie
           only two tones pass the minimum threshold - doesn't work
           well. The sinc function mess, due to rectangular windowing
           ensure that! Find the two highest energies and ensure they
           are considerably stronger than any of the others. */
        energy[0] = goertzel_result(&s->out[0]);
        energy[1] = goertzel_result(&s->out[1]);
        if (energy[0] > energy[1])
        {
            best = 0;
            second_best = 1;
        }
        else
        {
            best = 1;
            second_best = 0;
        }
        for (i = 2;  i < 6;  i++)
        {
            energy[i] = goertzel_result(&s->out[i]);
            if (energy[i] >= energy[best])
            {
                second_best = best;
                best = i;
            }
            else if (energy[i] >= energy[second_best])
            {
                second_best = i;
            }
        }
        /* Basic signal level and twist tests */
        hit = 0;
        if (energy[best] >= BELL_MF_THRESHOLD
            &&
            energy[second_best] >= BELL_MF_THRESHOLD
            &&
            energy[best] < energy[second_best]*BELL_MF_TWIST
            &&
            energy[best]*BELL_MF_TWIST > energy[second_best])
        {
            /* Relative peak test */
            hit = 'X';
            for (i = 0;  i < 6;  i++)
            {
                if (i != best  &&  i != second_best)
                {
                    if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best])
                    {
                        /* The best two are not clearly the best */
                        hit = 0;
                        break;
                    }
                }
            }
        }
        if (hit)
        {
            /* Get the values into ascending order */
            if (second_best < best)
            {
                i = best;
                best = second_best;
                second_best = i;
            }
            best = best*5 + second_best - 1;
            hit = bell_mf_positions[best];
            /* Look for two successive similar results */
            /* The logic in the next test is:
               For KP we need 4 successive identical clean detects, with
               two blocks of something different preceeding it. For anything
               else we need two successive identical clean detects, with
               two blocks of something different preceeding it. */
            if (hit == s->hits[4]
                &&
                hit == s->hits[3]
                &&
                   ((hit != '*'  &&  hit != s->hits[2]  &&  hit != s->hits[1])
                    ||
                    (hit == '*'  &&  hit == s->hits[2]  &&  hit != s->hits[1]  &&  hit != s->hits[0])))
            {
                if (s->current_digits < MAX_BELL_MF_DIGITS)
                {
                    s->digits[s->current_digits++] = (char) hit;
                    s->digits[s->current_digits] = '\0';
                    if (s->callback)
                    {
                        s->callback(s->callback_data, s->digits, s->current_digits);
                        s->current_digits = 0;
                    }
                }
                else
                {
                    s->lost_digits++;
                }
            }
        }
        s->hits[0] = s->hits[1];
        s->hits[1] = s->hits[2];
        s->hits[2] = s->hits[3];
        s->hits[3] = s->hits[4];
        s->hits[4] = hit;
        /* Reinitialise the detector for the next block */
        for (i = 0;  i < 6;  i++)
            goertzel_reset(&s->out[i]);
        s->current_sample = 0;
    }
    if (s->current_digits  &&  s->callback)
    {
        s->callback(s->callback_data, s->digits, s->current_digits);
        s->digits[0] = '\0';
        s->current_digits = 0;
    }
    return 0;
}
Example #5
0
File: dsp.c Project: OPSF/uClinux
static int dtmf_detect (dtmf_detect_state_t *s, int16_t amp[], int samples, 
		 int digitmode, int *writeback, int faxdetect)
{
	float row_energy[4];
	float col_energy[4];
#ifdef FAX_DETECT
	float fax_energy;
#ifdef OLD_DSP_ROUTINES
	float fax_energy_2nd;
#endif	
#endif /* FAX_DETECT */
	float famp;
	float v1;
	int i;
	int j;
	int sample;
	int best_row;
	int best_col;
	int hit;
	int limit;

	hit = 0;
	for (sample = 0;  sample < samples;  sample = limit) {
		/* 102 is optimised to meet the DTMF specs. */
		if ((samples - sample) >= (102 - s->current_sample))
			limit = sample + (102 - s->current_sample);
		else
			limit = samples;
#if defined(USE_3DNOW)
		_dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
		_dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
#ifdef OLD_DSP_ROUTINES
		_dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
		_dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
#endif		
		/* XXX Need to fax detect for 3dnow too XXX */
		#warning "Fax Support Broken"
#else
		/* The following unrolled loop takes only 35% (rough estimate) of the 
		   time of a rolled loop on the machine on which it was developed */
		for (j=sample;j<limit;j++) {
			famp = amp[j];
			s->energy += famp*famp;
			/* With GCC 2.95, the following unrolled code seems to take about 35%
			   (rough estimate) as long as a neat little 0-3 loop */
			v1 = s->row_out[0].v2;
			s->row_out[0].v2 = s->row_out[0].v3;
			s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp;
			v1 = s->col_out[0].v2;
			s->col_out[0].v2 = s->col_out[0].v3;
			s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp;
			v1 = s->row_out[1].v2;
			s->row_out[1].v2 = s->row_out[1].v3;
			s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp;
			v1 = s->col_out[1].v2;
			s->col_out[1].v2 = s->col_out[1].v3;
			s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp;
			v1 = s->row_out[2].v2;
			s->row_out[2].v2 = s->row_out[2].v3;
			s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp;
			v1 = s->col_out[2].v2;
			s->col_out[2].v2 = s->col_out[2].v3;
			s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp;
			v1 = s->row_out[3].v2;
			s->row_out[3].v2 = s->row_out[3].v3;
			s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp;
			v1 = s->col_out[3].v2;
			s->col_out[3].v2 = s->col_out[3].v3;
			s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp;
#ifdef FAX_DETECT
			/* Update fax tone */
			v1 = s->fax_tone.v2;
			s->fax_tone.v2 = s->fax_tone.v3;
			s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp;
#endif /* FAX_DETECT */
#ifdef OLD_DSP_ROUTINES
			v1 = s->col_out2nd[0].v2;
			s->col_out2nd[0].v2 = s->col_out2nd[0].v3;
			s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp;
			v1 = s->row_out2nd[0].v2;
			s->row_out2nd[0].v2 = s->row_out2nd[0].v3;
			s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp;
			v1 = s->col_out2nd[1].v2;
			s->col_out2nd[1].v2 = s->col_out2nd[1].v3;
			s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp;
			v1 = s->row_out2nd[1].v2;
			s->row_out2nd[1].v2 = s->row_out2nd[1].v3;
			s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp;
			v1 = s->col_out2nd[2].v2;
			s->col_out2nd[2].v2 = s->col_out2nd[2].v3;
			s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp;
			v1 = s->row_out2nd[2].v2;
			s->row_out2nd[2].v2 = s->row_out2nd[2].v3;
			s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp;
			v1 = s->col_out2nd[3].v2;
			s->col_out2nd[3].v2 = s->col_out2nd[3].v3;
			s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp;
			v1 = s->row_out2nd[3].v2;
			s->row_out2nd[3].v2 = s->row_out2nd[3].v3;
			s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp;
#ifdef FAX_DETECT
			/* Update fax tone */            
			v1 = s->fax_tone.v2;
			s->fax_tone2nd.v2 = s->fax_tone2nd.v3;
			s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp;
#endif /* FAX_DETECT */
#endif
		}
#endif
		s->current_sample += (limit - sample);
		if (s->current_sample < 102) {
			if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
				/* If we had a hit last time, go ahead and clear this out since likely it
				   will be another hit */
				for (i=sample;i<limit;i++) 
					amp[i] = 0;
				*writeback = 1;
			}
			continue;
		}
#ifdef FAX_DETECT
		/* Detect the fax energy, too */
		fax_energy = goertzel_result(&s->fax_tone);
#endif
		/* We are at the end of a DTMF detection block */
		/* Find the peak row and the peak column */
		row_energy[0] = goertzel_result (&s->row_out[0]);
		col_energy[0] = goertzel_result (&s->col_out[0]);

		for (best_row = best_col = 0, i = 1;  i < 4;  i++) {
			row_energy[i] = goertzel_result (&s->row_out[i]);
			if (row_energy[i] > row_energy[best_row])
				best_row = i;
			col_energy[i] = goertzel_result (&s->col_out[i]);
			if (col_energy[i] > col_energy[best_col])
				best_col = i;
		}
		hit = 0;
		/* Basic signal level test and the twist test */
		if (row_energy[best_row] >= DTMF_THRESHOLD && 
		    col_energy[best_col] >= DTMF_THRESHOLD &&
		    col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST &&
		    col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) {
			/* Relative peak test */
			for (i = 0;  i < 4;  i++) {
				if ((i != best_col &&
				    col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) ||
				    (i != best_row 
				     && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
					break;
				}
			}
#ifdef OLD_DSP_ROUTINES
			/* ... and second harmonic test */
			if (i >= 4 && 
			    (row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy &&
                	    goertzel_result(&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col]
			    && goertzel_result(&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) {
#else
			/* ... and fraction of total energy test */
			if (i >= 4 &&
			    (row_energy[best_row] + col_energy[best_col]) > DTMF_TO_TOTAL_ENERGY*s->energy) {
#endif
				/* Got a hit */
				hit = dtmf_positions[(best_row << 2) + best_col];
				if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) {
					/* Zero out frame data if this is part DTMF */
					for (i=sample;i<limit;i++) 
						amp[i] = 0;
					*writeback = 1;
				}
				/* Look for two successive similar results */
				/* The logic in the next test is:
				   We need two successive identical clean detects, with
				   something different preceeding it. This can work with
				   back to back differing digits. More importantly, it
				   can work with nasty phones that give a very wobbly start
				   to a digit */
#ifdef OLD_DSP_ROUTINES
				if (hit == s->hit3  &&  s->hit3 != s->hit2) {
					s->mhit = hit;
					s->digit_hits[(best_row << 2) + best_col]++;
					s->detected_digits++;
					if (s->current_digits < MAX_DTMF_DIGITS) {
						s->digits[s->current_digits++] = hit;
						s->digits[s->current_digits] = '\0';
					} else {
						s->lost_digits++;
					}
				}
#else				
				if (hit == s->hits[2]  &&  hit != s->hits[1]  &&  hit != s->hits[0]) {
					s->mhit = hit;
					s->digit_hits[(best_row << 2) + best_col]++;
					s->detected_digits++;
					if (s->current_digits < MAX_DTMF_DIGITS) {
						s->digits[s->current_digits++] = hit;
						s->digits[s->current_digits] = '\0';
					} else {
						s->lost_digits++;
					}
				}
#endif
			}
		} 
#ifdef FAX_DETECT
		if (!hit && (fax_energy >= FAX_THRESHOLD) && 
			(fax_energy >= DTMF_TO_TOTAL_ENERGY*s->energy) &&
			(faxdetect)) {
#if 0
			printf("Fax energy/Second Harmonic: %f\n", fax_energy);
#endif					
			/* XXX Probably need better checking than just this the energy XXX */
			hit = 'f';
			s->fax_hits++;
		} else {
			if (s->fax_hits > 5) {
				hit = 'f';
				s->mhit = 'f';
				s->detected_digits++;
				if (s->current_digits < MAX_DTMF_DIGITS) {
					s->digits[s->current_digits++] = hit;
					s->digits[s->current_digits] = '\0';
				} else {
					s->lost_digits++;
				}
			}
			s->fax_hits = 0;
		}
#endif /* FAX_DETECT */
#ifdef OLD_DSP_ROUTINES
		s->hit1 = s->hit2;
		s->hit2 = s->hit3;
		s->hit3 = hit;
#else
		s->hits[0] = s->hits[1];
		s->hits[1] = s->hits[2];
		s->hits[2] = hit;
#endif		
		/* Reinitialise the detector for the next block */
		for (i = 0;  i < 4;  i++) {
			goertzel_reset(&s->row_out[i]);
			goertzel_reset(&s->col_out[i]);
#ifdef OLD_DSP_ROUTINES
			goertzel_reset(&s->row_out2nd[i]);
			goertzel_reset(&s->col_out2nd[i]);
#endif			
		}
#ifdef FAX_DETECT
		goertzel_reset (&s->fax_tone);
#ifdef OLD_DSP_ROUTINES
		goertzel_reset (&s->fax_tone2nd);
#endif			
#endif
		s->energy = 0.0;
		s->current_sample = 0;
	}
	if ((!s->mhit) || (s->mhit != hit)) {
		s->mhit = 0;
		return(0);
	}
	return (hit);
}

/* MF goertzel size */
#ifdef OLD_DSP_ROUTINES
#define	MF_GSIZE 160
#else
#define MF_GSIZE 120
#endif

static int mf_detect (mf_detect_state_t *s, int16_t amp[],
                 int samples, int digitmode, int *writeback)
{
#ifdef OLD_DSP_ROUTINES
	float tone_energy[6];
	int best1;
	int best2;
	float max;
	int sofarsogood;
#else
	float energy[6];
	int best;
	int second_best;
#endif
	float famp;
	float v1;
	int i;
	int j;
	int sample;
	int hit;
	int limit;

	hit = 0;
	for (sample = 0;  sample < samples;  sample = limit) {
		/* 80 is optimised to meet the MF specs. */
		if ((samples - sample) >= (MF_GSIZE - s->current_sample))
			limit = sample + (MF_GSIZE - s->current_sample);
		else
			limit = samples;
#if defined(USE_3DNOW)
		_dtmf_goertzel_update (s->row_out, amp + sample, limit - sample);
		_dtmf_goertzel_update (s->col_out, amp + sample, limit - sample);
#ifdef OLD_DSP_ROUTINES
		_dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample);
		_dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample);
#endif
		/* XXX Need to fax detect for 3dnow too XXX */
		#warning "Fax Support Broken"
#else
		/* The following unrolled loop takes only 35% (rough estimate) of the 
		   time of a rolled loop on the machine on which it was developed */
		for (j = sample;  j < limit;  j++) {
			famp = amp[j];
#ifdef OLD_DSP_ROUTINES
			s->energy += famp*famp;
#endif
			/* With GCC 2.95, the following unrolled code seems to take about 35%
			   (rough estimate) as long as a neat little 0-3 loop */
			v1 = s->tone_out[0].v2;
			s->tone_out[0].v2 = s->tone_out[0].v3;
			s->tone_out[0].v3 = s->tone_out[0].fac*s->tone_out[0].v2 - v1 + famp;
			v1 = s->tone_out[1].v2;
			s->tone_out[1].v2 = s->tone_out[1].v3;
			s->tone_out[1].v3 = s->tone_out[1].fac*s->tone_out[1].v2 - v1 + famp;
			v1 = s->tone_out[2].v2;
			s->tone_out[2].v2 = s->tone_out[2].v3;
			s->tone_out[2].v3 = s->tone_out[2].fac*s->tone_out[2].v2 - v1 + famp;
			v1 = s->tone_out[3].v2;
			s->tone_out[3].v2 = s->tone_out[3].v3;
			s->tone_out[3].v3 = s->tone_out[3].fac*s->tone_out[3].v2 - v1 + famp;
			v1 = s->tone_out[4].v2;
			s->tone_out[4].v2 = s->tone_out[4].v3;
			s->tone_out[4].v3 = s->tone_out[4].fac*s->tone_out[4].v2 - v1 + famp;
			v1 = s->tone_out[5].v2;
			s->tone_out[5].v2 = s->tone_out[5].v3;
			s->tone_out[5].v3 = s->tone_out[5].fac*s->tone_out[5].v2 - v1 + famp;
#ifdef OLD_DSP_ROUTINES
			v1 = s->tone_out2nd[0].v2;
			s->tone_out2nd[0].v2 = s->tone_out2nd[0].v3;
			s->tone_out2nd[0].v3 = s->tone_out2nd[0].fac*s->tone_out2nd[0].v2 - v1 + famp;
			v1 = s->tone_out2nd[1].v2;
			s->tone_out2nd[1].v2 = s->tone_out2nd[1].v3;
			s->tone_out2nd[1].v3 = s->tone_out2nd[1].fac*s->tone_out2nd[1].v2 - v1 + famp;
			v1 = s->tone_out2nd[2].v2;
			s->tone_out2nd[2].v2 = s->tone_out2nd[2].v3;
			s->tone_out2nd[2].v3 = s->tone_out2nd[2].fac*s->tone_out2nd[2].v2 - v1 + famp;
			v1 = s->tone_out2nd[3].v2;
			s->tone_out2nd[3].v2 = s->tone_out2nd[3].v3;
			s->tone_out2nd[3].v3 = s->tone_out2nd[3].fac*s->tone_out2nd[3].v2 - v1 + famp;
			v1 = s->tone_out2nd[4].v2;
			s->tone_out2nd[4].v2 = s->tone_out2nd[4].v3;
			s->tone_out2nd[4].v3 = s->tone_out2nd[4].fac*s->tone_out2nd[2].v2 - v1 + famp;
			v1 = s->tone_out2nd[3].v2;
			s->tone_out2nd[5].v2 = s->tone_out2nd[6].v3;
			s->tone_out2nd[5].v3 = s->tone_out2nd[6].fac*s->tone_out2nd[3].v2 - v1 + famp;
#endif
		}
#endif
		s->current_sample += (limit - sample);
		if (s->current_sample < MF_GSIZE) {
			if (hit && !((digitmode & DSP_DIGITMODE_NOQUELCH))) {
				/* If we had a hit last time, go ahead and clear this out since likely it
				   will be another hit */
				for (i=sample;i<limit;i++) 
					amp[i] = 0;
				*writeback = 1;
			}
			continue;
		}
#ifdef OLD_DSP_ROUTINES		
		/* We're at the end of an MF detection block.  Go ahead and calculate
		   all the energies. */
		for (i=0;i<6;i++) {
			tone_energy[i] = goertzel_result(&s->tone_out[i]);
		}
		/* Find highest */
		best1 = 0;
		max = tone_energy[0];
		for (i=1;i<6;i++) {
			if (tone_energy[i] > max) {
				max = tone_energy[i];
				best1 = i;
			}
		}

		/* Find 2nd highest */
		if (best1) {
			max = tone_energy[0];
			best2 = 0;
		} else {
			max = tone_energy[1];
			best2 = 1;
		}

		for (i=0;i<6;i++) {
			if (i == best1) continue;
			if (tone_energy[i] > max) {
				max = tone_energy[i];
				best2 = i;
			}
		}
		hit = 0;
		if (best1 != best2) 
			sofarsogood=1;
		else 
			sofarsogood=0;
		/* Check for relative energies */
		for (i=0;i<6;i++) {
			if (i == best1) 
				continue;
			if (i == best2) 
				continue;
			if (tone_energy[best1] < tone_energy[i] * MF_RELATIVE_PEAK) {
				sofarsogood = 0;
				break;
			}
			if (tone_energy[best2] < tone_energy[i] * MF_RELATIVE_PEAK) {
				sofarsogood = 0;
				break;
			}
		}
		
		if (sofarsogood) {
			/* Check for 2nd harmonic */
			if (goertzel_result(&s->tone_out2nd[best1]) * MF_2ND_HARMONIC > tone_energy[best1]) 
				sofarsogood = 0;
			else if (goertzel_result(&s->tone_out2nd[best2]) * MF_2ND_HARMONIC > tone_energy[best2])
				sofarsogood = 0;
		}
		if (sofarsogood) {
			hit = mf_hit[best1][best2];
			if (!(digitmode & DSP_DIGITMODE_NOQUELCH)) {
				/* Zero out frame data if this is part DTMF */
				for (i=sample;i<limit;i++) 
					amp[i] = 0;
				*writeback = 1;
			}
			/* Look for two consecutive clean hits */
			if ((hit == s->hit3) && (s->hit3 != s->hit2)) {
				s->mhit = hit;
				s->detected_digits++;
				if (s->current_digits < MAX_DTMF_DIGITS - 2) {
					s->digits[s->current_digits++] = hit;
					s->digits[s->current_digits] = '\0';
				} else {
					s->lost_digits++;
				}
			}
		}
		
		s->hit1 = s->hit2;
		s->hit2 = s->hit3;
		s->hit3 = hit;
		/* Reinitialise the detector for the next block */
		for (i = 0;  i < 6;  i++) {
			goertzel_reset(&s->tone_out[i]);
			goertzel_reset(&s->tone_out2nd[i]);
		}
		s->energy = 0.0;
		s->current_sample = 0;
	}
#else
		/* We're at the end of an MF detection block.  */
		/* Find the two highest energies. The spec says to look for
		   two tones and two tones only. Taking this literally -ie
		   only two tones pass the minimum threshold - doesn't work
		   well. The sinc function mess, due to rectangular windowing
		   ensure that! Find the two highest energies and ensure they
		   are considerably stronger than any of the others. */
		energy[0] = goertzel_result(&s->tone_out[0]);
		energy[1] = goertzel_result(&s->tone_out[1]);
		if (energy[0] > energy[1]) {
			best = 0;
			second_best = 1;
		} else {
			best = 1;
			second_best = 0;
		}
		/*endif*/
		for (i=2;i<6;i++) {
			energy[i] = goertzel_result(&s->tone_out[i]);
			if (energy[i] >= energy[best]) {
				second_best = best;
				best = i;
			} else if (energy[i] >= energy[second_best]) {
				second_best = i;
			}
		}
		/* Basic signal level and twist tests */
		hit = 0;
		if (energy[best] >= BELL_MF_THRESHOLD && energy[second_best] >= BELL_MF_THRESHOLD
	            && energy[best] < energy[second_best]*BELL_MF_TWIST
	            && energy[best]*BELL_MF_TWIST > energy[second_best]) {
			/* Relative peak test */
			hit = -1;
			for (i=0;i<6;i++) {
				if (i != best && i != second_best) {
					if (energy[i]*BELL_MF_RELATIVE_PEAK >= energy[second_best]) {
						/* The best two are not clearly the best */
						hit = 0;
						break;
					}
				}
			}
		}
		if (hit) {
			/* Get the values into ascending order */
			if (second_best < best) {
				i = best;
				best = second_best;
				second_best = i;
			}
			best = best*5 + second_best - 1;
			hit = bell_mf_positions[best];
			/* Look for two successive similar results */
			/* The logic in the next test is:
			   For KP we need 4 successive identical clean detects, with
			   two blocks of something different preceeding it. For anything
			   else we need two successive identical clean detects, with
			   two blocks of something different preceeding it. */
			if (hit == s->hits[4] && hit == s->hits[3] &&
			   ((hit != '*' && hit != s->hits[2] && hit != s->hits[1])||
			    (hit == '*' && hit == s->hits[2] && hit != s->hits[1] && 
			    hit != s->hits[0]))) {
				s->detected_digits++;
				if (s->current_digits < MAX_DTMF_DIGITS) {
					s->digits[s->current_digits++] = hit;
					s->digits[s->current_digits] = '\0';
				} else {
					s->lost_digits++;
				}
			}
		} else {
			hit = 0;
		}
		s->hits[0] = s->hits[1];
		s->hits[1] = s->hits[2];
		s->hits[2] = s->hits[3];
		s->hits[3] = s->hits[4];
		s->hits[4] = hit;
		/* Reinitialise the detector for the next block */
		for (i = 0;  i < 6;  i++)
			goertzel_reset(&s->tone_out[i]);
		s->current_sample = 0;
	}
Example #6
0
int CGoertzelDTMFFax::fax_detect
(
	double					amp[], 
	int						samples
)
{
	double fax_energy;
	double fax_energy_2nd;
    double famp;
    float v1;
    int i;
    int j;
    int sample;
    int hit;
    int limit;
 
    hit = 0;
    for (sample = 0;  sample < samples;  sample = limit) 
	{
       /* 102 is optimised to meet the DTMF specs. */
       if ((samples - sample) >= (102 - state->current_sample))
          limit = sample + (102 - state->current_sample);
       else
          limit = samples;

       for (j=sample;j<limit;j++) 
	   {
          famp = amp[j];
          state->energy += famp*famp;

		  //goertzel_sample(&(state->fax_tone), famp);
          v1 = state->fax_tone.v2;
          state->fax_tone.v2 = state->fax_tone.v3;
          state->fax_tone.v3 = state->fax_tone.fac*state->fax_tone.v2 - v1 + famp;

		  //goertzel_sample(&(state->fax_tone2nd), famp);
          v1 = state->fax_tone.v2;
          state->fax_tone2nd.v2 = state->fax_tone2nd.v3;
          state->fax_tone2nd.v3 = state->fax_tone2nd.fac*state->fax_tone2nd.v2 - v1 + famp;

       }

	   state->current_sample += (limit - sample);
         
       /* Detect the fax energy */
       fax_energy = goertzel_result(&state->fax_tone);
	   
	   hit = 0;

       if ((fax_energy >= FAX_THRESHOLD) && 
          (fax_energy >= DTMF_TO_TOTAL_ENERGY*state->energy)) 
	   {               
		    
		    //Bug here...
		    //Test the 2nd harmonic too
		    
			/*fax_energy_2nd = goertzel_result(&state->fax_tone2nd);
			if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy)
			{
			
			  Probably need better checking than just this the energy
			}*/
			
			hit = 'f';
			state->fax_hits++;

			//Enough of it...
			if (state->fax_hits > 5) 
			{
				break;
			}
       }

       goertzel_reset (&state->fax_tone);
       goertzel_reset (&state->fax_tone2nd);

       state->energy = 0.0;
       state->current_sample = 0;
    }

    return (hit);
}