1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
3 // Copyright (C) 2015 Cherokees of Idaho.
4 //
5 // This file is part of GNU ccAudio2.
6 //
7 // GNU ccAudio2 is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Lesser General Public License as published
9 // by the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // GNU ccAuydio2 is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with GNU ccAudio2. If not, see <http://www.gnu.org/licenses/>.
19
20 #include <ccaudio2.h>
21 #include <ccaudio2-config.h>
22 #ifdef HAVE_ENDIAN_H
23 #include <sys/endian.h>
24 #ifndef __BYTE_ORDER
25 #define __LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
26 #define __BIG_ENDIAN (_BYTE_ORDER == _BIG_ENDIAN)
27 #define __BYTE_ORDER _BYTE_ORDER
28 #endif
29 #endif
30
31 #if !defined(__BIG_ENDIAN)
32 #define __LITTLE_ENDIAN 1234
33 #define __BIG_ENDIAN 4321
34 #define __PDP_ENDIAN 3412
35 #define __BYTE_ORDER __LITTLE_ENDIAN
36 #endif
37
38 using namespace ucommon;
39
40 static const char *delfile = NULL;
41
42 class AudioBuild : public AudioStream
43 {
44 private:
45 char **list;
46 char *getContinuation(void);
47 public:
48 AudioBuild();
49 void open(char **argv);
50
51 static void copyDirect(AudioStream &input, AudioStream &output);
52 static void copyConvert(AudioStream &input, AudioStream &output);
53 };
54
55 class PacketStream : public AudioStream
56 {
57 private:
58 char **list;
59 char *getContinuation(void);
60
61 public:
62 PacketStream();
63 void open(char **argv);
64 };
65
66 class PlayStream : public AudioStream
67 {
68 private:
69 char **list;
70 char *getContinuation(void);
71
72 public:
73 PlayStream();
74 void open(char **argv);
75 };
76
PlayStream()77 PlayStream::PlayStream() : AudioStream()
78 {
79 list = NULL;
80 }
81
open(char ** argv)82 void PlayStream::open(char **argv)
83 {
84 AudioStream::open(*(argv++), modeRead, 10);
85 if(is_open())
86 list = argv;
87 }
88
getContinuation(void)89 char *PlayStream::getContinuation(void)
90 {
91 if(!list)
92 return NULL;
93
94 return *(list++);
95 }
96
PacketStream()97 PacketStream::PacketStream() : AudioStream()
98 {
99 list = NULL;
100 }
101
open(char ** argv)102 void PacketStream::open(char **argv)
103 {
104 AudioStream::open(*(argv++), modeRead, 10);
105 if(is_open())
106 list = argv;
107 }
108
getContinuation(void)109 char *PacketStream::getContinuation(void)
110 {
111 if(!list)
112 return NULL;
113
114 return *(list++);
115 }
116
117
AudioBuild()118 AudioBuild::AudioBuild() : AudioStream()
119 {
120 list = NULL;
121 }
122
open(char ** argv)123 void AudioBuild::open(char **argv)
124 {
125 AudioStream::open(*(argv++), modeRead, 10);
126 if(is_open())
127 list = argv;
128 }
129
getContinuation(void)130 char *AudioBuild::getContinuation(void)
131 {
132 if(!list)
133 return NULL;
134
135 return *(list++);
136 }
137
copyConvert(AudioStream & input,AudioStream & output)138 void AudioBuild::copyConvert(AudioStream &input, AudioStream &output)
139 {
140 size_t samples, copied;
141 Linear buffer, source;
142 size_t pages, npages;
143 Info from, to;
144 bool mono = true;
145 AudioResample *resampler = NULL;
146 Linear resample = NULL;
147
148 input.getInfo(&from);
149 output.getInfo(&to);
150
151 if(is_stereo(from.encoding) || is_stereo(to.encoding))
152 mono = false;
153
154 samples = input.getCount();
155
156
157 if(mono)
158 buffer = new Audio::Sample[samples];
159 else
160 buffer = new Audio::Sample[samples * 2];
161
162 source = buffer;
163
164 if(from.rate != to.rate) {
165 resampler = new AudioResample((Audio::Rate)from.rate, (Audio::Rate)to.rate);
166 resample = new Audio::Sample[resampler->estimate(samples)];
167 source = resample;
168 }
169
170 for(;;)
171 {
172 if(mono)
173 pages = input.getMono(buffer, 1);
174 else
175 pages = input.getStereo(buffer, 1);
176
177 if(!pages)
178 break;
179
180 if(resampler)
181 copied = resampler->process(buffer, resample, samples);
182 else
183 copied = samples;
184
185 if(mono)
186 npages = output.bufMono(source, (unsigned)copied);
187 else
188 npages = output.bufStereo(source, (unsigned)copied);
189
190 if(!npages)
191 break;
192 }
193
194 delete[] buffer;
195
196 if(resampler)
197 delete resampler;
198
199 if(resample)
200 delete[] resample;
201 }
202
copyDirect(AudioStream & input,AudioStream & output)203 void AudioBuild::copyDirect(AudioStream &input, AudioStream &output)
204 {
205 unsigned bufsize;
206 Encoded buffer;
207 Info from, to;
208 // bool endian = false;
209 ssize_t status = 1;
210
211 input.getInfo(&from);
212 output.getInfo(&to);
213
214 // if(to.order && from.order && to.order != from.order && is_linear(from.encoding))
215 // endian = true;
216
217 bufsize = from.framesize;
218 buffer = new unsigned char[bufsize];
219
220 while(status > 0) {
221 status = input.getNative(buffer, bufsize);
222 if(status < 1)
223 break;
224
225 status = output.putNative(buffer, status);
226 }
227
228 delete[] buffer;
229 }
230
231
stop(void)232 static void stop(void)
233 {
234 if(delfile) {
235 remove(delfile);
236 delfile = NULL;
237 }
238 }
239
plugins(void)240 static void plugins(void)
241 {
242 printf("%s\n", Audio::getPluginPath());
243 exit(0);
244 }
245
codecs(void)246 static void codecs(void)
247 {
248 linked_pointer<AudioCodec> cp = AudioCodec::begin();
249
250 while(is(cp)) {
251 printf("%s - %s\n", cp->getName(), cp->getDescription());
252 cp.next();
253 }
254 exit(0);
255 }
256
version(void)257 static void version(void)
258 {
259 printf("%s\n", VERSION);
260 exit(0);
261 }
262
soundcard(unsigned index)263 static void soundcard(unsigned index)
264 {
265 AudioDevice *soundcard = Audio::getDevice(index);
266 const Audio::Info *info;
267
268 if(!Audio::is_available(index) && !soundcard)
269 printf("%s\n", _TEXT("Sound device inaccessible or unsupported"));
270 else if(!soundcard)
271 printf("%s\b", _TEXT("Sound device unavailable"));
272 else {
273 info = soundcard->getInfo();
274 printf("%s: %s\n", _TEXT("Soundcard Driver"), info->annotation);
275 if(Audio::is_stereo(info->encoding))
276 printf("%s: 2\n", _TEXT("Default Channels"));
277 else
278 printf("%s: 1\n", _TEXT("Default Channels"));
279 printf("%s: %s\n", _TEXT("Default Encoding"), Audio::getName(info->encoding));
280 printf("%s: %d\n", _TEXT("Default Buffers"), info->framecount);
281 printf("%s: %ldms\n", _TEXT("Default Framing"), info->framing);
282 printf("%s: %ld %s\n", _TEXT("Default Rate"), info->rate, _TEXT(" samples per second"));
283 }
284 exit(0);
285 }
286
showendian(void)287 static void showendian(void)
288 {
289 if(__BYTE_ORDER == __BIG_ENDIAN)
290 printf("%s\n", _TEXT("big"));
291 else
292 printf("%s\n", _TEXT("little"));
293 exit(0);
294 }
295
fname(const char * cp)296 static const char *fname(const char *cp)
297 {
298 const char *fn = strrchr(cp, '/');
299 if(!fn)
300 fn = strrchr(cp, '\\');
301 if(fn)
302 return ++fn;
303 return cp;
304 }
305
rewrite(const char * source,char * target,size_t max)306 static void rewrite(const char *source, char *target, size_t max)
307 {
308 char *fn;
309 char buffer[256];
310
311 #ifdef WIN32
312 char *ext;
313 snprintf(buffer, sizeof(buffer), "%s", source);
314 while(NULL != (fn = strchr(buffer, '\\')))
315 *fn = '/';
316
317 fn = strrchr(buffer, '/');
318 if(fn) {
319 *(fn++) = 0;
320 ext = strrchr(fn, '.');
321 if(ext)
322 *ext = 0;
323 snprintf(target, max, "%s/%s.tmp", buffer, fn);
324 }
325 else {
326 ext = strrchr(buffer, '.');
327 if(ext)
328 *ext = 0;
329 snprintf(target, max, "%s.tmp", buffer);
330 }
331 #else
332 snprintf(buffer, sizeof(buffer), "%s", source);
333 fn = strrchr(buffer, '/');
334 if(fn) {
335 *(fn++) = 0;
336 snprintf(target, max, "%s/.tmp.%s", buffer, fn);
337 }
338 else
339 snprintf(target, max, ".tmp.%s", source);
340 #endif
341 }
342
chart(char ** argv)343 static void chart(char **argv)
344 {
345 AudioFile file;
346 Audio::Info info;
347 AudioCodec *codec = NULL;
348 char *fn;
349 timeout_t framing = 20;
350 Audio::Level silence = 0;
351 unsigned char *buffer;
352 short max, current;
353 unsigned long sum;
354 unsigned long count;
355
356 retry:
357 if(!*argv) {
358 shell::errexit(2, "*** audiotool: -chart: %s\n",
359 _TEXT("missing arguments"));
360 }
361
362 fn = *argv;
363
364 if(eq(fn, "--")) {
365 ++argv;
366 goto skip;
367 }
368
369 if(eq(fn, "--", 2))
370 ++fn;
371
372 if(eq(fn, "-framing=", 9)) {
373 framing = atoi(fn + 9);
374 ++argv;
375 goto retry;
376 }
377 else if(eq(fn, "-framing"))
378 {
379 ++argv;
380 if(!*argv) {
381 shell::errexit(3, "*** audiotool: -chart: -framing: %s\n",
382 _TEXT("missing argument"));
383 }
384 framing = atoi(*(argv++));
385 goto retry;
386 }
387
388 if(eq(fn, "-silence=", 9)) {
389 silence = atoi(fn + 9);
390 ++argv;
391 goto retry;
392 }
393 else if(eq(fn, "-silence"))
394 {
395 ++argv;
396 if(!*argv) {
397 shell::errexit(3, "*** audiotool: -chart: -silence: %s\n",
398 _TEXT("missing argument"));
399 }
400 silence = atoi(*(argv++));
401 goto retry;
402 }
403
404 skip:
405
406 if(!framing)
407 framing = 20;
408
409 while(*argv) {
410 if(!fsys::is_file(*argv)) {
411 printf("%s: %s\n",
412 fname(*(argv++)), _TEXT("invalid"));
413 continue;
414 }
415 if(!fsys::is_readable(*argv)) {
416 printf("%s: %s\n",
417 fname(*(argv++)), _TEXT("inaccessable"));
418 continue;
419 }
420 file.open(*argv, Audio::modeRead, framing);
421 file.getInfo(&info);
422 if(!Audio::is_linear(info.encoding))
423 codec = AudioCodec::get(info);
424 if(!Audio::is_linear(info.encoding) && !codec) {
425 printf("%s: %s\n",
426 fname(*(argv++)), _TEXT("cannot load codec"));
427 continue;
428 }
429
430 printf("%s: ", fname(*(argv++)));
431 buffer = new unsigned char[info.framesize];
432
433 max = 0;
434 sum = 0;
435 count = 0;
436
437 // autochart for silence value
438
439 while(!silence) {
440 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
441 break;
442 ++count;
443 if(codec)
444 sum += codec->impulse(buffer, info.framecount);
445 else
446 sum += Audio::impulse(info, buffer, info.framecount);
447 }
448
449 if(!silence && count)
450 silence = (Audio::Level)(((sum / count) * 2) / 3);
451
452 max = 0;
453 sum = 0;
454 count = 0;
455
456 file.setPosition(0);
457
458 for(;;) {
459 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
460 break;
461 ++count;
462 if(codec) {
463 current = codec->peak(buffer, info.framecount);
464 if(current > max)
465 max = current;
466 sum += codec->impulse(buffer, info.framecount);
467 if(codec->is_silent(silence, buffer, info.framecount)) {
468 if(codec->peak(buffer, info.framecount) >= silence)
469 printf("^");
470 else
471 printf(".");
472 }
473 else
474 printf("+");
475 fflush(stdout);
476 continue;
477 }
478
479 current = Audio::peak(info, buffer, info.framecount);
480 if(current > max)
481 max = current;
482
483 sum += Audio::impulse(info, buffer, info.framecount);
484 if(Audio::impulse(info, buffer, info.framecount) < silence) {
485 if(Audio::peak(info, buffer, info.framecount) >= silence)
486 printf("^");
487 else
488 printf(".");
489 }
490 else
491 printf("+");
492 fflush(stdout);
493 }
494 printf("\n");
495 if(count)
496 printf("%s = %d, %s = %ld, %s = %d\n",
497 _TEXT("silence threashold"), silence,
498 _TEXT("avg frame energy"), (sum / count),
499 _TEXT("peak level"), max);
500
501 if(buffer)
502 delete[] buffer;
503
504
505 if(codec)
506 AudioCodec::release(codec);
507
508 codec = NULL;
509 buffer = NULL;
510
511 file.close();
512 }
513 exit(0);
514 }
515
info(char ** argv)516 static void info(char **argv)
517 {
518 AudioFile au;
519 Audio::Info info;
520 const char *fn;
521 timeout_t framing = 0;
522 unsigned long end;
523 unsigned long minutes, seconds, subsec, scale;
524
525 fn = *argv;
526 if(eq(fn, "--", 2))
527 ++fn;
528 if(eq(fn, "-framing=", 9)) {
529 framing = atoi(fn + 9);
530 ++argv;
531 }
532 else if(eq(fn, "-framing"))
533 {
534 framing = atoi(*(++argv));
535 ++argv;
536 }
537
538 while(*argv) {
539 if(!fsys::is_file(*argv)) {
540 printf("audiotool: %s: %s\n",
541 fname(*(argv++)), _TEXT("invalid"));
542 continue;
543 }
544 if(fsys::is_readable(*argv)) {
545 printf("audiotool: %s: %s\n",
546 fname(*(argv++)), _TEXT("inaccessable"));
547 continue;
548 }
549 au.open(*argv, Audio::modeInfo, framing);
550 au.getInfo(&info);
551 au.setPosition();
552 end = au.getPosition();
553 printf("%s\n", fname(*(argv++)));
554 fn = Audio::getMIME(info);
555 if(!fn)
556 switch(info.format) {
557 case Audio::raw:
558 fn = "raw audio";
559 break;
560 case Audio::snd:
561 fn = "sun audio";
562 break;
563 case Audio::riff:
564 fn = "riff";
565 break;
566 case Audio::wave:
567 fn = "ms wave";
568 break;
569 case Audio::mpeg:
570 fn = "mpeg audio";
571 break;
572 }
573
574
575 if(fn)
576 printf(" %s: %s\n", _TEXT("Format"), fn);
577 else
578 printf(" %s: %s\n", _TEXT("Format"), _TEXT("unknown"));
579
580 printf(" %s: %s\n", _TEXT("Encoding"), Audio::getName(info.encoding));
581 if(Audio::is_stereo(info.encoding))
582 printf(" %s: 2\n", _TEXT("Channels"));
583 else
584 printf(" %s: 1\n", _TEXT("Channels"));
585 if(info.framing)
586 printf(" %s: %ldms\n", _TEXT("Frame Size"), info.framing);
587 if(Audio::is_linear(info.encoding)) {
588 if(info.order == __BIG_ENDIAN)
589 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("big"));
590 else if(info.order == __LITTLE_ENDIAN)
591 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("little"));
592 else
593 printf(" %s: %s\n", _TEXT("Byte Order"), _TEXT("native"));
594 }
595 printf(" %s: %ld\n", _TEXT("Sample Rate"), info.rate);
596 printf(" %s: %ld\n", _TEXT("Bit Rate"), info.bitrate);
597 printf(" %s: %ld\n", _TEXT("Samples"), end);
598
599 scale = info.rate / 1000;
600
601 subsec = (end % info.rate) / scale;
602
603 end /= info.rate;
604 seconds = end % 60;
605 end /= 60;
606 minutes = end % 60;
607 end /= 60;
608 printf(" %s %02ld:%02ld:%02ld.%03ld\n",
609 _TEXT("Duration"), end, minutes, seconds, subsec);
610
611 if(info.headersize)
612 printf(" %s: %u, %s=%u, %s=%u\n",
613 _TEXT("Computed Frame Size"),
614 info.framesize - info.headersize - info.padding,
615 _TEXT("header"), info.headersize,
616 _TEXT("padding"), info.padding);;
617
618 au.close();
619 }
620 exit(0);
621 }
622
strip(char ** argv)623 static void strip(char **argv)
624 {
625 AudioFile file, tmp;
626 Audio::Info info;
627 AudioCodec *codec = NULL;
628 char *fn;
629 timeout_t framing = 20;
630 short silence = 0;
631 int rtn;
632 unsigned char *buffer;
633 Audio::Level max, current;
634 unsigned long sum;
635 unsigned long count;
636 char target[256];
637
638 retry:
639 if(!*argv) {
640 shell::errexit(2, "*** audiotool: -strip: %s\n",
641 _TEXT("missing arguments"));
642 }
643
644 fn = *argv;
645
646 if(eq(fn, "--")) {
647 ++argv;
648 goto skip;
649 }
650
651 if(eq(fn, "--", 2))
652 ++fn;
653 if(eq(fn, "-framing=", 9)) {
654 framing = atoi(fn + 9);
655 ++argv;
656 goto retry;
657 }
658 else if(eq(fn, "-framing"))
659 {
660 ++argv;
661 if(!*argv) {
662 shell::errexit(2, "*** audiotool: -strip: -framing: %s\n",
663 _TEXT("missing argument"));
664 }
665 framing = atoi(*(argv++));
666 goto retry;
667 }
668
669 if(eq(fn, "-silence=", 9)) {
670 silence = atoi(fn + 9);
671 ++argv;
672 goto retry;
673 }
674 else if(eq(fn, "-silence"))
675 {
676 ++argv;
677 if(!*argv) {
678 shell::errexit(2, "*** audiotool: -strip: -silence: %s\n",
679 _TEXT("missing argument"));
680 }
681 silence = atoi(*(argv++));
682 goto retry;
683 }
684
685 skip:
686
687 if(!framing)
688 framing = 20;
689
690 while(*argv) {
691 if(!fsys::is_file(*argv)) {
692 printf("%s: %s\n",
693 *(argv++), _TEXT("invalid"));
694 continue;
695 }
696 if(fsys::is_readable(*argv)) {
697 printf("%s: %s\n",
698 *(argv++), _TEXT("inaccessable"));
699 continue;
700 }
701 rewrite(*argv, target, sizeof(target));
702 delfile = target;
703 file.open(*argv, Audio::modeRead, framing);
704 file.getInfo(&info);
705 if(!Audio::is_linear(info.encoding))
706 codec = AudioCodec::get(info);
707 if(!Audio::is_linear(info.encoding) && !codec) {
708 printf("%s: %s\n",
709 *(argv++), _TEXT("cannot load codec"));
710 continue;
711 }
712
713 buffer = new unsigned char[info.framesize];
714
715 max = 0;
716 sum = 0;
717 count = 0;
718
719 // compute silence value
720
721 while(!silence) {
722 rtn = file.getBuffer(buffer, info.framesize);
723 if(rtn < (int)info.framesize)
724 break;
725 ++count;
726 if(codec)
727 sum += codec->impulse(buffer, info.framecount);
728 else
729 sum += Audio::impulse(info, buffer, info.framecount);
730 }
731
732 if(!silence && count)
733 silence = (Audio::Level)(((sum / count) * 2) / 3);
734
735 max = 0;
736 sum = 0;
737 count = 0;
738
739 file.setPosition(0);
740
741
742 tmp.create(target, &info);
743 if(!tmp.is_open()) {
744 printf("%s: %s\n",
745 *(argv++), _TEXT("cannot rewrite"));
746 continue;
747 }
748
749 for(;;)
750 {
751 rtn = file.getBuffer(buffer, info.framesize);
752 if(rtn < (int)info.framesize)
753 break;
754 ++count;
755 if(codec) {
756 if(codec->is_silent(silence, buffer, info.framecount)) {
757 if(codec->peak(buffer, info.framecount) >= silence)
758 tmp.putBuffer(buffer, info.framesize);
759 }
760 else
761 tmp.putBuffer(buffer, info.framesize);
762 continue;
763 }
764
765 current = Audio::peak(info, buffer, info.framecount);
766 if(current > max)
767 max = current;
768
769 sum += Audio::impulse(info, buffer, info.framecount);
770 if(Audio::impulse(info, buffer, info.framecount) < silence) {
771 if(Audio::peak(info, buffer, info.framecount) >= silence)
772 tmp.putBuffer(buffer, info.framecount);
773 }
774 else
775 tmp.putBuffer(buffer, info.framecount);
776 }
777 if(buffer)
778 delete[] buffer;
779
780 if(codec)
781 AudioCodec::release(codec);
782
783 codec = NULL;
784 buffer = NULL;
785
786 file.close();
787 tmp.close();
788
789 rtn = rename(target, *argv);
790 remove(target);
791 delfile = NULL;
792
793 if(rtn)
794 printf("%s: %s\n",
795 *argv, _TEXT("could not be replaced"));
796
797 ++argv;
798 }
799 exit(0);
800 }
801
trim(char ** argv)802 static void trim(char **argv)
803 {
804 AudioFile file, tmp;
805 unsigned long first = 0, last = 0, total = 0, padding = 0;
806 Audio::Info info;
807 AudioCodec *codec = NULL;
808 char *fn;
809 timeout_t framing = 20;
810 Audio::Level silence = 0;
811 int rtn;
812 unsigned char *buffer;
813 Audio::Linear samples = NULL;
814 unsigned long sum;
815 unsigned long count;
816 char target[256];
817 bool use = false;
818
819 retry:
820 if(!*argv) {
821 shell::errexit(2, "*** audiotool: -trim: %s\n",
822 _TEXT("missing arguments"));
823 exit(-1);
824 }
825
826 fn = *argv;
827
828 if(eq(fn, "--")) {
829 ++argv;
830 goto skip;
831 }
832
833 if(eq(fn, "--", 2))
834 ++fn;
835 if(eq(fn, "-framing=", 9)) {
836 framing = atoi(fn + 9);
837 ++argv;
838 goto retry;
839 }
840 else if(eq(fn, "-framing"))
841 {
842 ++argv;
843 if(!*argv) {
844 shell::errexit(3, "*** audiotool: -trim: -framing: %s\n",
845 _TEXT("missing argument"));
846 }
847 framing = atoi(*(argv++));
848 goto retry;
849 }
850
851 if(eq(fn, "-padding=", 9)) {
852 padding = atoi(fn + 9);
853 ++argv;
854 goto retry;
855 }
856 else if(eq(fn, "-padding"))
857 {
858 ++argv;
859 if(!*argv) {
860 shell::errexit(3, "*** audiotool: -trim: -padding: %s\n",
861 _TEXT("missing argument"));
862 }
863 padding = atol(*(argv++));
864 goto retry;
865 }
866
867 if(eq(fn, "-silence=", 9)) {
868 silence = atoi(fn + 9);
869 ++argv;
870 goto retry;
871 }
872 else if(eq(fn, "-silence"))
873 {
874 ++argv;
875 if(!*argv) {
876 shell::errexit(3, "*** audiotool: -trim: -silence: %s\n",
877 _TEXT("missing argument"));
878 }
879 silence = atoi(*(argv++));
880 goto retry;
881 }
882
883 skip:
884
885 if(!framing)
886 framing = 20;
887
888 while(*argv) {
889 if(!fsys::is_file(*argv)) {
890 printf("%s: %s\n",
891 *(argv++), _TEXT("invalid"));
892 continue;
893 }
894 if(fsys::is_readable(*argv)) {
895 printf("%s: %s\n",
896 *(argv++), _TEXT("inaccessable"));
897 continue;
898 }
899 rewrite(*argv, target, sizeof(target));
900 delfile = target;
901 file.open(*argv, Audio::modeRead, framing);
902 file.getInfo(&info);
903 if(!Audio::is_linear(info.encoding))
904 codec = AudioCodec::get(info);
905 if(!Audio::is_linear(info.encoding) && !codec) {
906 printf("%s: %s\n",
907 *(argv++), _TEXT("cannot load codec"));
908 continue;
909 }
910
911 buffer = new unsigned char[info.framesize];
912
913 sum = 0;
914 count = 0;
915
916 // compute silence value
917
918 while(!silence) {
919 rtn = file.getBuffer(buffer, info.framesize);
920 if(rtn < (int)info.framesize)
921 break;
922 ++count;
923 if(codec)
924 sum += codec->impulse(buffer, info.framecount);
925 else
926 sum += Audio::impulse(info, buffer, info.framecount);
927 }
928
929 if(!silence && count)
930 silence = (Audio::Level)(((sum / count) * 2) / 3);
931
932 sum = 0;
933 count = 0;
934
935 file.setPosition(0);
936
937 for(;;)
938 {
939 rtn = file.getBuffer(buffer, info.framesize);
940 if(rtn < (int)info.framesize)
941 break;
942
943 ++total;
944 if(codec) {
945 if(codec->is_silent(silence, buffer, info.framecount)) {
946 use = false;
947 if(codec->peak(buffer, info.framecount) >= silence)
948 use = true;
949 }
950 else
951 use = true;
952 }
953 if(use && !first)
954 first = total;
955 if(use)
956 last = total;
957 }
958
959 if(!last || !first) {
960 printf("%s: %s\n",
961 *(argv++), _TEXT("all silent, skipping"));
962 continue;
963 }
964
965 --first;
966 total = last - first;
967 file.setPosition(first * info.framecount);
968
969 tmp.create(target, &info);
970 if(!tmp.is_open()) {
971 printf("%s: %s\n",
972 *(argv++), _TEXT("cannot rewrite"));
973 continue;
974 }
975
976 while(total--) {
977 rtn = file.getBuffer(buffer, info.framesize);
978 if(rtn < (int)info.framesize)
979 break;
980 tmp.putBuffer(buffer, info.framesize);
981 }
982
983 if(padding) {
984 if(!codec)
985 memset(buffer, 0, info.framesize);
986 else if(Audio::is_stereo(info.encoding))
987 {
988 samples = new Audio::Sample[info.framecount * 2];
989 memset(samples, 0, info.framecount * 2);
990 codec->encode(samples, buffer, info.framecount);
991 }
992 else {
993 samples = new Audio::Sample[info.framecount];
994 memset(samples, 0, info.framecount);
995 codec->encode(samples, buffer, info.framecount);
996 }
997 }
998
999 while(padding--) {
1000 rtn = tmp.putBuffer(buffer, info.framesize);
1001 }
1002
1003 if(samples)
1004 delete[] samples;
1005
1006 if(buffer)
1007 delete[] buffer;
1008
1009 if(codec)
1010 AudioCodec::release(codec);
1011
1012 codec = NULL;
1013 buffer = NULL;
1014
1015 file.close();
1016 tmp.close();
1017
1018 rtn = rename(target, *argv);
1019 remove(target);
1020 delfile = NULL;
1021
1022 if(rtn)
1023 printf("%s: %s\n",
1024 *argv, _TEXT("could not be replaced"));
1025
1026 ++argv;
1027 }
1028 exit(0);
1029 }
1030
size(char ** argv)1031 static void size(char **argv)
1032 {
1033 char *fn = *(argv++);
1034 AudioFile file;
1035 Audio::Info info;
1036 unsigned long pos;
1037
1038 if(!fn) {
1039 shell::errexit(2, "*** audiotool: -size: %s\n",
1040 _TEXT("no file specified"));
1041 }
1042
1043 file.open(fn, Audio::modeRead);
1044 if(!file.is_open()) {
1045 shell::errexit(3, "*** audiotool: %s: %s\n",
1046 fname(fn), _TEXT("cannot access"));
1047 }
1048 file.getInfo(&info);
1049 file.setPosition();
1050 pos = file.getPosition();
1051 pos /= info.rate;
1052 printf("%ld\n", pos);
1053 exit(0);
1054 }
1055
play(char ** argv)1056 static void play(char **argv)
1057 {
1058 AudioDevice *dev;
1059 PlayStream playfile;
1060 const char *path = *argv;
1061 Audio::Linear buffer;
1062 Audio::Info info;
1063 unsigned bufcount, pages;
1064
1065 dev = Audio::getDevice();
1066
1067 if(!Audio::is_available() && !dev) {
1068 shell::errexit(10, "*** audiotool: %s\n",
1069 _TEXT("no device supported"));
1070 }
1071 else if(!dev) {
1072 shell::errexit(10, "*** audiotool: %s\n",
1073 _TEXT("device unavailable"));
1074 }
1075
1076 playfile.open(argv);
1077
1078 if(!playfile.is_open()) {
1079 shell::errexit(10, "*** audiotool: %s: %s\n",
1080 fname(path), _TEXT("unable to access"));
1081 }
1082
1083 if(!playfile.is_streamable()) {
1084 shell::errexit(10, "*** audiotool: %s: %s\n",
1085 fname(path), _TEXT("missing codec"));
1086 }
1087
1088 playfile.getInfo(&info);
1089 if(!dev->setAudio((Audio::Rate)info.rate, Audio::is_stereo(info.encoding), 10)) {
1090 shell::errexit(10, "*** audiotool: %s\n",
1091 _TEXT("sound device does not support rate"));
1092 exit(-1);
1093 }
1094
1095 bufcount = playfile.getCount();
1096 if(Audio::is_stereo(info.encoding))
1097 buffer = new Audio::Sample[bufcount * 2];
1098 else
1099 buffer = new Audio::Sample[bufcount];
1100
1101 for(;;) {
1102 if(Audio::is_stereo(info.encoding))
1103 pages = playfile.getStereo(buffer, 1);
1104 else
1105 pages = playfile.getMono(buffer, 1);
1106
1107 if(!pages)
1108 break;
1109
1110 dev->putSamples(buffer, bufcount);
1111 }
1112
1113 dev->sync();
1114 delete dev;
1115 playfile.close();
1116 exit(0);
1117 }
1118
packetdump(char ** argv)1119 static void packetdump(char **argv)
1120 {
1121 PacketStream packetfile;
1122 const char *path = *argv;
1123 Audio::Encoded buffer;
1124 Audio::Info info;
1125 ssize_t count;
1126
1127 packetfile.open(argv);
1128
1129 if(!packetfile.is_open()) {
1130 shell::errexit(2, "*** audiotool: %s: %s\n",
1131 fname(path), _TEXT("cannot access"));
1132 }
1133
1134 if(!packetfile.is_streamable()) {
1135 shell::errexit(2, "*** audiotool: %s: %s\n",
1136 fname(path), _TEXT("missing codec needed"));
1137 }
1138
1139 packetfile.getInfo(&info);
1140
1141 buffer = new unsigned char[Audio::maxFramesize(info)];
1142
1143 while((count = packetfile.getPacket(buffer)) > 0)
1144 printf("-- %ld\n", (long)count);
1145
1146 delete[] buffer;
1147 packetfile.close();
1148 exit(0);
1149 }
1150
1151
note(char ** argv)1152 static void note(char **argv)
1153 {
1154 char *fn = *(argv++);
1155 char *ann = NULL;
1156 AudioFile file, tmp;
1157 Audio::Info info;
1158 char target[256];
1159 unsigned char buffer[4096];
1160 int rtn;
1161
1162 if(!fn) {
1163 shell::errexit(2, "*** audiotool: -notation: %s\n",
1164 _TEXT("no file specified"));
1165 }
1166
1167 ann = *argv;
1168
1169 file.open(fn, Audio::modeRead);
1170 if(!file.is_open()) {
1171 shell::errexit(4, "*** audiotool: %s: %s\n:",
1172 fname(fn), _TEXT("cannot access"));
1173 }
1174 file.getInfo(&info);
1175 if(info.annotation && !ann)
1176 printf("%s\n", info.annotation);
1177 if(!ann)
1178 exit(0);
1179 rewrite(fn, target, sizeof(target));
1180 info.annotation = ann;
1181 delfile = target;
1182 remove(target);
1183 tmp.create(target, &info);
1184 if(!tmp.is_open()) {
1185 shell::errexit(5, "*** audiotool: %s: %s\n",
1186 fname(target), _TEXT("unable to create"));
1187 }
1188 for(;;) {
1189 rtn = file.getBuffer(buffer, sizeof(buffer));
1190 if(!rtn)
1191 break;
1192 if(rtn < 0) {
1193 remove(target);
1194 shell::errexit(6, "*** audiotool: %s: %s\n",
1195 fname(fn), _TEXT("read failed"));
1196 }
1197 rtn = tmp.putBuffer(buffer, rtn);
1198 if(rtn < 1) {
1199 remove(target);
1200 shell::errexit(6, "*** audiotool: %s: %s\n",
1201 fname(fn), _TEXT("write failed"));
1202 }
1203 }
1204 file.close();
1205 tmp.close();
1206 rtn = rename(target, fn);
1207 remove(target);
1208 delfile = NULL;
1209 if(rtn) {
1210 shell::errexit(6, "*** audiotool: %s: %s\n",
1211 fname(fn), _TEXT("could not replace"));
1212 }
1213
1214 exit(0);
1215 }
1216
build(char ** argv)1217 static void build(char **argv)
1218 {
1219 AudioBuild input;
1220 AudioStream output;
1221 Audio::Info info, make;
1222 const char *target = NULL;
1223 char *option;
1224 char *encoding = NULL;
1225 Audio::Rate rate = Audio::rateUnknown;
1226
1227 retry:
1228 if(!*argv) {
1229 shell::errexit(2, "*** audiotool: -build: %s\n",
1230 _TEXT("missing arguments"));
1231 }
1232
1233 option = *argv;
1234 if(eq("--", option)) {
1235 ++argv;
1236 goto skip;
1237 }
1238
1239 if(eq("--", option, 2))
1240 ++option;
1241
1242 if(eq(option, "-encoding=", 10)) {
1243 encoding = option + 10;
1244 ++argv;
1245 goto retry;
1246 }
1247
1248 if(eq(option, "-rate=", 6)) {
1249 rate = (Audio::Rate)atol(option + 6);
1250 ++argv;
1251 goto retry;
1252 }
1253
1254 if(eq(option, "-encoding")) {
1255 ++argv;
1256 if(!*argv) {
1257 shell::errexit(3, "*** audiotool: -build: -encoding: %s\n",
1258 _TEXT("missing argument"));
1259 }
1260 encoding = *(argv++);
1261 goto retry;
1262 }
1263
1264 if(eq(option, "-rate")) {
1265 ++argv;
1266 if(!*argv) {
1267 shell::errexit(3, "*** audiotool: -build: -rate: %s\n",
1268 _TEXT("missing argument"));
1269 }
1270 rate = (Audio::Rate)atol(*(argv++));
1271 goto retry;
1272 }
1273
1274 skip:
1275 if(*argv && **argv == '-') {
1276 shell::errexit(2, "*** auditool: -build: %s: %s\n",
1277 *argv, _TEXT("unknown option"));
1278 }
1279
1280 if(*argv)
1281 target = *(argv++);
1282
1283 if(!*argv) {
1284 shell::errexit(4, "*** audiotool: -build: %s\n",
1285 _TEXT("no files specified"));
1286 }
1287
1288 input.open(argv);
1289 if(!input.is_open()) {
1290 shell::errexit(4, "*** audiotool: %s: %s\n",
1291 *argv, _TEXT("cannot access"));
1292 }
1293 input.getInfo(&info);
1294 input.getInfo(&make);
1295 if(target)
1296 remove(target);
1297 if(encoding)
1298 make.encoding = Audio::getEncoding(encoding);
1299
1300 if(rate != Audio::rateUnknown)
1301 make.setRate(rate);
1302
1303 if(target)
1304 output.create(target, &make, false, 10);
1305 if(!output.is_open()) {
1306 shell::errexit(5, "*** audiotool: %s: %s\n",
1307 target, _TEXT("cannot create"));
1308 }
1309 output.getInfo(&make);
1310
1311 if(make.encoding == info.encoding && make.rate == info.rate)
1312 AudioBuild::copyDirect(input, output);
1313 else {
1314 if(!input.is_streamable()) {
1315 remove(target);
1316 shell::errexit(6, "*** audiotool: %s: %s\n",
1317 *argv, _TEXT("cannot load codec"));
1318 }
1319 if(!output.is_streamable()) {
1320 remove(target);
1321 shell::errexit(6, "*** audiotool: %s: %s\n",
1322 target, _TEXT("cannot load codec"));
1323 }
1324 AudioBuild::copyConvert(input, output);
1325 }
1326 input.close();
1327 output.close();
1328 exit(0);
1329 }
1330
append(char ** argv)1331 static void append(char **argv)
1332 {
1333 AudioBuild input;
1334 AudioStream output;
1335 Audio::Info info, make;
1336 const char *target = NULL;
1337 char *option;
1338 char *offset = NULL;
1339
1340 retry:
1341 option = *argv;
1342
1343 if(eq("--", option)) {
1344 ++argv;
1345 goto skip;
1346 }
1347
1348 if(eq("--", option, 2))
1349 ++option;
1350
1351 if(eq(option, "-offset=", 8)) {
1352 offset = option + 8;
1353 ++argv;
1354 goto retry;
1355 }
1356
1357 if(eq(option, "-offset")) {
1358 ++argv;
1359 if(!*argv) {
1360 shell::errexit(3, "*** audiotool: -append: -offset: %s\n",
1361 _TEXT("missing argument"));
1362 exit(-1);
1363 }
1364 offset = *(argv++);
1365 goto retry;
1366 }
1367
1368 skip:
1369 if(*argv && **argv == '-') {
1370 shell::errexit(2, "*** auditool: -append: %s: %s\n",
1371 *argv, _TEXT("unknown option"));
1372 }
1373
1374 if(*argv)
1375 target = *(argv++);
1376
1377 if(!*argv) {
1378 shell::errexit(4, "*** audiotool: -append: %s\n",
1379 _TEXT("no files specified"));
1380 }
1381
1382 input.open(argv);
1383 if(!input.is_open()) {
1384 shell::errexit(4, "*** audiotool: %s: %s\n",
1385 *argv, _TEXT("cannot access"));
1386 }
1387 input.getInfo(&info);
1388 output.open(target, Audio::modeWrite, 10);
1389 if(!output.is_open()) {
1390 shell::errexit(4, "*** audiotool: %s: %s\n",
1391 target, _TEXT("cannot access"));
1392 }
1393 output.getInfo(&make);
1394
1395 if(offset)
1396 output.setPosition(atol(offset));
1397 else
1398 output.setPosition();
1399
1400 if(make.encoding == info.encoding)
1401 AudioBuild::copyDirect(input, output);
1402 else {
1403 if(!input.is_streamable()) {
1404 shell::errexit(6, "*** audiotool: %s: %s\n",
1405 *argv, _TEXT("cannot load codec"));
1406 }
1407 if(!output.is_streamable()) {
1408 shell::errexit(6, "*** audiotool: %s: %s\n",
1409 target, _TEXT("cannot load codec"));
1410 }
1411 AudioBuild::copyConvert(input, output);
1412 }
1413 input.close();
1414 output.close();
1415 exit(0);
1416 }
1417
PROGRAM_MAIN(argc,argv)1418 PROGRAM_MAIN(argc, argv)
1419 {
1420 char *cp;
1421
1422 if(argc < 2) {
1423 shell::errexit(1, "%s\n",
1424 _TEXT("use: audiotool -command [-options...] [args...]"));
1425 }
1426 ++argv;
1427 cp = *argv;
1428 while(*cp == '-')
1429 ++cp;
1430
1431 shell::exiting(stop);
1432 Audio::init();
1433
1434 if(eq(cp, "version"))
1435 version();
1436 else if(eq(cp, "endian"))
1437 showendian();
1438 else if(eq(cp, "soundcard")) {
1439 if(*(++argv))
1440 soundcard(atoi(*argv));
1441 else
1442 soundcard(0);
1443 }
1444 else if(eq(cp, "build"))
1445 build(++argv);
1446 else if(eq(cp, "append"))
1447 append(++argv);
1448 else if(eq(cp, "chart"))
1449 chart(++argv);
1450 else if(eq(cp, "info"))
1451 info(++argv);
1452 else if(eq(cp, "note") || eq(cp, "annotate") || eq(cp, "notation"))
1453 note(++argv);
1454 else if(eq(cp, "packets") || eq(cp, "dump") || eq(cp, "packetdump"))
1455 packetdump(++argv);
1456 else if(eq(cp, "play"))
1457 play(++argv);
1458 else if(eq(cp, "strip"))
1459 strip(++argv);
1460 else if(eq(cp, "trim"))
1461 trim(++argv);
1462 else if(eq(cp, "size"))
1463 size(++argv);
1464 else if(eq(cp, "codecs"))
1465 codecs();
1466 else if(eq(cp, "plugins"))
1467 plugins();
1468
1469 shell::errexit(2, "*** audiotool: %s: %s\n",
1470 *argv, _TEXT("unknown option"));
1471 PROGRAM_EXIT(0);
1472 }
1473