Fixed a typo in spandsp's msvc/inttypes.h

Updated sig_tone processing in spandsp to the latest, to allow moy to
proceed with his signaling work.
This commit is contained in:
Steve Underwood 2010-05-11 22:38:36 +08:00
parent 1d0ce5570d
commit 3e30434a0c
4 changed files with 698 additions and 567 deletions

View File

@ -1,8 +1,8 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* sig_tone.c - Signalling tone processing for the 2280Hz, 2600Hz and similar
* signalling tone used in older protocols.
* sig_tone.c - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz
* and similar signalling tones used in older protocols.
*
* Written by Steve Underwood <steveu@coppice.org>
*
@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: sig_tone.c,v 1.33 2009/09/04 14:38:46 steveu Exp $
* $Id: sig_tone.c,v 1.39 2010/03/11 14:22:30 steveu Exp $
*/
/*! \file */
@ -53,6 +53,7 @@
#include "spandsp/saturated.h"
#include "spandsp/vector_int.h"
#include "spandsp/complex.h"
#include "spandsp/power_meter.h"
#include "spandsp/dds.h"
#include "spandsp/super_tone_rx.h"
#include "spandsp/sig_tone.h"
@ -62,56 +63,64 @@
/*! PI */
#define PI 3.14159265358979323
/* The coefficients for the data notch filter. This filter is also the
guard filter for tone detection. */
enum
{
NOTCH_COEFF_SET_2280HZ = 0,
NOTCH_COEFF_SET_2400HZ,
NOTCH_COEFF_SET_2600HZ
};
sig_tone_descriptor_t sig_tones[4] =
/* The coefficients for the data notch filters. These filters are also the
guard filters for tone detection. */
static const sig_tone_notch_coeffs_t notch_coeffs[3] =
{
{ /* 2280 Hz */
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3600, 14397, 32767},
{ 0, -9425, -28954},
{ 0, 14196, 32767},
{ 0, -17393, -28954},
12,
#else
{0.878906f, 0.439362f, 1.0f},
{0.0f, -0.287627f, -0.883605f},
{0.0f, 0.433228f, 1.0f},
{0.0f, -0.530792f, -0.883605f},
#endif
},
{ /* 2400Hz */
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3530, 20055, 32767},
{ 0, -14950, -28341},
{ 0, 20349, 32767},
{ 0, -22633, -28341},
12,
#else
{0.862000f, 0.612055f, 1.0f},
{0.0f, -0.456264f, -0.864899f},
{0.0f, 0.621021f, 1.0f},
{0.0f, -0.690738f, -0.864899f},
#endif
},
{ /* 2600Hz */
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3530, 29569, 32767},
{ 0, -24010, -28341},
{ 0, 29844, 32767},
{ 0, -31208, -28341},
12,
#else
{0.862000f, 0.902374f, 1.0f},
{0.0f, -0.732727f, -0.864899f},
{0.0f, 0.910766f, 1.0f},
{0.0f, -0.952393f, -0.864899f},
#endif
}
};
static const sig_tone_flat_coeffs_t flat_coeffs[1] =
{
{
/* 2280Hz (e.g. AC15, and many other European protocols) */
{2280, 0},
{{-10, -20}, {0, 0}}, /* -10+-1 dBmO and -20+-1 dBm0 */
ms_to_samples(400), /* 300ms to 550ms */
ms_to_samples(225),
ms_to_samples(225),
TRUE,
24,
64,
1,
{
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3600, 14397, 32767},
{ 0, -9425, -28954},
{ 0, 14196, 32767},
{ 0, -17393, -28954},
12,
#else
{0.878906f, 0.439362f, 1.0f},
{0.0f, -0.287627f, -0.883605f},
{0.0f, 0.433228f, 1.0f},
{0.0f, -0.530792f, -0.883605f},
#endif
},
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
0,
#else
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
#endif
}
},
#if defined(SPANDSP_USE_FIXED_POINT)
{ 12900, -16384, -16384},
{ 0, -8578, -11796},
@ -120,163 +129,96 @@ sig_tone_descriptor_t sig_tones[4] =
{0.393676f, -0.5f, -0.5f},
{0.0f, -0.261778f, -0.359985f},
#endif
}
};
31744,
1024,
static const sig_tone_descriptor_t sig_tones[3] =
{
{
/* 2280Hz (e.g. AC15, and many other European protocols) */
{2280, 0},
{{-10, -20}, {0, 0}}, /* -10+-1 dBm0 and -20+-1 dBm0 */
ms_to_samples(400), /* High to low timout - 300ms to 550ms */
ms_to_samples(225), /* Sharp to flat timeout */
ms_to_samples(225), /* Notch insertion timeout */
31744,
187,
31744,
187,
-1,
-32,
57
ms_to_samples(3), /* Tone on persistence check */
ms_to_samples(8), /* Tone off persistence check */
1,
{
&notch_coeffs[NOTCH_COEFF_SET_2280HZ],
NULL,
},
&flat_coeffs[NOTCH_COEFF_SET_2280HZ],
13.0f,
-30.0f,
-30.0f
},
{
/* 2600Hz (e.g. many US protocols) */
{2600, 0},
{{-8, -8}, {0, 0}},
ms_to_samples(400),
ms_to_samples(0),
ms_to_samples(0),
ms_to_samples(225),
ms_to_samples(225),
FALSE,
24,
64,
ms_to_samples(3),
ms_to_samples(8),
1,
{
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3539, 29569, 32767},
{ 0, -24010, -28341},
{ 0, 29844, 32767},
{ 0, -31208, -28341},
12,
#else
{0.864014f, 0.902374f, 1.0f},
{0.0f, -0.732727f, -0.864899f},
{0.0f, 0.910766f, 1.0f},
{0.0f, -0.952393f, -0.864899f},
#endif
},
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
0,
#else
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
#endif
}
&notch_coeffs[NOTCH_COEFF_SET_2600HZ],
NULL,
},
#if defined(SPANDSP_USE_FIXED_POINT)
{ 32768, 0, 0},
{ 0, 0, 0},
15,
#else
{1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
#endif
NULL,
31744,
1024,
31744,
170,
31744,
170,
-1,
-32,
52
15.6f,
-30.0f,
-30.0f
},
{
/* 2400Hz/2600Hz (e.g. SS5 and SS5bis) */
{2600, 2400},
{2400, 2600},
{{-8, -8}, {-8, -8}},
ms_to_samples(400),
ms_to_samples(0),
ms_to_samples(0),
ms_to_samples(225),
ms_to_samples(225),
FALSE,
24,
64,
ms_to_samples(3),
ms_to_samples(8),
2,
{
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3539, 29569, 32767},
{ 0, -24010, -28341},
{ 0, 29844, 32767},
{ 0, -31208, -28341},
12,
#else
{0.864014f, 0.902374f, 1.0f},
{0.0f, -0.732727f, -0.864899f},
{0.0f, 0.910766f, 1.0f},
{0.0f, -0.952393f, -0.864899f},
#endif
},
{
#if defined(SPANDSP_USE_FIXED_POINT)
{ 3539, 20349, 32767},
{ 0, -22075, -31856},
{ 0, 20174, 32767},
{ 0, -17832, -31836},
12,
#else
{0.864014f, 0.621007f, 1.0f},
{0.0f, -0.673667f, -0.972167f},
{0.0f, 0.615669f, 1.0f},
{0.0f, -0.544180f, -0.971546f},
#endif
}
&notch_coeffs[NOTCH_COEFF_SET_2400HZ],
&notch_coeffs[NOTCH_COEFF_SET_2600HZ]
},
#if defined(SPANDSP_USE_FIXED_POINT)
{ 32768, 0, 0},
{ 0, 0, 0},
15,
#else
{1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f},
#endif
NULL,
31744,
1024,
31744,
170,
31744,
170,
-1,
-32,
52
15.6f,
-30.0f,
-30.0f
}
};
static const int tone_present_bits[2] =
{
SIG_TONE_1_PRESENT,
SIG_TONE_2_PRESENT
};
static const int tone_change_bits[2] =
{
SIG_TONE_1_CHANGE,
SIG_TONE_2_CHANGE
};
SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len)
{
int i;
int j;
int k;
int n;
int16_t tone;
int need_update;
@ -306,7 +248,7 @@ SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len)
if (!(s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH))
vec_zeroi16(&amp[i], n);
/*endif*/
if ((s->current_tx_tone & (SIG_TONE_1_PRESENT || SIG_TONE_2_PRESENT)))
if ((s->current_tx_tone & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT)))
{
/* Are we in the early phase (high tone energy level), or the sustaining
phase (low tone energy level) of tone generation? */
@ -325,26 +267,19 @@ SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len)
high_low = 1;
}
/*endif*/
if ((s->current_tx_tone & SIG_TONE_1_PRESENT) && s->phase_rate[0])
for (k = 0; k < s->desc->tones; k++)
{
for (j = i; j < i + n; j++)
if ((s->current_tx_tone & tone_present_bits[k]) && s->phase_rate[k])
{
tone = dds_mod(&(s->phase_acc[0]), s->phase_rate[0], s->tone_scaling[0][high_low], 0);
amp[j] = saturate(amp[j] + tone);
for (j = i; j < i + n; j++)
{
tone = dds_mod(&(s->phase_acc[k]), s->phase_rate[k], s->tone_scaling[k][high_low], 0);
amp[j] = saturate(amp[j] + tone);
}
/*endfor*/
}
/*endfor*/
/*endif*/
}
/*endif*/
if ((s->current_tx_tone & SIG_TONE_2_PRESENT) && s->phase_rate[1])
{
for (j = i; j < i + n; j++)
{
tone = dds_mod(&(s->phase_acc[1]), s->phase_rate[1], s->tone_scaling[1][high_low], 0);
amp[j] = saturate(amp[j] + tone);
}
/*endfor*/
}
/*endif*/
}
/*endif*/
if (need_update && s->sig_update)
@ -421,82 +356,74 @@ SPAN_DECLARE(int) sig_tone_tx_free(sig_tone_tx_state_t *s)
SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
int32_t x;
int32_t notched_signal;
int32_t bandpass_signal;
int16_t x;
int32_t v;
int16_t notched_signal[2];
int16_t bandpass_signal;
#else
float x;
float notched_signal;
float v;
float notched_signal[2];
float bandpass_signal;
#endif
int i;
int j;
int32_t mown_notch[2];
int32_t mown_bandpass;
int32_t notch_power[2];
int32_t flat_power;
for (i = 0; i < len; i++)
{
if (s->signaling_state_duration < INT_MAX)
s->signaling_state_duration++;
if (s->signalling_state_duration < INT_MAX)
s->signalling_state_duration++;
/*endif*/
notched_signal = 0;
for (j = 0; j < s->desc->tones; j++)
{
/* The notch filter is two cascaded biquads. */
notched_signal = amp[i];
#if defined(SPANDSP_USE_FIXED_POINT)
notched_signal *= s->desc->tone[j].notch_a1[0];
notched_signal += s->tone[j].notch_z1[1]*s->desc->tone[j].notch_b1[1];
notched_signal += s->tone[j].notch_z1[2]*s->desc->tone[j].notch_b1[2];
x = notched_signal;
notched_signal += s->tone[j].notch_z1[1]*s->desc->tone[j].notch_a1[1];
notched_signal += s->tone[j].notch_z1[2]*s->desc->tone[j].notch_a1[2];
s->tone[j].notch_z1[2] = s->tone[j].notch_z1[1];
s->tone[j].notch_z1[1] = x >> 15;
notched_signal += s->tone[j].notch_z2[1]*s->desc->tone[j].notch_b2[1];
notched_signal += s->tone[j].notch_z2[2]*s->desc->tone[j].notch_b2[2];
x = notched_signal;
notched_signal += s->tone[j].notch_z2[1]*s->desc->tone[j].notch_a2[1];
notched_signal += s->tone[j].notch_z2[2]*s->desc->tone[j].notch_a2[2];
s->tone[j].notch_z2[2] = s->tone[j].notch_z2[1];
s->tone[j].notch_z2[1] = x >> 15;
notched_signal >>= s->desc->notch_postscale;
v = ((int32_t) amp[i]*s->desc->notch[j]->a1[0])
+ ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[j]->b1[1])
+ ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[j]->b1[2]);
x = v >> 15;
v += ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[j]->a1[1])
+ ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[j]->a1[2]);
s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0];
s->tone[j].notch_z1[0] = x;
v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[j]->b2[1])
+ ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[j]->b2[2]);
x = v >> 15;
v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[j]->a2[1])
+ ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[j]->a2[2]);
s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0];
s->tone[j].notch_z2[0] = x;
notched_signal[j] = v >> s->desc->notch[j]->postscale;
#else
notched_signal *= s->desc->tone[j].notch_a1[0];
notched_signal += s->tone[j].notch_z1[1]*s->desc->tone[j].notch_b1[1];
notched_signal += s->tone[j].notch_z1[2]*s->desc->tone[j].notch_b1[2];
x = notched_signal;
notched_signal += s->tone[j].notch_z1[1]*s->desc->tone[j].notch_a1[1];
notched_signal += s->tone[j].notch_z1[2]*s->desc->tone[j].notch_a1[2];
s->tone[j].notch_z1[2] = s->tone[j].notch_z1[1];
s->tone[j].notch_z1[1] = x;
notched_signal += s->tone[j].notch_z2[1]*s->desc->tone[j].notch_b2[1];
notched_signal += s->tone[j].notch_z2[2]*s->desc->tone[j].notch_b2[2];
x = notched_signal;
notched_signal += s->tone[j].notch_z2[1]*s->desc->tone[j].notch_a2[1];
notched_signal += s->tone[j].notch_z2[2]*s->desc->tone[j].notch_a2[2];
s->tone[j].notch_z2[2] = s->tone[j].notch_z2[1];
s->tone[j].notch_z2[1] = x;
v = amp[i]*s->desc->notch[j]->a1[0]
+ s->tone[j].notch_z1[0]*s->desc->notch[j]->b1[1]
+ s->tone[j].notch_z1[1]*s->desc->notch[j]->b1[2];
x = v;
v += s->tone[j].notch_z1[0]*s->desc->notch[j]->a1[1]
+ s->tone[j].notch_z1[1]*s->desc->notch[j]->a1[2];
s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0];
s->tone[j].notch_z1[0] = x;
v += s->tone[j].notch_z2[0]*s->desc->notch[j]->b2[1]
+ s->tone[j].notch_z2[1]*s->desc->notch[j]->b2[2];
x = v;
v += s->tone[j].notch_z2[0]*s->desc->notch[j]->a2[1]
+ s->tone[j].notch_z2[1]*s->desc->notch[j]->a2[2];
s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0];
s->tone[j].notch_z2[0] = x;
notched_signal[j] = v;
#endif
/* Modulus and leaky integrate the notched data. The result of
this isn't used in low tone detect mode, but we must keep notch_zl
rolling along. */
s->tone[j].notch_zl = ((s->tone[j].notch_zl*s->desc->notch_slugi) >> 15)
+ ((abs((int) notched_signal)*s->desc->notch_slugp) >> 15);
/* Mow the grass to weed out the noise! */
mown_notch[j] = s->tone[0].notch_zl & s->desc->notch_threshold;
this isn't used in low tone detect mode, but we must keep the
power measurement rolling along. */
notch_power[j] = power_meter_update(&s->tone[j].power, notched_signal[j]);
}
if (s->tone_present)
if (s->tone[0].tone_present || s->tone[1].tone_present)
{
if (s->flat_mode_timeout <= 0)
if (s->flat_mode_timeout && --s->flat_mode_timeout == 0)
s->flat_mode = TRUE;
else
s->flat_mode_timeout--;
/*endif*/
}
else
@ -509,55 +436,51 @@ SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len)
if (s->flat_mode)
{
/* Flat mode */
/* The bandpass filter is a single bi-quad stage */
bandpass_signal = amp[i];
#if defined(SPANDSP_USE_FIXED_POINT)
bandpass_signal *= s->desc->broad_a[0];
bandpass_signal += s->broad_z[1]*s->desc->broad_b[1];
bandpass_signal += s->broad_z[2]*s->desc->broad_b[2];
x = bandpass_signal;
bandpass_signal += s->broad_z[1]*s->desc->broad_a[1];
bandpass_signal += s->broad_z[2]*s->desc->broad_a[2];
s->broad_z[2] = s->broad_z[1];
s->broad_z[1] = x >> 15;
bandpass_signal >>= s->desc->broad_postscale;
#else
bandpass_signal *= s->desc->broad_a[0];
bandpass_signal += s->broad_z[1]*s->desc->broad_b[1];
bandpass_signal += s->broad_z[2]*s->desc->broad_b[2];
x = bandpass_signal;
bandpass_signal += s->broad_z[1]*s->desc->broad_a[1];
bandpass_signal += s->broad_z[2]*s->desc->broad_a[2];
s->broad_z[2] = s->broad_z[1];
s->broad_z[1] = x;
#endif
/* Leaky integrate the bandpassed data */
s->broad_zl = ((s->broad_zl*s->desc->broad_slugi) >> 15)
+ ((abs((int) bandpass_signal)*s->desc->broad_slugp) >> 15);
/* For the broad band receiver we use a simple linear threshold! */
if (s->tone_present)
if (s->desc->flat)
{
s->tone_present = (s->broad_zl > s->desc->broad_threshold);
if (!s->tone_present)
/* The bandpass filter is a single bi-quad stage */
#if defined(SPANDSP_USE_FIXED_POINT)
v = ((int32_t) amp[i]*s->desc->flat->a[0])
+ ((int32_t) s->flat_z[0]*s->desc->flat->b[1])
+ ((int32_t) s->flat_z[1]*s->desc->flat->b[2]);
x = v >> 15;
v += ((int32_t) s->flat_z[0]*s->desc->flat->a[1])
+ ((int32_t) s->flat_z[1]*s->desc->flat->a[2]);
s->flat_z[1] = s->flat_z[0];
s->flat_z[0] = x;
bandpass_signal = v >> s->desc->flat->postscale;
#else
v = amp[i]*s->desc->flat->a[0]
+ s->flat_z[0]*s->desc->flat->b[1]
+ s->flat_z[1]*s->desc->flat->b[2];
x = v;
v += s->flat_z[0]*s->desc->flat->a[1]
+ s->flat_z[1]*s->desc->flat->a[2];
s->flat_z[1] = s->flat_z[0];
s->flat_z[0] = x;
bandpass_signal = v;
#endif
}
flat_power = power_meter_update(&s->flat_power, bandpass_signal);
/* For the flat receiver we use a simple power threshold! */
if (s->tone[0].tone_present)
{
s->tone[0].tone_present = (flat_power > s->flat_detection_threshold);
if (!s->tone[0].tone_present)
{
if (s->sig_update)
s->sig_update(s->user_data, SIG_TONE_1_CHANGE, 0, s->signaling_state_duration);
/*endif*/
s->signaling_state_duration = 0;
s->signalling_state &= ~tone_present_bits[0];
s->signalling_state |= tone_change_bits[0];
}
/*endif*/
}
else
{
s->tone_present = (s->broad_zl > s->desc->broad_threshold);
if (s->tone_present)
s->tone[0].tone_present = (flat_power > s->flat_detection_threshold);
if (s->tone[0].tone_present)
{
if (s->sig_update)
s->sig_update(s->user_data, SIG_TONE_1_CHANGE | SIG_TONE_1_PRESENT, 0, s->signaling_state_duration);
/*endif*/
s->signaling_state_duration = 0;
s->signalling_state |= (tone_present_bits[0] | tone_change_bits[0]);
}
/*endif*/
}
@ -565,17 +488,14 @@ SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len)
/* Notch insertion logic */
/* tone_present and tone_on are equivalent in flat mode */
if (s->tone_present)
if (s->tone[0].tone_present)
{
s->notch_enabled = s->desc->notch_allowed;
s->notch_insertion_timeout = s->desc->notch_lag_time;
}
else
{
if (s->notch_insertion_timeout > 0)
if (s->notch_insertion_timeout)
s->notch_insertion_timeout--;
else
s->notch_enabled = FALSE;
/*endif*/
}
/*endif*/
@ -583,91 +503,84 @@ SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len)
else
{
/* Sharp mode */
flat_power = power_meter_update(&s->flat_power, amp[i]);
/* Modulus and leaky integrate the data */
s->broad_zl = ((s->broad_zl*s->desc->unfiltered_slugi) >> 15)
+ ((abs((int) amp[i])*s->desc->unfiltered_slugp) >> 15);
/* Mow the grass to weed out the noise! */
mown_bandpass = s->broad_zl & s->desc->unfiltered_threshold;
/* Persistence checking and notch insertion logic */
if (!s->tone_present)
for (j = 0; j < s->desc->tones; j++)
{
if (mown_notch[0] < mown_bandpass)
/* Persistence checking and notch insertion logic */
if (s->tone[j].tone_present)
{
/* Tone is detected this sample */
if (s->tone_persistence_timeout <= 0)
if (flat_power < s->sharp_detection_threshold
||
(notch_power[j] >> 6)*s->detection_ratio > (flat_power >> 6))
{
s->tone_present = TRUE;
s->notch_enabled = s->desc->notch_allowed;
s->tone_persistence_timeout = s->desc->tone_off_check_time;
s->notch_insertion_timeout = s->desc->notch_lag_time;
if (s->sig_update)
s->sig_update(s->user_data, SIG_TONE_1_CHANGE | SIG_TONE_1_PRESENT, 0, s->signaling_state_duration);
/* Tone is not detected this sample */
if (--s->tone[j].tone_persistence_timeout == 0)
{
/* Tone off is confirmed */
s->tone[j].tone_present = FALSE;
s->tone[j].tone_persistence_timeout = s->desc->tone_on_check_time;
s->signalling_state &= ~tone_present_bits[j];
s->signalling_state |= tone_change_bits[j];
}
/*endif*/
s->signaling_state_duration = 0;
}
else
{
s->tone_persistence_timeout--;
if (s->notch_insertion_timeout > 0)
s->notch_insertion_timeout--;
else
s->notch_enabled = FALSE;
/*endif*/
s->tone[j].tone_persistence_timeout = s->desc->tone_off_check_time;
}
/*endif*/
}
else
{
s->tone_persistence_timeout = s->desc->tone_on_check_time;
if (s->notch_insertion_timeout > 0)
if (s->notch_insertion_timeout)
s->notch_insertion_timeout--;
else
s->notch_enabled = FALSE;
/*endif*/
}
/*endif*/
}
else
{
if (mown_notch[0] > mown_bandpass)
{
/* Tone is not detected this sample */
if (s->tone_persistence_timeout <= 0)
if (flat_power > s->sharp_detection_threshold
&&
(notch_power[j] >> 6)*s->detection_ratio < (flat_power >> 6))
{
s->tone_present = FALSE;
s->tone_persistence_timeout = s->desc->tone_on_check_time;
if (s->sig_update)
s->sig_update(s->user_data, SIG_TONE_1_CHANGE, 0, s->signaling_state_duration);
/* Tone is detected this sample */
if (--s->tone[j].tone_persistence_timeout == 0)
{
/* Tone on is confirmed */
s->tone[j].tone_present = TRUE;
s->tone[j].tone_persistence_timeout = s->desc->tone_off_check_time;
s->notch_insertion_timeout = s->desc->notch_lag_time;
s->signalling_state |= (tone_present_bits[j] | tone_change_bits[j]);
}
/*endif*/
s->signaling_state_duration = 0;
}
else
{
s->tone_persistence_timeout--;
s->tone[j].tone_persistence_timeout = s->desc->tone_on_check_time;
}
/*endif*/
}
else
{
s->tone_persistence_timeout = s->desc->tone_off_check_time;
}
/*endif*/
}
/*endfor*/
}
/*endif*/
if (s->signalling_state & (SIG_TONE_1_CHANGE | SIG_TONE_2_CHANGE))
{
if (s->sig_update)
s->sig_update(s->user_data, s->signalling_state, 0, s->signalling_state_duration);
/*endif*/
s->signalling_state &= ~(SIG_TONE_1_CHANGE | SIG_TONE_2_CHANGE);
s->signalling_state_duration = 0;
}
/*endif*/
if ((s->current_rx_tone & SIG_TONE_RX_PASSTHROUGH))
{
if ((s->current_rx_tone & SIG_TONE_RX_FILTER_TONE) || s->notch_enabled)
amp[i] = (int16_t) notched_signal;
if ((s->current_rx_tone & SIG_TONE_RX_FILTER_TONE) || s->notch_insertion_timeout)
amp[i] = saturate16(notched_signal[0]);
/*endif*/
}
else
{
/* Simply mute the media path */
amp[i] = 0;
}
/*endif*/
@ -685,6 +598,11 @@ SPAN_DECLARE(void) sig_tone_rx_set_mode(sig_tone_rx_state_t *s, int mode, int du
SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data)
{
#if !defined(SPANDSP_USE_FIXED_POINT)
int i;
int j;
#endif
if (sig_update == NULL || tone_type < 1 || tone_type > 3)
return NULL;
/*endif*/
@ -695,16 +613,31 @@ SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int
return NULL;
}
memset(s, 0, sizeof(*s));
#if !defined(SPANDSP_USE_FIXED_POINT)
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
s->tone[j].notch_z1[i] = 0.0f;
s->tone[j].notch_z2[i] = 0.0f;
}
s->flat_z[i] = 0.0f;
}
#endif
s->sig_update = sig_update;
s->user_data = user_data;
s->desc = &sig_tones[tone_type - 1];
s->flat_mode_timeout = 0;
s->notch_insertion_timeout = 0;
s->tone_persistence_timeout = 0;
s->signaling_state_duration = 0;
power_meter_init(&s->tone[0].power, 5);
power_meter_init(&s->tone[1].power, 5);
power_meter_init(&s->flat_power, 5);
s->flat_detection_threshold = power_meter_level_dbm0(s->desc->flat_detection_threshold);
s->sharp_detection_threshold = power_meter_level_dbm0(s->desc->sharp_detection_threshold);
s->detection_ratio = powf(10.0f, s->desc->detection_ratio/10.0f) + 1.0f;
return s;
}
/*- End of function --------------------------------------------------------*/

