]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
update teletone see wiki for syntax changes in TTML
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 6 Jun 2007 23:28:00 +0000 (23:28 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 6 Jun 2007 23:28:00 +0000 (23:28 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5276 d0543943-73ff-0310-b7d9-9358b9ac24b2

libs/libteletone/src/libteletone_detect.c
libs/libteletone/src/libteletone_detect.h
libs/libteletone/src/libteletone_generate.c
libs/libteletone/src/libteletone_generate.h

index 8df7d569a4e386ea7d40a49561e2318b4a483cba..a089f8fc4878f97bb5cbbcd4103080a0f7a42a38 100644 (file)
@@ -90,7 +90,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <math.h>
+#include <libteletone_detect.h>
+
 #ifndef _MSC_VER
 #include <stdint.h>
 #endif
@@ -98,7 +99,7 @@
 #include <stdio.h>
 #include <time.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_col[GRID_FACTOR];
@@ -208,8 +209,8 @@ void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *ma
 }
 
 int teletone_multi_tone_detect (teletone_multi_tone_t *mt,
-                                          int16_t sample_buffer[],
-                                          int samples)
+                                                               int16_t sample_buffer[],
+                                                               int samples)
 {
        int sample, limit, j, x = 0;
        teletone_process_t v1, famp;
@@ -295,8 +296,8 @@ int teletone_multi_tone_detect (teletone_multi_tone_t *mt,
 
 
 int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
-                 int16_t sample_buffer[],
-                 int samples)
+                                                 int16_t sample_buffer[],
+                                                 int samples)
 {
     teletone_process_t row_energy[GRID_FACTOR];
     teletone_process_t col_energy[GRID_FACTOR];
@@ -426,8 +427,8 @@ int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
 
 
 int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
-              char *buf,
-              int max)
+                                          char *buf,
+                                          int max)
 {
     if (max > dtmf_detect_state->current_digits) {
         max = dtmf_detect_state->current_digits;
index eda4e49514e06c8f499e697050d8d1a2b194a7cf..15d5e9ddfb3ebcf3043cee6dc39a92716164c35a 100644 (file)
@@ -98,11 +98,11 @@ extern "C" {
 #endif
 #include <libteletone.h>
 
-/*! \file libteletone_detect.h
-    \brief Tone Detection Routines
+       /*! \file libteletone_detect.h
+         \brief Tone Detection Routines
 
-       This module is responsible for tone detection specifics
-*/
+         This module is responsible for tone detection specifics
+       */
 
 #ifndef FALSE
 #define FALSE   0
@@ -111,17 +111,17 @@ extern "C" {
 #endif
 #endif
 
-/* Basic DTMF specs:
- *
- * Minimum tone on = 40ms
- * Minimum tone off = 50ms
- * Maximum digit rate = 10 per second
- * Normal twist <= 8dB accepted
- * Reverse twist <= 4dB accepted
- * S/N >= 15dB will detect OK
- * Attenuation <= 26dB will detect OK
- * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
- */
+       /* Basic DTMF specs:
       *
       * Minimum tone on = 40ms
       * Minimum tone off = 50ms
       * Maximum digit rate = 10 per second
       * Normal twist <= 8dB accepted
       * Reverse twist <= 4dB accepted
       * S/N >= 15dB will detect OK
       * Attenuation <= 26dB will detect OK
       * Frequency tolerance +- 1.5% will detect, +-3.5% will reject
       */
 
 #define DTMF_THRESHOLD              8.0e7
 #define DTMF_NORMAL_TWIST           6.3     /* 8dB */
@@ -134,131 +134,131 @@ extern "C" {
 #define BLOCK_LEN 102
 #define M_TWO_PI 2.0*M_PI
 
-/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
-typedef struct {
-       teletone_process_t v2;
-       teletone_process_t v3;
-       teletone_process_t fac;
-} teletone_goertzel_state_t;
+       /*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */
+       typedef struct {
+               teletone_process_t v2;
+               teletone_process_t v3;
+               teletone_process_t fac;
+       } teletone_goertzel_state_t;
        
-/*! \brief A container for a DTMF detection state.*/
-typedef struct {
-    int hit1;
-    int hit2;
-    int hit3;
-    int hit4;
-    int mhit;
+       /*! \brief A container for a DTMF detection state.*/
+       typedef struct {
+               int hit1;
+               int hit2;
+               int hit3;
+               int hit4;
+               int mhit;
 
-    teletone_goertzel_state_t row_out[GRID_FACTOR];
-    teletone_goertzel_state_t col_out[GRID_FACTOR];
-    teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
-    teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
-    teletone_process_t energy;
+               teletone_goertzel_state_t row_out[GRID_FACTOR];
+               teletone_goertzel_state_t col_out[GRID_FACTOR];
+               teletone_goertzel_state_t row_out2nd[GRID_FACTOR];
+               teletone_goertzel_state_t col_out2nd[GRID_FACTOR];
+               teletone_process_t energy;
     
-    int current_sample;
-    char digits[TELETONE_MAX_DTMF_DIGITS + 1];
-    int current_digits;
-    int detected_digits;
-    int lost_digits;
-    int digit_hits[16];
-} teletone_dtmf_detect_state_t;
+               int current_sample;
+               char digits[TELETONE_MAX_DTMF_DIGITS + 1];
+               int current_digits;
+               int detected_digits;
+               int lost_digits;
+               int digit_hits[16];
+       } teletone_dtmf_detect_state_t;
 
-/*! \brief An abstraction to store the coefficient of a tone frequency */
-typedef struct {
-    teletone_process_t fac;
-} teletone_detection_descriptor_t;
+       /*! \brief An abstraction to store the coefficient of a tone frequency */
+       typedef struct {
+               teletone_process_t fac;
+       } teletone_detection_descriptor_t;
 
-/*! \brief A container for a single multi-tone detection 
-TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
-in a multi-tone representation.
-*/
-typedef struct {
-       int sample_rate;
+       /*! \brief A container for a single multi-tone detection 
+         TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present
+         in a multi-tone representation.
+       */
+       typedef struct {
+               int sample_rate;
 
-       teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
-       teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
-       teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
-       int tone_count;
+               teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES];
+               teletone_goertzel_state_t gs[TELETONE_MAX_TONES];
+               teletone_goertzel_state_t gs2[TELETONE_MAX_TONES];
+               int tone_count;
 
-       teletone_process_t energy;
-       int current_sample;
+               teletone_process_t energy;
+               int current_sample;
        
-       int min_samples;
-       int total_samples;
+               int min_samples;
+               int total_samples;
 
-       int positives;
-       int negatives;
-       int hits;
+               int positives;
+               int negatives;
+               int hits;
 
-       int positive_factor;
-       int negative_factor;
-       int hit_factor;
+               int positive_factor;
+               int negative_factor;
+               int hit_factor;
 
-} teletone_multi_tone_t;
+       } teletone_multi_tone_t;
 
 
-/*! 
-  \brief Initilize a multi-frequency tone detector
-  \param mt the multi-frequency tone descriptor
-  \param map a representation of the multi-frequency tone
-*/
-void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map);
+       /*! 
+         \brief Initilize a multi-frequency tone detector
+         \param mt the multi-frequency tone descriptor
+         \param map a representation of the multi-frequency tone
+       */
+       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
-  \param mt the multi-frequency tone descriptor
-  \param sample_buffer an array aof 16 bit signed linear samples
-  \param samples the number of samples present in sample_buffer
-  \return true when the tone was detected or false when it is not
-*/
-int teletone_multi_tone_detect (teletone_multi_tone_t *mt,
-                                                               int16_t sample_buffer[],
-                                                               int samples);
+       /*! 
+         \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt
+         \param mt the multi-frequency tone descriptor
+         \param sample_buffer an array aof 16 bit signed linear samples
+         \param samples the number of samples present in sample_buffer
+         \return true when the tone was detected or false when it is not
+       */
+       int teletone_multi_tone_detect (teletone_multi_tone_t *mt,
+                                                                       int16_t sample_buffer[],
+                                                                       int samples);
 
-/*! 
-  \brief Initilize a DTMF detection state object
-  \param dtmf_detect_state the DTMF detection state to initilize
-  \param sample_rate the desired sample rate
-*/
-void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate);
+       /*! 
+         \brief Initilize a DTMF detection state object
+         \param dtmf_detect_state the DTMF detection state to initilize
+         \param sample_rate the desired 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
-  \param dtmf_detect_state the detection state object to check
-  \param sample_buffer an array aof 16 bit signed linear samples
-  \param samples the number of samples present in sample_buffer
-  \return true when DTMF was detected or false when it is not
-*/
-int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
-                                                 int16_t sample_buffer[],
-                                                 int samples);
-/*! 
-  \brief retrieve any collected digits into a string buffer
-  \param dtmf_detect_state the detection state object to check
-  \param buf the string buffer to write to
-  \param max the maximum length of buf
-  \return the number of characters written to buf
-*/
-int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
-                                          char *buf,
-                                          int max);
-
-/*! 
-  \brief Step through the Goertzel Algorithm for each sample in a buffer
-  \param goertzel_state the goertzel state to step the samples through
-  \param sample_buffer an array aof 16 bit signed linear samples
-  \param samples the number of samples present in sample_buffer
-*/
-void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+       /*! 
+         \brief Check a sample buffer for the presence of DTMF digits
+         \param dtmf_detect_state the detection state object to check
+         \param sample_buffer an array aof 16 bit signed linear samples
+         \param samples the number of samples present in sample_buffer
+         \return true when DTMF was detected or false when it is not
+       */
+       int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state,
                                                          int16_t sample_buffer[],
                                                          int samples);
