1 //
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
19 #include <config.h>
20
22 using namespace UCOMMON_NAMESPACE;
23
24 #ifdef HAVE_ENDIAN_H
25 #include <endian.h>
26 #endif
27
28 #if !defined(__BIG_ENDIAN)
29 #define __LITTLE_ENDIAN 1234
30 #define __BIG_ENDIAN 4321
31 #define __PDP_ENDIAN 3412
32 #define __BYTE_ORDER __LITTLE_ENDIAN
33 #endif
34
35 static const char *delfile = NULL;
36 static shell::stringopt encopt('e', "--encoding", _TEXT("audio encoding"), "name", NULL);
37 static shell::numericopt framing('f', "--framing", _TEXT("audio framing"), "msec", 20);
38 static shell::numericopt pad('p', "--padding", _TEXT("padding frames"), "count", 0);
39 static shell::numericopt rateopt('r', "--rate", _TEXT("audio rate"), "samples per second", 0);
40 static shell::numericopt silent('s', "--silence", _TEXT("silence level"), "level", 0);
41 static shell::flagopt helpflag('h',"--help", _TEXT("display this list"));
42 static shell::flagopt althelp('?', NULL, NULL);
43 static shell::stringopt lang('L', "--lang", _TEXT("specify language"), "language", "C");
44 static shell::stringopt prefix('P', "--prefix", _TEXT("specify alternate prefix path"), "path", NULL);
45 static shell::stringopt suffix('S', "--suffix", _TEXT("audio extension"), ".ext", ".au");
46 static shell::stringopt voice('V', "--voice", _TEXT("specify voice library"), "name", "default");
47 static shell::stringopt phrasebook('B', "--phrasebook", _TEXT("specify phrasebook directory"), "path", NULL);
48 static Env::pathinfo_t rules;
49
51 {
52 private:
53 char pathbuf[256];
54 char **list;
55 const char *getContinuation(void);
56
57 public:
59 void open(char **argv);
60
63 };
64
66 {
67 private:
68 char pathbuf[256];
69 char **list;
70 const char *getContinuation(void);
71
72 public:
74 void open(char **argv);
75 };
76
78 {
79 list = NULL;
80 }
81
83 {
84 const char *out = Env::path(rules, *(argv++), pathbuf, sizeof(pathbuf));
85 if(out)
86 AudioStream::open(out, modeRead, 10);
87 if(is_open())
88 list = argv;
89 }
90
91 const char *PacketStream::getContinuation(void)
92 {
93 if(!list)
94 return NULL;
95
96 return Env::path(rules, *(list++), pathbuf, sizeof(pathbuf));
97 }
98
99
101 {
102 list = NULL;
103 }
104
106 {
107 const char *out = Env::path(rules, *(argv++), pathbuf, sizeof(pathbuf));
108 if(out)
109 AudioStream::open(out, modeRead, 10);
110 if(is_open())
111 list = argv;
112 }
113
114 const char *AudioBuild::getContinuation(void)
115 {
116 if(!list)
117 return NULL;
118
119 return Env::path(rules, *(list++), pathbuf, sizeof(pathbuf));
120 }
121
123 {
124 unsigned long samples, copied;
125 linear_t buffer, source;
126 unsigned pages;
127 info_t from, to;
128 bool mono = true;
129 Audio::resample *resampler = NULL;
130 linear_t resample = NULL;
131
132 input.getInfo(from);
133 output.getInfo(to);
134
135 if(is_stereo(from.encoding) || is_stereo(to.encoding))
136 mono = false;
137
138 samples = input.getCount();
139
140
141 if(mono)
142 buffer = new Audio::sample_t[samples];
143 else
144 buffer = new Audio::sample_t[samples * 2];
145
146 source = buffer;
147
148 if(from.rate != to.rate) {
149 resampler = new Audio::resample((Audio::rate_t)from.rate, (Audio::rate_t)to.rate);
150 resample = new Audio::sample_t[resampler->estimate(samples)];
151 source = resample;
152 }
153
154 for(;;)
155 {
156 if(mono)
157 pages = input.getMono(buffer, 1);
158 else
159 pages = input.getStereo(buffer, 1);
160
161 if(!pages)
162 break;
163
164 if(resampler)
165 copied = resampler->process(buffer, resample, samples);
166 else
167 copied = samples;
168
169 if(mono)
170 output.bufMono(source, copied); // used to set npages
171 else
172 output.bufStereo(source, copied); // used to set npages
173
174 // if(!npages)
175 // break;
176 }
177
178 delete[] buffer;
179
180 if(resampler)
181 delete resampler;
182
183 if(resample)
184 delete[] resample;
185 }
186
188 {
189 unsigned bufsize;
190 encoded_t buffer;
191 info_t from, to;
192 // bool endian = false;
193 ssize_t status = 1;
194
195 input.getInfo(from);
196 output.getInfo(to);
197
198 // if(to.order && from.order && to.order != from.order && is_linear(from.encoding))
199 // endian = true;
200
201 bufsize = from.framesize;
202 buffer = new unsigned char[bufsize];
203
204 while(status > 0) {
205 status = input.getNative(buffer, bufsize);
206 if(status < 1)
207 break;
208
209 status = output.putNative(buffer, status);
210 }
211
212 delete[] buffer;
213 }
214
215 static void stop(void)
216 {
217 if(delfile) {
218 remove(delfile);
219 delfile = NULL;
220 }
221 }
222
223 static void codecs(void)
224 {
225 linked_pointer<AudioCodec> cp = AudioCodec::begin();
226
227 while(is(cp)) {
228 printf("%s - %s\n", cp->getName(), cp->getDescription());
229 cp.next();
230 }
231 exit(0);
232 }
233
234 static void version(void)
235 {
236 printf("%s\n", VERSION);
237 exit(0);
238 }
239
240 static void showendian(void)
241 {
243 printf("%s\n", _TEXT("big"));
244 else
245 printf("%s\n", _TEXT("little"));
246 exit(0);
247 }
248
249 static const char *fname(const char *cp)
250 {
251 const char *fn = strrchr(cp, '/');
252 if(!fn)
253 fn = strrchr(cp, '\\');
254 if(fn)
255 return ++fn;
256 return cp;
257 }
258
259 static void rewrite(const char *source, char *target, size_t max)
260 {
261 char *fn;
262 char buffer[256];
263
264 #ifdef WIN32
265 char *ext;
266 snprintf(buffer, sizeof(buffer), "%s", source);
267 while(NULL != (fn = strchr(buffer, '\\')))
268 *fn = '/';
269
270 fn = strrchr(buffer, '/');
271 if(fn) {
272 *(fn++) = 0;
273 ext = strrchr(fn, '.');
274 if(ext)
275 *ext = 0;
276 snprintf(target, max, "%s/%s.tmp", buffer, fn);
277 }
278 else {
279 ext = strrchr(buffer, '.');
280 if(ext)
281 *ext = 0;
282 snprintf(target, max, "%s.tmp", buffer);
283 }
284 #else
285 snprintf(buffer, sizeof(buffer), "%s", source);
286 fn = strrchr(buffer, '/');
287 if(fn) {
288 *(fn++) = 0;
289 snprintf(target, max, "%s/.tmp.%s", buffer, fn);
290 }
291 else
292 snprintf(target, max, ".tmp.%s", source);
293 #endif
294 }
295
296 static void chart(char **argv)
297 {
298 AudioFile file;
299 Audio::info_t info;
301 Audio::level_t silence = (Audio::level_t)*silent;
302 unsigned char *buffer;
303 short max, current;
304 unsigned long sum;
305 unsigned long count;
306 char pathbuf[256];
307
308 if(!*argv) {
309 shell::errexit(2, "*** audiotool: -chart: %s\n",
310 _TEXT("missing arguments"));
311 }
312
313 while(*argv) {
314 const char *out = Env::path(rules, *argv, pathbuf, sizeof(pathbuf));
315 if(!out || !fsys::isfile(out)) {
316 printf("%s: %s\n",
317 fname(*(argv++)), _TEXT("invalid"));
318 continue;
319 }
320 if(fsys::access(out, R_OK)) {
321 printf("%s: %s\n",
322 fname(*(argv++)), _TEXT("inaccessable"));
323 continue;
324 }
325 file.open(out, Audio::modeRead, *framing);
326 file.getInfo(info);
327 if(!Audio::is_linear(info.encoding))
328 codec = AudioCodec::get(info);
329 if(!Audio::is_linear(info.encoding) && !codec) {
330 printf("%s: %s\n",
331 fname(*(argv++)), _TEXT("cannot load codec"));
332 continue;
333 }
334
335 printf("%s: ", fname(*(argv++)));
336 buffer = new unsigned char[info.framesize];
337
338 max = 0;
339 sum = 0;
340 count = 0;
341
342 // autochart for silence value
343
344 while(!silence) {
345 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
346 break;
347 ++count;
348 if(codec)
349 sum += codec->impulse(buffer, info.framecount);
350 else
351 sum += Audio::impulse(info, buffer, info.framecount);
352 }
353
354 if(!silence && count)
355 silence = (Audio::level_t)(((sum / count) * 2) / 3);
356
357 max = 0;
358 sum = 0;
359 count = 0;
360
361 file.setPosition(0);
362
363 for(;;) {
364 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
365 break;
366 ++count;
367 if(codec) {
368 current = codec->peak(buffer, info.framecount);
369 if(current > max)
370 max = current;
371 sum += codec->impulse(buffer, info.framecount);
372 if(codec->is_silent(silence, buffer, info.framecount)) {
373 if(codec->peak(buffer, info.framecount) >= silence)
374 printf("^");
375 else
376 printf(".");
377 }
378 else
379 printf("+");
380 fflush(stdout);
381 continue;
382 }
383
384 current = Audio::peak(info, buffer, info.framecount);
385 if(current > max)
386 max = current;
387
388 sum += Audio::impulse(info, buffer, info.framecount);
389 if(Audio::impulse(info, buffer, info.framecount) < silence) {
390 if(Audio::peak(info, buffer, info.framecount) >= silence)
391 printf("^");
392 else
393 printf(".");
394 }
395 else
396 printf("+");
397 fflush(stdout);
398 }
399 printf("\n");
400 if(count)
401 printf("%s = %d, %s = %ld, %s = %d\n",
402 _TEXT("silence threashold"), silence,
403 _TEXT("avg frame energy"), (sum / count),
404 _TEXT("peak level"), max);
405
406 if(buffer)
407 delete[] buffer;
408
409
410 if(codec)
411 AudioCodec::release(codec);
412
413 codec = NULL;
414 buffer = NULL;
415
416 file.close();
417 }
418 exit(0);
419 }
420
421 static void info(char **argv)
422 {
423 AudioFile au;
424 Audio::Info info;
425 const char *fn;
426 unsigned long end;
427 unsigned long minutes, seconds, subsec, scale;
428 char pathbuf[256];
429
430 while(*argv) {
431 const char *out = Env::path(rules, *argv, pathbuf, sizeof(pathbuf));
432 if(!out || !fsys::isfile(out)) {
433 printf("audiotool: %s: %s\n",
434 fname(*(argv++)), _TEXT("invalid"));
435 continue;
436 }
437 if(fsys::access(out, R_OK)) {
438 printf("audiotool: %s: %s\n",
439 fname(*(argv++)), _TEXT("inaccessable"));
440 continue;
441 }
442 au.open(out, Audio::modeInfo, *framing);
443 au.getInfo(info);
444 au.setPosition();
445 end = au.getPosition();
446 printf("%s\n", fname(*(argv++)));
447 fn = Audio::getMIME(info);
448 if(!fn)
449 switch(info.format) {
450 case Audio::raw:
451 fn = "raw audio";
452 break;
453 case Audio::snd:
454 fn = "sun audio";
455 break;
456 case Audio::riff:
457 fn = "riff";
458 break;
459 case Audio::wave:
460 fn = "ms wave";
461 break;
462 }
463
464
465 if(fn)
466 printf(" %s: %s\n", _TEXT("Format"), fn);
467 else
468 printf(" %s: %s\n", _TEXT("Format"), _TEXT("unknown"));
469
470 printf(" %s: %s\n", _TEXT("Encoding"), Audio::getName(info.encoding));
471 if(Audio::is_stereo(info.encoding))
472 printf(" %s: 2\n", _TEXT("Channels"));
473 else
474 printf(" %s: 1\n", _TEXT("Channels"));
475 if(info.framing)
476 printf(" %s: %ldms\n", _TEXT("Frame Size"), info.framing);
477 if(Audio::is_linear(info.encoding)) {
479 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("big"));
481 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("little"));
482 else
483 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("native"));
484 }
485 printf(" %s: %ld\n", _TEXT("Sample Rate"), info.rate);
486 printf(" %s: %ld\n", _TEXT("Bit Rate"), info.bitrate);
487 printf(" %s: %ld\n", _TEXT("Samples"), end);
488
489 scale = info.rate / 1000;
490
491 subsec = (end % info.rate) / scale;
492
493 end /= info.rate;
494 seconds = end % 60;
495 end /= 60;
496 minutes = end % 60;
497 end /= 60;
498 printf(" %s %02ld:%02ld:%02ld.%03ld\n",
499 _TEXT("Duration"), end, minutes, seconds, subsec);
500
501 if(info.headersize)
502 printf(" %s: %u, %s=%u, %s=%u\n",
503 _TEXT("Computed Frame Size"),
504 info.framesize - info.headersize - info.padding,
505 _TEXT("header"), info.headersize,
506 _TEXT("padding"), info.padding);;
507
508 au.close();
509 }
510 exit(0);
511 }
512
513 static void strip(char **argv)
514 {
515 AudioFile file, tmp;
516 Audio::info_t info;
518 short silence = (short)(*silent);
519 int rtn;
520 unsigned char *buffer;
521 Audio::level_t max, current;
522 unsigned long sum;
523 unsigned long count;
524 char target[256];
525 char source[256];
526
527 if(!*argv) {
528 shell::errexit(2, "*** audiotool: -strip: %s\n",
529 _TEXT("missing arguments"));
530 }
531
532 while(*argv) {
533 const char *out = Env::path(rules, *argv, source, sizeof(source));
534 if(!out || !fsys::isfile(out)) {
535 printf("%s: %s\n",
536 *(argv++), _TEXT("invalid"));
537 continue;
538 }
539 if(fsys::access(out, R_OK)) {
540 printf("%s: %s\n",
541 *(argv++), _TEXT("inaccessable"));
542 continue;
543 }
544 rewrite(out, target, sizeof(target));
545 delfile = target;
546 file.open(out, Audio::modeRead, *framing);
547 file.getInfo(info);
548 if(!Audio::is_linear(info.encoding))
549 codec = AudioCodec::get(info);
550 if(!Audio::is_linear(info.encoding) && !codec) {
551 printf("%s: %s\n",
552 *(argv++), _TEXT("cannot load codec"));
553 continue;
554 }
555
556 buffer = new unsigned char[info.framesize];
557
558 max = 0;
559 sum = 0;
560 count = 0;
561
562 // compute silence value
563
564 while(!silence) {
565 rtn = file.getBuffer(buffer, info.framesize);
566 if(rtn < (int)info.framesize)
567 break;
568 ++count;
569 if(codec)
570 sum += codec->impulse(buffer, info.framecount);
571 else
572 sum += Audio::impulse(info, buffer, info.framecount);
573 }
574
575 if(!silence && count)
576 silence = (Audio::level_t)(((sum / count) * 2) / 3);
577
578 max = 0;
579 sum = 0;
580 count = 0;
581
582 file.setPosition(0);
583
584
585 tmp.create(target, info);
586 if(!tmp.is_open()) {
587 printf("%s: %s\n",
588 *(argv++), _TEXT("cannot rewrite"));
589 continue;
590 }
591
592 for(;;)
593 {
594 rtn = file.getBuffer(buffer, info.framesize);
595 if(rtn < (int)info.framesize)
596 break;
597 ++count;
598 if(codec) {
599 if(codec->is_silent(silence, buffer, info.framecount)) {
600 if(codec->peak(buffer, info.framecount) >= silence)
601 tmp.putBuffer(buffer, info.framesize);
602 }
603 else
604 tmp.putBuffer(buffer, info.framesize);
605 continue;
606 }
607
608 current = Audio::peak(info, buffer, info.framecount);
609 if(current > max)
610 max = current;
611
612 sum += Audio::impulse(info, buffer, info.framecount);
613 if(Audio::impulse(info, buffer, info.framecount) < silence) {
614 if(Audio::peak(info, buffer, info.framecount) >= silence)
615 tmp.putBuffer(buffer, info.framecount);
616 }
617 else
618 tmp.putBuffer(buffer, info.framecount);
619 }
620 if(buffer)
621 delete[] buffer;
622
623 if(codec)
624 AudioCodec::release(codec);
625
626 codec = NULL;
627 buffer = NULL;
628
629 file.close();
630 tmp.close();
631
632 rtn = rename(target, out);
633 remove(target);
634 delfile = NULL;
635
636 if(rtn)
637 printf("%s: %s\n",
638 *argv, _TEXT("could not be replaced"));
639
640 ++argv;
641 }
642 exit(0);
643 }
644
645 static void trim(char **argv)
646 {
647 AudioFile file, tmp;
648 unsigned long first = 0, last = 0, total = 0, padding = *pad;
649 Audio::info_t info;
651 Audio::level_t silence = (Audio::level_t)(*silent);
652 int rtn;
653 unsigned char *buffer;
654 Audio::linear_t samples = NULL;
655 unsigned long sum;
656 unsigned long count;
657 char target[256];
658 char source[256];
659 bool use = false;
660
661 if(!*argv) {
662 shell::errexit(2, "*** audiotool: -trim: %s\n",
663 _TEXT("missing arguments"));
664 exit(-1);
665 }
666
667 while(*argv) {
668 const char *out = Env::path(rules, *argv, source, sizeof(source));
669 if(!out || !fsys::isfile(out)) {
670 printf("%s: %s\n",
671 *(argv++), _TEXT("invalid"));
672 continue;
673 }
674 if(fsys::access(out, R_OK)) {
675 printf("%s: %s\n",
676 *(argv++), _TEXT("inaccessable"));
677 continue;
678 }
679 rewrite(out, target, sizeof(target));
680 delfile = target;
681 file.open(out, Audio::modeRead, *framing);
682 file.getInfo(info);
683 if(!Audio::is_linear(info.encoding))
684 codec = AudioCodec::get(info);
685 if(!Audio::is_linear(info.encoding) && !codec) {
686 printf("%s: %s\n",
687 *(argv++), _TEXT("cannot load codec"));
688 continue;
689 }
690
691 buffer = new unsigned char[info.framesize];
692
693 sum = 0;
694 count = 0;
695
696 // compute silence value
697
698 while(!silence) {
699 rtn = file.getBuffer(buffer, info.framesize);
700 if(rtn < (int)info.framesize)
701 break;
702 ++count;
703 if(codec)
704 sum += codec->impulse(buffer, info.framecount);
705 else
706 sum += Audio::impulse(info, buffer, info.framecount);
707 }
708
709 if(!silence && count)
710 silence = (Audio::level_t)(((sum / count) * 2) / 3);
711
712 sum = 0;
713 count = 0;
714
715 file.setPosition(0);
716
717 for(;;)
718 {
719 rtn = file.getBuffer(buffer, info.framesize);
720 if(rtn < (int)info.framesize)
721 break;
722
723 ++total;
724 if(codec) {
725 if(codec->is_silent(silence, buffer, info.framecount)) {
726 use = false;
727 if(codec->peak(buffer, info.framecount) >= silence)
728 use = true;
729 }
730 else
731 use = true;
732 }
733 if(use && !first)
734 first = total;
735 if(use)
736 last = total;
737 }
738
739 if(!last || !first) {
740 printf("%s: %s\n",
741 *(argv++), _TEXT("all silent, skipping"));
742 continue;
743 }
744
745 --first;
746 total = last - first;
747 file.setPosition(first * info.framecount);
748
749 tmp.create(target, info);
750 if(!tmp.is_open()) {
751 printf("%s: %s\n",
752 *(argv++), _TEXT("cannot rewrite"));
753 continue;
754 }
755
756 while(total--) {
757 rtn = file.getBuffer(buffer, info.framesize);
758 if(rtn < (int)info.framesize)
759 break;
760 tmp.putBuffer(buffer, info.framesize);
761 }
762
763 if(padding) {
764 if(!codec)
765 memset(buffer, 0, info.framesize);
766 else if(Audio::is_stereo(info.encoding))
767 {
768 samples = new Audio::sample_t[info.framecount * 2];
769 memset(samples, 0, info.framecount * 2);
770 codec->encode(samples, buffer, info.framecount);
771 }
772 else {
773 samples = new Audio::sample_t[info.framecount];
774 memset(samples, 0, info.framecount);
775 codec->encode(samples, buffer, info.framecount);
776 }
777 }
778
779 while(padding--) {
780 rtn = tmp.putBuffer(buffer, info.framesize);
781 }
782
783 if(samples)
784 delete[] samples;
785
786 if(buffer)
787 delete[] buffer;
788
789 if(codec)
790 AudioCodec::release(codec);
791
792 codec = NULL;
793 buffer = NULL;
794
795 file.close();
796 tmp.close();
797
798 rtn = rename(target, out);
799 remove(target);
800 delfile = NULL;
801
802 if(rtn)
803 printf("%s: %s\n",
804 *argv, _TEXT("could not be replaced"));
805
806 ++argv;
807 }
808 exit(0);
809 }
810
811 static void size(char **argv)
812 {
813 char *fn = *(argv++);
814 AudioFile file;
815 Audio::info_t info;
816 unsigned long pos;
817 char pathbuf[256];
818
819 if(!fn) {
820 shell::errexit(2, "*** audiotool: -size: %s\n",
821 _TEXT("no file specified"));
822 }
823
824 const char *out = Env::path(rules, fn, pathbuf, sizeof(pathbuf));
825 if(out)
826 file.open(out, Audio::modeRead);
827 if(!file.is_open()) {
828 shell::errexit(3, "*** audiotool: %s: %s\n",
829 fname(fn), _TEXT("cannot access"));
830 }
831 file.getInfo(info);
832 file.setPosition();
833 pos = file.getPosition();
834 pos /= info.rate;
835 printf("%ld\n", pos);
836 exit(0);
837 }
838
839 static void packetdump(char **argv)
840 {
842 const char *path = *argv;
843 Audio::encoded_t buffer;
844 Audio::info_t info;
845 ssize_t count;
846
847 packetfile.
open(argv);
848
849 if(!packetfile.is_open()) {
850 shell::errexit(2, "*** audiotool: %s: %s\n",
851 fname(path), _TEXT("cannot access"));
852 }
853
854 if(!packetfile.is_streamable()) {
855 shell::errexit(2, "*** audiotool: %s: %s\n",
856 fname(path), _TEXT("missing codec needed"));
857 }
858
859 packetfile.getInfo(info);
860
861 buffer = new unsigned char[Audio::maxFramesize(info)];
862
863 while((count = packetfile.getPacket(buffer)) > 0)
864 printf("-- %ld\n", (long)count);
865
866 delete[] buffer;
867 packetfile.close();
868 exit(0);
869 }
870
871 static void note(char **argv)
872 {
873 char *fn = *(argv++);
874 char *ann = NULL;
875 AudioFile file, tmp;
876 Audio::info_t info;
877 char target[256];
878 char source[256];
879 unsigned char buffer[4096];
880 int rtn;
881
882 if(!fn) {
883 shell::errexit(2, "*** audiotool: -notation: %s\n",
884 _TEXT("no file specified"));
885 }
886
887 ann = *argv;
888
889 const char *out = Env::path(rules, fn, source, sizeof(source));
890 if(out)
891 file.open(out, Audio::modeRead);
892 if(!file.is_open()) {
893 shell::errexit(4, "*** audiotool: %s: %s\n:",
894 fname(fn), _TEXT("cannot access"));
895 }
896 file.getInfo(info);
897 if(info.annotation && !ann)
898 printf("%s\n", info.annotation);
899 if(!ann)
900 exit(0);
901 rewrite(out, target, sizeof(target));
902 info.annotation = ann;
903 delfile = target;
904 remove(target);
905 tmp.create(target, info);
906 if(!tmp.is_open()) {
907 shell::errexit(5, "*** audiotool: %s: %s\n",
908 fname(target), _TEXT("unable to create"));
909 }
910 for(;;) {
911 rtn = file.getBuffer(buffer, sizeof(buffer));
912 if(!rtn)
913 break;
914 if(rtn < 0) {
915 remove(target);
916 shell::errexit(6, "*** audiotool: %s: %s\n",
917 fname(fn), _TEXT("read failed"));
918 }
919 rtn = tmp.putBuffer(buffer, rtn);
920 if(rtn < 1) {
921 remove(target);
922 shell::errexit(6, "*** audiotool: %s: %s\n",
923 fname(fn), _TEXT("write failed"));
924 }
925 }
926 file.close();
927 tmp.close();
928 rtn = rename(target, out);
929 remove(target);
930 delfile = NULL;
931 if(rtn) {
932 shell::errexit(6, "*** audiotool: %s: %s\n",
933 fname(fn), _TEXT("could not replace"));
934 }
935
936 exit(0);
937 }
938
939 static void build(char **argv)
940 {
943 Audio::info_t info, make;
944 const char *target;
945 const char *encoding = *encopt;
946 Audio::rate_t rate = (Audio::rate_t)(*rateopt);
947 char pathbuf[256];
948
949 if(!*argv) {
950 shell::errexit(2, "*** audiotool: -build: %s\n",
951 _TEXT("missing arguments"));
952 }
953
954 if(*argv && **argv == '-') {
955 shell::errexit(2, "*** auditool: -build: %s: %s\n",
956 *argv, _TEXT("unknown option"));
957 }
958
959 if(*argv) {
960 target = Env::path(rules, *(argv++), pathbuf, sizeof(pathbuf));
961
962 if(!target) {
963 shell::errexit(4, "*** audiotool: -build: %s\n",
964 _TEXT("no files specified"));
965 }
966 }
967
968 if(!*argv) {
969 shell::errexit(4, "*** audiotool: -build: %s\n",
970 _TEXT("no files specified"));
971 }
972
974 if(!input.is_open()) {
975 shell::errexit(4, "*** audiotool: %s: %s\n",
976 *argv, _TEXT("cannot access"));
977 }
978 input.getInfo(info);
979 input.getInfo(make);
980 remove(target);
981 if(encoding)
982 make.encoding = Audio::getEncoding(encoding);
983
984 if(rate != Audio::rateUnknown)
985 make.setRate(rate);
986
987 output.create(target, make, 10);
988 if(!output.is_open()) {
989 shell::errexit(5, "*** audiotool: %s: %s\n",
990 target, _TEXT("cannot create"));
991 }
992 output.getInfo(make);
993
994 if(make.encoding == info.encoding && make.rate == info.rate)
996 else {
997 if(!input.is_streamable()) {
998 remove(target);
999 shell::errexit(6, "*** audiotool: %s: %s\n",
1000 *argv, _TEXT("cannot load codec"));
1001 }
1002 if(!output.is_streamable()) {
1003 remove(target);
1004 shell::errexit(6, "*** audiotool: %s: %s\n",
1005 target, _TEXT("cannot load codec"));
1006 }
1008 }
1009 input.close();
1010 output.close();
1011 exit(0);
1012 }
1013
1014 static void append(char **argv)
1015 {
1018 Audio::Info info, make;
1019 const char *target;
1020 char *option;
1021 char *offset = NULL;
1022 char pathbuf[256];
1023
1024 retry:
1025 option = *argv;
1026
1027 if(eq("--", option)) {
1028 ++argv;
1029 goto skip;
1030 }
1031
1032 if(eq("--", option, 2))
1033 ++option;
1034
1035 if(eq(option, "-offset=", 8)) {
1036 offset = option + 8;
1037 ++argv;
1038 goto retry;
1039 }
1040
1041 if(eq(option, "-offset")) {
1042 ++argv;
1043 if(!*argv) {
1044 shell::errexit(3, "*** audiotool: -append: -offset: %s\n",
1045 _TEXT("missing argument"));
1046 exit(-1);
1047 }
1048 offset = *(argv++);
1049 goto retry;
1050 }
1051
1052 skip:
1053 if(*argv && **argv == '-') {
1054 shell::errexit(2, "*** auditool: -append: %s: %s\n",
1055 *argv, _TEXT("unknown option"));
1056 }
1057
1058 if(*argv) {
1059 target = Env::path(rules, *(argv++), pathbuf, sizeof(pathbuf));
1060
1061 if(!target) {
1062 shell::errexit(4, "*** audiotool: -build: %s\n",
1063 _TEXT("no files specified"));
1064 }
1065 }
1066
1067 if(!*argv) {
1068 shell::errexit(4, "*** audiotool: -append: %s\n",
1069 _TEXT("no files specified"));
1070 }
1071
1073 if(!input.is_open()) {
1074 shell::errexit(4, "*** audiotool: %s: %s\n",
1075 *argv, _TEXT("cannot access"));
1076 }
1077 input.getInfo(info);
1078 output.open(target, Audio::modeWrite, 10);
1079 if(!output.is_open()) {
1080 shell::errexit(4, "*** audiotool: %s: %s\n",
1081 target, _TEXT("cannot access"));
1082 }
1083 output.getInfo(make);
1084
1085 if(offset)
1086 output.setPosition(atol(offset));
1087 else
1088 output.setPosition();
1089
1090 if(make.encoding == info.encoding)
1092 else {
1093 if(!input.is_streamable()) {
1094 shell::errexit(6, "*** audiotool: %s: %s\n",
1095 *argv, _TEXT("cannot load codec"));
1096 }
1097 if(!output.is_streamable()) {
1098 shell::errexit(6, "*** audiotool: %s: %s\n",
1099 target, _TEXT("cannot load codec"));
1100 }
1102 }
1103 input.close();
1104 output.close();
1105 exit(0);
1106 }
1107
1109 {
1110 shell::bind("audiotool");
1111 shell args(argc, argv);
1112
1113 Env::tool(&args);
1114
1115 rules.voices = *voice;
1116
1117 if(is(prefix))
1118 Env::set("prefix", *prefix);
1119
1120 if(is(phrasebook))
1121 Env::set("voices", *phrasebook);
1122
1123 if(is(suffix))
1124 Env::set("extension", *suffix);
1125
1126 if(is(lang))
1127 rules.book = Phrasebook::find(*lang);
1128 else
1129 rules.book = Phrasebook::find(NULL);
1130
1131 if(is(helpflag) || is(althelp)) {
1132 printf("%s\n", _TEXT("Usage: audiotool [options] command arguments..."));
1133 printf("%s\n\n", _TEXT("Audio tool and audio file operations"));
1134 printf("%s\n", _TEXT("Options:"));
1135 shell::help();
1136 printf("\n%s\n", _TEXT("Report bugs to dyfet@gnu.org"));
1137 PROGRAM_EXIT(0);
1138 }
1139
1140 if(!args())
1141 shell::errexit(1, "*** audiotool: %s\n",
1142 _TEXT("no command specified"));
1143
1144 const char *cp = args[0];
1145
1146 argv = args.argv();
1147 ++argv;
1148
1149 shell::exiting(stop);
1150
1151 if(eq(cp, "version"))
1152 version();
1153 else if(eq(cp, "endian"))
1154 showendian();
1155 else if(eq(cp, "build"))
1156 build(argv);
1157 else if(eq(cp, "append"))
1158 append(argv);
1159 else if(eq(cp, "chart"))
1160 chart(argv);
1161 else if(eq(cp, "info"))
1162 info(argv);
1163 else if(eq(cp, "note") || eq(cp, "annotate") || eq(cp, "notation"))
1164 note(argv);
1165 else if(eq(cp, "packets") || eq(cp, "dump") || eq(cp, "packetdump"))
1166 packetdump(argv);
1167 else if(eq(cp, "strip"))
1168 strip(argv);
1169 else if(eq(cp, "trim"))
1170 trim(argv);
1171 else if(eq(cp, "size"))
1172 size(argv);
1173 else if(eq(cp, "codecs"))
1174 codecs();
1175
1176 shell::errexit(2, "*** audiotool: %s: %s\n",
1177 cp, _TEXT("unknown option"));
1178 PROGRAM_EXIT(0);
1179 }
static void copyConvert(AudioStream &input, AudioStream &output)
#define BAYONNE_NAMESPACE
static void copyDirect(AudioStream &input, AudioStream &output)
GNU Bayonne library namespace.