713f818a5c674b1d8cf96739af220e9ba893c8b3
[lcr.git] / ss5_decode.c
1 /*
2  * SS5 signal decoder.
3  *
4  * Copyright            by Andreas Eversberg (jolly@eversberg.eu)
5  *                      based on different decoders such as ISDN4Linux
6  *                      copyright by Karsten Keil
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  */
12
13 #include "main.h"
14 #include "ss5_decode.h"
15
16 /* enable level debugging */
17 //#define DEBUG_LEVELS
18
19 #define NCOEFF          8       /* number of frequencies to be analyzed */
20
21 #define TONE_MIN_DB     0.01995262 /* -17 db */
22 #define TONE_DIFF_DB    0.2 // 0.31622777 /*  -5 db */
23 #define NOISE_MIN_DB    (TONE_MIN_DB / 2) /* noise must be higher than the minimum of two tones */
24 #define SNR             1.3     /* noise may not exceed signal by that factor */
25
26 /* For DTMF recognition:
27  * 2 * cos(2 * PI * k / N) precalculated for all k
28  */
29 static signed long long cos2pik[NCOEFF] =
30 {
31         /* k = 2*cos(2*PI*f/8000), k << 15 
32          * 700, 900, 1100, 1300, 1500, 1700, 2400, 2600 */
33         55879, 49834, 42562, 34242, 25080, 15299, -20252, -29753
34 };
35
36 /* detection matrix for two frequencies */
37 static char decode_two[8][8] =
38 {
39         {' ', '1', '2', '4', '7', '*', ' ', ' '}, /* * = code 11 */
40         {'1', ' ', '3', '5', '8', '#', ' ', ' '}, /* # = code 12 */
41         {'2', '3', ' ', '6', '9', 'a', ' ', ' '}, /* a = KP1 */
42         {'4', '5', '6', ' ', '0', 'b', ' ', ' '}, /* b = KP2 */
43         {'7', '8', '9', '0', ' ', 'c', ' ', ' '}, /* c = ST */
44         {'*', '#', 'a', 'b', 'c', ' ', ' ', ' '},
45         {' ', ' ', ' ', ' ', ' ', ' ', ' ', 'C'}, /* C = 2600+2400 */
46         {' ', ' ', ' ', ' ', ' ', ' ', 'C', ' '}
47 };
48
49 static char decode_one[8] =
50         {' ', ' ', ' ', ' ', ' ', ' ', 'A', 'B'}; /* A = 2400, B = 2600 */
51 /*
52  * calculate the coefficients of the given sample and decode
53  */
54
55 char ss5_decode(unsigned char *data, int len)
56 {
57         signed short buf[len];
58         signed long sk, sk1, sk2, low, high;
59         int k, n, i;
60         int f1 = 0, f2 = 0;
61         double result[NCOEFF], power, noise;
62 #ifdef DEBUG_LEVELS
63         double snr;
64 #endif
65         signed long long cos2pik_;
66         char digit = ' ';
67
68         /* convert samples */
69         for (i = 0; i < len; i++)
70                 buf[i] = audio_law_to_s32[*data++];
71
72         /* now we do noise level calculation */
73         low = 32767;
74         high = -32768;
75         for (n = 0; n < len; n++) {
76                 sk = buf[n];
77                 if (sk < low)
78                         low = sk;
79                 if (sk > high)
80                         high = sk;
81         }
82         noise = ((double)(high-low) / 65536.0);
83
84         /* check for minimum noise, or tone detection will not be necessary */
85         if (noise < NOISE_MIN_DB)
86                 return digit;
87
88         /* now we have a full buffer of signed long samples - we do goertzel */
89         for (k = 0; k < NCOEFF; k++) {
90                 sk = 0;
91                 sk1 = 0;
92                 sk2 = 0;
93                 cos2pik_ = cos2pik[k];
94                 for (n = 0; n < len; n++) {
95                         sk = ((cos2pik_*sk1)>>15) - sk2 + buf[n];
96                         sk2 = sk1;
97                         sk1 = sk;
98                 }
99                 sk >>= 8;
100                 sk2 >>= 8;
101                 if (sk > 32767 || sk < -32767 || sk2 > 32767 || sk2 < -32767)
102                         PERROR("Tone-Detection overflow\n");
103                 /* compute |X(k)|**2 */
104                 result[k] = sqrt (
105                                 (sk * sk) -
106                                 (((cos2pik[k] * sk) >> 15) * sk2) +
107                                 (sk2 * sk2)
108                         ) / len / 62; /* level of 1 is 0 db*/
109         }
110
111         /* find the two loudest frequencies + one less lower frequency to detect noise */
112         power = 0.0;
113         for (i = 0; i < NCOEFF; i++) {
114                 if (result[i] > power) {
115                         power = result[i];
116                         f1 = i;
117                 }
118         }
119         power = 0.0;
120         for (i = 0; i < NCOEFF; i++) {
121                 if (i != f1 && result[i] > power) {
122                         power = result[i];
123                         f2 = i;
124                 }
125         }
126
127 #ifdef DEBUG_LEVELS
128         snr = 0;
129 #endif
130         /* check one frequency */
131         if (result[f1] > TONE_MIN_DB /* must be at least -17 db */
132          && result[f1]*SNR > noise) { /*  */
133                 digit = decode_one[f1];
134 #ifdef DEBUG_LEVELS
135                 if (digit != ' ')
136                         snr = result[f1] / noise;
137 #endif
138         }
139         /* check two frequencies */
140         if (result[f1] > TONE_MIN_DB && result[f2] > TONE_MIN_DB /* must be at lease -17 db */
141          && result[f1]*TONE_DIFF_DB <= result[f2] /* f2 must be not less than 5 db below f1 */
142          && (result[f1]+result[f2])*SNR > noise) { /* */
143                 digit = decode_two[f1][f2];
144 #ifdef DEBUG_LEVELS
145                 if (digit != ' ')
146                         snr = (result[f1]+result[f2]) / noise;
147 #endif
148         }
149
150         /* debug powers */
151 #ifdef DEBUG_LEVELS
152         for (i = 0; i < NCOEFF; i++)
153                 printf("%d:%3d %c ", i, (int)(result[i]*100), (f1==i || f2==i)?'*':' ');
154         printf("N:%3d digit:%c snr=%3d\n", (int)(noise*100), digit, (int)(snr*100));
155 //      if (result[f1]*TONE_DIFF_DB <= result[f2]) /* f2 must be not less than 5 db below f1 */
156 //              printf("jo!");
157 #endif
158
159         return digit;
160 }
161
162 void ss5_test_decode(void)
163 {
164 #ifdef DEBUG_LEVELS
165         double phase;
166         int i, j;
167         signed short sample;
168
169         unsigned char buffer[SS5_DECODER_NPOINTS];
170         for (i = 0; i < 4000; i += 10) {
171                 phase = 2.0 * 3.14159265 * i / 8000.0;
172                 for (j = 0; j < SS5_DECODER_NPOINTS; j++) {
173                         sample = sin(phase * j) * 1000;
174                         buffer[j] = audio_s16_to_law[sample & 0xffff];
175                 }
176                 printf("FRQ:%04d:", i);
177                 ss5_decode(buffer, SS5_DECODER_NPOINTS);
178         }
179 #endif
180 }
181