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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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_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_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)
|
||||
{
|
||||
|
@ -38,17 +34,15 @@ void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level)
|
|||
|
||||
memset(dtmf, 0, sizeof(*dtmf));
|
||||
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++) {
|
||||
dsp_sine_dtmf_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_low[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_LOW * dBm_level;
|
||||
dtmf->sine_high[i] = sin((double)i / 65536.0 * 2.0 * PI) * PEAK_DTMF_HIGH * dBm_level;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -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;
|
||||
default:
|
||||
dtmf->tone = 0;
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
dtmf->tone = tone;
|
||||
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[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. */
|
||||
void dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length)
|
||||
/* Generate audio stream from DTMF tone.
|
||||
* 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;
|
||||
int i, pos, max;
|
||||
sample_t *sine_low, *sine_high;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
/* use silence, if no tone */
|
||||
if (!dtmf->tone) {
|
||||
memset(samples, 0, length * sizeof(*samples));
|
||||
return;
|
||||
}
|
||||
/* if no tone */
|
||||
if (!dtmf->tone)
|
||||
return 0;
|
||||
|
||||
sine_low = dtmf->sine_low;
|
||||
sine_high = dtmf->sine_high;
|
||||
phaseshift = dtmf->phaseshift65536;
|
||||
phase = dtmf->phase65536;
|
||||
pos = dtmf->pos;
|
||||
max = dtmf->max;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
*samples++ = dsp_sine_dtmf_low[(uint16_t)phase[0]]
|
||||
+ dsp_sine_dtmf_high[(uint16_t)phase[1]];
|
||||
*samples++ = sine_low[(uint16_t)phase[0]]
|
||||
+ sine_high[(uint16_t)phase[1]];
|
||||
phase[0] += phaseshift[0];
|
||||
if (phase[0] >= 65536)
|
||||
phase[0] -= 65536;
|
||||
if (phase[0] >= 65536.0)
|
||||
phase[0] -= 65536.0;
|
||||
phase[1] += phaseshift[1];
|
||||
if (phase[1] >= 65536)
|
||||
phase[1] -= 65536;
|
||||
if (phase[1] >= 65536.0)
|
||||
phase[1] -= 65536.0;
|
||||
|
||||
dtmf->pos++;
|
||||
/* 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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
length -= i;
|
||||
count += i;
|
||||
|
||||
dtmf->pos = pos;
|
||||
|
||||
/* if tone ends, fill rest with silence */
|
||||
if (length)
|
||||
memset(samples, 0, length * sizeof(*samples));
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
typedef struct dtmf_enc {
|
||||
int samplerate; /* samplerate */
|
||||
char tone; /* current tone to be played */
|
||||
int on, off; /* samples to turn on and afterwards off */
|
||||
int pos; /* sample counter for tone */
|
||||
int max; /* max number of samples for tone duration */
|
||||
double phaseshift65536[2]; /* how much the phase of sine wave changes per sample */
|
||||
double phase65536[2]; /* current phase */
|
||||
sample_t sine_low[65536]; /* sine tables at individual levels */
|
||||
sample_t sine_high[65536];
|
||||
} dtmf_enc_t;
|
||||
|
||||
void dtmf_encode_init(dtmf_enc_t *dtmf, int samplerate, double dBm_level);
|
||||
void dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone);
|
||||
void dtmf_encode(dtmf_enc_t *dtmf, sample_t *samples, int length);
|
||||
int dtmf_encode_set_tone(dtmf_enc_t *dtmf, char tone, double on_duration, double off_duration);
|
||||
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"
|
||||
|
||||
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_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"
|
||||
|
||||
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_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)
|
||||
&& 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)
|
||||
expand_audio(&nmt->cstate, samples, count);
|
||||
if (nmt->dsp_mode == DSP_MODE_DTMF)
|
||||
dtmf_encode(&nmt->dtmf, samples, count);
|
||||
expand_audio(&nmt->cstate, samples, len);
|
||||
if (nmt->dsp_mode == DSP_MODE_DTMF) {
|
||||
/* 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;
|
||||
pos = nmt->sender.rxbuf_pos;
|
||||
for (i = 0; i < count; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
spl[pos++] = samples[i];
|
||||
if (pos == 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 SUPERVISORY_TO1 3.0 /* 3 sec to detect after setup */
|
||||
#define SUPERVISORY_TO2 20.0 /* 20 sec lost until abort */
|
||||
#define DTMF_DURATION 0.1 /* 100ms */
|
||||
|
||||
/* Counters */
|
||||
#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;
|
||||
}
|
||||
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);
|
||||
nmt->mft_num++;
|
||||
break;
|
||||
|
@ -1542,7 +1543,7 @@ static void rx_active(nmt_t *nmt, frame_t *frame)
|
|||
break;
|
||||
}
|
||||
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);
|
||||
nmt->mft_num++;
|
||||
break;
|
||||
|
|
|
@ -96,7 +96,7 @@ int main(void)
|
|||
for (i = 0; i < 16; i++) {
|
||||
printf("Testing digit '%c' encoding and decoding:\n", test_digits[i]);
|
||||
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);
|
||||
got_digit = 0;
|
||||
dtmf_decode(&dtmf_dec, samples, SAMPLERATE);
|
||||
|
|
Loading…
Reference in New Issue