libteletone_generate.h File Reference

Tone Generation Routines. More...

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <libteletone.h>

Include dependency graph for libteletone_generate.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  teletone_dds_state
struct  teletone_generation_session
 An abstraction to store a tone generation session. More...

Defines

#define TELETONE_VOL_DB_MAX   0
#define TELETONE_VOL_DB_MIN   -63
#define MAX_PHASE_TONES   4
#define SINE_TABLE_MAX   128
#define SINE_TABLE_LEN   (SINE_TABLE_MAX - 1)
#define MAX_PHASE_ACCUMULATOR   0x10000 * 0x10000
#define DBM0_MAX_POWER   (3.14f + 3.02f)

Typedefs

typedef teletone_dds_state teletone_dds_state_t
typedef int16_t teletone_audio_t
typedef int(*) tone_handler (struct teletone_generation_session *ts, teletone_tone_map_t *map)
typedef teletone_generation_session teletone_generation_session_t

Functions

float powf (float, float)
static __inline__ int32_t teletone_dds_phase_rate (teletone_process_t tone, uint32_t rate)
static __inline__ int16_t teletone_dds_state_modulate_sample (teletone_dds_state_t *dds, uint32_t pindex)
static __inline__ void teletone_dds_state_set_tx_level (teletone_dds_state_t *dds, float tx_level)
static __inline__ void teletone_dds_state_reset_accum (teletone_dds_state_t *dds)
static __inline__ int teletone_dds_state_set_tone (teletone_dds_state_t *dds, teletone_process_t tone, uint32_t rate, uint32_t pindex)
int teletone_set_tone (teletone_generation_session_t *ts, int index,...)
 Assign a set of tones to a tone_session indexed by a paticular index/character.
int teletone_set_map (teletone_tone_map_t *map,...)
 Assign a set of tones to a single tone map.
int teletone_init_session (teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data)
 Initilize a tone generation session.
int teletone_destroy_session (teletone_generation_session_t *ts)
 Free the buffer allocated by a tone generation session.
int teletone_mux_tones (teletone_generation_session_t *ts, teletone_tone_map_t *map)
 Execute a single tone generation instruction.
int teletone_run (teletone_generation_session_t *ts, const char *cmd)
 Execute a tone generation script and call callbacks after each instruction.

Variables

int16_t TELETONE_SINES [SINE_TABLE_MAX]


Detailed Description

Tone Generation Routines.

This module is responsible for tone generation specifics

Definition in file libteletone_generate.h.


Define Documentation

#define DBM0_MAX_POWER   (3.14f + 3.02f)

Definition at line 138 of file libteletone_generate.h.

Referenced by teletone_dds_state_set_tx_level().

#define MAX_PHASE_ACCUMULATOR   0x10000 * 0x10000

Definition at line 135 of file libteletone_generate.h.

Referenced by teletone_dds_phase_rate().

#define MAX_PHASE_TONES   4

Definition at line 123 of file libteletone_generate.h.

Referenced by teletone_dds_state_modulate_sample(), and teletone_dds_state_set_tone().

#define SINE_TABLE_LEN   (SINE_TABLE_MAX - 1)

Definition at line 134 of file libteletone_generate.h.

Referenced by teletone_dds_state_modulate_sample().

#define SINE_TABLE_MAX   128

Definition at line 133 of file libteletone_generate.h.

Referenced by teletone_dds_state_modulate_sample().

#define TELETONE_VOL_DB_MAX   0

Definition at line 121 of file libteletone_generate.h.

#define TELETONE_VOL_DB_MIN   -63

Definition at line 122 of file libteletone_generate.h.

Referenced by teletone_run().


Typedef Documentation

typedef int16_t teletone_audio_t

Definition at line 199 of file libteletone_generate.h.

typedef struct teletone_dds_state teletone_dds_state_t

Definition at line 131 of file libteletone_generate.h.

typedef struct teletone_generation_session teletone_generation_session_t

Definition at line 248 of file libteletone_generate.h.

typedef int(*) tone_handler(struct teletone_generation_session *ts, teletone_tone_map_t *map)

Definition at line 201 of file libteletone_generate.h.


Function Documentation

float powf ( float  ,
float   
)

Referenced by teletone_dds_state_set_tx_level().

static __inline__ int32_t teletone_dds_phase_rate ( teletone_process_t  tone,
uint32_t  rate 
) [static]

