~ubuntu-branches/ubuntu/hardy/ecasound2.2/hardy

« back to all changes in this revision

Viewing changes to ecatools/ecalength.c

  • Committer: Bazaar Package Importer
  • Author(s): Junichi Uekawa
  • Date: 2005-04-14 09:15:48 UTC
  • Revision ID: james.westby@ubuntu.com-20050414091548-o7kgb47z0tcunh0s
Tags: upstream-2.4.1
ImportĀ upstreamĀ versionĀ 2.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*   
 
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.  
 
5
 
 
6
    Limitations:  
 
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 
 
13
      correctly. :(
 
14
    - It is not foolproof, feeding it with something other than an audio  
 
15
    file WILL result in ugly things being spewed back.  
 
16
         (A bit better)
 
17
    - A thousand more that I haven't thought of.  
 
18
 
 
19
    Please post back any improvement you make; I can be reached at:  
 
20
    observer@colba.net  
 
21
 
 
22
    note: Compile it with:  
 
23
    gcc -Wall -o ecalength ecalength.c `libecasoundc-config --cflags --libs`
 
24
 
 
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 
 
34
  to self-adjust.
 
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 
 
41
  comment it a bit.
 
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.
 
51
*/ 
 
52
 
 
53
#include <stdio.h> 
 
54
#include <unistd.h> 
 
55
#include <string.h>
 
56
#include <stdlib.h> /* exit() */
 
57
 
 
58
#include "ecasoundc.h"
 
59
 
 
60
#define FALSE          0 
 
61
#define TRUE           1 
 
62
 
 
63
void make_human(int length, unsigned int *min, unsigned char *sec); 
 
64
void print_help(char* name); 
 
65
void print_usage(char* name);
 
66
 
 
67
struct options { 
 
68
  char adjust;
 
69
  char format; 
 
70
  char total; 
 
71
  char script; 
 
72
  char human;
 
73
  char bits;
 
74
  char ccount; 
 
75
  char rate;
 
76
  char samples;
 
77
};
 
78
 
 
79
int main(int argc, char *argv[]) { 
 
80
  char cmd[512], fstring[16], status = 0, *optstr = "ftsmhbcra:u"; 
 
81
  int curopt;
 
82
  unsigned char sec; 
 
83
  float curfilelength, totlength = 0; 
 
84
  unsigned int min, curarg; 
 
85
  FILE *file; 
 
86
  struct options opts; 
 
87
 
 
88
  /* No surprises please */
 
89
  opts.adjust = FALSE;
 
90
  opts.format = FALSE; 
 
91
  opts.total = FALSE; 
 
92
  opts.script = FALSE; 
 
93
  opts.human = FALSE; 
 
94
  opts.bits = FALSE;
 
95
  opts.ccount = FALSE;
 
96
  opts.rate = FALSE;
 
97
  opts.samples = FALSE;
 
98
 
 
99
  /* Now let's parse and set. */
 
100
  while ((curopt = getopt(argc, argv, optstr)) != -1) { 
 
101
    switch (curopt) { 
 
102
    case 'a' : opts.adjust = TRUE;
 
103
      strcpy(fstring, optarg);
 
104
      break;
 
105
    case 'f' : opts.format = TRUE; 
 
106
      break; 
 
107
    case 't' : opts.total = TRUE; 
 
108
      break; 
 
109
    case 's' : opts.script = TRUE; 
 
110
      break; 
 
111
    case 'm' : opts.human = TRUE; 
 
112
      break; 
 
113
    case 'b' : opts.bits = TRUE;
 
114
      break;
 
115
    case 'c' : opts.ccount = TRUE;
 
116
      break;
 
117
    case 'r' : opts.rate = TRUE;
 
118
      break;
 
119
    case 'u' : opts.samples = TRUE;
 
120
      break;
 
121
    case 'h' : print_help(argv[0]);
 
122
      exit(0);
 
123
    case '?' : print_usage(argv[0]);
 
124
      exit(1);
 
125
    } 
 
126
  } 
 
127
 
 
128
  /* No file? */
 
129
  if (argc-optind == 0) {
 
130
    print_help(argv[0]);
 
131
    exit(1);
 
132
  }
 
133
 
 
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 
 
136
   * expected. */
 
137
  if (!opts.script) {
 
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 
 
140
      * here. */ 
 
141
      /* Local string where we store naughty switches. */
 
142
      char badopts[10] = "\0";
 
143
      
 
144
      /* Off we go. */
 
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", 
 
153
                        badopts); 
 
154
      }
 
155
  } else {
 
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";
 
159
 
 
160
      /* The whole format thing is a bit complex so I guess we want to help 
 
161
       * out. */
 
162
      if (!opts.format) {
 
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);
 
168
         }
 
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");
 
171
         }
 
172
      }
 
173
 
 
174
      /* Catch-all piece of logic to filter errors. */
 
175
      if ((opts.script) && (((opts.format) && (opts.human)) || ((opts.format)
 
176
                                       && (((opts.bits) && ((opts.ccount) || 
 
177
                                                            (opts.rate))) ||
 
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]);
 
182
         exit(1);
 
183
      }
 
184
  }
 