+       /*! 
+         \brief retrieve any collected digits into a string buffer
+         \param dtmf_detect_state the detection state object to check
+         \param buf the string buffer to write to
+         \param max the maximum length of buf
+         \return the number of characters written to buf
+       */
+       int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state,
+                                                  char *buf,
+                                                  int max);
+
+       /*! 
+         \brief Step through the Goertzel Algorithm for each sample in a buffer
+         \param goertzel_state the goertzel state to step the samples through
+         \param sample_buffer an array aof 16 bit signed linear samples
+         \param samples the number of samples present in sample_buffer
+       */
+       void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state,
+                                                                 int16_t sample_buffer[],
+                                                                 int samples);
 
-/*! 
-  \brief Compute the result of the last applied step of the Goertzel Algorithm
-  \param goertzel_state the goertzel state to retrieve from
-  \return the computed value for consideration in furthur audio tests
-*/
-teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state);
+       /*! 
+         \brief Compute the result of the last applied step of the Goertzel Algorithm
+         \param goertzel_state the goertzel state to retrieve from
+         \return the computed value for consideration in furthur audio tests
+       */
+       teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state);
 
 
 
index 4e388c8d3b832bcc99c6461be05b2af643b580d0..edd573c7a1a8e50a947e0dc280fe83d967901710 100644 (file)
@@ -70,6 +70,7 @@
  */
 
 #include <libteletone.h>
