update teletone see wiki for syntax changes in TTML

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5276 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2007-06-06 23:28:00 +00:00
parent 32bdf10952
commit 88fdfab48f
4 changed files with 269 additions and 163 deletions

View File

@ -90,7 +90,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <math.h> #include <libteletone_detect.h>
#ifndef _MSC_VER #ifndef _MSC_VER
#include <stdint.h> #include <stdint.h>
#endif #endif
@ -98,7 +99,7 @@
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <fcntl.h> #include <fcntl.h>
#include <libteletone_detect.h>
static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]; static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR];
static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]; static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR];

View File

@ -98,11 +98,11 @@ extern "C" {
#endif #endif
#include <libteletone.h> #include <libteletone.h>
/*! \file libteletone_detect.h /*! \file libteletone_detect.h
\brief Tone Detection Routines \brief Tone Detection Routines
This module is responsible for tone detection specifics This module is responsible for tone detection specifics
*/ */
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
@ -111,7 +111,7 @@ extern "C" {
#endif #endif
#endif #endif
/* Basic DTMF specs: /* Basic DTMF specs:
* *
* Minimum tone on = 40ms * Minimum tone on = 40ms
* Minimum tone off = 50ms * Minimum tone off = 50ms
@ -134,15 +134,15 @@ extern "C" {
#define BLOCK_LEN 102 #define BLOCK_LEN 102
#define M_TWO_PI 2.0*M_PI #define M_TWO_PI 2.0*M_PI
/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */ /*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
typedef struct { typedef struct {
teletone_process_t v2; teletone_process_t v2;
teletone_process_t v3; teletone_process_t v3;
teletone_process_t fac; teletone_process_t fac;
} teletone_goertzel_state_t; } teletone_goertzel_state_t;
/*! \brief A container for a DTMF detection state.*/ /*! \brief A container for a DTMF detection state.*/
typedef struct { typedef struct {
int hit1; int hit1;
int hit2; int hit2;
int hit3; int hit3;
@ -161,18 +161,18 @@ typedef struct {
int detected_digits; int detected_digits;
int lost_digits; int lost_digits;
int digit_hits[16]; int digit_hits[16];
} teletone_dtmf_detect_state_t; } teletone_dtmf_detect_state_t;
/*! \brief An abstraction to store the coefficient of a tone frequency */ /*! \brief An abstraction to store the coefficient of a tone frequency */
typedef struct { typedef struct {
teletone_process_t fac; teletone_process_t fac;
} teletone_detection_descriptor_t; } teletone_detection_descriptor_t;
/*! \brief A container for a single multi-tone detection /*! \brief A container for a single multi-tone detection
TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
in a multi-tone representation. in a multi-tone representation.
*/ */
typedef struct { typedef struct {
int sample_rate; int sample_rate;
teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES]; teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
@ -194,71 +194,71 @@ typedef struct {
int negative_factor; int negative_factor;
int hit_factor; int hit_factor;
} teletone_multi_tone_t; } teletone_multi_tone_t;
/*! /*!
\brief Initilize a multi-frequency tone detector \brief Initilize a multi-frequency tone detector
\param mt the multi-frequency tone descriptor \param mt the multi-frequency tone descriptor
\param map a representation of the multi-frequency tone \param map a representation of the multi-frequency tone
*/ */
void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map); void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
/*! /*!
\brief Check a sample buffer for the presence of the mulit-frequency tone described by mt \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
\param mt the multi-frequency tone descriptor \param mt the multi-frequency tone descriptor
\param sample_buffer an array aof 16 bit signed linear samples \param sample_buffer an array aof 16 bit signed linear samples
\param samples the number of samples present in sample_buffer \param samples the number of samples present in sample_buffer
\return true when the tone was detected or false when it is not \return true when the tone was detected or false when it is not
*/ */
int teletone_multi_tone_detect (teletone_multi_tone_t *mt, int teletone_multi_tone_detect (teletone_multi_tone_t *mt,
int16_t sample_buffer[], int16_t sample_buffer[],
int samples); int samples);
/*! /*!
\brief Initilize a DTMF detection state object \brief Initilize a DTMF detection state object
\param dtmf_detect_state the DTMF detection state to initilize \param dtmf_detect_state the DTMF detection state to initilize
\param sample_rate the desired sample rate \param sample_rate the desired sample rate
*/ */
void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate); void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
/*! /*!
\brief Check a sample buffer for the presence of DTMF digits \brief Check a sample buffer for the presence of DTMF digits
\param dtmf_detect_state the detection state object to check \param dtmf_detect_state the detection state object to check
\param sample_buffer an array aof 16 bit signed linear samples \param sample_buffer an array aof 16 bit signed linear samples
\param samples the number of samples present in sample_buffer \param samples the number of samples present in sample_buffer
\return true when DTMF was detected or false when it is not \return true when DTMF was detected or false when it is not
*/ */
int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state, int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
int16_t sample_buffer[], int16_t sample_buffer[],
int samples); int samples);
/*! /*!
\brief retrieve any collected digits into a string buffer \brief retrieve any collected digits into a string buffer
\param dtmf_detect_state the detection state object to check \param dtmf_detect_state the detection state object to check
\param buf the string buffer to write to \param buf the string buffer to write to
\param max the maximum length of buf \param max the maximum length of buf
\return the number of characters written to buf \return the number of characters written to buf
*/ */
int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
char *buf, char *buf,
int max); int max);
/*! /*!
\brief Step through the Goertzel Algorithm for each sample in a buffer \brief Step through the Goertzel Algorithm for each sample in a buffer
\param goertzel_state the goertzel state to step the samples through \param goertzel_state the goertzel state to step the samples through
\param sample_buffer an array aof 16 bit signed linear samples \param sample_buffer an array aof 16 bit signed linear samples
\param samples the number of samples present in sample_buffer \param samples the number of samples present in sample_buffer
*/ */
void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state, void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
int16_t sample_buffer[], int16_t sample_buffer[],
int samples); int samples);
/*! /*!
\brief Compute the result of the last applied step of the Goertzel Algorithm \brief Compute the result of the last applied step of the Goertzel Algorithm
\param goertzel_state the goertzel state to retrieve from \param goertzel_state the goertzel state to retrieve from
\return the computed value for consideration in furthur audio tests \return the computed value for consideration in furthur audio tests
*/ */
teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state); teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state);

