Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
tonetool.cpp
Go to the documentation of this file.
1 // Copyright (C) 2006-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU ccAudio2.
4 //
5 // GNU ccAudio2 is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU ccAudio2 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 Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with GNU ccAudio2. If not, see <http://www.gnu.org/licenses/>.
17 
18 #include <bayonne.h>
19 #include <config.h>
20 
21 using namespace BAYONNE_NAMESPACE;
22 using namespace UCOMMON_NAMESPACE;
23 
24 static const char *delfile = NULL;
25 static shell::flagopt helpflag('h',"--help", _TEXT("display this list"));
26 static shell::flagopt althelp('?', NULL, NULL);
27 static shell::stringopt configdir('C', "--config", _TEXT("config directory"), "path", NULL);
28 static shell::stringopt encoding('e', "--encoding", _TEXT("audio format"), "type", "pcmu");
29 static shell::numericopt framing('f', "--framing", _TEXT("audio framing"), "msec", 20);
30 static shell::numericopt interdigit('i', "--interdigit", _TEXT("interdigit timing"), "msec", 60);
31 static shell::numericopt level('l', "--level", _TEXT("audio level"), "level", 30000);
32 static shell::numericopt maxtime('m', "--max", _TEXT("max time"), "msec", 60000);
33 static shell::numericopt offset('s', "--offset", _TEXT("offset into stream"), "msec", 0);
34 static shell::stringopt lang('L', "--lang", _TEXT("specify language"), "language", "C");
35 static shell::stringopt prefix('P', "--prefix", _TEXT("specify alternate prefix path"), "path", NULL);
36 static shell::stringopt suffix('S', "--suffix", _TEXT("audio extension"), ".ext", ".au");
37 static shell::stringopt voice('V', "--voice", _TEXT("specify voice library"), "name", "default");
38 static shell::stringopt phrasebook('B', "--phrasebook", _TEXT("specify phrasebook directory"), "path", NULL);
39 static Env::pathinfo_t ruleset;
40 
41 static Tonegen *getTone(char **argv, Audio::level_t l, timeout_t framing, timeout_t interdigit)
42 {
43  Tonegen::key_t *key;
44  char *name, *locale;
45 
46  if(!stricmp(*argv, "dtmf"))
47  return new DTMFDialer(*(++argv), l, framing, interdigit);
48  else if(!stricmp(*argv, "mf"))
49  return new MFDialer(*(++argv), l, framing, interdigit);
50 
51  name = *(argv++);
52  locale = *(argv);
53  key = Tonegen::find(name, locale);
54  if(!key)
55  return NULL;
56 
57  return new Tonegen(key, l, framing);
58 }
59 
60 static const char *fname(const char *cp)
61 {
62  const char *fn = strrchr(cp, '/');
63  if(!fn)
64  fn = strrchr(cp, '\\');
65  if(fn)
66  return ++fn;
67  return cp;
68 }
69 
70 void writeTones(char **argv, bool append)
71 {
72  Tonegen *tone;
73  AudioStream output;
74  Audio::info_t info, make;
75  const char *target;
76  unsigned maxframes;
77  Audio::linear_t buffer;
78  char *filename = (char *)"tones.conf";
79  char pathbuf[256];
80 
81  Tonegen::load(filename);
82 
83  if(*argv)
84  target = *(argv++);
85 
86  if(!*argv) {
87  shell::errexit(3, "*** tonetool: %s\n",
88  _TEXT("no tone spec to use"));
89  }
90 
91  if(!append)
92  make.encoding = Audio::getEncoding(*encoding);
93 
94  ruleset.voices = *voice;
95 
96  if(!Env::path(ruleset, target, pathbuf, sizeof(pathbuf), true))
97  shell::errexit(3, "*** tonetool: %s: %s\n",
98  target, _TEXT("invalid destination"));
99  else
100  target = pathbuf;
101 
102  make.rate = Audio::rate8khz;
103 
104  if(!append) {
105  remove(target);
106  output.create(target, make, *framing);
107  }
108  else {
109  output.open(target, Audio::modeWrite, *framing);
110  if(is(offset))
111  output.setPosition(*offset);
112  else
113  output.setPosition();
114  }
115 
116  if(!output.is_open()) {
117  shell::errexit(3, "*** tonetool: %s: %s\n",
118  fname(target), _TEXT("cannot access"));
119  }
120 
121  if(!output.is_streamable()) {
122  shell::errexit(4, "*** tonetool: %s: %s\n",
123  fname(target), _TEXT("unable to load codec"));
124  }
125 
126  output.getInfo(info);
127 
128  tone = getTone(argv, ((Audio::level_t)*level), info.framing, *interdigit);
129 
130  if(!tone) {
131  shell::errexit(5, "*** tonetool: %s\n",
132  _TEXT("unrecognized tone spec used"));
133  }
134 
135  printf("%s: ", fname(target));
136  maxframes = *maxtime / info.framing;
137 
138  while(maxframes--) {
139  buffer = tone->getFrame();
140  if(!buffer) {
141  if(tone->is_complete())
142  break;
143  printf("!");
144  continue;
145  }
146  output.putMono(buffer);
147  if(tone->is_silent())
148  printf(".");
149  else
150  printf("+");
151  }
152  printf("\n");
153  output.close();
154  exit(0);
155 }
156 
157 void listTones(char **argv)
158 {
159  const char *locale = NULL;
160  const char *option;
161  Tonegen::key_t *key;
162  Tonegen::def_t *def;
163 
164 retry:
165  option = *argv;
166 
167  if(eq("--", option)) {
168  ++argv;
169  goto skip;
170  }
171 
172  if(eq("--", option, 2))
173  ++option;
174 
175  if(eq(option, "-locale=", 8)) {
176  locale = option + 8;
177  ++argv;
178  goto retry;
179  }
180 
181  if(eq(option, "-locale")) {
182  ++argv;
183  if(!(*argv)) {
184  shell::errexit(2, "*** tonetool: -locale: %s\n",
185  _TEXT("missing argument"));
186  }
187 
188  locale = *(argv++);
189  goto retry;
190  }
191 
192 
193 skip:
194  if(*argv && **argv == '-') {
195  shell::errexit(1, "*** tonetool: %s: %s\n",
196  *argv, _TEXT("unknown option"));
197  }
198 
199  if(!*argv) {
200  shell::errexit(3, "*** tonetool: %s\n",
201  _TEXT("tone name missing"));
202  }
203 
204  if(!Tonegen::load(locale)) {
205  shell::errexit(4, "*** tonetool: %s\n",
206  _TEXT("unable to load"));
207  }
208 
209  while(*argv) {
210  printf("%s:", *argv);
211  key = Tonegen::find(*(argv++), locale);
212  if(!key) {
213  printf(" %s\n", _TEXT("not found"));
214  continue;
215  }
216  printf("\n");
217  def = key->first;
218  while(def) {
219  printf(" ");
220  if(def->f2 && def->f1)
221  printf("%d+%d", def->f1, def->f2);
222  else
223  printf("%d", def->f1);
224 
225  if(def->duration)
226  printf(" %ldms\n", def->duration);
227  else {
228  printf(" forever\n");
229  break;
230  }
231 
232  if(def->silence)
233  printf(" silence %ldms\n", def->silence);
234 
235  if(def == key->last) {
236  if(def->next == key->first)
237  printf(" repeat full\n");
238  else if(def->next)
239  printf(" repeat partial\n");
240  break;
241  }
242  def = def->next;
243  }
244  }
245  exit(0);
246 }
247 
248 void toneDetect(char **argv)
249 {
250  DTMFDetect *dtmf;
251  AudioStream input;
252  Audio::Info info, make;
253  const char *target;
254  Audio::linear_t buffer;
255  char result[128];
256  char pathbuf[256];
257 
258  ruleset.voices = *voice;
259 
260  while(*argv) {
261  target = *(argv++);
262 
263  if(!Env::path(ruleset, target, pathbuf, sizeof(pathbuf)))
264  shell::errexit(3, "*** tonetool: %s: %s\n",
265  target, _TEXT("invalid destination"));
266  else
267  target = pathbuf;
268 
269  input.open(target, Audio::modeRead, *framing);
270 
271  if(!input.is_open()) {
272  shell::errexit(3, "*** tonetool: %s: %s\n",
273  fname(target), _TEXT("cannot access"));
274  }
275 
276  if(!input.is_streamable()) {
277  shell::errexit(4, "*** tonetool: %s: %s\n",
278  fname(target), _TEXT("unable to load codec"));
279  }
280 
281  input.getInfo(info);
282  dtmf = new DTMFDetect;
283 
284  buffer = new Audio::sample_t[input.getCount()];
285  for(;;)
286  {
287  if(!input.getMono(buffer, 1))
288  break;
289 
290  dtmf->putSamples(buffer, input.getCount());
291  }
292 
293  dtmf->getResult(result, sizeof(result));
294  printf("%s: %s\n", fname(target), result);
295 
296  input.close();
297  delete[] buffer;
298  delete dtmf;
299  }
300  exit(0);
301 }
302 
303 static void stop(void)
304 {
305  if(delfile) {
306  ::remove(delfile);
307  delfile = NULL;
308  }
309 }
310 
311 PROGRAM_MAIN(argc, argv)
312 {
313  shell::bind("tonetool");
314  shell args(argc, argv);
315 
316  Env::tool(&args);
317 
318  if(is(prefix))
319  Env::set("prefix", *prefix);
320 
321  if(is(phrasebook))
322  Env::set("voices", *phrasebook);
323 
324  if(is(suffix))
325  Env::set("extension", *suffix);
326 
327  if(is(configdir))
328  Env::set("config", *configdir);
329 
330  if(is(lang))
331  ruleset.book = Phrasebook::find(*lang);
332  else
333  ruleset.book = Phrasebook::find(NULL);
334 
335  if(is(helpflag) || is(althelp)) {
336  printf("%s\n", _TEXT("Usage: tonetool [options] command [arguments...]"));
337  printf("%s\n\n", _TEXT("Tone tool operations"));
338  printf("%s\n", _TEXT("Options:"));
339  shell::help();
340  printf("\n%s\n", _TEXT("Report bugs to dyfet@gnu.org"));
341  PROGRAM_EXIT(0);
342  }
343 
344  if(!args())
345  shell::errexit(1, "*** tonetool: %s\n",
346  _TEXT("no command specified"));
347 
348  const char *cp = args[0];
349 
350  argv = args.argv();
351  ++argv;
352 
353  shell::exiting(stop);
354 
355  if(eq(cp, "list"))
356  listTones(argv);
357  else if(eq(cp, "detect"))
358  toneDetect(argv);
359  else if(eq(cp, "create"))
360  writeTones(argv, false);
361  else if(eq(cp, "append"))
362  writeTones(argv, true);
363 
364  shell::errexit(1, "*** tonetool: %s: %s\n",
365  cp, _TEXT("unknown option"));
366 
367  PROGRAM_EXIT(0);
368 }
369 
PROGRAM_MAIN(argc, argv)
Definition: tonetool.cpp:311
void toneDetect(char **argv)
Definition: tonetool.cpp:248
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
void writeTones(char **argv, bool append)
Definition: tonetool.cpp:70
GNU Bayonne library namespace.
void listTones(char **argv)
Definition: tonetool.cpp:157