+
 #define SMAX 32767
 #define SMIN -32768
 #define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN;
 #pragma warning(disable:4706)
 #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, ...)
 {
@@ -122,8 +142,9 @@ int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_ha
        ts->tmp_wait = -1;
        ts->handler = handler;
        ts->user_data = user_data;
-       ts->volume = 1500;
+       ts->volume = -7;
        ts->decay_step = 0;
+       ts->decay_factor = 1;
        if (buflen) {
                if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
                        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)
 {
-       teletone_process_t period = (1.0 / ts->rate) / ts->channels;
+       /*teletone_process_t period = (1.0 / ts->rate) / ts->channels;*/
        int i, c;
        int freqlen = 0;
-       teletone_process_t tones[TELETONE_MAX_TONES];
-       int decay = 0;
+       teletone_dds_state_t tones[TELETONE_MAX_TONES];
+       //int decay = 0;
        int duration;
        int wait = 0;
-       teletone_process_t sample;
-       
+       int32_t sample;
+       int32_t dc = 0;
+       float vol = ts->volume;
        ts->samples = 0;
-
+       memset(tones, 0, sizeof(tones[0]) * TELETONE_MAX_TONES);
        duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration;
        wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait;
 
        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++) {
-                       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) {
@@ -220,17 +231,28 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
                                return -1;
                        }
                }
+
                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) {
-                               ts->volume += ts->decay_direction;
+                       if (ts->decay_direction && ++dc >= ts->decay_step) {
+                               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++) {
-                               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;
                        
                        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, ") [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,
                                        duration,
                                        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),
                                        ts->decay_factor,
                                        ts->decay_step,
+                                       ts->decay_step / (ts->rate / 1000),                                     
                                        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);
                                        break;
                                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;
                                case '>':
-                                       ts->decay_factor = atoi(cur + 2);
+                                       ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
                                        ts->decay_direction = -1;
                                        break;
                                case '<':
-                                       ts->decay_factor = atoi(cur + 2);
+                                       ts->decay_step = atoi(cur + 2) * (ts->rate / 1000);
                                        ts->decay_direction = 1;
                                        break;
                                case '+':
-                                       ts->decay_step = atoi(cur + 2);
+                                       ts->decay_factor = atof(cur + 2);
                                        break;
                                case 'w':
                                        ts->wait = atoi(cur + 2) * (ts->rate / 1000);
index 3d625e8f52cebba2788f0511af2df43228d062d6..be791555bd19f6737a8b15b4aa636a022eb2c788 100644 (file)
 #define LIBTELETONE_GENERATE_H
 #ifdef __cplusplus
 extern "C" {
+#ifdef _doh
+}
+#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 <stdio.h>
 #include <string.h>
-#include <math.h>
 #ifndef _MSC_VER
 #include <unistd.h>
+#include <stdint.h>
 #endif
 #include <fcntl.h>
 #include <sys/types.h>
@@ -87,12 +104,71 @@ extern "C" {
 #include <stdarg.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
-    \brief Tone Generation Routines
+  \brief Tone Generation Routines
 
-       This module is responsible for tone generation specifics
+  This module is responsible for tone generation specifics
 */
 
 typedef int16_t teletone_audio_t;
@@ -120,13 +196,13 @@ struct teletone_generation_session {
        /*! Number of loops to repeat the entire set of instructions*/
        int LOOPS;
        /*! 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*/
        int decay_direction;
        /*! Number of samples between increase/decrease of volume */
        int decay_step;
        /*! Volume factor of the tone */
-       int volume;
+       float volume;
        /*! Debug on/off */
        int debug;
        /*! FILE stream to write debug data to */