Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
tonegen.cpp
Go to the documentation of this file.
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>
21 #include <bayonne.h>
22 #include <ctype.h>
23 
24 #ifdef HAVE_MATH_H
25 #include <math.h>
26 #endif
27 
28 using namespace BAYONNE_NAMESPACE;
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;
41 static unsigned used = MAP_PAGE_SIZE;
42 static Tonegen::key_t *hash[MAP_HASH_SIZE];
43 
44 static unsigned key(const char *id)
45 {
46  unsigned val = 0;
47  while(*id)
48  val = (val << 1) ^ (*(id++) & 0x1f);
49 
50  return val % MAP_HASH_SIZE;
51 }
52 
53 static void *map(unsigned len)
54 {
55  unsigned char *pos;
56  unsigned fix = len % MAP_PAGE_FIX;
57 
58  if(fix)
59  len += MAP_PAGE_FIX - fix;
60 
61  if(used + len > MAP_PAGE_SIZE) {
62  page = (unsigned char *)(new void *[MAP_PAGE_COUNT]);
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 MAP_PAGE_COUNT
Definition: tonegen.cpp:36
#define MAP_PAGE_FIX
Definition: tonegen.cpp:38
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
#define MAP_HASH_SIZE
Definition: tonegen.cpp:35
GNU Bayonne library namespace.
#define MAP_PAGE_SIZE
Definition: tonegen.cpp:37
#define M_PI
Definition: tonegen.cpp:32