View File

@ -2,7 +2,7 @@
* SpanDSP - a series of DSP components for telephony
*
* private/sig_tone.h - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz
* and similar signalling tone used in older protocols.
* and similar signalling tones used in older protocols.
*
* Written by Steve Underwood <steveu@coppice.org>
*
@ -23,116 +23,116 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: sig_tone.h,v 1.4 2009/09/04 14:38:47 steveu Exp $
* $Id: sig_tone.h,v 1.9 2010/03/11 14:22:30 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_SIG_TONE_H_)
#define _SPANDSP_PRIVATE_SIG_TONE_H_
/*! \brief The coefficient set for a pair of cascaded bi-quads that make a signalling notch filter. */
typedef struct
{
#if defined(SPANDSP_USE_FIXED_POINT)
int16_t a1[3];
int16_t b1[3];
int16_t a2[3];
int16_t b2[3];
int postscale;
#else
float a1[3];
float b1[3];
float a2[3];
float b2[3];
#endif
} sig_tone_notch_coeffs_t;
/*! \brief The coefficient set for a bi-quad that makes a signalling flat filter.
Some signalling tone schemes require such a filter, and some don't.
It is termed a flat filter, to distinguish it from the sharp filter,
but obviously it is not actually flat. It is a broad band weighting
filter. */
typedef struct
{
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief Flat mode bandpass bi-quad parameters */
int16_t a[3];
/*! \brief Flat mode bandpass bi-quad parameters */
int16_t b[3];
/*! \brief Post filter scaling */
int postscale;
#else
/*! \brief Flat mode bandpass bi-quad parameters */
float a[3];
/*! \brief Flat mode bandpass bi-quad parameters */
float b[3];
#endif
} sig_tone_flat_coeffs_t;
/*!
Signaling tone descriptor. This defines the working state for a
single instance of the transmit and receive sides of a signaling
signalling tone descriptor. This defines the working state for a
single instance of the transmit and receive sides of a signalling
tone processor.
*/
struct sig_tone_descriptor_s
typedef struct
{
/*! \brief The tones used. */
int tone_freq[2];
/*! \brief The high and low tone amplitudes for each of the tones. */
/*! \brief The high and low tone amplitudes for each of the tones, in dBm0. */
int tone_amp[2][2];
/*! \brief The delay, in audio samples, before the high level tone drops
to a low level tone. */
to a low level tone. Some signalling protocols require the
signalling tone be started at a high level, to ensure crisp
initial detection at the receiver, but require the tone
amplitude to drop by a number of dBs if it is sustained,
to reduce crosstalk levels. */
int high_low_timeout;
/*! \brief Some signaling tone detectors use a sharp initial filter,
changing to a broader band filter after some delay. This
/*! \brief Some signalling tone detectors use a sharp initial filter,
changing to a broader, flatter, filter after some delay. This
parameter defines the delay. 0 means it never changes. */
int sharp_flat_timeout;
/*! \brief Parameters to control the behaviour of the notch filter, used
to remove the tone from the voice path in some protocols. */
to remove the tone from the voice path in some protocols. The
notch is applied as fast as possible, when the signalling tone
is detected. Its removal is delayed by this timeout, to avoid
clicky noises from repeated switching of the filter on rapid
pulses of signalling tone. */
int notch_lag_time;
/*! \brief TRUE if the notch may be used in the media flow. */
int notch_allowed;
/*! \brief The tone on persistence check, in audio samples. */
int tone_on_check_time;
/*! \brief The tone off persistence check, in audio samples. */
int tone_off_check_time;
/*! \brief ??? */
/*! \brief The number of tones used. */
int tones;
/*! \brief The coefficients for the cascaded bi-quads notch filter. */
struct
{
#if defined(SPANDSP_USE_FIXED_POINT)
int32_t notch_a1[3];
int32_t notch_b1[3];
int32_t notch_a2[3];
int32_t notch_b2[3];
int notch_postscale;
#else
float notch_a1[3];
float notch_b1[3];
float notch_a2[3];
float notch_b2[3];
#endif
} tone[2];
const sig_tone_notch_coeffs_t *notch[2];
/*! \brief The coefficients for the single bi-quad flat mode filter. */
const sig_tone_flat_coeffs_t *flat;
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief Flat mode bandpass bi-quad parameters */
int32_t broad_a[3];
/*! \brief Flat mode bandpass bi-quad parameters */
int32_t broad_b[3];
/*! \brief Post filter scaling */
int broad_postscale;
#else
/*! \brief Flat mode bandpass bi-quad parameters */
float broad_a[3];
/*! \brief Flat mode bandpass bi-quad parameters */
float broad_b[3];
#endif
/*! \brief The coefficients for the post notch leaky integrator. */
int32_t notch_slugi;
/*! \brief ??? */
int32_t notch_slugp;
/*! \brief The coefficients for the post modulus leaky integrator in the
unfiltered data path. The prescale value incorporates the
detection ratio. This is called the guard ratio in some
protocols. */
int32_t unfiltered_slugi;
/*! \brief ??? */
int32_t unfiltered_slugp;
/*! \brief The coefficients for the post modulus leaky integrator in the
bandpass filter data path. */
int32_t broad_slugi;
/*! \brief ??? */
int32_t broad_slugp;
/*! \brief Masks which effectively threshold the notched, weighted and
bandpassed data. */
int32_t notch_threshold;
/*! \brief ??? */
int32_t unfiltered_threshold;
/*! \brief ??? */
int32_t broad_threshold;
};
/*! \brief Minimum signalling tone to total power ratio, in dB */
int16_t detection_ratio;
/*! \brief Minimum total power for detection in sharp mode, in dB */
int16_t sharp_detection_threshold;
/*! \brief Minimum total power for detection in flat mode, in dB */
int16_t flat_detection_threshold;
} sig_tone_descriptor_t;
/*!
Signaling tone transmit state
Signalling tone transmit state
*/
struct sig_tone_tx_state_s
{
/*! \brief The callback function used to handle signaling changes. */
/*! \brief The callback function used to handle signalling changes. */
tone_report_func_t sig_update;
/*! \brief A user specified opaque pointer passed to the callback function. */
void *user_data;
/*! \brief Tone descriptor */
sig_tone_descriptor_t *desc;
const sig_tone_descriptor_t *desc;
/*! The phase rates for the one or two tones */
int32_t phase_rate[2];
@ -148,22 +148,22 @@ struct sig_tone_tx_state_s
int current_tx_tone;
/*! \brief Current transmit timeout */
int current_tx_timeout;
/*! \brief Time in current signaling state, in samples. */
int signaling_state_duration;
/*! \brief Time in current signalling state, in samples. */
int signalling_state_duration;
};
/*!
Signaling tone receive state
Signalling tone receive state
*/
struct sig_tone_rx_state_s
{
/*! \brief The callback function used to handle signaling changes. */
/*! \brief The callback function used to handle signalling changes. */
tone_report_func_t sig_update;
/*! \brief A user specified opaque pointer passed to the callback function. */
void *user_data;
/*! \brief Tone descriptor */
sig_tone_descriptor_t *desc;
const sig_tone_descriptor_t *desc;
/*! \brief The current receive tone */
int current_rx_tone;
@ -174,45 +174,54 @@ struct sig_tone_rx_state_s
{
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief The z's for the notch filter */
int32_t notch_z1[3];
int16_t notch_z1[2];
/*! \brief The z's for the notch filter */
int32_t notch_z2[3];
int16_t notch_z2[2];
#else
/*! \brief The z's for the notch filter */
float notch_z1[3];
float notch_z1[2];
/*! \brief The z's for the notch filter */
float notch_z2[3];
float notch_z2[2];
#endif
/*! \brief The z's for the notch integrators. */
int32_t notch_zl;
/*! \brief The power output of the notch. */
power_meter_t power;
/*! \brief Persistence check for tone present */
int tone_persistence_timeout;
/*! \brief TRUE if the tone is declared to be present */
int tone_present;
} tone[2];
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief The z's for the weighting/bandpass filter. */
int32_t broad_z[3];
int16_t flat_z[2];
#else
/*! \brief The z's for the weighting/bandpass filter. */
float broad_z[3];
float flat_z[2];
#endif
/*! \brief The z for the broadband integrator. */
int32_t broad_zl;
/*! \brief The output power of the flat (unfiltered or flat filtered) path. */
power_meter_t flat_power;
/*! \brief ??? */
/*! \brief The minimum reading from the power meter for detection in flat mode */
int32_t flat_detection_threshold;
/*! \brief The minimum reading from the power meter for detection in sharp mode */
int32_t sharp_detection_threshold;
/*! \brief The minimum ratio between notched power and total power for detection */
int32_t detection_ratio;
/*! \brief TRUE if in flat mode. FALSE if in sharp mode. */
int flat_mode;
/*! \brief ??? */
int tone_present;
/*! \brief ??? */
/*! \brief TRUE if the notch filter is enabled in the media path */
int notch_enabled;
/*! \brief ??? */
int flat_mode_timeout;
/*! \brief ??? */
int notch_insertion_timeout;
/*! \brief ??? */
int tone_persistence_timeout;
/*! \brief ??? */
int signaling_state_duration;
int signalling_state;
/*! \brief ??? */
int signalling_state_duration;
};
#endif

