1 // Copyright (C) 2008-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU Bayonne.
4 //
5 // GNU Bayonne is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU Bayonne is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
17
18 #include <config.h>
19 #include <ucommon/ucommon.h>
20 #include <ucommon/export.h>
22 #include <ctype.h>
23
24 #ifdef HAVE_MATH_H
25 #include <math.h>
26 #endif
27
29 using namespace UCOMMON_NAMESPACE;
30
31 #ifndef M_PI
32 #define M_PI 3.14159265358979323846
33 #endif
34
35 #define MAP_HASH_SIZE 197
36 #define MAP_PAGE_COUNT 255
37 #define MAP_PAGE_SIZE (sizeof(void *[MAP_PAGE_COUNT]))
38 #define MAP_PAGE_FIX (MAP_PAGE_SIZE / MAP_PAGE_COUNT)
39
40 static unsigned char *page = NULL;
43
44 static unsigned key(const char *id)
45 {
46 unsigned val = 0;
47 while(*id)
48 val = (val << 1) ^ (*(id++) & 0x1f);
49
51 }
52
53 static void *map(unsigned len)
54 {
55 unsigned char *pos;
57
58 if(fix)
60
63 used = 0;
64 }
65
66 pos = page + used;
67 used += len;
68 return pos;
69 }
70
71 Tonegen::Tonegen(timeout_t duration, rate_t r)
72 {
73 rate = r;
74 df1 = df2 = 0;
75 samples = (duration *(long)rate) / 1000;
76 frame = new sample_t[samples];
77 silencer = true;
78 complete = false;
79 def = NULL;
80
81 reset();
82 }
83
84 Tonegen::Tonegen(key_t *k, level_t l, timeout_t duration)
85 {
86 rate = rate8khz;
87 df1 = df2 = 0;
88 samples = (duration *(long)rate) / 1000;
89 frame = new sample_t[samples];
90 silencer = true;
91 complete = false;
92
93 reset();
94
95 tone = k;
96
97 if(!tone) {
98 complete = true;
99 return;
100 }
101
102 framing = duration;
103 def = tone->first;
104 complete = false;
105 remaining = silent = count = 0;
106 level = l;
107 }
108
109 Tonegen::Tonegen(unsigned freq, level_t l, timeout_t duration, rate_t r)
110 {
111 rate = r;
112 df1 = (freq *
M_PI * 2) / (
long)rate;
113 df2 = (freq *
M_PI * 2) / (
long)rate;
114 p1 = 0, p2 = 0;
115 samples = (duration * (long)rate) / 1000;
116 m1 = l / 2;
117 m2 = l / 2;
118 silencer = false;
119 complete = false;
120 def = NULL;
121
122 frame = new sample_t[samples];
123 }
124
125 Tonegen::Tonegen(unsigned f1, unsigned f2, level_t l1, level_t l2, timeout_t duration, rate_t r)
126 {
127 rate = r;
128 df1 = (f1 *
M_PI * 2) / (
long)r;
129 df2 = (f2 *
M_PI * 2) / (
long)r;
130 p1 = 0, p2 = 0;
131 samples = (duration * (long)r) / 1000;
132 m1 = l1 / 2;
133 m2 = l2 / 2;
134 silencer = false;
135 complete = false;
136 def = NULL;
137
138 frame = new sample_t[samples];
139 }
140
141 unsigned Tonegen::getFrames(linear_t buffer, unsigned pages)
142 {
143 unsigned count = 0;
144 linear_t save = frame;
145
146 while(count < pages) {
147 frame = buffer;
148 buffer += samples;
149 if(!getFrame())
150 break;
151 ++count;
152 }
153
154 if(count && count < pages)
155 memset(buffer, 0, samples * (pages - count) * 2);
156
157 frame = save;
158 return count;
159 }
160
161 void Tonegen::silence(void)
162 {
163 silencer = true;
164 }
165
166 void Tonegen::reset(void)
167 {
168 m1 = m2 = 0;
169 p1 = p2 = 0;
170 }
171
172 void Tonegen::single(unsigned freq, level_t l)
173 {
174 df1 = (freq *
M_PI * 2) / (
long)rate;
175 df2 = (freq *
M_PI * 2) / (
long)rate;
176 m1 = l / 2;
177 m2 = l / 2;
178 silencer = false;
179 complete = false;
180 def = NULL;
181 }
182
183 void Tonegen::dual(unsigned f1, unsigned f2, level_t l1, level_t l2)
184 {
185 df1 = (f1 *
M_PI * 2) / (
long)rate;
186 df2 = (f2 *
M_PI * 2) / (
long)rate;
187 m1 = l1 / 2;
188 m2 = l2 / 2;
189 silencer = false;
190 complete = false;
191 def = NULL;
192 }
193
194 Audio::linear_t Tonegen::getFrame(void)
195 {
196 unsigned count = samples;
197 linear_t data = frame;
198
199 if(complete)
200 return NULL;
201
202 if(def) {
203 if(count >= def->count && !remaining && !silent) {
204 def = def->next;
205 count = 0;
206 if(!def) {
207 complete = true;
208 return NULL;
209 }
210 }
211
212 if(!remaining && !silent) {
213 if(count && !def->duration)
214 goto get;
215
216 if(def->f2)
217 dual(def->f1, def->f2, level, level);
218 else
219 single(def->f1, level);
220 ++count;
221 remaining = def->duration / framing;
222 if(def->silence)
223 silent = (def->duration + def->silence) / framing - remaining;
224 else
225 silent = 0;
226 }
227
228 if(!remaining && m1 && silent)
229 reset();
230
231 if(remaining)
232 --remaining;
233 else if(silent)
234 --silent;
235 }
236
237 get:
238
239 if(is_silent() && !p1 && !p2) {
240 if(!p1 && !p2) {
241 memset(frame, 0, samples * 2);
242 return frame;
243 }
244 }
245 else if(silencer)
246 {
247 while(count--) {
248 if(p1 <= 0 && df1 >= p1) {
249 p1 = 0;
250 df1 = 0;
251 m1 = 0;
252 }
253 if(p1 >= 0 && -df1 >= p1) {
254 p1 = 0;
255 df1 = 0;
256 m1 = 0;
257 }
258 if(p2 <= 0 && df2 >= p1) {
259 p2 = 0;
260 df2 = 0;
261 m2 = 0;
262 }
263 if(p2 >= 0 && -df2 >= p1) {
264 p2 = 0;
265 df2 = 0;
266 m2 = 0;
267 }
268
269 if(!m1 && !m2) {
270 *(data++) = 0;
271 continue;
272 }
273
274 *(data++) = (level_t)(sin(p1) * (double)m1) +
275 (level_t)(sin(p2) * (double)m2);
276
277 p1 += df1;
278 p2 += df2;
279 }
280 }
281 else {
282 while(count--) {
283 *(data++) = (level_t)(sin(p1) * (double)m1) +
284 (level_t)(sin(p2) * (double)m2);
285
286 p1 += df1;
287 p2 += df2;
288 }
289 }
290
291 return frame;
292 }
293
294 Tonegen::~Tonegen()
295 {
296 cleanup();
297 }
298
299 void Tonegen::cleanup(void)
300 {
301 if(frame) {
302 delete[] frame;
303 frame = NULL;
304 }
305 }
306
307 bool Tonegen::is_silent(void)
308 {
309 if(!m1 && !m2)
310 return true;
311
312 return false;
313 }
314
315 bool Tonegen::load(const char *l)
316 {
317 char buffer[256];
318 char locale[256];
319 char *loclist[128], *cp, *ep, *name;
320 char *lists[64];
321 char **field, *freq, *fdur, *fcount;
322 def_t *def, *first, *again, *last, *final = NULL;
323 key_t *tk;
324 unsigned count, i, k;
325 unsigned lcount = 0;
326 FILE *fp;
327 char namebuf[65];
328 bool loaded = false;
329
330 fp = fopen(config("tones.conf"), "r");
331 if(!fp)
332 return false;
333
334 memset(&hash, 0, sizeof(hash));
335
336 for(;;)
337 {
338 if(!fgets(buffer, sizeof(buffer) - 1, fp) || feof(fp))
339 break;
340 cp = buffer;
341 while(isspace(*cp))
342 ++cp;
343
344 if(*cp == '[') {
345 if(loaded)
346 break;
347 strcpy(locale, buffer);
348 cp = locale;
349 lcount = 0;
350 cp = strtok(cp, "[]|\r\n");
351 while(cp) {
352 if(*cp && !l)
353 loclist[lcount++] = cp;
354 else if(*cp && !stricmp(cp, l))
355 {
356 loclist[lcount++] = cp;
357 loaded = true;
358 }
359 cp = strtok(NULL, "[]|\r\n");
360 }
361 continue;
362 }
363
364 if(!isalpha(*cp) || !lcount)
365 continue;
366
367 ep = strchr(cp, '=');
368 if(!ep)
369 continue;
370 *(ep++) = 0;
371 name = strtok(cp, " \t");
372 cp = strchr(ep, ';');
373 if(cp)
374 *cp = 0;
375 cp = strchr(ep, '#');
376 if(cp)
377 *cp = 0;
378 cp = strtok(ep, ",");
379 count = 0;
380 while(cp) {
381 while(isspace(*cp))
382 ++cp;
383
384 lists[count++] = cp;
385 cp = strtok(NULL, ",");
386 }
387 if(!count)
388 continue;
389
390 field = &lists[0];
391 first = last = again = NULL;
392 while(count--) {
393 freq = strtok(*field, " \t\r\n");
394 fdur = strtok(NULL, " \t\r\n");
395 fcount = strtok(NULL, " \t\r\n");
396
397 if(!freq)
398 goto skip;
399
400 freq = strtok(freq, " \r\r\n");
401
402 if(isalpha(*freq)) {
403 tk = find(freq, loclist[0]);
404 if(tk) {
405 if(!first)
406 first = tk->first;
407 else {
408 final = tk->last;
409 again = tk->first;
410 }
411 }
412 break;
413 }
414
415 def = (def_t *)map(sizeof(def_t));
416 memset(def, 0, sizeof(def_t));
417 if(!first)
418 first = def;
419 else
420 last->next = def;
421
422 last = final = def;
423
424 def->next = NULL;
425
426 if(!fdur || !atol(fdur)) {
427 again = def;
428 count = 0;
429 }
430 else if((!fcount || !atoi(fcount)) && !count)
431 again = first;
432
433 cp = strtok(freq, " \t\r\n");
434 ep = cp;
435 while(isdigit(*ep))
436 ++ep;
437 def->f1 = atoi(cp);
438 if(*ep)
439 def->f2 = atoi(++ep);
440 else
441 def->f2 = 0;
442
443 if(!fcount)
444 fcount = (char *)"1";
445
446 def->count = atoi(fcount);
447 if(!def->count)
448 ++def->count;
449
450 if(!fdur)
451 goto skip;
452
453 cp = strtok(fdur, " \t\r\n");
454 ep = cp;
455 while(isdigit(*ep))
456 ++ep;
457 def->duration = atol(cp);
458 if(*ep)
459 def->silence = atol(++ep);
460 else
461 def->silence = 0;
462
463 skip:
464 ++field;
465 }
466 if(last)
467 last->next = again;
468 field = &loclist[0];
469 i = lcount;
470 while(i--) {
471 snprintf(namebuf, sizeof(namebuf), "%s.%s",
472 *(field++), name);
473 tk = (key_t *)map((unsigned)sizeof(key_t) + strlen(namebuf));
474 strcpy(tk->id, namebuf);
475 tk->first = first;
476 tk->last = final;
477 k = key(namebuf);
478 tk->next = hash[k];
479 hash[k] = tk;
480 }
481 }
482
483 fclose(fp);
484
485 if(page)
486 return true;
487 return false;
488 }
489
490 Tonegen::key_t *Tonegen::find(const char *id, const char *locale)
491 {
492 unsigned k;
493 key_t *tk;
494 char namebuf[65];
495
496 if(!locale)
497 locale="us";
498
499 snprintf(namebuf, sizeof(namebuf), "%s.%s", locale, id);
500 k = key(namebuf);
501 tk = hash[k];
502
503 while(tk) {
504 if(!stricmp(namebuf, tk->id))
505 break;
506 tk = tk->next;
507 }
508 return tk;
509 }
510
511
512
#define BAYONNE_NAMESPACE
GNU Bayonne library namespace.