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:
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user