View File

@ -2,7 +2,7 @@
* SpanDSP - a series of DSP components for telephony
*
* sig_tone.h - Signalling tone processing for the 2280Hz, 2400Hz, 2600Hz
* and similar signalling tone used in older protocols.
* and similar signalling tones used in older protocols.
*
* Written by Steve Underwood <steveu@coppice.org>
*
@ -23,15 +23,15 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: sig_tone.h,v 1.20 2009/09/04 14:38:46 steveu Exp $
* $Id: sig_tone.h,v 1.23 2010/03/09 13:43:04 steveu Exp $
*/
/*! \file */
/*! \page sig_tone_page The signaling tone processor
/*! \page sig_tone_page The 2280/2400/2600Hz signalling tone processor
\section sig_tone_sec_1 What does it do?
The signaling tone processor handles the 2280Hz, 2400Hz and 2600Hz tones, used
in many analogue signaling procotols, and digital ones derived from them.
The signalling tone processor handles the 2280Hz, 2400Hz and 2600Hz tones, used
in many analogue signalling procotols, and digital ones derived from them.
\section sig_tone_sec_2 How does it work?
Most single and two voice frequency signalling systems share many features, as these
@ -57,30 +57,30 @@ least supervisory information may be heard.
/* The optional tone sets */
enum
{
/*! European 2280Hz signaling tone. Tone 1 is 2280Hz. Tone 2 is not used. */
/*! European 2280Hz signalling tone. Tone 1 is 2280Hz. Tone 2 is not used. */
SIG_TONE_2280HZ = 1,
/*! US 2600Hz signaling tone. Tone 1 is 2600Hz. Tone 2 is not used. */
/*! US 2600Hz signalling tone. Tone 1 is 2600Hz. Tone 2 is not used. */
SIG_TONE_2600HZ,
/*! US 2400Hz + 2600Hz signaling tones. Tone 1 is 2600Hz. Tone 2 is 2400Hz. */
/*! US 2400Hz + 2600Hz signalling tones. Tone 1 is 2600Hz. Tone 2 is 2400Hz. */
SIG_TONE_2400HZ_2600HZ
};
/* Mode control and report bits for transmit and receive */
enum
{
/*! Signaling tone 1 is present */
/*! Signalling tone 1 is present */
SIG_TONE_1_PRESENT = 0x001,
/*! Signaling tone 1 has changed state (ignored when setting tx mode) */
/*! Signalling tone 1 has changed state (ignored when setting tx mode) */
SIG_TONE_1_CHANGE = 0x002,
/*! Signaling tone 2 is present */
/*! Signalling tone 2 is present */
SIG_TONE_2_PRESENT = 0x004,
/*! Signaling tone 2 has changed state (ignored when setting tx mode) */
/*! Signalling tone 2 has changed state (ignored when setting tx mode) */
SIG_TONE_2_CHANGE = 0x008,
/*! The media signal is passing through. Tones might be added to it. */
SIG_TONE_TX_PASSTHROUGH = 0x010,
/*! The media signal is passing through. Tones might be extracted from it, if detected. */
SIG_TONE_RX_PASSTHROUGH = 0x040,
/*! Force filtering of the signaling tone, whether signaling is being detected or not.
/*! Force filtering of the signalling tone, whether signalling is being detected or not.
This is mostly useful for test purposes. */
SIG_TONE_RX_FILTER_TONE = 0x080,
/*! Request an update of the transmit status, upon timeout of the previous status. */
@ -89,13 +89,6 @@ enum
SIG_TONE_RX_UPDATE_REQUEST = 0x200
};
/*!
Signaling tone descriptor. This defines the working state for a
single instance of the transmit and receive sides of a signaling
tone processor.
*/
typedef struct sig_tone_descriptor_s sig_tone_descriptor_t;
typedef struct sig_tone_tx_state_s sig_tone_tx_state_t;
typedef struct sig_tone_rx_state_s sig_tone_rx_state_t;
@ -107,7 +100,7 @@ extern "C"
/*! Process a block of received audio samples.
\brief Process a block of received audio samples.
\param s The signaling tone context.
\param s The signalling tone context.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. */
@ -115,36 +108,36 @@ SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len);
/*! Set the receive mode.
\brief Set the receive mode.
\param s The signaling tone context.
\param s The signalling tone context.
\param mode The new mode for the receiver.
\param duration The duration for this mode, before an update is requested.
A duration of zero means forever. */
SPAN_DECLARE(void) sig_tone_rx_set_mode(sig_tone_rx_state_t *s, int mode, int duration);
/*! Initialise a signaling tone receiver context.
\brief Initialise a signaling tone context.
\param s The signaling tone context.
\param tone_type The type of signaling tone.
\param sig_update Callback function to handle signaling updates.
/*! Initialise a signalling tone receiver context.
\brief Initialise a signalling tone context.
\param s The signalling tone context.
\param tone_type The type of signalling tone.
\param sig_update Callback function to handle signalling updates.
\param user_data An opaque pointer.
\return A pointer to the signalling tone context, or NULL if there was a problem. */
SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data);
/*! Release a signaling tone receiver context.
\brief Release a signaling tone receiver context.
\param s The signaling tone context.
/*! Release a signalling tone receiver context.
\brief Release a signalling tone receiver context.
\param s The signalling tone context.
\return 0 for OK */
SPAN_DECLARE(int) sig_tone_rx_release(sig_tone_rx_state_t *s);
/*! Free a signaling tone receiver context.
\brief Free a signaling tone receiver context.
\param s The signaling tone context.
/*! Free a signalling tone receiver context.
\brief Free a signalling tone receiver context.
\param s The signalling tone context.
\return 0 for OK */
SPAN_DECLARE(int) sig_tone_rx_free(sig_tone_rx_state_t *s);
/*! Generate a block of signaling tone audio samples.
\brief Generate a block of signaling tone audio samples.
\param s The signaling tone context.
/*! Generate a block of signalling tone audio samples.
\brief Generate a block of signalling tone audio samples.
\param s The signalling tone context.
\param amp The audio sample buffer.
\param len The number of samples to be generated.
\return The number of samples actually generated. */
@ -152,30 +145,30 @@ SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len);
/*! Set the tone mode.
\brief Set the tone mode.
\param s The signaling tone context.
\param s The signalling tone context.
\param mode The new mode for the transmitted tones.
\param duration The duration for this mode, before an update is requested.
A duration of zero means forever. */
SPAN_DECLARE(void) sig_tone_tx_set_mode(sig_tone_tx_state_t *s, int mode, int duration);
/*! Initialise a signaling tone transmitter context.
\brief Initialise a signaling tone context.
\param s The signaling tone context.
\param tone_type The type of signaling tone.
\param sig_update Callback function to handle signaling updates.
/*! Initialise a signalling tone transmitter context.
\brief Initialise a signalling tone context.
\param s The signalling tone context.
\param tone_type The type of signalling tone.
\param sig_update Callback function to handle signalling updates.
\param user_data An opaque pointer.
\return A pointer to the signalling tone context, or NULL if there was a problem. */
SPAN_DECLARE(sig_tone_tx_state_t *) sig_tone_tx_init(sig_tone_tx_state_t *s, int tone_type, tone_report_func_t sig_update, void *user_data);
/*! Release a signaling tone transmitter context.
\brief Release a signaling tone transmitter context.
\param s The signaling tone context.
/*! Release a signalling tone transmitter context.
\brief Release a signalling tone transmitter context.
\param s The signalling tone context.
\return 0 for OK */
SPAN_DECLARE(int) sig_tone_tx_release(sig_tone_tx_state_t *s);
/*! Free a signaling tone transmitter context.
\brief Free a signaling tone transmitter context.
\param s The signaling tone context.
/*! Free a signalling tone transmitter context.
\brief Free a signalling tone transmitter context.
\param s The signalling tone context.
\return 0 for OK */
SPAN_DECLARE(int) sig_tone_tx_free(sig_tone_tx_state_t *s);