Definition at line 142 of file libteletone_generate.h.

References MAX_PHASE_ACCUMULATOR.

Referenced by teletone_dds_state_set_tone().

00143 {
00144         return (int32_t) ((tone * MAX_PHASE_ACCUMULATOR) / rate);
00145 }

static __inline__ int16_t teletone_dds_state_modulate_sample ( teletone_dds_state_t dds,
uint32_t  pindex 
) [static]

Definition at line 147 of file libteletone_generate.h.

References MAX_PHASE_TONES, teletone_dds_state::phase_accumulator, teletone_dds_state::phase_rate, teletone_dds_state::scale_factor, SINE_TABLE_LEN, SINE_TABLE_MAX, and TELETONE_SINES.

00148 {
00149         int32_t bitmask = dds->phase_accumulator, sine_index = (bitmask >>= 23) & SINE_TABLE_LEN;
00150         int16_t sample;
00151 
00152         if (pindex >= MAX_PHASE_TONES)  {
00153                 pindex = 0;
00154         }
00155 
00156         if (bitmask & SINE_TABLE_MAX) {
00157                 sine_index = SINE_TABLE_LEN - sine_index;
00158         }
00159 
00160         sample = TELETONE_SINES[sine_index];
00161         
00162         if (bitmask & (SINE_TABLE_MAX * 2)) {
00163                 sample *= -1;
00164         }
00165 
00166         dds->phase_accumulator += dds->phase_rate[pindex];
00167         return (int16_t) (sample * dds->scale_factor >> 15);
00168 }

static __inline__ void teletone_dds_state_reset_accum ( teletone_dds_state_t dds  )  [static]

Definition at line 176 of file libteletone_generate.h.

References teletone_dds_state::phase_accumulator.

00177 {
00178         dds->phase_accumulator = 0;
00179 }

static __inline__ int teletone_dds_state_set_tone ( teletone_dds_state_t dds,
teletone_process_t  tone,
uint32_t  rate,
uint32_t  pindex 
) [static]

Definition at line 181 of file libteletone_generate.h.

References MAX_PHASE_TONES, teletone_dds_state::phase_rate, and teletone_dds_phase_rate().

Referenced by teletone_mux_tones().

00182 {
00183         if (pindex < MAX_PHASE_TONES)  {
00184                 dds->phase_rate[pindex] = teletone_dds_phase_rate(tone, rate);
00185                 return 0;
00186         }
00187         
00188         return -1;
00189 }

static __inline__ void teletone_dds_state_set_tx_level ( teletone_dds_state_t dds,
float  tx_level 
) [static]

Definition at line 170 of file libteletone_generate.h.

References DBM0_MAX_POWER, powf(), teletone_dds_state::scale_factor, and teletone_dds_state::tx_level.

Referenced by teletone_mux_tones().

00171 {
00172         dds->scale_factor = (int) (powf(10.0f, (tx_level - DBM0_MAX_POWER) / 20.0f) * (32767.0f * 1.414214f));
00173         dds->tx_level = tx_level;
00174 }

int teletone_destroy_session ( teletone_generation_session_t ts  ) 

Free the buffer allocated by a tone generation session.

Parameters:
ts the tone generation session to destroy
Returns:
0

Definition at line 177 of file libteletone_generate.c.

Referenced by inband_dtmf_generate_callback(), main(), setup_ringback(), switch_ivr_gentones(), and switch_ivr_wait_for_answer().

00178 {
00179         if (ts->buffer) {
00180                 free(ts->buffer);
00181                 ts->buffer = NULL;
00182                 ts->samples = 0;
00183         }
00184         return 0;
00185 }

int teletone_init_session ( teletone_generation_session_t ts,
int  buflen,
tone_handler  handler,
void *  user_data 
)

Initilize a tone generation session.

Parameters:
ts the tone generation session to initilize
buflen the size of the buffer(in samples) to dynamically allocate
handler a callback function to execute when a tone generation instruction is complete
user_data optional user data to send
Returns:
0

Definition at line 134 of file libteletone_generate.c.

References teletone_set_tone().

Referenced by inband_dtmf_generate_callback(), main(), setup_ringback(), switch_ivr_gentones(), and switch_ivr_wait_for_answer().

