add dds to teletone

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@223 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
Anthony Minessale 2007-06-06 22:58:13 +00:00
parent f23950ffdd
commit ffbba3d321
7 changed files with 294 additions and 151 deletions

View File

@ -63,8 +63,34 @@ $(SRC)/zap_zt.o \
$(SRC)/zap_wanpipe.o $(SRC)/zap_wanpipe.o
HEADERS=$(SRC)/isdn/include/Q931.h \ HEADERS= $(SRC)/include/fsk.h \
$(SRC)/include/openzap.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) PWD=$(shell pwd)
INCS=-I$(PWD)/$(SRC)//include -I$(PWD)/$(SRC)//isdn/include INCS=-I$(PWD)/$(SRC)//include -I$(PWD)/$(SRC)//isdn/include
@ -76,6 +102,8 @@ TMP=-I$(LIBPRI) -I$(SRC)/include -I./src -w
include general.makefile include general.makefile
$(OBJS): $(HEADERS)
all: $(MYLIB) all: $(MYLIB)
$(MYLIB): $(OBJS) $(HEADERS) $(MYLIB): $(OBJS) $(HEADERS)
@ -88,6 +116,9 @@ testapp: $(SRC)/testapp.c $(MYLIB)
testcid: $(SRC)/testcid.c $(MYLIB) testcid: $(SRC)/testcid.c $(MYLIB)
$(CC) $(INCS) -L. $(SRC)/testcid.c -o testcid -lopenzap -lm -lpthread $(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) testisdn: $(SRC)/testisdn.c $(MYLIB)
$(CC) $(INCS) -L. $(SRC)/testisdn.c -o testisdn -lopenzap -lm -lpthread $(CC) $(INCS) -L. $(SRC)/testisdn.c -o testisdn -lopenzap -lm -lpthread
@ -127,6 +158,6 @@ mod_openzap-clean:
@if [ -f mod_openzap/mod_openzap.so ] ; then cd mod_openzap && make clean ; fi @if [ -f mod_openzap/mod_openzap.so ] ; then cd mod_openzap && make clean ; fi
clean: mod_openzap-clean 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 @if [ -f $(LIBPRI)/$(LIBPRIA) ] ; then cd $(LIBPRI) && make clean ; fi

View File

@ -1,3 +1,3 @@
CC=gcc CC=gcc
CC_CFLAGS += -Wall -Werror -Wextra -std=c99 -pedantic -ansi -Wno-unused-parameter CC_CFLAGS += -Wall -Werror -Wextra -std=c99 -pedantic -Wno-unused-parameter

View File

@ -73,32 +73,37 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#ifdef _doh
}
#endif #endif
#endif
#define TELETONE_MAX_DTMF_DIGITS 128 #define TELETONE_MAX_DTMF_DIGITS 128
#define TELETONE_MAX_TONES 6 #define TELETONE_MAX_TONES 6
#define TELETONE_TONE_RANGE 127 #define TELETONE_TONE_RANGE 127
typedef double teletone_process_t; typedef double teletone_process_t;
/*! \file libteletone.h /*! \file libteletone.h
\brief Top level include file \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 */ /*! \brief An abstraction to store a tone mapping */
typedef struct { typedef struct {
/*! An array of tone frequencies */ /*! An array of tone frequencies */
teletone_process_t freqs[TELETONE_MAX_TONES]; teletone_process_t freqs[TELETONE_MAX_TONES];
} teletone_tone_map_t; } teletone_tone_map_t;
#if !defined(M_PI) #if !defined(M_PI)
/* C99 systems may not define M_PI */ /* C99 systems may not define M_PI */
#define M_PI 3.14159265358979323846264338327 #define M_PI 3.14159265358979323846264338327
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
typedef __int16 int16_t; typedef __int16 int16_t;
#endif #endif
#include <libteletone_generate.h> #include <libteletone_generate.h>

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,20 +104,79 @@ 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;
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 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; typedef int16_t teletone_audio_t;
struct teletone_generation_session; struct teletone_generation_session;
typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map); typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
/*! \brief An abstraction to store a tone generation session */ /*! \brief An abstraction to store a tone generation session */
struct teletone_generation_session { struct teletone_generation_session {
/*! An array of tone mappings to character mappings */ /*! An array of tone mappings to character mappings */
teletone_tone_map_t TONES[TELETONE_TONE_RANGE]; teletone_tone_map_t TONES[TELETONE_TONE_RANGE];
/*! The number of channels the output audio should be in */ /*! The number of channels the output audio should be in */
@ -120,13 +196,13 @@ extern "C" {
/*! 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 */
@ -142,60 +218,60 @@ extern "C" {
/*! Callback function called during generation */ /*! Callback function called during generation */
int dynamic; int dynamic;
tone_handler handler; tone_handler handler;
}; };
typedef struct teletone_generation_session teletone_generation_session_t; 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 \brief Assign a set of tones to a tone_session indexed by a paticular index/character
\param ts the tone generation session \param ts the tone generation session
\param index the index to map the tone to \param index the index to map the tone to
\param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
\return 0 \return 0
*/ */
int teletone_set_tone(teletone_generation_session_t *ts, int index, ...); int teletone_set_tone(teletone_generation_session_t *ts, int index, ...);
/*! /*!
\brief Assign a set of tones to a single tone map \brief Assign a set of tones to a single tone map
\param map the map to assign the tones to \param map the map to assign the tones to
\param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0
\return 0 \return 0
*/ */
int teletone_set_map(teletone_tone_map_t *map, ...); int teletone_set_map(teletone_tone_map_t *map, ...);
/*! /*!
\brief Initilize a tone generation session \brief Initilize a tone generation session
\param ts the tone generation session to initilize \param ts the tone generation session to initilize
\param buflen the size of the buffer(in samples) to dynamically allocate \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 handler a callback function to execute when a tone generation instruction is complete
\param user_data optional user data to send \param user_data optional user data to send
\return 0 \return 0
*/ */
int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data); 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 \brief Free the buffer allocated by a tone generation session
\param ts the tone generation session to destroy \param ts the tone generation session to destroy
\return 0 \return 0
*/ */
int teletone_destroy_session(teletone_generation_session_t *ts); int teletone_destroy_session(teletone_generation_session_t *ts);
/*! /*!
\brief Execute a single tone generation instruction \brief Execute a single tone generation instruction
\param ts the tone generation session to consult for parameters \param ts the tone generation session to consult for parameters
\param map the tone mapping to use for the frequencies \param map the tone mapping to use for the frequencies
\return 0 \return 0
*/ */
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);
/*! /*!
\brief Execute a tone generation script and call callbacks after each instruction \brief Execute a tone generation script and call callbacks after each instruction
\param ts the tone generation session to execute on \param ts the tone generation session to execute on
\param cmd the script to execute \param cmd the script to execute
\return 0 \return 0
*/ */
int teletone_run(teletone_generation_session_t *ts, char *cmd); int teletone_run(teletone_generation_session_t *ts, char *cmd);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -34,8 +34,9 @@
#ifndef OPENZAP_H #ifndef OPENZAP_H
#define OPENZAP_H #define OPENZAP_H
#ifndef _XOPEN_SOURCE #ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500 #define _XOPEN_SOURCE 600
#endif #endif
#ifndef HAVE_STRINGS_H #ifndef HAVE_STRINGS_H

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

@ -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
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, ...) 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);