View File

@ -22,12 +22,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: sig_tone_tests.c,v 1.27 2009/09/23 16:02:59 steveu Exp $
* $Id: sig_tone_tests.c,v 1.32 2010/03/11 14:22:30 steveu Exp $
*/
/*! \file */
/*! \page sig_tone_tests_page The signaling tone processor tests
/*! \page sig_tone_tests_page The 2280/2400/2600Hz signalling tone Rx/Tx tests
\section sig_tone_tests_sec_1 What does it do?
???.
@ -55,17 +55,38 @@
#define SAMPLES_PER_CHUNK 160
#define MITEL_DIR "../test-data/mitel/"
#define BELLCORE_DIR "../test-data/bellcore/"
const char *bellcore_files[] =
{
MITEL_DIR "mitel-cm7291-talkoff.wav",
BELLCORE_DIR "tr-tsy-00763-1.wav",
BELLCORE_DIR "tr-tsy-00763-2.wav",
BELLCORE_DIR "tr-tsy-00763-3.wav",
BELLCORE_DIR "tr-tsy-00763-4.wav",
BELLCORE_DIR "tr-tsy-00763-5.wav",
BELLCORE_DIR "tr-tsy-00763-6.wav",
""
};
static int number_of_tones = 1;
static int sampleno = 0;
static int tone_1_present = 0;
static int tone_2_present = 0;
static int tx_section = 0;
static int dial_pulses = 0;
static int rx_handler_callbacks = 0;
static int tx_handler_callbacks = 0;
static void tx_handler(void *user_data, int what, int level, int duration)
{
sig_tone_tx_state_t *s;
s = (sig_tone_tx_state_t *) user_data;
tx_handler_callbacks++;
//printf("What - %d, duration - %d\n", what, duration);
if ((what & SIG_TONE_TX_UPDATE_REQUEST))
{
@ -84,13 +105,19 @@ static void tx_handler(void *user_data, int what, int level, int duration)
tx_section++;
else
tx_section--;
/*endif*/
sig_tone_tx_set_mode(s, 0, ms_to_samples(67));
break;
case 2:
tx_section++;
sig_tone_tx_set_mode(s, SIG_TONE_1_PRESENT, ms_to_samples(600));
printf("600ms on - %d samples\n", ms_to_samples(600));
if (number_of_tones == 2)
sig_tone_tx_set_mode(s, SIG_TONE_2_PRESENT, ms_to_samples(600));
else
sig_tone_tx_set_mode(s, SIG_TONE_1_PRESENT, ms_to_samples(600));
break;
case 3:
printf("End of sequence\n");
sig_tone_tx_set_mode(s, SIG_TONE_1_PRESENT | SIG_TONE_TX_PASSTHROUGH, 0);
break;
}
@ -104,6 +131,7 @@ static void rx_handler(void *user_data, int what, int level, int duration)
{
float ms;
rx_handler_callbacks++;
ms = 1000.0f*(float) duration/(float) SAMPLE_RATE;
printf("What - %d, duration - %d\n", what, duration);
if ((what & SIG_TONE_1_CHANGE))
@ -121,52 +149,184 @@ static void rx_handler(void *user_data, int what, int level, int duration)
}
/*- End of function --------------------------------------------------------*/
static void map_frequency_response(sig_tone_rx_state_t *s)
static void map_frequency_response(sig_tone_rx_state_t *s,
double f1,
double f2,
double f3,
double f4)
{
int16_t buf[8192];
int16_t buf[SAMPLES_PER_CHUNK];
int i;
int len;
double sumin;
double sumout;
swept_tone_state_t *swept;
double freq;
double gain;
/* Things like noise don't highlight the frequency response of the high Q notch
very well. We use a slowly swept frequency to check it. */
printf("Frequency response test\n");
sig_tone_rx_set_mode(s, SIG_TONE_RX_PASSTHROUGH | SIG_TONE_RX_FILTER_TONE, 0);
swept = swept_tone_init(NULL, 200.0f, 3900.0f, -10.0f, 120*SAMPLE_RATE, 0);
for (;;)
{
if ((len = swept_tone(swept, buf, SAMPLES_PER_CHUNK)) <= 0)
break;
/*endif*/
sumin = 0.0;
for (i = 0; i < len; i++)
sumin += (double) buf[i]*(double) buf[i];
/*endfor*/
sig_tone_rx(s, buf, len);
sumout = 0.0;
for (i = 0; i < len; i++)
sumout += (double) buf[i]*(double) buf[i];
/*endfor*/
printf("%7.1f %f\n", swept_tone_current_frequency(swept), 10.0*log10(sumout/sumin));
freq = swept_tone_current_frequency(swept);
if (sumin)
gain = 10.0*log10(sumout/sumin);
else
gain = 0.0;
printf("%7.1f Hz %f dBm0\n", freq, gain);
if (gain > 0.0
||
(freq < f1 && gain < -1.0)
||
(freq > f2 && freq < f3 && gain > -30.0)
||
(freq > f4 && gain < -1.0))
{
printf(" Failed\n");
exit(2);
}
/*endif*/
}
/*endfor*/
swept_tone_free(swept);
printf(" Passed\n");
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
static void speech_immunity_tests(sig_tone_rx_state_t *s)
{
int j;
int total_hits;
SNDFILE *inhandle;
int16_t amp[SAMPLE_RATE];
int frames;
printf("Speech immunity test\n");
total_hits = 0;
for (j = 0; bellcore_files[j][0]; j++)
{
/* Push some silence through, so we should be in the tone off state */
vec_zeroi16(amp, SAMPLE_RATE);
sig_tone_rx(s, amp, SAMPLE_RATE);
rx_handler_callbacks = 0;
if ((inhandle = sf_open_telephony_read(bellcore_files[j], 1)) == NULL)
{
printf(" Cannot open speech file '%s'\n", bellcore_files[j]);
exit(2);
}
/*endif*/
while ((frames = sf_readf_short(inhandle, amp, SAMPLE_RATE)))
{
sig_tone_rx(s, amp, frames);
}
/*endwhile*/
if (sf_close(inhandle) != 0)
{
printf(" Cannot close speech file '%s'\n", bellcore_files[j]);
exit(2);
}
/*endif*/
printf(" File %d gave %d false hits.\n", j + 1, rx_handler_callbacks);
total_hits += rx_handler_callbacks;
}
/*endfor*/
printf(" %d hits in total\n", total_hits);
if (total_hits > 0)
{
printf(" Failed\n");
exit(2);
}
/*endif*/
printf(" Passed\n");
}
/*- End of function --------------------------------------------------------*/
static void level_and_ratio_tests(sig_tone_rx_state_t *s, double pitch)
{
awgn_state_t noise_source;
int32_t phase_rate;
uint32_t phase;
int16_t gain;
int16_t amp[SAMPLE_RATE];
int i;
int j;
int k;
float noise_level;
float tone_level;
power_meter_t noise_meter;
power_meter_t tone_meter;
int16_t noise;
int16_t tone;
printf("Acceptable level and ratio test\n");
phase = 0;
phase_rate = dds_phase_rate(pitch);
for (k = -25; k > -60; k--)
{
noise_level = k;
awgn_init_dbm0(&noise_source, 1234567, noise_level);
tone_level = noise_level;
/* Push some silence through, so we should be in the tone off state */
vec_zeroi16(amp, SAMPLE_RATE);
sig_tone_rx(s, amp, SAMPLE_RATE);
power_meter_init(&noise_meter, 6);
power_meter_init(&tone_meter, 6);
for (j = 0; j < 20; j++)
{
rx_handler_callbacks = 0;
gain = dds_scaling_dbm0(tone_level);
for (i = 0; i < SAMPLES_PER_CHUNK; i++)
{
noise = awgn(&noise_source);
tone = dds_mod(&phase, phase_rate, gain, 0);
power_meter_update(&noise_meter, noise);
power_meter_update(&tone_meter, tone);
amp[i] = noise + tone;
}
/*endfor*/
sig_tone_rx(s, amp, SAMPLES_PER_CHUNK);
if (rx_handler_callbacks)
{
printf("Hit at tone = %fdBm0, noise = %fdBm0\n", tone_level, noise_level);
printf("Noise = %fdBm0, tone = %fdBm0\n", power_meter_current_dbm0(&noise_meter), power_meter_current_dbm0(&tone_meter));
}
/*endif*/
tone_level += 1.0f;
}
/*endfor*/
}
/*endfor*/
printf(" Passed\n");
}
/*- End of function --------------------------------------------------------*/
static void sequence_tests(sig_tone_tx_state_t *tx_state, sig_tone_rx_state_t *rx_state, codec_munge_state_t *munge)
{
int i;
awgn_state_t noise_source;
SNDFILE *outhandle;
int16_t amp[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
SNDFILE *outhandle;
int outframes;
int i;
int type;
int rx_samples;
int tx_samples;
sig_tone_tx_state_t tx_state;
sig_tone_rx_state_t rx_state;
awgn_state_t noise_source;
codec_munge_state_t *munge;
printf("Signalling sequence test\n");
if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL)
{
fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
@ -175,76 +335,35 @@ int main(int argc, char *argv[])
/*endif*/
awgn_init_dbm0(&noise_source, 1234567, -20.0f);
for (type = 1; type <= 3; type++)
for (sampleno = 0; sampleno < 60000; sampleno += SAMPLES_PER_CHUNK)
{
sampleno = 0;
tone_1_present = 0;
tone_2_present = 0;
tx_section = 0;
munge = NULL;
switch (type)
if (sampleno == 8000)
{
case 1:
printf("2280Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ALAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2280HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2280HZ, rx_handler, &rx_state);
rx_state.current_rx_tone |= SIG_TONE_RX_PASSTHROUGH;
break;
case 2:
printf("2600Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ULAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2600HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2600HZ, rx_handler, &rx_state);
rx_state.current_rx_tone |= SIG_TONE_RX_PASSTHROUGH;
break;
case 3:
printf("2400Hz/2600Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ULAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2400HZ_2600HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2400HZ_2600HZ, rx_handler, &rx_state);
rx_state.current_rx_tone |= SIG_TONE_RX_PASSTHROUGH;
break;
}
/*endswitch*/
/* Set to the default of hook condition */
sig_tone_rx_set_mode(&rx_state, SIG_TONE_RX_PASSTHROUGH | SIG_TONE_RX_FILTER_TONE, 0);
sig_tone_tx_set_mode(&tx_state, SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT | SIG_TONE_TX_PASSTHROUGH, 0);
map_frequency_response(&rx_state);
sig_tone_rx_set_mode(&rx_state, SIG_TONE_RX_PASSTHROUGH, 0);
for (sampleno = 0; sampleno < 30000; sampleno += SAMPLES_PER_CHUNK)
{
if (sampleno == 8000)
{
/* 100ms seize */
printf("100ms seize - %d samples\n", ms_to_samples(100));
dial_pulses = 0;
sig_tone_tx_set_mode(&tx_state, 0, ms_to_samples(100));
}
for (i = 0; i < SAMPLES_PER_CHUNK; i++)
amp[i] = awgn(&noise_source);
/*endfor*/
tx_samples = sig_tone_tx(&tx_state, amp, SAMPLES_PER_CHUNK);
for (i = 0; i < tx_samples; i++)
out_amp[2*i] = amp[i];
/*endfor*/
codec_munge(munge, amp, tx_samples);
rx_samples = sig_tone_rx(&rx_state, amp, tx_samples);
for (i = 0; i < rx_samples; i++)
out_amp[2*i + 1] = amp[i];
/*endfor*/
outframes = sf_writef_short(outhandle, out_amp, rx_samples);
if (outframes != rx_samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
/*endif*/
/* 100ms seize */
printf("100ms seize - %d samples\n", ms_to_samples(100));
dial_pulses = 0;
sig_tone_tx_set_mode(tx_state, 0, ms_to_samples(100));
}
/*endif*/
for (i = 0; i < SAMPLES_PER_CHUNK; i++)
amp[i] = awgn(&noise_source);
/*endfor*/
tx_samples = sig_tone_tx(tx_state, amp, SAMPLES_PER_CHUNK);
for (i = 0; i < tx_samples; i++)
out_amp[2*i] = amp[i];
/*endfor*/
codec_munge(munge, amp, tx_samples);
rx_samples = sig_tone_rx(rx_state, amp, tx_samples);
for (i = 0; i < rx_samples; i++)
out_amp[2*i + 1] = amp[i];
/*endfor*/
outframes = sf_writef_short(outhandle, out_amp, rx_samples);
if (outframes != rx_samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
/*endif*/
}
/*endfor*/
if (sf_close(outhandle) != 0)
@ -253,6 +372,83 @@ int main(int argc, char *argv[])
exit(2);
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
int type;
sig_tone_tx_state_t tx_state;
sig_tone_rx_state_t rx_state;
codec_munge_state_t *munge;
double f1;
double f2;
double fc;
double f3;
double f4;
for (type = 1; type <= 3; type++)
{
sampleno = 0;
tone_1_present = 0;
tone_2_present = 0;
tx_section = 0;
munge = NULL;
f1 =
f2 =
fc =
f3 =
f4 = 0.0;
switch (type)
{
case 1:
printf("2280Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ALAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2280HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2280HZ, rx_handler, &rx_state);
number_of_tones = 1;
f1 = 2280.0 - 200.0;
f2 = 2280.0 - 20.0;
fc = 2280.0;
f3 = 2280.0 + 20.0;
f4 = 2280.0 + 200.0;
break;
case 2:
printf("2600Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ULAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2600HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2600HZ, rx_handler, &rx_state);
number_of_tones = 1;
f1 = 2600.0 - 200.0;
f2 = 2600.0 - 20.0;
fc = 2600.0;
f3 = 2600.0 + 20.0;
f4 = 2600.0 + 200.0;
break;
case 3:
printf("2400Hz/2600Hz tests.\n");
munge = codec_munge_init(MUNGE_CODEC_ULAW, 0);
sig_tone_tx_init(&tx_state, SIG_TONE_2400HZ_2600HZ, tx_handler, &tx_state);
sig_tone_rx_init(&rx_state, SIG_TONE_2400HZ_2600HZ, rx_handler, &rx_state);
number_of_tones = 2;
f1 = 2400.0 - 200.0;
f2 = 2400.0 - 20.0;
fc = 2400.0;
f3 = 2400.0 + 20.0;
f4 = 2400.0 + 200.0;
break;
}
/*endswitch*/
/* Set to the default on hook condition */
map_frequency_response(&rx_state, f1, f2, f3, f4);
speech_immunity_tests(&rx_state);
level_and_ratio_tests(&rx_state, fc);
sig_tone_tx_set_mode(&tx_state, SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT | SIG_TONE_TX_PASSTHROUGH, 0);
sig_tone_rx_set_mode(&rx_state, SIG_TONE_RX_PASSTHROUGH, 0);
sequence_tests(&tx_state, &rx_state, munge);
}
/*endfor*/
printf("Tests completed.\n");
return 0;