00135 {
00136         memset(ts, 0, sizeof(*ts));
00137         ts->rate = 8000;
00138         ts->channels = 1;
00139         ts->duration = 2000;
00140         ts->wait = 500;
00141         ts->tmp_duration = -1;
00142         ts->tmp_wait = -1;
00143         ts->handler = handler;
00144         ts->user_data = user_data;
00145         ts->volume = -7;
00146         ts->decay_step = 0;
00147         ts->decay_factor = 1;
00148         if (buflen) {
00149                 if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
00150                         return -1;
00151                 }
00152                 ts->datalen = buflen;
00153         } else {
00154                 ts->dynamic = 1024;
00155         }
00156         /* Add Standard DTMF Tones */
00157         teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
00158         teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
00159         teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0);
00160         teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0);
00161         teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0);
00162         teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0);
00163         teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0);
00164         teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0);
00165         teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0);
00166         teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0);
00167         teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0);
00168         teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0);
00169         teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0);
00170         teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0);
00171         teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0);
00172         teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0);
00173         
00174         return 0;
00175 }

int teletone_mux_tones ( teletone_generation_session_t ts,
teletone_tone_map_t map 
)

Execute a single tone generation instruction.

Parameters:
ts the tone generation session to consult for parameters
map the tone mapping to use for the frequencies
Returns:
0

Definition at line 206 of file libteletone_generate.c.

References ensure_buffer(), teletone_dds_state_set_tone(), teletone_dds_state_set_tx_level(), and TELETONE_MAX_TONES.

Referenced by teletone_dtmf_generate_handler(), and teletone_handler().