185
 
 
186
  /* Setting things up. */
 
187
  eci_init(); 
 
188
  eci_command("cs-add main"); 
 
189
  eci_command("c-add main"); 
 
190
  eci_command("ao-add null"); 
 
191
 
 
192
  /* Setting the format if needed. */
 
193
  if (opts.adjust) {
 
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); }
 
196
    eci_command(cmd);
 
197
    if (strlen(eci_last_error()) != 0) {
 
198
      fprintf(stderr, "Argument to -a is badly formatted.\n");
 
199
      print_usage(argv[0]);
 
200
      exit(1);
 
201
    }
 
202
  }
 
203
 
 
204
  curarg = optind; 
 
205
 
 
206
  /* The real thing. */
 
207
  while(curarg < argc) { 
 
208
    if ((file = fopen(argv[curarg], "r")) != NULL) { 
 
209
      fclose(file); 
 
210
      sprintf(cmd, "ai-add \"%s\"", argv[curarg]); 
 
211
      eci_command(cmd); 
 
212
      eci_command("cs-connect"); 
 
213
      if (strlen(eci_last_error()) == 0) {
 
214
        sprintf(cmd, "ai-select \"%s\"", argv[curarg]); 
 
215
        eci_command(cmd); 
 
216
        eci_command("ai-get-length"); 
 
217
        curfilelength = eci_last_float(); 
 
218
        if (opts.format) { 
 
219
          eci_command("ai-get-format"); 
 
220
          strcpy(fstring, eci_last_string()); 
 
221
        } 
 
222
 
 
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) {
 
226
            long samplecount;
 
227
 
 
228
            eci_command("ai-get-length-samples");
 
229
            samplecount = eci_last_long_integer();
 
230
            printf("%li", samplecount);
 
231
        }
 
232
        
 
233
        /* Here cometh the cleansing. */
 
234
        eci_command("cs-disconnect"); 
 
235
        eci_command("ai-remove"); 
 
236
        
 
237
        /* Need we humanize ourselves? */
 
238
        if (!(opts.script) || ((opts.script && opts.human))) { 
 
239
          make_human((int)(curfilelength+0.5), &min, &sec); 
 
240
        } 
 
241
 
 
242
        if (!(opts.script)) { printf("%s: ", argv[curarg]); } 
 
243
        if (!(opts.script) ||  
 
244
            ((opts.script) && (!(opts.format) && !(opts.human) &&
 
245
                              !(opts.samples)))) { 
 
246
          printf("%.3f", curfilelength); 
 
247
        } 
 
248
        if (!(opts.script)) { printf("s   \t("); } 
 
249
        if (!(opts.script) || ((opts.script) && (opts.human))) { 
 
250
          printf("%im%is", min, sec); 
 
251
        } 
 
252
        if (!(opts.script)) { printf(")"); } 
 
253
        if ((opts.format) && 
 
254
            !((opts.format) && ((opts.bits) || (opts.ccount) || (opts.rate)))) { 
 
255
          if (!(opts.script)) { printf("   \t"); } 
 
256
          printf("%s", fstring); 
 
257
        } 
 
258
 
 
259
        if ((opts.format) && (opts.script) && (opts.bits)) { 
 
260
          printf("%s", strtok(fstring+1, "_")); 
 
261
        }
 
262
 
 
263
        if ((opts.script) && (opts.format) && (opts.ccount)) {
 
264
          strtok(fstring, ",");
 
265
          printf("%s", strtok(NULL, ","));
 
266
        }
 
267
 
 
268
        if ((opts.format) && (opts.script) && (opts.rate)) {
 
269
          strtok(fstring, ",");
 
270
          strtok(NULL, ",");
 
271
          printf("%s", strtok(NULL, ","));
 
272
        }
 
273
 
 
274
        printf("\n"); 
 
275
 
 
276
        if ((opts.total) && !(opts.script)) { 
 
277
          totlength += curfilelength; 
 
278
        } 
 
279
      }
 
280
          else {
 
281
            if (opts.script) { printf("-2\n"); }
 
282
            else { printf("%s: Read error.\n", argv[curarg]); }
 
283
            status = -2;
 
284
            eci_command("ai-remove");
 
285
          }
 
286
    } 
 
287
    else { 
 
288
      if (opts.script) { printf("-1\n"); }
 
289
      else { printf("%s: fopen error.\n", argv[curarg]); }
 
290
      status = -1;
 
291
    } 
 
292
    curarg++; 
 
293
  } 
 
294
 
 
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); 
 
299
  } 
 
300
 
 
301
  eci_command("cs-remove"); 
 
302
  eci_cleanup(); 
 
303
  exit(status); 
 
304
 
305
 
 
306
void make_human(int length, unsigned int *min, unsigned char *sec) { 
 
307
  *min = (length/60); 
 
308
  *sec = (length % 60); 
 
309
 
310
 
 
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);
 
336
}
 
337
 
 
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);
 
340
}