DTMF: Now allows to give duration and pause for digit
Also the dtmf encoder will return less samples, if the digit(+pause) ends, so that the caller call set the next digit to play seamlessly. A reset function allows to clear the decoder states, to prevent glitches when re-attaching to an interrupted stream.
This commit is contained in:
parent
a756ba8fd9
commit
b60c844b4f
|
@ -98,6 +98,12 @@ void dtmf_decode_exit(dtmf_dec_t *dtmf)
|
||||||
fm_demod_exit(&dtmf->demod_high);
|
fm_demod_exit(&dtmf->demod_high);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dtmf_decode_reset(dtmf_dec_t *dtmf)
|
||||||
|
{
|
||||||
|
dtmf->detected = 0;
|
||||||
|
dtmf->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void dtmf_decode_filter(dtmf_dec_t *dtmf, sample_t *samples, int length, sample_t *frequency_low, sample_t *frequency_high, sample_t *amplitude_low, sample_t *amplitude_high)
|
void dtmf_decode_filter(dtmf_dec_t *dtmf, sample_t *samples, int length, sample_t *frequency_low, sample_t *frequency_high, sample_t *amplitude_low, sample_t *amplitude_high)
|
||||||
{
|
{
|
||||||
sample_t I_low[length], Q_low[length];
|
sample_t I_low[length], Q_low[length];
|
||||||
|
|
|
@ -30,6 +30,7 @@ typedef struct dtmf_dec {
|
||||||
|
|
||||||
int dtmf_decode_init(dtmf_dec_t *dtmf, void *priv, void (*recv_digit)(void *priv, char digit, dtmf_meas_t *meas), int samplerate, double max_amplitude, double min_amplitude);
|
int dtmf_decode_init(dtmf_dec_t *dtmf, void *priv, void (*recv_digit)(void *priv, char digit, dtmf_meas_t *meas), int samplerate, double max_amplitude, double min_amplitude);
|
||||||
void dtmf_decode_exit(dtmf_dec_t *dtmf);
|
void dtmf_decode_exit(dtmf_dec_t *dtmf);
|
||||||
|
void dtmf_decode_reset(dtmf_dec_t *dtmf);
|
||||||
void dtmf_decode(dtmf_dec_t *dtmf, sample_t *samples, int length);
|
void dtmf_decode(dtmf_dec_t *dtmf, sample_t *samples, int length);
|
||||||
void dtmf_decode_filter(dtmf_dec_t *dtmf, sample_t *samples, int length, sample_t *frequency_low, sample_t *frequency_high, sample_t *amplitude_low, sample_t *amplitude_high);
|
void dtmf_decode_filter(dtmf_dec_t *dtmf, sample_t *samples, int length, sample_t *frequency_low, sample_t *frequency_high, sample_t *amplitude_low, sample_t *amplitude_high);
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,6 @@
|
||||||
|
|
||||||
#define PEAK_DTMF_LOW 0.2818 /* -11 dBm, relative to 0 dBm level */
|
#define PEAK_DTMF_LOW 0.2818 /* -11 dBm, relative to 0 dBm level */
|
||||||
#define PEAK_DTMF_HIGH 0.3548 /* -9 dBm, relative to 0 dBm level */
|
#define PEAK_DTMF_HIGH 0.3548 /* -9 dBm, relative to 0 dBm level */
|
||||||
#define DTMF_DURATION 0.100 /* duration in seconds */
|
|
||||||
|
|
||||||
static sample_t dsp_sine_dtmf_low[65536];
|
|
||||||
static sample_t dsp_sine_dtmf_high[65536];
|
|
||||||
|
|
||||||
void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level)
|
void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level)
|
||||||
{
|
{
|
||||||
|
@ -38,17 +34,15 @@ void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level)
|
||||||
|
|
||||||
memset(dtmf, 0, sizeof(*dtmf));
|
memset(dtmf, 0, sizeof(*dtmf));
|
||||||
dtmf->samplerate = samplerate;
|
dtmf->samplerate = samplerate;
|
||||||
dtmf->max = (int)((double)samplerate * DTMF_DURATION + 0.5);
|
|
||||||
|
|
||||||
// FIXME: do this globally and not per instance */
|
|
||||||
for (i = 0; i < 65536; i++) {
|
for (i = 0; i < 65536; i++) {
|
||||||
dsp_sine_dtmf_low[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_LOW * dBm_level;
|
dtmf->sine_low[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_LOW * dBm_level;
|
||||||
dsp_sine_dtmf_high[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_HIGH * dBm_level;
|
dtmf->sine_high[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_HIGH * dBm_level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set dtmf tone */
|
/* set dtmf tone */
|
||||||
void dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone)
|
int dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone, double on_duration, double off_duration)
|
||||||
{
|
{
|
||||||
double f1, f2;
|
double f1, f2;
|
||||||
|
|
||||||
|
@ -71,53 +65,66 @@ void dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone)
|
||||||
case'd':case 'D': f1 = 941.0; f2 = 1633.0; break;
|
case'd':case 'D': f1 = 941.0; f2 = 1633.0; break;
|
||||||
default:
|
default:
|
||||||
dtmf->tone = 0;
|
dtmf->tone = 0;
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
dtmf->tone = tone;
|
dtmf->tone = tone;
|
||||||
dtmf->pos = 0;
|
dtmf->pos = 0;
|
||||||
|
dtmf->on = (int)((double)dtmf->samplerate * on_duration);
|
||||||
|
dtmf->off = dtmf->on + (int)((double)dtmf->samplerate * off_duration);
|
||||||
dtmf->phaseshift65536[0] = 65536.0 / ((double)dtmf->samplerate / f1);
|
dtmf->phaseshift65536[0] = 65536.0 / ((double)dtmf->samplerate / f1);
|
||||||
dtmf->phaseshift65536[1] = 65536.0 / ((double)dtmf->samplerate / f2);
|
dtmf->phaseshift65536[1] = 65536.0 / ((double)dtmf->samplerate / f2);
|
||||||
|
dtmf->phase65536[0] = 0.0;
|
||||||
|
dtmf->phase65536[1] = 0.0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate audio stream from DTMF tone. Keep phase for next call of function. */
|
/* Generate audio stream from DTMF tone.
|
||||||
void dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length)
|
* Keep phase for next call of function.
|
||||||
|
* Stop, if tone has finished and return only the samples that were used.
|
||||||
|
*/
|
||||||
|
int dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length)
|
||||||
{
|
{
|
||||||
double *phaseshift, *phase;
|
double *phaseshift, *phase;
|
||||||
int i, pos, max;
|
sample_t *sine_low, *sine_high;
|
||||||
|
int count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* use silence, if no tone */
|
/* if no tone */
|
||||||
if (!dtmf->tone) {
|
if (!dtmf->tone)
|
||||||
memset(samples, 0, length * sizeof(*samples));
|
return 0;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sine_low = dtmf->sine_low;
|
||||||
|
sine_high = dtmf->sine_high;
|
||||||
phaseshift = dtmf->phaseshift65536;
|
phaseshift = dtmf->phaseshift65536;
|
||||||
phase = dtmf->phase65536;
|
phase = dtmf->phase65536;
|
||||||
pos = dtmf->pos;
|
|
||||||
max = dtmf->max;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
*samples++ = dsp_sine_dtmf_low[(uint16_t)phase[0]]
|
*samples++ = sine_low[(uint16_t)phase[0]]
|
||||||
+ dsp_sine_dtmf_high[(uint16_t)phase[1]];
|
+ sine_high[(uint16_t)phase[1]];
|
||||||
phase[0] += phaseshift[0];
|
phase[0] += phaseshift[0];
|
||||||
if (phase[0] >= 65536)
|
if (phase[0] >= 65536.0)
|
||||||
phase[0] -= 65536;
|
phase[0] -= 65536.0;
|
||||||
phase[1] += phaseshift[1];
|
phase[1] += phaseshift[1];
|
||||||
if (phase[1] >= 65536)
|
if (phase[1] >= 65536.0)
|
||||||
phase[1] -= 65536;
|
phase[1] -= 65536.0;
|
||||||
|
|
||||||
|
dtmf->pos++;
|
||||||
/* tone ends */
|
/* tone ends */
|
||||||
if (++pos == max) {
|
if (dtmf->pos == dtmf->on) {
|
||||||
|
phaseshift[0] = 0.0;
|
||||||
|
phaseshift[1] = 0.0;
|
||||||
|
phase[0] = 0.0;
|
||||||
|
phase[1] = 0.0;
|
||||||
|
}
|
||||||
|
/* pause ends */
|
||||||
|
if (dtmf->pos == dtmf->off) {
|
||||||
dtmf->tone = 0;
|
dtmf->tone = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
length -= i;
|
count += i;
|
||||||
|
|
||||||
dtmf->pos = pos;
|
return count;
|
||||||
|
|
||||||
/* if tone ends, fill rest with silence */
|
|
||||||
if (length)
|
|
||||||
memset(samples, 0, length * sizeof(*samples));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,16 @@
|
||||||
typedef struct dtmf_enc {
|
typedef struct dtmf_enc {
|
||||||
int samplerate; /* samplerate */
|
int samplerate; /* samplerate */
|
||||||
char tone; /* current tone to be played */
|
char tone; /* current tone to be played */
|
||||||
|
int on, off; /* samples to turn on and afterwards off */
|
||||||
int pos; /* sample counter for tone */
|
int pos; /* sample counter for tone */
|
||||||
int max; /* max number of samples for tone duration */
|
int max; /* max number of samples for tone duration */
|
||||||
double phaseshift65536[2]; /* how much the phase of sine wave changes per sample */
|
double phaseshift65536[2]; /* how much the phase of sine wave changes per sample */
|
||||||
double phase65536[2]; /* current phase */
|
double phase65536[2]; /* current phase */
|
||||||
|
sample_t sine_low[65536]; /* sine tables at individual levels */
|
||||||
|
sample_t sine_high[65536];
|
||||||
} dtmf_enc_t;
|
} dtmf_enc_t;
|
||||||
|
|
||||||
void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level);
|
void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level);
|
||||||
void dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone);
|
int dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone, double on_duration, double off_duration);
|
||||||
void dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length);
|
int dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef _LIB_FM_H
|
||||||
|
#define _LIB_FM_H
|
||||||
|
|
||||||
#include "../libfilter/iir_filter.h"
|
#include "../libfilter/iir_filter.h"
|
||||||
|
|
||||||
int fm_init(int fast_math);
|
int fm_init(int fast_math);
|
||||||
|
@ -38,3 +41,4 @@ void fm_demod_exit(fm_demod_t *demod);
|
||||||
void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q);
|
void fm_demodulate_complex(fm_demod_t *demod, sample_t *frequency, int length, float *baseband, sample_t *I, sample_t *Q);
|
||||||
void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q);
|
void fm_demodulate_real(fm_demod_t *demod, sample_t *frequency, int length, sample_t *baseband, sample_t *I, sample_t *Q);
|
||||||
|
|
||||||
|
#endif /* _LIB_FM_H */
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef _LIB_FSK_H
|
||||||
|
#define _LIB_FSK_H
|
||||||
|
|
||||||
#include "../libfm/fm.h"
|
#include "../libfm/fm.h"
|
||||||
|
|
||||||
typedef struct fsk_mod {
|
typedef struct fsk_mod {
|
||||||
|
@ -41,3 +44,4 @@ int fsk_demod_init(fsk_demod_t *fsk, void *inst, void (*receive_bit)(void *inst,
|
||||||
void fsk_demod_cleanup(fsk_demod_t *fsk);
|
void fsk_demod_cleanup(fsk_demod_t *fsk);
|
||||||
void fsk_demod_receive(fsk_demod_t *fsk, sample_t *sample, int length);
|
void fsk_demod_receive(fsk_demod_t *fsk, sample_t *sample, int length);
|
||||||
|
|
||||||
|
#endif /* _LIB_FSK_H */
|
||||||
|
|
|
@ -356,16 +356,20 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at
|
||||||
|
|
||||||
if ((nmt->dsp_mode == DSP_MODE_AUDIO || nmt->dsp_mode == DSP_MODE_DTMF)
|
if ((nmt->dsp_mode == DSP_MODE_AUDIO || nmt->dsp_mode == DSP_MODE_DTMF)
|
||||||
&& nmt->trans && nmt->trans->callref) {
|
&& nmt->trans && nmt->trans->callref) {
|
||||||
int count;
|
int len, count;
|
||||||
|
|
||||||
count = samplerate_downsample(&nmt->sender.srstate, samples, length);
|
len = samplerate_downsample(&nmt->sender.srstate, samples, length);
|
||||||
if (nmt->compandor)
|
if (nmt->compandor)
|
||||||
expand_audio(&nmt->cstate, samples, count);
|
expand_audio(&nmt->cstate, samples, len);
|
||||||
if (nmt->dsp_mode == DSP_MODE_DTMF)
|
if (nmt->dsp_mode == DSP_MODE_DTMF) {
|
||||||
dtmf_encode(&nmt->dtmf, samples, count);
|
/* encode and fill with silence after finish */
|
||||||
|
count = dtmf_encode(&nmt->dtmf, samples, len);
|
||||||
|
if (count < len)
|
||||||
|
memset(samples + count, 0, sizeof(*samples) * (len - count));
|
||||||
|
}
|
||||||
spl = nmt->sender.rxbuf;
|
spl = nmt->sender.rxbuf;
|
||||||
pos = nmt->sender.rxbuf_pos;
|
pos = nmt->sender.rxbuf_pos;
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
spl[pos++] = samples[i];
|
spl[pos++] = samples[i];
|
||||||
if (pos == 160) {
|
if (pos == 160) {
|
||||||
call_up_audio(nmt->trans->callref, spl, 160);
|
call_up_audio(nmt->trans->callref, spl, 160);
|
||||||
|
|
|
@ -58,6 +58,7 @@ static int sms_ref = 0;
|
||||||
#define RINGING_TO 60.0 /* how long may the phone ring */
|
#define RINGING_TO 60.0 /* how long may the phone ring */
|
||||||
#define SUPERVISORY_TO1 3.0 /* 3 sec to detect after setup */
|
#define SUPERVISORY_TO1 3.0 /* 3 sec to detect after setup */
|
||||||
#define SUPERVISORY_TO2 20.0 /* 20 sec lost until abort */
|
#define SUPERVISORY_TO2 20.0 /* 20 sec lost until abort */
|
||||||
|
#define DTMF_DURATION 0.1 /* 100ms */
|
||||||
|
|
||||||
/* Counters */
|
/* Counters */
|
||||||
#define PAGE_TRIES 3 /* How many time do we try to page the phone */
|
#define PAGE_TRIES 3 /* How many time do we try to page the phone */
|
||||||
|
@ -1519,7 +1520,7 @@ static void rx_active(nmt_t *nmt, frame_t *frame)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
digit = nmt_value2digit(frame->digit);
|
digit = nmt_value2digit(frame->digit);
|
||||||
dtmf_encode_set_tone(&nmt->dtmf, digit);
|
dtmf_encode_set_tone(&nmt->dtmf, digit, DTMF_DURATION, 0.0);
|
||||||
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Received (odd) digit %c.\n", digit);
|
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Received (odd) digit %c.\n", digit);
|
||||||
nmt->mft_num++;
|
nmt->mft_num++;
|
||||||
break;
|
break;
|
||||||
|
@ -1542,7 +1543,7 @@ static void rx_active(nmt_t *nmt, frame_t *frame)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
digit = nmt_value2digit(frame->digit);
|
digit = nmt_value2digit(frame->digit);
|
||||||
dtmf_encode_set_tone(&nmt->dtmf, digit);
|
dtmf_encode_set_tone(&nmt->dtmf, digit, DTMF_DURATION, 0.0);
|
||||||
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Received (even) digit %c.\n", digit);
|
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Received (even) digit %c.\n", digit);
|
||||||
nmt->mft_num++;
|
nmt->mft_num++;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -96,7 +96,7 @@ int main(void)
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
printf("Testing digit '%c' encoding and decoding:\n", test_digits[i]);
|
printf("Testing digit '%c' encoding and decoding:\n", test_digits[i]);
|
||||||
memset(samples, 0, sizeof(samples[0]) * SAMPLERATE);
|
memset(samples, 0, sizeof(samples[0]) * SAMPLERATE);
|
||||||
dtmf_encode_set_tone(&dtmf_enc, test_digits[i]);
|
dtmf_encode_set_tone(&dtmf_enc, test_digits[i], 1.0, 0.0);
|
||||||
dtmf_encode(&dtmf_enc, samples + SAMPLERATE / 10, SAMPLERATE / 20);
|
dtmf_encode(&dtmf_enc, samples + SAMPLERATE / 10, SAMPLERATE / 20);
|
||||||
got_digit = 0;
|
got_digit = 0;
|
||||||
dtmf_decode(&dtmf_dec, samples, SAMPLERATE);
|
dtmf_decode(&dtmf_dec, samples, SAMPLERATE);
|
||||||
|
|
Loading…
Reference in New Issue