00207 {
00208         /*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
00209         int i, c;
00210         int freqlen = 0;
00211         teletone_dds_state_t tones[TELETONE_MAX_TONES+1];
00212         //int decay = 0;
00213         int duration;
00214         int wait = 0;
00215         int32_t sample;
00216         int32_t dc = 0;
00217         float vol = ts->volume;
00218         ts->samples = 0;
00219         memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
00220         duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
00221         wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
00222 
00223         if (map->freqs[0] > 0) {
00224                 for (freqlen = 0; freqlen < TELETONE_MAX_TONES && map->freqs[freqlen]; freqlen++) {
00225                         teletone_dds_state_set_tone(&tones[freqlen], map->freqs[freqlen], ts->rate, 0);
00226                         teletone_dds_state_set_tx_level(&tones[freqlen], vol);
00227                 }
00228         
00229                 if (ts->channels > 1) {
00230                         duration *= ts->channels;
00231                 }
00232 
00233                 if (ts->dynamic) {
00234                         if (ensure_buffer(ts, duration)) {
00235                                 return -1;
00236                         }
00237                 }
00238 
00239                 for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
00240                         if (ts->decay_direction && ++dc >= ts->decay_step) {
00241                                 float nvol = vol + ts->decay_direction * ts->decay_factor;
00242                                 int j;
00243 
00244                                 if (nvol <= TELETONE_VOL_DB_MAX && nvol >= TELETONE_VOL_DB_MIN) {
00245                                         vol = nvol;
00246                                         for (j = 0; j < TELETONE_MAX_TONES && map->freqs[j]; j++) {                                     
00247                                                 teletone_dds_state_set_tx_level(&tones[j], vol);
00248                                         }
00249                                         dc = 0;
00250                                 }
00251                         }
00252 
00253                         sample = 128;
00254 
00255                         for (i = 0; i < freqlen; i++) {
00256                                 int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0);
00257                                 sample += s;
00258                         }
00259                         sample /= freqlen;
00260                         ts->buffer[ts->samples] = (teletone_audio_t)sample;
00261                         
00262                         for (c = 1; c < ts->channels; c++) {
00263                                 ts->buffer[ts->samples+1] = ts->buffer[ts->samples];
00264                                 ts->samples++;
00265                         }
00266                         
00267                 }
00268         }
00269         if (ts->dynamic) {
00270                 if (ensure_buffer(ts, wait)) {
00271                         return -1;
00272                 }
00273         }
00274         for (c = 0; c < ts->channels; c++) {
00275                 for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
00276                         ts->buffer[ts->samples++] = 0;
00277                 }
00278         }
00279 
00280         if (ts->debug && ts->debug_stream) {
00281                 if (map->freqs[0] <= 0) {
00282                         fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000));
00283                 } else {
00284                         fprintf(ts->debug_stream, "Generate: (");
00285 
00286                         for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) {
00287                                 fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]);
00288                         }
00289                          
00290                         fprintf(ts->debug_stream, 
00291                                         ") [volume %0.2fdB; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %0.2fdB; decay_step %d(%dms); wrote %d bytes]\n",
00292                                         ts->volume,
00293                                         duration,
00294                                         duration / (ts->rate / 1000), 
00295                                         ts->channels,
00296                                         ts->channels == 1 ? "" : "s",
00297                                         wait,
00298                                         wait / (ts->rate / 1000),
00299                                         ts->decay_factor,
00300                                         ts->decay_step,
00301                                         ts->decay_step / (ts->rate / 1000),                                     
00302                                         ts->samples * 2);
00303                 }
00304         }       
00305         return ts->samples / ts->channels;
00306 }

int teletone_run ( teletone_generation_session_t ts,
const char *  cmd 
)

Execute a tone generation script and call callbacks after each instruction.

Parameters:
ts the tone generation session to execute on
cmd the script to execute
Returns:
0

Definition at line 321 of file libteletone_generate.c.

References teletone_tone_map_t::freqs, my_strdup(), TELETONE_MAX_TONES, TELETONE_TONE_RANGE, and TELETONE_VOL_DB_MIN.

Referenced by inband_dtmf_generate_callback(), main(), setup_ringback(), switch_ivr_gentones(), and switch_ivr_wait_for_answer().

00322 {
00323         char *data = NULL, *cur = NULL, *end = NULL;
00324         int LOOPING = 0;
00325         
00326         if (!cmd) {
00327                 return -1;
00328         }
00329 
00330         do {
00331                 if (!(data = my_strdup(cmd))) {
00332                         return -1;
00333                 }
00334 
00335                 cur = data;
00336 
00337                 while (*cur) {
00338                         if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
00339                                 cur++;
00340                                 continue;
00341                         }
00342 
00343                         if ((end = strchr(cur, ';')) != 0) {
00344                                 *end++ = '\0';
00345                         }
00346                         
00347                         if (*(cur + 1) == '=') {
00348                                 switch(*cur) {
00349                                 case 'c':
00350                                         ts->channels = atoi(cur + 2);
00351                                         break;
00352                                 case 'r':
00353                                         ts->rate = atoi(cur + 2);
00354                                         break;
00355                                 case 'd':
00356                                         ts->duration = atoi(cur + 2) * (ts->rate / 1000);
00357                                         break;
00358                                 case 'v':
00359                                         {
00360                                                 float vol = (float)atof(cur + 2);
00361                                                 if (vol <= TELETONE_VOL_DB_MAX && vol >= TELETONE_VOL_DB_MIN) {
00362                                                         ts->volume = vol;
00363                                                 }
00364                                         }
00365                                         break;
00366                                 case '>':
00367                                         ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
00368                                         ts->decay_direction = -1;
00369                                         break;
00370                                 case '<':
00371                                         ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
00372                                         ts->decay_direction = 1;
00373                                         break;
00374                                 case '+':
00375                                         ts->decay_factor = (float)atof(cur + 2);
00376                                         break;
00377                                 case 'w':
00378                                         ts->wait = atoi(cur + 2) * (ts->rate / 1000);
00379                                         break;
00380                                 case 'l':
00381                                         ts->loops = atoi(cur + 2); 
00382                                         break;
00383                                 case 'L':
00384                                         if (!LOOPING) {
00385                                                 ts->LOOPS = atoi(cur + 2); 
00386                                         }
00387                                         LOOPING++;
00388                                         break;
00389                                 }
00390                         } else {
00391                                 while (*cur) {
00392                                         char *p = NULL, *e = NULL;
00393                                         teletone_tone_map_t mymap, *mapp = NULL;
00394 
00395                                         if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
00396                                                 cur++;
00397                                                 continue;
00398                                         }
00399                                         
00400                                         ts->tmp_duration = -1;
00401                                         ts->tmp_wait = -1;
00402 
00403                                         memset(&mymap, 0, sizeof(mymap));
00404 
00405                                         if (*(cur + 1) == '(') {
00406                                                 p = cur + 2;
00407                                                 if (*cur) {
00408                                                         char *next;
00409                                                         int i = 0;
00410                                                         if ((e = strchr(p, ')')) != 0) {
00411                                                                 *e++ = '\0';
00412                                                         }
00413                                                         do {
00414                                                                 if (!p) {
00415                                                                         break;
00416                                                                 }
00417                                                                 if ((next = strchr(p, ',')) != 0) {
00418                                                                         *next++ = '\0';
00419                                                                 }
00420                                                                 if (i == 0) {
00421                                                                         ts->tmp_duration = atoi(p) * (ts->rate / 1000);
00422                                                                         i++;
00423                                                                 } else if (i == 1) {
00424                                                                         ts->tmp_wait = atoi(p) * (ts->rate / 1000);
00425                                                                         i++;
00426                                                                 } else {
00427                                                                         mymap.freqs[i++ - 2] = atof(p);
00428                                                                 }
00429                                                                 p = next;
00430 
00431                                                         } while (next && (i-2) < TELETONE_MAX_TONES);
00432                                                         if (i > 2 && *cur == '%') {
00433                                                                 mapp = &mymap;
00434                                                         } else if ((i != 2 || *cur == '%')) { 
00435                                                                 if (ts->debug && ts->debug_stream) {
00436                                                                         fprintf(ts->debug_stream, "Syntax Error!\n");
00437                                                                 }
00438                                                                 goto bottom;
00439                                                         }
00440                                                 } 
00441                                         }
00442 
00443                                         if (*cur && !mapp) {
00444                                                 if (*cur > 0 && *cur < TELETONE_TONE_RANGE) { 
00445                                                         mapp = &ts->TONES[(int)*cur];
00446                                                 } else if (ts->debug && ts->debug_stream) {
00447                                                         fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur);
00448                                                 }
00449                                         }
00450 
00451                                         if (mapp) {
00452                                                 if (mapp->freqs[0]) {
00453                                                         if (ts->handler) {
00454                                                                 do {
00455                                                                         ts->handler(ts, mapp);
00456                                                                         if (ts->loops > 0) {
00457                                                                                 ts->loops--;
00458                                                                         }
00459                                                                 } while (ts->loops);
00460                                                         }
00461                                                 } else if (ts->debug && ts->debug_stream) {
00462                                                         fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur);
00463                                                 }
00464                                         }
00465                                         
00466                                         if (e) {
00467                                                 cur = e;
00468                                         } else {
00469                                                 cur++;
00470                                         }
00471                                 }
00472                         }
00473 
00474                         if (end) {
00475                                 cur = end;
00476                         } else if (*cur){
00477                                 cur++;
00478                         }
00479                 }
00480         bottom:
00481                 free(data);
00482                 data = NULL;
00483                 if (ts->LOOPS > 0) {
00484                         ts->LOOPS--;
00485                 }
00486 
00487         } while (ts->LOOPS);
00488 
00489         return 0;
00490 }

int teletone_set_map ( teletone_tone_map_t map,
  ... 
)

Assign a set of tones to a single tone map.

Parameters:
map the map to assign the tones to
... up to TELETONE_MAX_TONES frequencies terminated by 0.0
Returns:
0

Definition at line 118 of file libteletone_generate.c.

References TELETONE_MAX_TONES.

00119 {
00120         va_list ap;
00121         int i = 0;
00122         teletone_process_t x = 0;
00123 
00124         va_start(ap, map);
00125         while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
00126                 map->freqs[i++] = x;
00127         }
00128         va_end(ap);
00129 
00130         return (i > TELETONE_MAX_TONES) ? -1 : 0;
00131         
00132 }

int teletone_set_tone ( teletone_generation_session_t ts,
int  index,
  ... 
)

Assign a set of tones to a tone_session indexed by a paticular index/character.

Parameters:
ts the tone generation session
index the index to map the tone to
... up to TELETONE_MAX_TONES frequencies terminated by 0.0
Returns:
0

Definition at line 102 of file libteletone_generate.c.

References TELETONE_MAX_TONES.

Referenced by teletone_init_session().

00103 {
00104         va_list ap;
00105         int i = 0;
00106         teletone_process_t x = 0;
00107 
00108         va_start(ap, index);
00109         while (i < TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) {
00110                 ts->TONES[index].freqs[i++] = x;
00111         }
00112         va_end(ap);
00113 
00114         return (i > TELETONE_MAX_TONES) ? -1 : 0;
00115         
00116 }


Variable Documentation

int16_t TELETONE_SINES[SINE_TABLE_MAX]

Definition at line 82 of file libteletone_generate.c.

Referenced by teletone_dds_state_modulate_sample().


Generated on Wed May 16 04:00:07 2012 for FreeSWITCH API Documentation by  doxygen 1.4.7