From ffbba3d3218a95cc55517b50efa5413ee8735b9e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 6 Jun 2007 22:58:13 +0000 Subject: [PATCH] add dds to teletone git-svn-id: http://svn.openzap.org/svn/openzap/trunk@223 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/openzap/Makefile | 41 ++- libs/openzap/general.makefile | 4 +- libs/openzap/src/include/libteletone.h | 29 +- .../src/include/libteletone_generate.h | 276 +++++++++++------- libs/openzap/src/include/openzap.h | 3 +- libs/openzap/src/libteletone_detect.c | 5 +- libs/openzap/src/libteletone_generate.c | 87 ++++-- 7 files changed, 294 insertions(+), 151 deletions(-) diff --git a/libs/openzap/Makefile b/libs/openzap/Makefile index 64d1910a94..819e96c0f5 100644 --- a/libs/openzap/Makefile +++ b/libs/openzap/Makefile @@ -63,8 +63,34 @@ $(SRC)/zap_zt.o \ $(SRC)/zap_wanpipe.o -HEADERS=$(SRC)/isdn/include/Q931.h \ - $(SRC)/include/openzap.h +HEADERS= $(SRC)/include/fsk.h \ +$(SRC)/include/g711.h \ +$(SRC)/include/hashtable.h \ +$(SRC)/include/hashtable_itr.h \ +$(SRC)/include/hashtable_private.h \ +$(SRC)/include/libteletone_detect.h \ +$(SRC)/include/libteletone_generate.h \ +$(SRC)/include/libteletone.h \ +$(SRC)/include/openzap.h \ +$(SRC)/include/sangoma_tdm_api.h \ +$(SRC)/include/uart.h \ +$(SRC)/include/wanpipe_tdm_api_iface.h \ +$(SRC)/include/zap_analog.h \ +$(SRC)/include/zap_buffer.h \ +$(SRC)/include/zap_config.h \ +$(SRC)/include/zap_isdn.h \ +$(SRC)/include/zap_skel.h \ +$(SRC)/include/zap_threadmutex.h \ +$(SRC)/include/zap_types.h \ +$(SRC)/include/zap_wanpipe.h \ +$(SRC)/include/zap_zt.h \ +$(SRC)/isdn/include/mfifo.h \ +$(SRC)/isdn/include/national.h \ +$(SRC)/isdn/include/Q921.h \ +$(SRC)/isdn/include/Q931.h \ +$(SRC)/isdn/include/Q931ie.h \ +$(SRC)/isdn/include/Q932.h + PWD=$(shell pwd) INCS=-I$(PWD)/$(SRC)//include -I$(PWD)/$(SRC)//isdn/include @@ -76,10 +102,12 @@ TMP=-I$(LIBPRI) -I$(SRC)/include -I./src -w include general.makefile +$(OBJS): $(HEADERS) + all: $(MYLIB) $(MYLIB): $(OBJS) $(HEADERS) - ar rcs $(MYLIB) $(OBJS) + ar rcs $(MYLIB) $(OBJS) ranlib $(MYLIB) testapp: $(SRC)/testapp.c $(MYLIB) @@ -88,6 +116,9 @@ testapp: $(SRC)/testapp.c $(MYLIB) testcid: $(SRC)/testcid.c $(MYLIB) $(CC) $(INCS) -L. $(SRC)/testcid.c -o testcid -lopenzap -lm -lpthread +testtones: $(SRC)/testtones.c $(MYLIB) + $(CC) $(INCS) -L. $(SRC)/testtones.c -o testtones -lopenzap -lm -lpthread + testisdn: $(SRC)/testisdn.c $(MYLIB) $(CC) $(INCS) -L. $(SRC)/testisdn.c -o testisdn -lopenzap -lm -lpthread @@ -109,7 +140,7 @@ priserver: $(MYLIB) $(SRC)/priserver.o $(SRC)/sangoma_pri.o $(LIBPRI)/$(LIBPRIA) $(SRC)/zap_io.o: $(SRC)/zap_io.c $(CC) $(MOD_CFLAGS) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@ -%.o: %.c +%.o: %.c $(CC) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@ dox: @@ -127,6 +158,6 @@ mod_openzap-clean: @if [ -f mod_openzap/mod_openzap.so ] ; then cd mod_openzap && make clean ; fi clean: mod_openzap-clean - rm -f $(SRC)/*.o $(SRC)/isdn/*.o $(MYLIB) *~ \#* testapp testcid priserver testisdn testanalog + rm -f $(SRC)/*.o $(SRC)/isdn/*.o $(MYLIB) *~ \#* testapp testcid testtones priserver testisdn testanalog @if [ -f $(LIBPRI)/$(LIBPRIA) ] ; then cd $(LIBPRI) && make clean ; fi diff --git a/libs/openzap/general.makefile b/libs/openzap/general.makefile index e642a7d88e..5b2fcb9821 100644 --- a/libs/openzap/general.makefile +++ b/libs/openzap/general.makefile @@ -1,3 +1,3 @@ -CC=gcc -CC_CFLAGS += -Wall -Werror -Wextra -std=c99 -pedantic -ansi -Wno-unused-parameter +CC=gcc +CC_CFLAGS += -Wall -Werror -Wextra -std=c99 -pedantic -Wno-unused-parameter diff --git a/libs/openzap/src/include/libteletone.h b/libs/openzap/src/include/libteletone.h index e81ef5e90d..351afa1413 100644 --- a/libs/openzap/src/include/libteletone.h +++ b/libs/openzap/src/include/libteletone.h @@ -73,32 +73,37 @@ #ifdef __cplusplus extern "C" { +#ifdef _doh +} #endif +#endif + #define TELETONE_MAX_DTMF_DIGITS 128 #define TELETONE_MAX_TONES 6 #define TELETONE_TONE_RANGE 127 - typedef double teletone_process_t; +typedef double teletone_process_t; - /*! \file libteletone.h - \brief Top level include file +/*! \file libteletone.h + \brief Top level include file - This file should be included by applications using the library - */ + This file should be included by applications using the library +*/ + +/*! \brief An abstraction to store a tone mapping */ +typedef struct { + /*! An array of tone frequencies */ + teletone_process_t freqs[TELETONE_MAX_TONES]; +} teletone_tone_map_t; - /*! \brief An abstraction to store a tone mapping */ - typedef struct { - /*! An array of tone frequencies */ - teletone_process_t freqs[TELETONE_MAX_TONES]; - } teletone_tone_map_t; #if !defined(M_PI) - /* C99 systems may not define M_PI */ +/* C99 systems may not define M_PI */ #define M_PI 3.14159265358979323846264338327 #endif #ifdef _MSC_VER - typedef __int16 int16_t; +typedef __int16 int16_t; #endif #include diff --git a/libs/openzap/src/include/libteletone_generate.h b/libs/openzap/src/include/libteletone_generate.h index e37778d278..0ed8930539 100644 --- a/libs/openzap/src/include/libteletone_generate.h +++ b/libs/openzap/src/include/libteletone_generate.h @@ -72,13 +72,30 @@ #define LIBTELETONE_GENERATE_H #ifdef __cplusplus extern "C" { +#ifdef _doh +} #endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#if !defined(powf) +extern float powf (float, float); +#endif +#include +#include + #include #include #include -#include #ifndef _MSC_VER #include +#include #endif #include #include @@ -87,115 +104,174 @@ extern "C" { #include #include +#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; + int32_t 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) + +const 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); - /*! \file libteletone_generate.h - \brief Tone Generation Routines + 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; +} - This module is responsible for tone generation specifics - */ - - typedef int16_t teletone_audio_t; - struct teletone_generation_session; - typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map); - - /*! \brief An abstraction to store a tone generation session */ - struct teletone_generation_session { - /*! An array of tone mappings to character mappings */ - teletone_tone_map_t TONES[TELETONE_TONE_RANGE]; - /*! The number of channels the output audio should be in */ - int channels; - /*! The Rate in hz of the output audio */ - int rate; - /*! The duration (in samples) of the output audio */ - int duration; - /*! The duration of silence to append after the initial audio is generated */ - int wait; - /*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */ - int tmp_duration; - /*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/ - int tmp_wait; - /*! Number of loops to repeat a single instruction*/ - int loops; - /*! 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; - /*! 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; - /*! Debug on/off */ - int debug; - /*! FILE stream to write debug data to */ - FILE *debug_stream; - /*! Extra user data to attach to the session*/ - void *user_data; - /*! Buffer for storing sample data (dynamic) */ - teletone_audio_t *buffer; - /*! Size of the buffer */ - int datalen; - /*! In-Use size of the buffer */ - int samples; - /*! Callback function called during generation */ - int dynamic; - tone_handler handler; - }; - - typedef struct teletone_generation_session teletone_generation_session_t; +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)); +} - /*! - \brief Assign a set of tones to a tone_session indexed by a paticular index/character - \param ts the tone generation session - \param index the index to map the tone to - \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 - \return 0 - */ - int teletone_set_tone(teletone_generation_session_t *ts, int index, ...); - /*! - \brief Assign a set of tones to a single tone map - \param map the map to assign the tones to - \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 - \return 0 - */ - int teletone_set_map(teletone_tone_map_t *map, ...); +/*! \file libteletone_generate.h + \brief Tone Generation Routines - /*! - \brief Initilize a tone generation session - \param ts the tone generation session to initilize - \param buflen the size of the buffer(in samples) to dynamically allocate - \param handler a callback function to execute when a tone generation instruction is complete - \param user_data optional user data to send - \return 0 - */ - int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data); + This module is responsible for tone generation specifics +*/ - /*! - \brief Free the buffer allocated by a tone generation session - \param ts the tone generation session to destroy - \return 0 - */ - int teletone_destroy_session(teletone_generation_session_t *ts); +typedef int16_t teletone_audio_t; +struct teletone_generation_session; +typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map); - /*! - \brief Execute a single tone generation instruction - \param ts the tone generation session to consult for parameters - \param map the tone mapping to use for the frequencies - \return 0 - */ - int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map); +/*! \brief An abstraction to store a tone generation session */ +struct teletone_generation_session { + /*! An array of tone mappings to character mappings */ + teletone_tone_map_t TONES[TELETONE_TONE_RANGE]; + /*! The number of channels the output audio should be in */ + int channels; + /*! The Rate in hz of the output audio */ + int rate; + /*! The duration (in samples) of the output audio */ + int duration; + /*! The duration of silence to append after the initial audio is generated */ + int wait; + /*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */ + int tmp_duration; + /*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/ + int tmp_wait; + /*! Number of loops to repeat a single instruction*/ + int loops; + /*! 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%) */ + 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 */ + float volume; + /*! Debug on/off */ + int debug; + /*! FILE stream to write debug data to */ + FILE *debug_stream; + /*! Extra user data to attach to the session*/ + void *user_data; + /*! Buffer for storing sample data (dynamic) */ + teletone_audio_t *buffer; + /*! Size of the buffer */ + int datalen; + /*! In-Use size of the buffer */ + int samples; + /*! Callback function called during generation */ + int dynamic; + tone_handler handler; +}; - /*! - \brief Execute a tone generation script and call callbacks after each instruction - \param ts the tone generation session to execute on - \param cmd the script to execute - \return 0 - */ - int teletone_run(teletone_generation_session_t *ts, char *cmd); +typedef struct teletone_generation_session teletone_generation_session_t; + + +/*! + \brief Assign a set of tones to a tone_session indexed by a paticular index/character + \param ts the tone generation session + \param index the index to map the tone to + \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 + \return 0 +*/ +int teletone_set_tone(teletone_generation_session_t *ts, int index, ...); + +/*! + \brief Assign a set of tones to a single tone map + \param map the map to assign the tones to + \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 + \return 0 +*/ +int teletone_set_map(teletone_tone_map_t *map, ...); + +/*! + \brief Initilize a tone generation session + \param ts the tone generation session to initilize + \param buflen the size of the buffer(in samples) to dynamically allocate + \param handler a callback function to execute when a tone generation instruction is complete + \param user_data optional user data to send + \return 0 +*/ +int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data); + +/*! + \brief Free the buffer allocated by a tone generation session + \param ts the tone generation session to destroy + \return 0 +*/ +int teletone_destroy_session(teletone_generation_session_t *ts); + +/*! + \brief Execute a single tone generation instruction + \param ts the tone generation session to consult for parameters + \param map the tone mapping to use for the frequencies + \return 0 +*/ +int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map); + +/*! + \brief Execute a tone generation script and call callbacks after each instruction + \param ts the tone generation session to execute on + \param cmd the script to execute + \return 0 +*/ +int teletone_run(teletone_generation_session_t *ts, char *cmd); #ifdef __cplusplus } diff --git a/libs/openzap/src/include/openzap.h b/libs/openzap/src/include/openzap.h index dfa4837845..01eb7e75ba 100644 --- a/libs/openzap/src/include/openzap.h +++ b/libs/openzap/src/include/openzap.h @@ -34,8 +34,9 @@ #ifndef OPENZAP_H #define OPENZAP_H + #ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE 500 +#define _XOPEN_SOURCE 600 #endif #ifndef HAVE_STRINGS_H diff --git a/libs/openzap/src/libteletone_detect.c b/libs/openzap/src/libteletone_detect.c index 1af9b8fc43..a089f8fc48 100644 --- a/libs/openzap/src/libteletone_detect.c +++ b/libs/openzap/src/libteletone_detect.c @@ -90,7 +90,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include + #ifndef _MSC_VER #include #endif @@ -98,7 +99,7 @@ #include #include #include -#include + static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]; static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]; diff --git a/libs/openzap/src/libteletone_generate.c b/libs/openzap/src/libteletone_generate.c index 4e388c8d3b..9a36e6280c 100644 --- a/libs/openzap/src/libteletone_generate.c +++ b/libs/openzap/src/libteletone_generate.c @@ -70,6 +70,7 @@ */ #include + #define SMAX 32767 #define SMIN -32768 #define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN; @@ -78,6 +79,25 @@ #pragma warning(disable:4706) #endif +const 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);