From 26638d3a550219159766dc4eab65354bd4c2c3d7 Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Mon, 19 Oct 2009 22:02:41 +0000 Subject: Add dynamic range compression support for analog channels. (closes issue AST-29) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@224637 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_dahdi.c | 104 +++++++++++++++++++++++++++++++---------- configs/chan_dahdi.conf.sample | 12 +++++ 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index d8950eea2..9693e2eab 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include #ifdef __NetBSD__ #include #include @@ -719,6 +720,10 @@ struct dahdi_pvt { float rxgain; /*! \brief Tx gain set by chan_dahdi.conf */ float txgain; + + float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */ + float rxdrc; + int tonezone; /*!< tone zone for this chan, or -1 for default */ enum DAHDI_IFLIST which_iflist; /*!< Which interface list is this structure listed? */ struct dahdi_pvt *next; /*!< Next channel in list */ @@ -4135,17 +4140,43 @@ static void dahdi_disable_ec(struct dahdi_pvt *p) p->echocanon = 0; } -static void fill_txgain(struct dahdi_gains *g, float gain, int law) +/* perform a dynamic range compression transform on the given sample */ +static int drc_sample(int sample, float drc) +{ + float neg; + float shallow, steep; + float max = MAXSHORT; + + neg = (sample < 0 ? -1 : 1); + steep = drc*sample; + shallow = neg*(max-max/drc)+(float)sample/drc; + if (abs(steep) < abs(shallow)) { + sample = steep; + } + else { + sample = shallow; + } + + return sample; +} + + +static void fill_txgain(struct dahdi_gains *g, float gain, float drc, int law) { int j; int k; + float linear_gain = pow(10.0, gain / 20.0); switch (law) { case DAHDI_LAW_ALAW: for (j = 0; j < ARRAY_LEN(g->txgain); j++) { - if (gain) { - k = (int) (((float) AST_ALAW(j)) * linear_gain); + if (gain || drc) { + k = AST_ALAW(j); + if (drc) { + k = drc_sample(k, drc); + } + k = (float)k*linear_gain; if (k > 32767) k = 32767; if (k < -32767) k = -32767; g->txgain[j] = AST_LIN2A(k); @@ -4156,11 +4187,16 @@ static void fill_txgain(struct dahdi_gains *g, float gain, int law) break; case DAHDI_LAW_MULAW: for (j = 0; j < ARRAY_LEN(g->txgain); j++) { - if (gain) { - k = (int) (((float) AST_MULAW(j)) * linear_gain); + if (gain || drc) { + k = AST_MULAW(j); + if (drc) { + k = drc_sample(k, drc); + } + k = (float)k*linear_gain; if (k > 32767) k = 32767; if (k < -32767) k = -32767; g->txgain[j] = AST_LIN2MU(k); + } else { g->txgain[j] = j; } @@ -4169,7 +4205,7 @@ static void fill_txgain(struct dahdi_gains *g, float gain, int law) } } -static void fill_rxgain(struct dahdi_gains *g, float gain, int law) +static void fill_rxgain(struct dahdi_gains *g, float gain, float drc, int law) { int j; int k; @@ -4178,8 +4214,12 @@ static void fill_rxgain(struct dahdi_gains *g, float gain, int law) switch (law) { case DAHDI_LAW_ALAW: for (j = 0; j < ARRAY_LEN(g->rxgain); j++) { - if (gain) { - k = (int) (((float) AST_ALAW(j)) * linear_gain); + if (gain || drc) { + k = AST_ALAW(j); + if (drc) { + k = drc_sample(k, drc); + } + k = (float)k*linear_gain; if (k > 32767) k = 32767; if (k < -32767) k = -32767; g->rxgain[j] = AST_LIN2A(k); @@ -4190,8 +4230,12 @@ static void fill_rxgain(struct dahdi_gains *g, float gain, int law) break; case DAHDI_LAW_MULAW: for (j = 0; j < ARRAY_LEN(g->rxgain); j++) { - if (gain) { - k = (int) (((float) AST_MULAW(j)) * linear_gain); + if (gain || drc) { + k = AST_MULAW(j); + if (drc) { + k = drc_sample(k, drc); + } + k = (float)k*linear_gain; if (k > 32767) k = 32767; if (k < -32767) k = -32767; g->rxgain[j] = AST_LIN2MU(k); @@ -4203,7 +4247,7 @@ static void fill_rxgain(struct dahdi_gains *g, float gain, int law) } } -static int set_actual_txgain(int fd, int chan, float gain, int law) +static int set_actual_txgain(int fd, int chan, float gain, float drc, int law) { struct dahdi_gains g; int res; @@ -4216,12 +4260,12 @@ static int set_actual_txgain(int fd, int chan, float gain, int law) return res; } - fill_txgain(&g, gain, law); + fill_txgain(&g, gain, drc, law); return ioctl(fd, DAHDI_SETGAINS, &g); } -static int set_actual_rxgain(int fd, int chan, float gain, int law) +static int set_actual_rxgain(int fd, int chan, float gain, float drc, int law) { struct dahdi_gains g; int res; @@ -4234,14 +4278,14 @@ static int set_actual_rxgain(int fd, int chan, float gain, int law) return res; } - fill_rxgain(&g, gain, law); + fill_rxgain(&g, gain, drc, law); return ioctl(fd, DAHDI_SETGAINS, &g); } -static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law) +static int set_actual_gain(int fd, int chan, float rxgain, float txgain, float rxdrc, float txdrc, int law) { - return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law); + return set_actual_txgain(fd, chan, txgain, txdrc, law) | set_actual_rxgain(fd, chan, rxgain, rxdrc, law); } static int bump_gains(struct dahdi_pvt *p) @@ -4249,7 +4293,7 @@ static int bump_gains(struct dahdi_pvt *p) int res; /* Bump receive gain by value stored in cid_rxgain */ - res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law); + res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->rxdrc, p->txdrc, p->law); if (res) { ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno)); return -1; @@ -4262,7 +4306,7 @@ static int restore_gains(struct dahdi_pvt *p) { int res; - res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law); + res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law); if (res) { ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno)); return -1; @@ -4507,7 +4551,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout) ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno)); p->outgoing = 1; - set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law); + set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->rxdrc, p->txdrc, p->law); #ifdef HAVE_PRI if (dahdi_sig_pri_lib_handles(p->sig)) { @@ -5709,7 +5753,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int return -1; } ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp); - return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->law); + return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->txdrc, p->law); case AST_OPTION_RXGAIN: scp = (signed char *) data; idx = dahdi_get_index(chan, p, 0); @@ -5718,7 +5762,7 @@ static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int return -1; } ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp); - return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->law); + return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->rxdrc, p->law); case AST_OPTION_TONE_VERIFY: if (!p->dsp) break; @@ -11325,9 +11369,11 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp->cid_rxgain = conf->chan.cid_rxgain; tmp->rxgain = conf->chan.rxgain; tmp->txgain = conf->chan.txgain; + tmp->txdrc = conf->chan.txdrc; + tmp->rxdrc = conf->chan.rxdrc; tmp->tonezone = conf->chan.tonezone; if (tmp->subs[SUB_REAL].dfd > -1) { - set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law); + set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->rxdrc, tmp->txdrc, tmp->law); if (tmp->dsp) ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax); update_conf(tmp); @@ -13973,6 +14019,8 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown"); ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no"); ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no"); + ast_cli(a->fd, "Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain); + ast_cli(a->fd, "Dynamic Range Compression (RX/TX): %.2f/%.2f\n", tmp->rxdrc, tmp->txdrc); ast_cli(a->fd, "DND: %s\n", dahdi_dnd(tmp, -1) ? "yes" : "no"); ast_cli(a->fd, "Echo Cancellation:\n"); @@ -14338,9 +14386,9 @@ static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_a break; if (tx) - res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law); + res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->txdrc, tmp->law); else - res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law); + res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->rxdrc, tmp->law); if (res) { ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel); @@ -15540,6 +15588,14 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) { ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno); } + } else if (!strcasecmp(v->name, "txdrc")) { + if (sscanf(v->value, "%f", &confp->chan.txdrc) != 1) { + ast_log(LOG_WARNING, "Invalid txdrc: %s\n", v->value); + } + } else if (!strcasecmp(v->name, "rxdrc")) { + if (sscanf(v->value, "%f", &confp->chan.rxdrc) != 1) { + ast_log(LOG_WARNING, "Invalid rxdrc: %s\n", v->value); + } } else if (!strcasecmp(v->name, "tonezone")) { if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) { ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno); diff --git a/configs/chan_dahdi.conf.sample b/configs/chan_dahdi.conf.sample index 4ab2a5561..93848827d 100644 --- a/configs/chan_dahdi.conf.sample +++ b/configs/chan_dahdi.conf.sample @@ -577,16 +577,28 @@ echocancelwhenbridged=yes ; increases the volume level on a channel, and a ; negavive value decreases volume level. ; +; Dynamic Range Compression: you can also enable dynamic range compression +; on a channel. This will amplify quiet sounds while leaving +; louder sounds untouched. This is useful in situations where +; a linear gain setting would cause clipping. Acceptable values +; are in the range of 0.0 to around 6.0 with higher values +; causing more compression to be done. +; ; There are several independent gain settings: ; rxgain: gain for the rx (receive - into Asterisk) channel. Default: 0.0 ; txgain: gain for the tx (transmit - out of Asterisk Asterisk) channel. ; Default: 0.0 ; cid_rxgain: set the gain just for the caller ID sounds Asterisk ; emits. Default: 5.0 . +; rxdrc: dynamic range compression for the rx channel. Default: 0.0 +; txdrc: dynamic range compression for the tx channel. Default: 0.0 ;rxgain=2.0 ;txgain=3.0 ; +;rxdrc=1.0 +;txdrc=4.0 +; ; Logical groups can be assigned to allow outgoing roll-over. Groups range ; from 0 to 63, and multiple groups can be specified. By default the ; channel is not a member of any group. -- cgit v1.2.3