issue #5622
[asterisk/asterisk.git] / indications.c
index 59641e0..a708a86 100755 (executable)
@@ -1,19 +1,31 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
- * Tone Management
- * 
  * Copyright (C) 2002, Pauline Middelink
  *
- * Pauline Middelink <middelink@polyware.nl>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
  *
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Tone Management
+ * 
+ * \author Pauline Middelink <middelink@polyware.nl>
  *
  * This set of function allow us to play a list of tones on a channel.
  * Each element has two frequencies, which are mixed together and a
  * duration. For silence both frequencies can be set to 0.
  * The playtones can be given as a comma separated string.
+ *
  */
 
 #include <stdio.h>
@@ -23,7 +35,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION("$Revision$")
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/indications.h"
 #include "asterisk/frame.h"
@@ -33,11 +45,31 @@ ASTERISK_FILE_VERSION("$Revision$")
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
 
+static int midi_tohz[128] = {
+                       8,8,9,9,10,10,11,12,12,13,14,
+                       15,16,17,18,19,20,21,23,24,25,
+                       27,29,30,32,34,36,38,41,43,46,
+                       48,51,55,58,61,65,69,73,77,82,
+                       87,92,97,103,110,116,123,130,138,146,
+                       155,164,174,184,195,207,220,233,246,261,
+                       277,293,311,329,349,369,391,415,440,466,
+                       493,523,554,587,622,659,698,739,783,830,
+                       880,932,987,1046,1108,1174,1244,1318,1396,1479,
+                       1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,
+                       2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,
+                       4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,
+                       8869,9397,9956,10548,11175,11839,12543
+                       };
+
 struct playtones_item {
-       int freq1;
-       int freq2;
-       int duration;
+       int fac1;
+       int init_v2_1;
+       int init_v3_1;
+       int fac2;
+       int init_v2_2;
+       int init_v3_2;
        int modulate;
+       int duration;
 };
 
 struct playtones_def {
@@ -50,10 +82,17 @@ struct playtones_def {
 
 struct playtones_state {
        int vol;
+       int v1_1;
+       int v2_1;
+       int v3_1;
+       int v1_2;
+       int v2_2;
+       int v3_2;
        int reppos;
        int nitems;
        struct playtones_item *items;
        int npos;
+       int oldnpos;
        int pos;
        int origwfmt;
        struct ast_frame f;
@@ -88,6 +127,7 @@ static void * playtones_alloc(struct ast_channel *chan, void *params)
                ps->reppos = pd->reppos;
                ps->nitems = pd->nitems;
                ps->items = pd->items;
+               ps->oldnpos = -1;
        }
        /* Let interrupts interrupt :) */
        if (pd->interruptible)
@@ -113,20 +153,34 @@ static int playtones_generator(struct ast_channel *chan, void *data, int len, in
        memset(&ps->f, 0, sizeof(ps->f));
 
        pi = &ps->items[ps->npos];
+       if (ps->oldnpos != ps->npos) {
+               /* Load new parameters */
+               ps->v1_1 = 0;
+               ps->v2_1 = pi->init_v2_1;
+               ps->v3_1 = pi->init_v3_1;
+               ps->v1_2 = 0;
+               ps->v2_2 = pi->init_v2_2;
+               ps->v3_2 = pi->init_v3_2;
+               ps->oldnpos = ps->npos;
+       }
        for (x=0;x<len/2;x++) {
-               if (pi->modulate)
-               /* Modulate 1st tone with 2nd, to 90% modulation depth */
-               ps->data[x] = ps->vol * 2 * (
-                       sin((pi->freq1 * 2.0 * M_PI / 8000.0) * (ps->pos + x)) *
-                       (0.9 * fabs(sin((pi->freq2 * 2.0 * M_PI / 8000.0) * (ps->pos + x))) + 0.1)
-                       );
-               else
-                       /* Add 2 tones together */
-                       ps->data[x] = ps->vol * (
-                               sin((pi->freq1 * 2.0 * M_PI / 8000.0) * (ps->pos + x)) +
-                               sin((pi->freq2 * 2.0 * M_PI / 8000.0) * (ps->pos + x))
-                       );
+               ps->v1_1 = ps->v2_1;
+               ps->v2_1 = ps->v3_1;
+               ps->v3_1 = (pi->fac1 * ps->v2_1 >> 15) - ps->v1_1;
+               
+               ps->v1_2 = ps->v2_2;
+               ps->v2_2 = ps->v3_2;
+               ps->v3_2 = (pi->fac2 * ps->v2_2 >> 15) - ps->v1_2;
+               if (pi->modulate) {
+                       int p;
+                       p = ps->v3_2 - 32768;
+                       if (p < 0) p = -p;
+                       p = ((p * 9) / 10) + 1;
+                       ps->data[x] = (ps->v3_1 * p) >> 15;
+               } else
+                       ps->data[x] = ps->v3_1 + ps->v3_2; 
        }
+       
        ps->f.frametype = AST_FRAME_VOICE;
        ps->f.subclass = AST_FORMAT_SLINEAR;
        ps->f.datalen = len;
@@ -165,7 +219,7 @@ int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst,
        if (!data)
                return -1;
        if (vol < 1)
-               d.vol = 8192;
+               d.vol = 7219; /* Default to -8db */
 
        d.interruptible = interruptible;
        
@@ -178,7 +232,7 @@ int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst,
                separator = ",";
        s = strsep(&stringp,separator);
        while (s && *s) {
-               int freq1, freq2, time, modulate=0;
+               int freq1, freq2, time, modulate=0, midinote=0;
 
                if (s[0]=='!')
                        s++;
@@ -203,16 +257,61 @@ int ast_playtones_start(struct ast_channel *chan, int vol, const char *playlst,
                        /* f1 format */
                        freq2 = 0;
                        time = 0;
+               } else if (sscanf(s, "M%d+M%d/%d", &freq1, &freq2, &time) == 3) {
+                       /* Mf1+Mf2/time format */
+                       midinote = 1;
+               } else if (sscanf(s, "M%d+M%d", &freq1, &freq2) == 2) {
+                       /* Mf1+Mf2 format */
+                       time = 0;
+                       midinote = 1;
+               } else if (sscanf(s, "M%d*M%d/%d", &freq1, &freq2, &time) == 3) {
+                       /* Mf1*Mf2/time format */
+                       modulate = 1;
+                       midinote = 1;
+               } else if (sscanf(s, "M%d*M%d", &freq1, &freq2) == 2) {
+                       /* Mf1*Mf2 format */
+                       time = 0;
+                       modulate = 1;
+                       midinote = 1;
+               } else if (sscanf(s, "M%d/%d", &freq1, &time) == 2) {
+                       /* Mf1/time format */
+                       freq2 = -1;
+                       midinote = 1;
+               } else if (sscanf(s, "M%d", &freq1) == 1) {
+                       /* Mf1 format */
+                       freq2 = -1;
+                       time = 0;
+                       midinote = 1;
                } else {
                        ast_log(LOG_WARNING,"%s: tone component '%s' of '%s' is no good\n",chan->name,s,playlst);
                        return -1;
                }
 
+               if (midinote) {
+                       /* midi notes must be between 0 and 127 */
+                       if ((freq1 >= 0) && (freq1 <= 127))
+                               freq1 = midi_tohz[freq1];
+                       else
+                               freq1 = 0;
+
+                       if ((freq2 >= 0) && (freq2 <= 127))
+                               freq2 = midi_tohz[freq2];
+                       else
+                               freq2 = 0;
+               }
+
                d.items = realloc(d.items,(d.nitems+1)*sizeof(struct playtones_item));
-               if (d.items == NULL)
+               if (d.items == NULL) {
+                       ast_log(LOG_WARNING, "Realloc failed!\n");
                        return -1;
-               d.items[d.nitems].freq1    = freq1;
-               d.items[d.nitems].freq2    = freq2;
+               }
+               d.items[d.nitems].fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
+               d.items[d.nitems].init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * d.vol;
+               d.items[d.nitems].init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * d.vol;
+
+               d.items[d.nitems].fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
+               d.items[d.nitems].init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * d.vol;
+               d.items[d.nitems].init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * d.vol;
                d.items[d.nitems].duration = time;
                d.items[d.nitems].modulate = modulate;
                d.nitems++;