22 using namespace UCOMMON_NAMESPACE;
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
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;
55 const char *getContinuation(
void);
59 void open(
char **argv);
70 const char *getContinuation(
void);
74 void open(
char **argv);
84 const char *out = Env::path(rules, *(argv++), pathbuf,
sizeof(pathbuf));
86 AudioStream::open(out, modeRead, 10);
91 const char *PacketStream::getContinuation(
void)
96 return Env::path(rules, *(list++), pathbuf,
sizeof(pathbuf));
107 const char *out = Env::path(rules, *(argv++), pathbuf,
sizeof(pathbuf));
109 AudioStream::open(out, modeRead, 10);
114 const char *AudioBuild::getContinuation(
void)
119 return Env::path(rules, *(list++), pathbuf,
sizeof(pathbuf));
124 unsigned long samples, copied;
125 linear_t buffer, source;
129 Audio::resample *resampler = NULL;
130 linear_t resample = NULL;
135 if(is_stereo(from.encoding) || is_stereo(to.encoding))
138 samples = input.getCount();
142 buffer =
new Audio::sample_t[samples];
144 buffer =
new Audio::sample_t[samples * 2];
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)];
157 pages = input.getMono(buffer, 1);
159 pages = input.getStereo(buffer, 1);
165 copied = resampler->process(buffer, resample, samples);
170 output.bufMono(source, copied);
172 output.bufStereo(source, copied);
201 bufsize = from.framesize;
202 buffer =
new unsigned char[bufsize];
205 status = input.getNative(buffer, bufsize);
209 status = output.putNative(buffer, status);
215 static void stop(
void)
223 static void codecs(
void)
225 linked_pointer<AudioCodec> cp = AudioCodec::begin();
228 printf(
"%s - %s\n", cp->getName(), cp->getDescription());
234 static void version(
void)
236 printf(
"%s\n", VERSION);
240 static void showendian(
void)
243 printf(
"%s\n", _TEXT(
"big"));
245 printf(
"%s\n", _TEXT(
"little"));
249 static const char *fname(
const char *cp)
251 const char *fn = strrchr(cp,
'/');
253 fn = strrchr(cp,
'\\');
259 static void rewrite(
const char *source,
char *target,
size_t max)
266 snprintf(buffer,
sizeof(buffer),
"%s", source);
267 while(NULL != (fn = strchr(buffer,
'\\')))
270 fn = strrchr(buffer,
'/');
273 ext = strrchr(fn,
'.');
276 snprintf(target, max,
"%s/%s.tmp", buffer, fn);
279 ext = strrchr(buffer,
'.');
282 snprintf(target, max,
"%s.tmp", buffer);
285 snprintf(buffer,
sizeof(buffer),
"%s", source);
286 fn = strrchr(buffer,
'/');
289 snprintf(target, max,
"%s/.tmp.%s", buffer, fn);
292 snprintf(target, max,
".tmp.%s", source);
296 static void chart(
char **argv)
301 Audio::level_t silence = (Audio::level_t)*silent;
302 unsigned char *buffer;
309 shell::errexit(2,
"*** audiotool: -chart: %s\n",
310 _TEXT(
"missing arguments"));
314 const char *out = Env::path(rules, *argv, pathbuf,
sizeof(pathbuf));
315 if(!out || !fsys::isfile(out)) {
317 fname(*(argv++)), _TEXT(
"invalid"));
320 if(fsys::access(out, R_OK)) {
322 fname(*(argv++)), _TEXT(
"inaccessable"));
325 file.open(out, Audio::modeRead, *framing);
327 if(!Audio::is_linear(info.encoding))
328 codec = AudioCodec::get(info);
329 if(!Audio::is_linear(info.encoding) && !codec) {
331 fname(*(argv++)), _TEXT(
"cannot load codec"));
335 printf(
"%s: ", fname(*(argv++)));
336 buffer =
new unsigned char[info.framesize];
345 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
349 sum += codec->impulse(buffer, info.framecount);
351 sum += Audio::impulse(info, buffer, info.framecount);
354 if(!silence && count)
355 silence = (Audio::level_t)(((sum / count) * 2) / 3);
364 if(file.getBuffer(buffer, info.framesize) < (int)info.framesize)
368 current = codec->peak(buffer, info.framecount);
371 sum += codec->impulse(buffer, info.framecount);
372 if(codec->is_silent(silence, buffer, info.framecount)) {
373 if(codec->peak(buffer, info.framecount) >= silence)
384 current = Audio::peak(info, buffer, info.framecount);
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)
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);
411 AudioCodec::release(codec);
421 static void info(
char **argv)
427 unsigned long minutes, seconds, subsec, scale;
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"));
437 if(fsys::access(out, R_OK)) {
438 printf(
"audiotool: %s: %s\n",
439 fname(*(argv++)), _TEXT(
"inaccessable"));
442 au.open(out, Audio::modeInfo, *framing);
445 end = au.getPosition();
446 printf(
"%s\n", fname(*(argv++)));
447 fn = Audio::getMIME(info);
449 switch(info.format) {
466 printf(
" %s: %s\n", _TEXT(
"Format"), fn);
468 printf(
" %s: %s\n", _TEXT(
"Format"), _TEXT(
"unknown"));
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"));
474 printf(
" %s: 1\n", _TEXT(
"Channels"));
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"));
483 printf(
" %s: %s\n", _TEXT(
"Byte Order"), _TEXT(
"native"));
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);
489 scale = info.rate / 1000;
491 subsec = (end % info.rate) / scale;
498 printf(
" %s %02ld:%02ld:%02ld.%03ld\n",
499 _TEXT(
"Duration"), end, minutes, seconds, subsec);
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);;
513 static void strip(
char **argv)
518 short silence = (short)(*silent);
520 unsigned char *buffer;
521 Audio::level_t max, current;
528 shell::errexit(2,
"*** audiotool: -strip: %s\n",
529 _TEXT(
"missing arguments"));
533 const char *out = Env::path(rules, *argv, source,
sizeof(source));
534 if(!out || !fsys::isfile(out)) {
536 *(argv++), _TEXT(
"invalid"));
539 if(fsys::access(out, R_OK)) {
541 *(argv++), _TEXT(
"inaccessable"));
544 rewrite(out, target,
sizeof(target));
546 file.open(out, Audio::modeRead, *framing);
548 if(!Audio::is_linear(info.encoding))
549 codec = AudioCodec::get(info);
550 if(!Audio::is_linear(info.encoding) && !codec) {
552 *(argv++), _TEXT(
"cannot load codec"));
556 buffer =
new unsigned char[info.framesize];
565 rtn = file.getBuffer(buffer, info.framesize);
566 if(rtn < (
int)info.framesize)
570 sum += codec->impulse(buffer, info.framecount);
572 sum += Audio::impulse(info, buffer, info.framecount);
575 if(!silence && count)
576 silence = (Audio::level_t)(((sum / count) * 2) / 3);
585 tmp.create(target, info);
588 *(argv++), _TEXT(
"cannot rewrite"));
594 rtn = file.getBuffer(buffer, info.framesize);
595 if(rtn < (
int)info.framesize)
599 if(codec->is_silent(silence, buffer, info.framecount)) {
600 if(codec->peak(buffer, info.framecount) >= silence)
601 tmp.putBuffer(buffer, info.framesize);
604 tmp.putBuffer(buffer, info.framesize);
608 current = Audio::peak(info, buffer, info.framecount);
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);
618 tmp.putBuffer(buffer, info.framecount);
624 AudioCodec::release(codec);
632 rtn = rename(target, out);
638 *argv, _TEXT(
"could not be replaced"));
645 static void trim(
char **argv)
648 unsigned long first = 0, last = 0, total = 0, padding = *pad;
651 Audio::level_t silence = (Audio::level_t)(*silent);
653 unsigned char *buffer;
654 Audio::linear_t samples = NULL;
662 shell::errexit(2,
"*** audiotool: -trim: %s\n",
663 _TEXT(
"missing arguments"));
668 const char *out = Env::path(rules, *argv, source,
sizeof(source));
669 if(!out || !fsys::isfile(out)) {
671 *(argv++), _TEXT(
"invalid"));
674 if(fsys::access(out, R_OK)) {
676 *(argv++), _TEXT(
"inaccessable"));
679 rewrite(out, target,
sizeof(target));
681 file.open(out, Audio::modeRead, *framing);
683 if(!Audio::is_linear(info.encoding))
684 codec = AudioCodec::get(info);
685 if(!Audio::is_linear(info.encoding) && !codec) {
687 *(argv++), _TEXT(
"cannot load codec"));
691 buffer =
new unsigned char[info.framesize];
699 rtn = file.getBuffer(buffer, info.framesize);
700 if(rtn < (
int)info.framesize)
704 sum += codec->impulse(buffer, info.framecount);
706 sum += Audio::impulse(info, buffer, info.framecount);
709 if(!silence && count)
710 silence = (Audio::level_t)(((sum / count) * 2) / 3);
719 rtn = file.getBuffer(buffer, info.framesize);
720 if(rtn < (
int)info.framesize)
725 if(codec->is_silent(silence, buffer, info.framecount)) {
727 if(codec->peak(buffer, info.framecount) >= silence)
739 if(!last || !first) {
741 *(argv++), _TEXT(
"all silent, skipping"));
746 total = last - first;
747 file.setPosition(first * info.framecount);
749 tmp.create(target, info);
752 *(argv++), _TEXT(
"cannot rewrite"));
757 rtn = file.getBuffer(buffer, info.framesize);
758 if(rtn < (
int)info.framesize)
760 tmp.putBuffer(buffer, info.framesize);
765 memset(buffer, 0, info.framesize);
766 else if(Audio::is_stereo(info.encoding))
768 samples =
new Audio::sample_t[info.framecount * 2];
769 memset(samples, 0, info.framecount * 2);
770 codec->encode(samples, buffer, info.framecount);
773 samples =
new Audio::sample_t[info.framecount];
774 memset(samples, 0, info.framecount);
775 codec->encode(samples, buffer, info.framecount);
780 rtn = tmp.putBuffer(buffer, info.framesize);
790 AudioCodec::release(codec);
798 rtn = rename(target, out);
804 *argv, _TEXT(
"could not be replaced"));
811 static void size(
char **argv)
813 char *fn = *(argv++);
820 shell::errexit(2,
"*** audiotool: -size: %s\n",
821 _TEXT(
"no file specified"));
824 const char *out = Env::path(rules, fn, pathbuf,
sizeof(pathbuf));
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"));
833 pos = file.getPosition();
835 printf(
"%ld\n", pos);
839 static void packetdump(
char **argv)
842 const char *path = *argv;
843 Audio::encoded_t buffer;
847 packetfile.
open(argv);
849 if(!packetfile.is_open()) {
850 shell::errexit(2,
"*** audiotool: %s: %s\n",
851 fname(path), _TEXT(
"cannot access"));
854 if(!packetfile.is_streamable()) {
855 shell::errexit(2,
"*** audiotool: %s: %s\n",
856 fname(path), _TEXT(
"missing codec needed"));
859 packetfile.getInfo(info);
861 buffer =
new unsigned char[Audio::maxFramesize(info)];
863 while((count = packetfile.getPacket(buffer)) > 0)
864 printf(
"-- %ld\n", (
long)count);
871 static void note(
char **argv)
873 char *fn = *(argv++);
879 unsigned char buffer[4096];
883 shell::errexit(2,
"*** audiotool: -notation: %s\n",
884 _TEXT(
"no file specified"));
889 const char *out = Env::path(rules, fn, source,
sizeof(source));
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"));
897 if(info.annotation && !ann)
898 printf(
"%s\n", info.annotation);
901 rewrite(out, target,
sizeof(target));
902 info.annotation = ann;
905 tmp.create(target, info);
907 shell::errexit(5,
"*** audiotool: %s: %s\n",
908 fname(target), _TEXT(
"unable to create"));
911 rtn = file.getBuffer(buffer,
sizeof(buffer));
916 shell::errexit(6,
"*** audiotool: %s: %s\n",
917 fname(fn), _TEXT(
"read failed"));
919 rtn = tmp.putBuffer(buffer, rtn);
922 shell::errexit(6,
"*** audiotool: %s: %s\n",
923 fname(fn), _TEXT(
"write failed"));
928 rtn = rename(target, out);
932 shell::errexit(6,
"*** audiotool: %s: %s\n",
933 fname(fn), _TEXT(
"could not replace"));
939 static void build(
char **argv)
943 Audio::info_t info, make;
945 const char *encoding = *encopt;
946 Audio::rate_t rate = (Audio::rate_t)(*rateopt);
950 shell::errexit(2,
"*** audiotool: -build: %s\n",
951 _TEXT(
"missing arguments"));
954 if(*argv && **argv ==
'-') {
955 shell::errexit(2,
"*** auditool: -build: %s: %s\n",
956 *argv, _TEXT(
"unknown option"));
960 target = Env::path(rules, *(argv++), pathbuf,
sizeof(pathbuf));
963 shell::errexit(4,
"*** audiotool: -build: %s\n",
964 _TEXT(
"no files specified"));
969 shell::errexit(4,
"*** audiotool: -build: %s\n",
970 _TEXT(
"no files specified"));
974 if(!input.is_open()) {
975 shell::errexit(4,
"*** audiotool: %s: %s\n",
976 *argv, _TEXT(
"cannot access"));
982 make.encoding = Audio::getEncoding(encoding);
984 if(rate != Audio::rateUnknown)
987 output.create(target, make, 10);
988 if(!output.is_open()) {
989 shell::errexit(5,
"*** audiotool: %s: %s\n",
990 target, _TEXT(
"cannot create"));
992 output.getInfo(make);
994 if(make.encoding == info.encoding && make.rate == info.rate)
997 if(!input.is_streamable()) {
999 shell::errexit(6,
"*** audiotool: %s: %s\n",
1000 *argv, _TEXT(
"cannot load codec"));
1002 if(!output.is_streamable()) {
1004 shell::errexit(6,
"*** audiotool: %s: %s\n",
1005 target, _TEXT(
"cannot load codec"));
1014 static void append(
char **argv)
1018 Audio::Info info, make;
1021 char *offset = NULL;
1027 if(eq(
"--", option)) {
1032 if(eq(
"--", option, 2))
1035 if(eq(option,
"-offset=", 8)) {
1036 offset = option + 8;
1041 if(eq(option,
"-offset")) {
1044 shell::errexit(3,
"*** audiotool: -append: -offset: %s\n",
1045 _TEXT(
"missing argument"));
1053 if(*argv && **argv ==
'-') {
1054 shell::errexit(2,
"*** auditool: -append: %s: %s\n",
1055 *argv, _TEXT(
"unknown option"));
1059 target = Env::path(rules, *(argv++), pathbuf,
sizeof(pathbuf));
1062 shell::errexit(4,
"*** audiotool: -build: %s\n",
1063 _TEXT(
"no files specified"));
1068 shell::errexit(4,
"*** audiotool: -append: %s\n",
1069 _TEXT(
"no files specified"));
1073 if(!input.is_open()) {
1074 shell::errexit(4,
"*** audiotool: %s: %s\n",
1075 *argv, _TEXT(
"cannot access"));
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"));
1083 output.getInfo(make);
1086 output.setPosition(atol(offset));
1088 output.setPosition();
1090 if(make.encoding == info.encoding)
1093 if(!input.is_streamable()) {
1094 shell::errexit(6,
"*** audiotool: %s: %s\n",
1095 *argv, _TEXT(
"cannot load codec"));
1097 if(!output.is_streamable()) {
1098 shell::errexit(6,
"*** audiotool: %s: %s\n",
1099 target, _TEXT(
"cannot load codec"));
1110 shell::bind(
"audiotool");
1111 shell args(argc, argv);
1115 rules.voices = *voice;
1118 Env::set(
"prefix", *prefix);
1121 Env::set(
"voices", *phrasebook);
1124 Env::set(
"extension", *suffix);
1127 rules.book = Phrasebook::find(*lang);
1129 rules.book = Phrasebook::find(NULL);
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:"));
1136 printf(
"\n%s\n", _TEXT(
"Report bugs to dyfet@gnu.org"));
1141 shell::errexit(1,
"*** audiotool: %s\n",
1142 _TEXT(
"no command specified"));
1144 const char *cp = args[0];
1149 shell::exiting(stop);
1151 if(eq(cp,
"version"))
1153 else if(eq(cp,
"endian"))
1155 else if(eq(cp,
"build"))
1157 else if(eq(cp,
"append"))
1159 else if(eq(cp,
"chart"))
1161 else if(eq(cp,
"info"))
1163 else if(eq(cp,
"note") || eq(cp,
"annotate") || eq(cp,
"notation"))
1165 else if(eq(cp,
"packets") || eq(cp,
"dump") || eq(cp,
"packetdump"))
1167 else if(eq(cp,
"strip"))
1169 else if(eq(cp,
"trim"))
1171 else if(eq(cp,
"size"))
1173 else if(eq(cp,
"codecs"))
1176 shell::errexit(2,
"*** audiotool: %s: %s\n",
1177 cp, _TEXT(
"unknown option"));
static void copyConvert(AudioStream &input, AudioStream &output)
#define BAYONNE_NAMESPACE
static void copyDirect(AudioStream &input, AudioStream &output)
GNU Bayonne library namespace.