2
This is ecalength, a few lines of code pompously named so because they
3
let one retrieve the length of an audio file from the command line
4
using ecasound's engine.
7
- It will only work correctly if the audio file is at a sampling rate
8
of 44100 hz, unless the file is a wave file; for other formats such
9
as .au, .raw and .cdr that have a sr other than 44100 the format needs
10
to be specified with the -a switch.
11
NOTE: mp3 files do have sr information in their headers but
12
unfortunately ecasound currently seems unable to parse this information
14
- It is not foolproof, feeding it with something other than an audio
15
file WILL result in ugly things being spewed back.
17
- A thousand more that I haven't thought of.
19
Please post back any improvement you make; I can be reached at:
22
note: Compile it with:
23
gcc -Wall -o ecalength ecalength.c `libecasoundc-config --cflags --libs`
25
* updated: Thu May 10 15:56:18 EDT 2001
26
- Now works with the new ai/ao scheme.
27
- Switches implemented, made suitable for scripting.
28
- Format querying/setting.
29
- Better error handling.
30
* updated: Wed Nov 14 23:26:19 EST 2001
31
- New option -su lets us return the file's length in samples.
32
(This breaks compatibility with stable series.)
33
- Reworked the comment above to say that basically only wave files are able
35
- Started to wondered whether my nice options structure isn't a bit too
36
unobvious for anyone else than me. (???)
37
- Help screen's getting a bit long, I have to scrollback to see the error
38
message. (???) (addressed)
39
* updated: Thu Nov 15 11:51:35 EST 2001
40
- Tried to format the code a bit better however hopeless it looks, tried to
42
- Tried to catch wrong switches a bit better.
43
- Only print full help message when no other message is being spewed.
44
* updated: Sun Jan 6 14:37:02 EST 2002
45
- Woo! Ecasound's internals now support quoting, had to take advantage of this.
46
* updated: Mon Apr 29 02:41:13 EEST 2002
47
- Renamed to ecalength.cpp to avoid troubles with linking ecalength
48
against uninstalled libecasoundc.
49
* updated: Thu Oct 31 17:41:05 EET 2002
50
- Renamed to ecalength.c. Updated the compilation instructions.
56
#include <stdlib.h> /* exit() */
58
#include "ecasoundc.h"
63
void make_human(int length, unsigned int *min, unsigned char *sec);
64
void print_help(char* name);
65
void print_usage(char* name);
79
int main(int argc, char *argv[]) {
80
char cmd[512], fstring[16], status = 0, *optstr = "ftsmhbcra:u";
83
float curfilelength, totlength = 0;
84
unsigned int min, curarg;
88
/* No surprises please */
99
/* Now let's parse and set. */
100
while ((curopt = getopt(argc, argv, optstr)) != -1) {
102
case 'a' : opts.adjust = TRUE;
103
strcpy(fstring, optarg);
105
case 'f' : opts.format = TRUE;
107
case 't' : opts.total = TRUE;
109
case 's' : opts.script = TRUE;
111
case 'm' : opts.human = TRUE;
113
case 'b' : opts.bits = TRUE;
115
case 'c' : opts.ccount = TRUE;
117
case 'r' : opts.rate = TRUE;
119
case 'u' : opts.samples = TRUE;
121
case 'h' : print_help(argv[0]);
123
case '?' : print_usage(argv[0]);
129
if (argc-optind == 0) {
134
/* Well, let's not just shut up if options are out of context, let's whine
135
* about it a bit so that people know why they're not getting what they
138
/* If not in script mode then we should check and make sure that we warn
139
* if script options have been set. I assume it's fine to spit to stdout
141
/* Local string where we store naughty switches. */
142
char badopts[10] = "\0";
145
if (opts.format) { strcat(badopts, "f"); }
146
if (opts.bits) { strcat(badopts, "b"); }
147
if (opts.ccount) { strcat(badopts, "c"); }
148
if (opts.rate) { strcat(badopts, "r"); }
149
if (opts.human) { strcat(badopts, "m"); }
150
if (opts.samples) { strcat(badopts, "u"); }
151
if (strlen(badopts)) {
152
printf("-%s :: Out of context options will be ignored.\n",
156
/* Now, if we're in script mode we want to make sure of a few things,
157
* we also want to warn on stderr, of course. */
158
char badopts[20] = "\0";
160
/* The whole format thing is a bit complex so I guess we want to help
163
if (opts.bits) { strcat(badopts, "b"); }
164
if (opts.ccount) { strcat(badopts, "c"); }
165
if (opts.rate) { strcat(badopts, "r"); }
166
if (strlen(badopts) == 1) {
167
fprintf(stderr, "You can't specify -%s just like that, you need to enter format mode with -f.\n", badopts);
169
if (strlen(badopts) > 1) {
170
fprintf(stderr, "Look out, you're not in format mode and you have more than one format specifier anyway: just use the -h switch for now.\n");
174
/* Catch-all piece of logic to filter errors. */
175
if ((opts.script) && (((opts.format) && (opts.human)) || ((opts.format)
176
&& (((opts.bits) && ((opts.ccount) ||
178
((opts.ccount) && (opts.rate)))) ||
179
(opts.samples && (opts.format || opts.human)))) {
180
fprintf(stderr, "Error: In script mode not more than one further mode can be specified.\n");
181
print_usage(argv[0]);
186
/* Setting things up. */
188
eci_command("cs-add main");
189
eci_command("c-add main");
190
eci_command("ao-add null");
192
/* Setting the format if needed. */
194
if (strncmp(":", fstring, 1) == 0) { sprintf(cmd, "cs-set-audio-format %s", fstring+1); }
195
else { sprintf(cmd, "cs-set-audio-format %s", fstring); }
197
if (strlen(eci_last_error()) != 0) {
198
fprintf(stderr, "Argument to -a is badly formatted.\n");
199
print_usage(argv[0]);
206
/* The real thing. */
207
while(curarg < argc) {
208
if ((file = fopen(argv[curarg], "r")) != NULL) {
210
sprintf(cmd, "ai-add \"%s\"", argv[curarg]);
212
eci_command("cs-connect");
213
if (strlen(eci_last_error()) == 0) {
214
sprintf(cmd, "ai-select \"%s\"", argv[curarg]);
216
eci_command("ai-get-length");
217
curfilelength = eci_last_float();
219
eci_command("ai-get-format");
220
strcpy(fstring, eci_last_string());
223
/* We wanted to print the length in samples so we've done nothing
224
* all along; let's act now. */
225
if (opts.script && opts.samples) {
228
eci_command("ai-get-length-samples");
229
samplecount = eci_last_long_integer();
230
printf("%li", samplecount);
233
/* Here cometh the cleansing. */
234
eci_command("cs-disconnect");
235
eci_command("ai-remove");
237
/* Need we humanize ourselves? */
238
if (!(opts.script) || ((opts.script && opts.human))) {
239
make_human((int)(curfilelength+0.5), &min, &sec);
242
if (!(opts.script)) { printf("%s: ", argv[curarg]); }
243
if (!(opts.script) ||
244
((opts.script) && (!(opts.format) && !(opts.human) &&
246
printf("%.3f", curfilelength);
248
if (!(opts.script)) { printf("s \t("); }
249
if (!(opts.script) || ((opts.script) && (opts.human))) {
250
printf("%im%is", min, sec);
252
if (!(opts.script)) { printf(")"); }
254
!((opts.format) && ((opts.bits) || (opts.ccount) || (opts.rate)))) {
255
if (!(opts.script)) { printf(" \t"); }
256
printf("%s", fstring);
259
if ((opts.format) && (opts.script) && (opts.bits)) {
260
printf("%s", strtok(fstring+1, "_"));
263
if ((opts.script) && (opts.format) && (opts.ccount)) {
264
strtok(fstring, ",");
265
printf("%s", strtok(NULL, ","));
268
if ((opts.format) && (opts.script) && (opts.rate)) {
269
strtok(fstring, ",");
271
printf("%s", strtok(NULL, ","));
276
if ((opts.total) && !(opts.script)) {
277
totlength += curfilelength;
281
if (opts.script) { printf("-2\n"); }
282
else { printf("%s: Read error.\n", argv[curarg]); }
284
eci_command("ai-remove");
288
if (opts.script) { printf("-1\n"); }
289
else { printf("%s: fopen error.\n", argv[curarg]); }
295
if ((opts.total) && !(opts.script)) {
296
/* This could be made a script option as well, does anyone care? */
297
make_human((int)(totlength+0.5), &min, &sec);
298
printf("Total: %.3fs \t\t(%im%is)\n", totlength, min, sec);
301
eci_command("cs-remove");
306
void make_human(int length, unsigned int *min, unsigned char *sec) {
308
*sec = (length % 60);
311
void print_help(char *name) {
312
printf("Usage: %s [-ahtsfmbcru] FILE1 [FILE2] [FILEn]\n "
313
"\t-h Prints this usage message. (help)\n"
314
"\t-a[:]bits,channels,rate Changes the format assumed by default \n"
315
"\t for headerless data. (adjust)\n"
316
"\t-t Prints the summed length of all the files processed. (total)\n"
317
"\t (Ignored if with -s) \n"
318
"\t-s Enables script mode: One info type per file per line. (script)\n"
319
"\t (Defaults to length in secs.) \n"
320
"\t-f With -s will return the format string as info, alone it will \n"
321
"\t add it to the main display. (format)\n"
322
"\t -b If -s and -f are enabled with this the info printed will be \n"
323
"\t the sample's bitwidth. (bits)\n"
324
"\t -c If -s and -f are enabled with this the info printed will be \n"
325
"\t the channel count. (channel count)\n"
326
"\t -r If -s and -f are enabled with this the info printed will be \n"
327
"\t the sampling rate. (rate)\n"
328
"\t-m Will print human computable time as in main display but in \n"
329
"\t batch fashion. (minutes)\n"
330
"\t (Only with -s)\n"
331
"\t-u This batchmode option returns the length of specified files \n"
332
"\t in samples. (Smallest Unit)\n"
333
"\t (This information is worthless if you don't know the sampling \n"
334
"\t rate of the file.) (Only with -s)\n"
335
"(Note that out of context options will be ignored.)\n\n", name);
338
void print_usage(char *name) {
339
printf("Usage: %s [-ahtsfmbcru] FILE1 [FILE2] [FILEn]\n\n\t Use the -h switch for help or see the man page.\n\n", name);