View File

@ -70,6 +70,7 @@
*/ */
#include <libteletone.h> #include <libteletone.h>
#define SMAX 32767 #define SMAX 32767
#define SMIN -32768 #define SMIN -32768
#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN; #define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
@ -78,6 +79,25 @@
#pragma warning(disable:4706) #pragma warning(disable:4706)
#endif #endif
int16_t TELETONE_SINES[SINE_TABLE_MAX] = {
0x00c9, 0x025b, 0x03ed, 0x057f, 0x0711, 0x08a2, 0x0a33, 0x0bc4,
0x0d54, 0x0ee4, 0x1073, 0x1201, 0x138f, 0x151c, 0x16a8, 0x1833,
0x19be, 0x1b47, 0x1cd0, 0x1e57, 0x1fdd, 0x2162, 0x22e5, 0x2467,
0x25e8, 0x2768, 0x28e5, 0x2a62, 0x2bdc, 0x2d55, 0x2ecc, 0x3042,
0x31b5, 0x3327, 0x3497, 0x3604, 0x3770, 0x38d9, 0x3a40, 0x3ba5,
0x3d08, 0x3e68, 0x3fc6, 0x4121, 0x427a, 0x43d1, 0x4524, 0x4675,
0x47c4, 0x490f, 0x4a58, 0x4b9e, 0x4ce1, 0x4e21, 0x4f5e, 0x5098,
0x51cf, 0x5303, 0x5433, 0x5560, 0x568a, 0x57b1, 0x58d4, 0x59f4,
0x5b10, 0x5c29, 0x5d3e, 0x5e50, 0x5f5e, 0x6068, 0x616f, 0x6272,
0x6371, 0x646c, 0x6564, 0x6657, 0x6747, 0x6832, 0x691a, 0x69fd,
0x6add, 0x6bb8, 0x6c8f, 0x6d62, 0x6e31, 0x6efb, 0x6fc2, 0x7083,
0x7141, 0x71fa, 0x72af, 0x735f, 0x740b, 0x74b3, 0x7556, 0x75f4,
0x768e, 0x7723, 0x77b4, 0x7840, 0x78c8, 0x794a, 0x79c9, 0x7a42,
0x7ab7, 0x7b27, 0x7b92, 0x7bf9, 0x7c5a, 0x7cb7, 0x7d0f, 0x7d63,
0x7db1, 0x7dfb, 0x7e3f, 0x7e7f, 0x7eba, 0x7ef0, 0x7f22, 0x7f4e,
0x7f75, 0x7f98, 0x7fb5, 0x7fce, 0x7fe2, 0x7ff1, 0x7ffa, 0x7fff
};
int teletone_set_tone(teletone_generation_session_t *ts, int index, ...) int teletone_set_tone(teletone_generation_session_t *ts, int index, ...)
{ {
@ -122,8 +142,9 @@ int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_ha
ts->tmp_wait = -1; ts->tmp_wait = -1;
ts->handler = handler; ts->handler = handler;
ts->user_data = user_data; ts->user_data = user_data;
ts->volume = 1500; ts->volume = -7;
ts->decay_step = 0; ts->decay_step = 0;
ts->decay_factor = 1;
if (buflen) { if (buflen) {
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) { if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
return -1; return -1;
@ -181,34 +202,24 @@ static int ensure_buffer(teletone_generation_session_t *ts, int need)
int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map) int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
{ {
teletone_process_t period = (1.0 / ts->rate) / ts->channels; /*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
int i, c; int i, c;
int freqlen = 0; int freqlen = 0;
teletone_process_t tones[TELETONE_MAX_TONES]; teletone_dds_state_t tones[TELETONE_MAX_TONES];
int decay = 0; //int decay = 0;
int duration; int duration;
int wait = 0; int wait = 0;
teletone_process_t sample; int32_t sample;
int32_t dc = 0;
float vol = ts->volume;
ts->samples = 0; ts->samples = 0;
memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration; duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait; wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
if (map->freqs[0] > 0) { if (map->freqs[0] > 0) {
if (ts->decay_step) {
if (ts->decay_factor) {
decay = (duration - (duration / ts->decay_factor));
} else {
decay = 0;
}
}
if (ts->volume < 0) {
ts->volume = 0;
}
for (freqlen = 0; map->freqs[freqlen] && freqlen < TELETONE_MAX_TONES; freqlen++) { for (freqlen = 0; map->freqs[freqlen] && freqlen < TELETONE_MAX_TONES; freqlen++) {
tones[freqlen] = (teletone_process_t) map->freqs[freqlen] * (2 * M_PI); teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, vol);
} }
if (ts->channels > 1) { if (ts->channels > 1) {
@ -220,17 +231,28 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
return -1; return -1;
} }
} }
for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) { for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
if (ts->decay_step && !(ts->samples % ts->decay_step) && ts->volume > 0 && ts->samples > decay) { if (ts->decay_direction && ++dc >= ts->decay_step) {
ts->volume += ts->decay_direction; float nvol = vol + ts->decay_direction * ts->decay_factor;
int j;
if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
vol = nvol;
for (j = 0; map->freqs[j] && j < TELETONE_MAX_TONES; j++) {
teletone_dds_state_set_tx_level(&tones[j], vol);
}
dc = 0;
}
} }
sample = (teletone_process_t) 128; sample = 128;
for (i = 0; i < freqlen; i++) { for (i = 0; i < freqlen; i++) {
sample += ((teletone_process_t) 2 * (ts->volume > 0 ? ts->volume : 1) * cos(tones[i] * ts->samples * period)); int32_t s = teletone_dds_modulate_sample(&tones[i]);
sample += s;
} }
normalize_to_16bit(sample); sample /= freqlen;
ts->buffer[ts->samples] = (teletone_audio_t)sample; ts->buffer[ts->samples] = (teletone_audio_t)sample;
for (c = 1; c < ts->channels; c++) { for (c = 1; c < ts->channels; c++) {
@ -261,7 +283,8 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]); fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
} }
fprintf(ts->debug_stream, ") [volume %d; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %d; decay_step %d; wrote %d bytes]\n", fprintf(ts->debug_stream,
") [volume %0.2fDb; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2f; decay_step %d(%dms); wrote %d bytes]\n",
ts->volume, ts->volume,
duration, duration,
duration / (ts->rate / 1000), duration / (ts->rate / 1000),
@ -271,6 +294,7 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
wait / (ts->rate / 1000), wait / (ts->rate / 1000),
ts->decay_factor, ts->decay_factor,
ts->decay_step, ts->decay_step,
ts->decay_step / (ts->rate / 1000),
ts->samples * 2); ts->samples * 2);
} }
} }
@ -330,18 +354,23 @@ int teletone_run(teletone_generation_session_t *ts, char *cmd)
ts->duration = atoi(cur + 2) * (ts->rate / 1000); ts->duration = atoi(cur + 2) * (ts->rate / 1000);
break; break;
case 'v': case 'v':
ts->volume = atoi(cur + 2); {
float vol = atof(cur + 2);
if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
ts->volume = vol;
}
}
break; break;
case '>': case '>':
ts->decay_factor = atoi(cur + 2); ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
ts->decay_direction = -1; ts->decay_direction = -1;
break; break;
case '<': case '<':
ts->decay_factor = atoi(cur + 2); ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
ts->decay_direction = 1; ts->decay_direction = 1;
break; break;
case '+': case '+':
ts->decay_step = atoi(cur + 2); ts->decay_factor = atof(cur + 2);
break; break;
case 'w': case 'w':
ts->wait = atoi(cur + 2) * (ts->rate / 1000); ts->wait = atoi(cur + 2) * (ts->rate / 1000);

View File

@ -72,13 +72,30 @@
#define LIBTELETONE_GENERATE_H #define LIBTELETONE_GENERATE_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#ifdef _doh
}
#endif #endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#if !defined(powf)
extern float powf (float, float);
#endif
#include <string.h>
#include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h>
#ifndef _MSC_VER #ifndef _MSC_VER
#include <unistd.h> #include <unistd.h>
#include <stdint.h>
#endif #endif
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
@ -87,6 +104,65 @@ extern "C" {
#include <stdarg.h> #include <stdarg.h>
#include <libteletone.h> #include <libteletone.h>
#define TELETONE_VOL_DB_MAX 0
#define TELETONE_VOL_DB_MIN -63
struct teletone_dds_state {
uint32_t phase_rate;
uint32_t scale_factor;
uint32_t phase_accumulator;
int16_t sample;
float tx_level;
};
typedef struct teletone_dds_state teletone_dds_state_t;
#define SINE_TABLE_MAX 128
#define SINE_TABLE_LEN (SINE_TABLE_MAX - 1)
#define MAX_PHASE_ACCUMULATOR 0x10000 * 0x10000
/* 3.14 == the max power on ulaw (alaw is 3.17) */
/* 3.02 represents twice the power */
#define DBM0_MAX_POWER (3.14f + 3.02f)
extern int16_t TELETONE_SINES[SINE_TABLE_MAX];
static __inline__ int16_t teletone_dds_modulate_sample(teletone_dds_state_t *dds)
{
int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
int16_t sample;
if (bitmask & SINE_TABLE_MAX) {
sine_index = SINE_TABLE_LEN - sine_index;
}
sample = TELETONE_SINES[sine_index];
if (bitmask & (SINE_TABLE_MAX * 2)) {
sample *= -1;
}
dds->phase_accumulator += dds->phase_rate;
return (int16_t) (sample * dds->scale_factor >> 15);
}
static __inline__ void teletone_dds_state_set_tone(teletone_dds_state_t *dds, float tone, uint32_t rate, float tx_level)
{
dds->phase_accumulator = 0;
dds->phase_rate = (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
if (dds->tx_level != tx_level || !dds->scale_factor) {
dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
}
dds->tx_level = tx_level;
}
static __inline__ void teletone_dds_state_set_tx_level(teletone_dds_state_t *dds, float tx_level)
{
dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
}
/*! \file libteletone_generate.h /*! \file libteletone_generate.h
@ -120,13 +196,13 @@ struct teletone_generation_session {
/*! Number of loops to repeat the entire set of instructions*/ /*! Number of loops to repeat the entire set of instructions*/
int LOOPS; int LOOPS;
/*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */ /*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */
int decay_factor; float decay_factor;
/*! Direction to perform volume increase/decrease 1/-1*/ /*! Direction to perform volume increase/decrease 1/-1*/
int decay_direction; int decay_direction;
/*! Number of samples between increase/decrease of volume */ /*! Number of samples between increase/decrease of volume */
int decay_step; int decay_step;
/*! Volume factor of the tone */ /*! Volume factor of the tone */
int volume; float volume;
/*! Debug on/off */ /*! Debug on/off */
int debug; int debug;
/*! FILE stream to write debug data to */ /*! FILE stream to write debug data to */